Commit Graph

21 Commits

Author SHA1 Message Date
Fraser Waters 3c9424ccc0
Fix lookup module deps with go.work files ()
<!--- 
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->

# Description

<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->

Fixes https://github.com/pulumi/pulumi/issues/15741.

`go list -m` returns all modules in a workspace if inside a Go
workspace. We only need the one module found in the Pulumi program
directory (or above it). So we set `GOWORK=off` before calling `go list
-m`.

## Checklist

- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
  - [x] I have formatted my code using `gofumpt`

<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!--- 
User-facing changes require a CHANGELOG entry.
-->
- [x] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-03-21 09:48:04 +00:00
Fraser Waters 941f3d0902
Clean up project usage ()
<!--- 
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->

# Description

<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->


The project field on `GetProgramDependenciesRequest` and
`GetRequiredPluginsRequest` was marked deprecated at the start of
December. None of the language runtimes are using this, so this cleans
up the engine side code so we don't need to thread a
`*workspace.Project` down to the plugin layer to fill in these fields
anymore.

I haven't fully removed them from the Protobuf structs yet, we probably
could but just to give a little more time for people to get a clear
usage error if still using it.

## Checklist

- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
  - [x] I have formatted my code using `gofumpt`

<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [ ] I have added tests that prove my fix is effective or that my
feature works
<!--- 
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-01-16 17:06:14 +00:00
Fraser Waters 6e986f90af
Pass root and main info to language host methods ()
<!--- 
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->

# Description

<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->

This is two changes rolled together in a way.

Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.

Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3;     // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.

`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).

These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).

The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).

## Checklist

- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
  - [ ] I have formatted my code using `gofumpt`

<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!--- 
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
Fraser Waters 0f4ddc2ccf
Use EqualError/ErrorContains instead of Error ()
<!--- 
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->

# Description

<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->

This is a pass over all of /sdk to replace asserts that just checked we
had an error with asserts for what the error value is.

Just checking for an error is a weak test that can result in error paths
being broken and tests not detecting it.
2023-12-08 06:40:14 +00:00
Abhinav Gupta a244de9092
fix(host/go): Download external plugins even if they're not imported
We previously changed how the Go language host retrieves information
about a Go module:

    before: go list -m -json -mod=mod all
    after:  go list -m -json $importPath1 $importPath1

This change made it possible for us to supprot running in vendored mode
which allowed for use of private plugins that are not go-get-able.

This uncovered a corner case in the `go` command's behavior
when running in module mode:

If a package is listed in the go.mod
but it's not imported by the current module,
`go list -m -json $importPath` will not list its Dir in the output
even if it's present in the module cache.
For example, given a go.mod file that declares a dependency
but code that doesn't import it, as of Go 1.20.5,

    export GOMODCACHE=$(mktemp -d)
    go mod download -json
    go list -m -json $importPath

The output of `go mod download` will include information
about the dependency and the `Dir` where it was downloaded,
but `go list -m` will not.

Unfortunately, we can't just use `go mod download`
because that breaks vendoring:
vendored dependencies cannot always be redownloaded.

To resolve this issue,
we switch to a two-pass variant to gather this information:

- Run `go list -m` to get whatever information we can locally.
  This will be sufficient for the majority of use cases.
- For the handful of cases where the dependency isn't imported,
  we'll use `go mod download -json` to download them on-demand
  and get their location from that instead.

The `go mod download` step will take place only if we're in module mode.
In vendor mode, we'll work with what we have.

Resolves 
2023-07-11 16:22:15 -07:00
Fraser Waters 5c999e28ca Test components in convert 2023-06-01 20:54:44 +01:00
Abhinav Gupta cb03565fcd
ci: Lint Go language host
The Go language host is a separate Go module
and did not have linting enabled.

This adds it to the list of packages that should be linted in CI
and fixes issues that were found:

- not gofumpted
- using ioutil
2023-05-19 15:01:42 -07:00
Abhinav Gupta dfefb0a613
fix(host/go): Allow Pulumi program in a subdir of the module
Fixes a regression in the Go language host where we started misbehaving
if the Pulumi.yaml was in a subdirectory of the Go module.

    myproject/
      |- go.mod
      |- foo.go
      '- infra/
          |- Pulumi.yaml
          '- main.go

This regression was introduced in ,
where we started parsing go.mod files to extract version information
and incorrectly assumed that the go.mod file was in the request
directory.

To fix this, we'll use the following command to get the absolute path
to the go.mod file.

    go list -m -f '{{.GoMod}}'

This command works in the root or subdirectory of a module
in both vendor and module mode.

Testing:
Includes a regression test in both module and vendor mode.

Resolves 
2023-05-17 13:20:38 -07:00
Fraser Waters 1a38eadc69 gRPC for GenerateProject/Program/Package
This changes codegen to be invoked via gRPC from pkg, rather than
invoking pkg/codegen directly.

Consider it a proof-of-concept for moving codegen to a gRPC interface
without the worries of forwards-backwards compatability (because we ship
language plugins at a fixed version side-by-side to users).
2023-05-06 13:14:59 +01:00
Abhinav Gupta 33b5ad6527
feat(go/host): Support vendored dependencies
The Go language host cannot resolve dependencies or plugins if a Pulumi
program vendors its dependencies.

BACKGROUND

The GetRequiredPlugins and GetProgramDependencies methods of the Go
language host rely on the following two commands:

    go list -m -mod=mod all
    go list -m -mod=mod ...
    # '...' means current module and its descendants

GetRequiredPlugins additionally searches the source directories for each
returned module for pulumi-plugin.json files at a pre-determined paths.

    $module/pulumi-plugin.json
    $module/go/pulumi-plugin.json
    $module/go/*/pulumi-plugin.json

This works for most Pulumi programs, except those that vendor private
dependencies with 'go mod vendor'.
For those programs, the above commands fail because -mod=mod forces them
to run in module mode, and their private dependencies are not accessible
in module mode (because they are not exposed publicly).

We use the -mod=mod flag to force 'go list' to run in module mode
because otherwise, it will automatically use vendor mode if a vendor
directory is present. However, in vendor mode, the two 'go list'
commands above are not supported.
The following links add more context on why, but in short:
vendor does not have enough information for the general 'go list'.

- https://stackoverflow.com/a/60660593,
- https://github.com/golang/go/issues/35589#issuecomment-554488544

In short,

- list all with -mod=mod fails because the dependency is private
- list without -mod=mod will use vendor mode
- vendor mode doesn't support the listing all

SOLUTION

Drop the -mod=mod flag so that 'go list' can decide whether to run in
module mode or vendor mode.
However, instead of running it with 'all' or '...',
pass in a list of dependencies extracted from the go.mod.

    go list -m import/path1 import/path2 # ...

This operation is completely offline in vendor mode
so it can list information about private dependencies too.

This alone isn't enough though because in vendor mode,
the JSON output does not include the module root directory.
E.g.

    % go list -mod=vendor -json -m github.com/pulumi/pulumi/sdk/v3
    {
            "Path": "github.com/pulumi/pulumi/sdk/v3",
            "Version": "v3.55.0",
            "GoVersion": "1.18"
    }

    # Versus

    % go list -mod=mod -json -m github.com/pulumi/pulumi/sdk/v3
    {
            "Path": "github.com/pulumi/pulumi/sdk/v3",
            "Version": "v3.55.0",
            "Time": "2023-02-14T11:04:22Z",
            "Dir": "[...]/go/pkg/mod/github.com/pulumi/pulumi/sdk/v3@v3.55.0",
            "GoMod": "[...]/go/pkg/mod/cache/download/github.com/pulumi/pulumi/sdk/v3/@v/v3.55.0.mod",
            "GoVersion": "1.18"
    }

Therefore, we have to manually calculate the path for each module root.
That's easy enough: vendor/$importPath.

Lastly, since GetProgramDependencies only needs a dependency list,
it now extracts information from the go.mod without calling 'go list'.

TESTING

Adds a variant of the test added in  that verifies the
functionality with vendoring. It removes the sources for the
dependencies to simulate private dependencies. The new test fails
without the accompanying change.

The fix was further manually verified against the reproduction included
in .

    % cd go-output
    % pulumi plugin rm -a -y
    % pulumi preview
    Previewing update (abhinav):
    Downloading plugin: 15.19 MiB / 15.19 MiB [=========================] 100.00% 0s
                                                                                    [resource plugin random-4.8.2] installing
         Type                      Name               Plan
     +   pulumi:pulumi:Stack       go-output-abhinav  create
     +   └─ random:index:RandomId  rrr                create

    Resources:
        + 2 to create

    % pulumi plugin ls
    NAME    KIND      VERSION  SIZE   INSTALLED       LAST USED
    random  resource  4.8.2    33 MB  26 seconds ago  26 seconds ago

    TOTAL plugin cache size: 33 MB

Note that the version of random (4.8.2) is what's specified in the
go.mod, not the latest release (v4.12.1).

    % grep pulumi-random go.mod
            github.com/pulumi/pulumi-random/sdk/v4 v4.8.2

With the plugin downloaded, I ran this again without an internet
connection.

    % pulumi preview
    Previewing update (abhinav):
         Type                      Name               Plan
     +   pulumi:pulumi:Stack       go-output-abhinav  create
     +   └─ random:index:RandomId  rrr                create

    Resources:
        + 2 to create

This means that if the dependencies are vendored, and the plugin is
already available, we won't make additional network requests, which also
addresses .

Resolves 
Resolves 
2023-04-24 09:49:16 -07:00
Abhinav Gupta d959af047c
fix(go/host): Don't change working directory in test
This should've been part of  but was missed.
The function that actually held the test body
was still changing the current directory.
2023-04-23 07:28:59 -07:00
Abhinav Gupta 723b01efd6
refactor(go/host): Inject current working directory
Refactors the Go language host to inject CWD into it
instead of always using `os.Getwd`.
This allows the test for plugin and dependency behavior
to run in parallel.

Note: Some of the RPCs methods get a Directory or Pwd in the request
but it wasn't being used before so we were running in the directory
where the host was started.
This retains that behvaior for those methods rather than changing it
because it's not clear whether that omission was intentional.
2023-04-21 10:28:25 -07:00
Abhinav Gupta dbcb6e8f17
test(go/host): GetRequiredPlugins and GetProgramDependencies
Adds a test that sets up a Go module with a few dependencies
and queries its plugins and dependencies with the Go language host.
This test passes today because we're running in module mode.

A sibling test will be added for vendor mode
to verify the fix for , where this same check would fail
if we vendor the dependencies into the Pulumi program.

NOTE:
The test does not run in parallel because we need to change the
working directory. This is resolved in a follow-up.
2023-04-21 10:28:23 -07:00
Abhinav Gupta 5467e5ff9f
refactor(go/host): Extract global state into a struct
Refactors the Go language host plugin
to extract global state (e.g. stdout, command line args)
into a mainCmd struct.
The command line parsing logic is placed into a separate,
independently tested function.

This change does not modify any behavior.
2023-04-20 17:53:05 -07:00
Abhinav Gupta 7aa5b77a0c
all: Reformat with gofumpt
Per team discussion, switching to gofumpt.

[gofumpt][1] is an alternative, stricter alternative to gofmt.
It addresses other stylistic concerns that gofmt doesn't yet cover.

  [1]: https://github.com/mvdan/gofumpt

See the full list of [Added rules][2], but it includes:

- Dropping empty lines around function bodies
- Dropping unnecessary variable grouping when there's only one variable
- Ensuring an empty line between multi-line functions
- simplification (`-s` in gofmt) is always enabled
- Ensuring multi-line function signatures end with
  `) {` on a separate line.

  [2]: https://github.com/mvdan/gofumpt#Added-rules

gofumpt is stricter, but there's no lock-in.
All gofumpt output is valid gofmt output,
so if we decide we don't like it, it's easy to switch back
without any code changes.

gofumpt support is built into the tooling we use for development
so this won't change development workflows.

- golangci-lint includes a gofumpt check (enabled in this PR)
- gopls, the LSP for Go, includes a gofumpt option
  (see [installation instrutions][3])

  [3]: https://github.com/mvdan/gofumpt#installation

This change was generated by running:

```bash
gofumpt -w $(rg --files -g '*.go' | rg -v testdata | rg -v compilation_error)
```

The following files were manually tweaked afterwards:

- pkg/cmd/pulumi/stack_change_secrets_provider.go:
  one of the lines overflowed and had comments in an inconvenient place
- pkg/cmd/pulumi/destroy.go:
  `var x T = y` where `T` wasn't necessary
- pkg/cmd/pulumi/policy_new.go:
  long line because of error message
- pkg/backend/snapshot_test.go:
  long line trying to assign three variables in the same assignment

I have included mention of gofumpt in the CONTRIBUTING.md.
2023-03-03 09:00:24 -08:00
杨成锴 7b09ad142a chore: Update doc comments, coding style, fix lint
* about error string: error string should not be capitalized or end with punctuation mark
* apply suggestions from code review
* lint: fix format error and simplify the code

Co-authored-by: Fraser Waters <frassle@gmail.com>
Co-authored-by: Aaron Friel <mayreply@aaronfriel.com>
2022-10-13 13:50:49 -07:00
Aaron Friel ed2923653c ci: radical idea - what if slow tests & no stdout makes GH consider runner dead? 2022-03-06 14:52:13 -08:00
Justin Van Patten 043c42b336
Use `pulumi-plugin.json` rather than `pulumiplugin.json` ()
Current/older versions of the Python language host cannot read `pulumiplugin.json` without returning an error. This hasn't been a problem because none of our packages have included the file. However, we're going to start including this file by default in packages. To avoid this error on older CLIs, we'll use a different file name. And since we're introducing the use of this file in the .NET and Go language hosts, we'll use the new name for these languages as well for consistency.
2021-12-15 10:41:44 -08:00
Ian Wahbe c02bff9acf
[codegen/go] Emit `pulumiplugin.json` as part of codegen ()
* Emit `pulumiplugin.json`.

Test changes will follow in a later commit.

* Test changes

* Update changelog

* Expand lookup scope
2021-12-06 13:10:30 -08:00
Ian Wahbe feef62e108
[sdk/go] Check for pulumiplugin.json in `GetRequiredPlugins` ()
* Check pulumiplugin.json in `GetRequiredPlugins`

* Add error check in test

* Update CHANGELOG_PENDING.md
2021-12-01 16:12:28 -08:00
Evan Boyle ab659aa0c1
Reimplement getRequiredPlugins for go sdk () 2020-04-06 12:30:40 -07:00