From d9e466f8c694f1177cf32f97b2af63e111cde013 Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 14 Aug 2023 14:31:53 +0100 Subject: [PATCH 01/22] feat(compute/build): support native go --- .fastly/config.toml | 7 ++--- .github/workflows/pr_test.yml | 4 +-- .github/workflows/tag_release.yml | 2 +- pkg/commands/compute/build_test.go | 41 ++++++++--------------------- pkg/commands/compute/language_go.go | 38 +++++++++++++++++++++----- pkg/config/config.go | 5 +++- pkg/manifest/file.go | 10 +++++-- 7 files changed, 62 insertions(+), 45 deletions(-) diff --git a/.fastly/config.toml b/.fastly/config.toml index dcd9e100f..273cd1b5e 100644 --- a/.fastly/config.toml +++ b/.fastly/config.toml @@ -1,12 +1,13 @@ -config_version = 2 +config_version = 3 [fastly] api_endpoint = "https://api.fastly.com" [language] [language.go] -tinygo_constraint = ">= 0.26.0-0" # NOTE -0 indicates to the CLI's semver package that we accept pre-releases (TinyGo users commonly use pre-releases). -toolchain_constraint = ">= 1.18" +tinygo_constraint = ">= 0.26.0-0" # NOTE -0 indicates to the CLI's semver package that we accept pre-releases (TinyGo users commonly use pre-releases). +toolchain_constraint = ">= 1.18" # Go toolchain constraint for use with TinyGo. +native_toolchain_constraint = ">= 1.21" # Go toolchain constraint for use with WASI support. [language.rust] toolchain_constraint = ">= 1.56.1" diff --git a/.github/workflows/pr_test.yml b/.github/workflows/pr_test.yml index 7c6ece293..53799655e 100644 --- a/.github/workflows/pr_test.yml +++ b/.github/workflows/pr_test.yml @@ -29,7 +29,7 @@ jobs: - name: Install Go uses: actions/setup-go@v4 with: - go-version: 1.20.x + go-version: 1.21.x # NOTE: Manage GitHub Actions cache via https://github.com/fastly/cli/actions/caches # This is useful if you need to clear the cache when a dependency doesn't update correctly. # @@ -87,7 +87,7 @@ jobs: strategy: matrix: tinygo-version: [0.27.0] - go-version: [1.20.x] + go-version: [1.21.x] node-version: [18] platform: [ubuntu-latest, macos-latest, windows-latest] runs-on: ${{ matrix.platform }} diff --git a/.github/workflows/tag_release.yml b/.github/workflows/tag_release.yml index cda4886f9..296c6b072 100644 --- a/.github/workflows/tag_release.yml +++ b/.github/workflows/tag_release.yml @@ -15,7 +15,7 @@ jobs: - name: "Install Go" uses: actions/setup-go@v4 with: - go-version: '1.20.x' + go-version: '1.21.x' - name: "Set GOHOSTOS and GOHOSTARCH" run: echo "GOHOSTOS=$(go env GOHOSTOS)" >> $GITHUB_ENV && echo "GOHOSTARCH=$(go env GOHOSTARCH)" >> $GITHUB_ENV - name: "Install Rust" diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index 75fd49ee7..3529f361f 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -248,13 +248,14 @@ func TestBuildGo(t *testing.T) { // // NOTE: This test passes --verbose so we can validate specific outputs. { - name: "build script inserted dynamically when missing", + name: "build success", args: args("compute build --verbose"), applicationConfig: config.File{ Language: config.Language{ Go: config.Go{ - TinyGoConstraint: ">= 0.26.0-0", - ToolchainConstraint: ">= 1.17", + TinyGoConstraint: ">= 0.26.0-0", + ToolchainConstraint: ">= 1.18", + NativeToolchainConstraint: ">= 1.21", }, }, }, @@ -264,8 +265,11 @@ func TestBuildGo(t *testing.T) { language = "go"`, wantOutput: []string{ "No [scripts.build] found in fastly.toml.", // requires --verbose + "The Fastly CLI requires a go version '>= 1.21'", "The following default build command for", - "tinygo build", + "env GOARCH=wasm GOOS=wasip1", + "Creating ./bin directory (for Wasm binary)", + "Built package", }, }, { @@ -274,8 +278,9 @@ func TestBuildGo(t *testing.T) { applicationConfig: config.File{ Language: config.Language{ Go: config.Go{ - TinyGoConstraint: ">= 0.26.0-0", - ToolchainConstraint: ">= 1.17", + TinyGoConstraint: ">= 0.26.0-0", + ToolchainConstraint: ">= 1.18", + NativeToolchainConstraint: ">= 1.21", }, }, }, @@ -288,30 +293,6 @@ func TestBuildGo(t *testing.T) { build = "echo no compilation happening"`, wantRemediationError: compute.DefaultBuildErrorRemediation, }, - // NOTE: This test passes --verbose so we can validate specific outputs. - { - name: "successful build", - args: args("compute build --verbose"), - applicationConfig: config.File{ - Language: config.Language{ - Go: config.Go{ - TinyGoConstraint: ">= 0.26.0-0", - ToolchainConstraint: ">= 1.17", - }, - }, - }, - fastlyManifest: fmt.Sprintf(` - manifest_version = 2 - name = "test" - language = "go" - - [scripts] - build = "%s"`, compute.GoDefaultBuildCommand), - wantOutput: []string{ - "Creating ./bin directory (for Wasm binary)", - "Built package", - }, - }, } for testcaseIdx := range scenarios { testcase := &scenarios[testcaseIdx] diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index c5af7e5e5..e25910040 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -8,6 +8,7 @@ import ( "strings" "github.com/Masterminds/semver/v3" + "github.com/fastly/cli/pkg/config" fsterr "github.com/fastly/cli/pkg/errors" "github.com/fastly/cli/pkg/global" @@ -15,7 +16,7 @@ import ( "github.com/fastly/cli/pkg/text" ) -// GoDefaultBuildCommand is a build command compiled into the CLI binary so it +// TinyGoDefaultBuildCommand is a build command compiled into the CLI binary so it // can be used as a fallback for customer's who have an existing C@E project and // are simply upgrading their CLI version and might not be familiar with the // changes in the 4.0.0 release with regards to how build logic has moved to the @@ -24,7 +25,14 @@ import ( // NOTE: In the 5.x CLI releases we persisted the default to the fastly.toml // We no longer do that. In 6.x we use the default and just inform the user. // This makes the experience less confusing as users didn't expect file changes. -const GoDefaultBuildCommand = "tinygo build -target=wasi -gc=conservative -o bin/main.wasm ./" +const TinyGoDefaultBuildCommand = "tinygo build -target=wasi -gc=conservative -o bin/main.wasm ./" + +// GoDefaultBuildCommand is a build command compiled into the CLI binary so it +// can be used as a fallback for customer's who have an existing C@E project and +// who don't have a `scripts.build` defined. +// +// NOTE: Only used if `toolchain = "go"` and if Go 1.21+ is installed. +const GoDefaultBuildCommand = "env GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" // GoSourceDirectory represents the source code directory. │ │ const GoSourceDirectory = "." @@ -51,6 +59,7 @@ func NewGo( postBuild: fastlyManifest.Scripts.PostBuild, spinner: spinner, timeout: flags.Timeout, + toolchain: fastlyManifest.Scripts.Toolchain, verbose: globals.Verbose(), } } @@ -85,6 +94,8 @@ type Go struct { spinner text.Spinner // timeout is the build execution threshold. timeout int + // toolchain indicates the toolchain used for compiling your program. + toolchain string // verbose indicates if the user set --verbose verbose bool } @@ -92,8 +103,12 @@ type Go struct { // Build compiles the user's source code into a Wasm binary. func (g *Go) Build() error { var noBuildScript bool + if g.build == "" { g.build = GoDefaultBuildCommand + if g.toolchain == "tinygo" { + g.build = TinyGoDefaultBuildCommand + } noBuildScript = true } @@ -101,13 +116,24 @@ func (g *Go) Build() error { text.Info(g.output, "No [scripts.build] found in fastly.toml. The following default build command for Go will be used: `%s`\n", g.build) } + constraint := g.config.NativeToolchainConstraint + + if g.toolchain == "tinygo" { + constraint = g.config.ToolchainConstraint + } else { + text.Info(g.output, "The standard Go compiler %s now supports WASI. To keep using TinyGo set `toolchain = 'tinygo'`.", constraint) + } + g.toolchainConstraint( - "go", `go version go(?P\d[^\s]+)`, g.config.ToolchainConstraint, - ) - g.toolchainConstraint( - "tinygo", `tinygo version (?P\d[^\s]+)`, g.config.TinyGoConstraint, + "go", `go version go(?P\d[^\s]+)`, constraint, ) + if g.toolchain == "tinygo" { + g.toolchainConstraint( + "tinygo", `tinygo version (?P\d[^\s]+)`, g.config.TinyGoConstraint, + ) + } + bt := BuildToolchain{ autoYes: g.autoYes, buildFn: g.Shell.Build, diff --git a/pkg/config/config.go b/pkg/config/config.go index c45ce89c4..0a2c4e552 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -88,11 +88,14 @@ type Go struct { // TinyGoConstraint is the `tinygo` version that we support. TinyGoConstraint string `toml:"tinygo_constraint"` - // ToolchainConstraint is the `go` version that we support. + // ToolchainConstraint is the `go` version that we support with TinyGo. // // We aim for go versions that support go modules by default. // https://go.dev/blog/using-go-modules ToolchainConstraint string `toml:"toolchain_constraint"` + + // NativeToolchainConstraint is the `go` version that we support with WASI. + NativeToolchainConstraint string `toml:"native_toolchain_constraint"` } // Rust represents Rust C@E language specific configuration. diff --git a/pkg/manifest/file.go b/pkg/manifest/file.go index b705c8662..913146940 100644 --- a/pkg/manifest/file.go +++ b/pkg/manifest/file.go @@ -188,7 +188,13 @@ func appendSpecRef(w io.Writer) error { // Scripts represents build configuration. type Scripts struct { - Build string `toml:"build,omitempty"` + // Build is a custom build script. + Build string `toml:"build,omitempty"` + // PostBuild is executed after the build step. PostBuild string `toml:"post_build,omitempty"` - PostInit string `toml:"post_init,omitempty"` + // PostInit is executed after the init step. + PostInit string `toml:"post_init,omitempty"` + // Toolchain indicates the toolchain used for compiling your program. + // Supported languages: Go (allowed inputs: go, tinygo). + Toolchain string `toml:"toolchain,omitempty"` } From 4b1062e34743a22faa398f5dc83eb9a749de3832 Mon Sep 17 00:00:00 2001 From: Integralist Date: Mon, 14 Aug 2023 15:43:28 +0100 Subject: [PATCH 02/22] refactor(compute/build): clarify toolchain configuration --- pkg/commands/compute/language_go.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index e25910040..4cfec7ec7 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -121,7 +121,7 @@ func (g *Go) Build() error { if g.toolchain == "tinygo" { constraint = g.config.ToolchainConstraint } else { - text.Info(g.output, "The standard Go compiler %s now supports WASI. To keep using TinyGo set `toolchain = 'tinygo'`.", constraint) + text.Info(g.output, "The standard Go compiler %s now supports WASI. To keep using TinyGo set `[scripts.toolchain]` to 'tinygo'.", constraint) } g.toolchainConstraint( From ab5430ec6982981eee42bd592dd313469013348f Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 16 Aug 2023 11:30:26 +0100 Subject: [PATCH 03/22] fix(compute/build/go): remove env from default build script --- pkg/commands/compute/language_go.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 4cfec7ec7..71f0f9e85 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -32,7 +32,7 @@ const TinyGoDefaultBuildCommand = "tinygo build -target=wasi -gc=conservative -o // who don't have a `scripts.build` defined. // // NOTE: Only used if `toolchain = "go"` and if Go 1.21+ is installed. -const GoDefaultBuildCommand = "env GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" +const GoDefaultBuildCommand = "GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" // GoSourceDirectory represents the source code directory. │ │ const GoSourceDirectory = "." From 0e10b66857b8949dae147272742a8df74572db74 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 16 Aug 2023 11:30:47 +0100 Subject: [PATCH 04/22] feat(scripts): add tinygo default starter kit --- scripts/config.sh | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/scripts/config.sh b/scripts/config.sh index 1c7c36ec5..60c958fc9 100755 --- a/scripts/config.sh +++ b/scripts/config.sh @@ -10,15 +10,16 @@ then fi kits=( + compute-starter-kit-assemblyscript-default + compute-starter-kit-go-default + compute-starter-kit-javascript-default + compute-starter-kit-javascript-empty compute-starter-kit-rust-default compute-starter-kit-rust-empty compute-starter-kit-rust-static-content compute-starter-kit-rust-websockets - compute-starter-kit-javascript-default - compute-starter-kit-javascript-empty + compute-starter-kit-tinygo-default compute-starter-kit-typescript - compute-starter-kit-assemblyscript-default - compute-starter-kit-go-default ) function parse() { From 09396deccef7f3d80ba2fed60e00f68b7eacf13c Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 16 Aug 2023 14:14:55 +0100 Subject: [PATCH 05/22] refactor: default to tinygo if no build script --- .fastly/config.toml | 4 +-- pkg/commands/compute/build_test.go | 20 +++++++----- pkg/commands/compute/language_go.go | 49 ++++++++++++++--------------- pkg/config/config.go | 10 +++--- scripts/config.sh | 2 +- 5 files changed, 44 insertions(+), 41 deletions(-) diff --git a/.fastly/config.toml b/.fastly/config.toml index 273cd1b5e..3ad4a1713 100644 --- a/.fastly/config.toml +++ b/.fastly/config.toml @@ -6,8 +6,8 @@ api_endpoint = "https://api.fastly.com" [language] [language.go] tinygo_constraint = ">= 0.26.0-0" # NOTE -0 indicates to the CLI's semver package that we accept pre-releases (TinyGo users commonly use pre-releases). -toolchain_constraint = ">= 1.18" # Go toolchain constraint for use with TinyGo. -native_toolchain_constraint = ">= 1.21" # Go toolchain constraint for use with WASI support. +toolchain_constraint = ">= 1.21" # Go toolchain constraint for use with WASI support. +toolchain_constraint_tinygo = ">= 1.18" # Go toolchain constraint for use with TinyGo. [language.rust] toolchain_constraint = ">= 1.56.1" diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index 3529f361f..e54250ec4 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -254,24 +254,28 @@ func TestBuildGo(t *testing.T) { Language: config.Language{ Go: config.Go{ TinyGoConstraint: ">= 0.26.0-0", - ToolchainConstraint: ">= 1.18", - NativeToolchainConstraint: ">= 1.21", + ToolchainConstraintTinyGo: ">= 1.18", + ToolchainConstraint: ">= 1.21", }, }, }, fastlyManifest: ` manifest_version = 2 name = "test" - language = "go"`, + language = "go" + [scripts] + build = "GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" + `, wantOutput: []string{ - "No [scripts.build] found in fastly.toml.", // requires --verbose "The Fastly CLI requires a go version '>= 1.21'", - "The following default build command for", - "env GOARCH=wasm GOOS=wasip1", + "Build script to execute", + "GOARCH=wasm GOOS=wasip1", "Creating ./bin directory (for Wasm binary)", "Built package", }, }, + // The following test case is expected to fail because we specify a custom + // build script that doesn't actually produce a ./bin/main.wasm { name: "build error", args: args("compute build"), @@ -279,8 +283,8 @@ func TestBuildGo(t *testing.T) { Language: config.Language{ Go: config.Go{ TinyGoConstraint: ">= 0.26.0-0", - ToolchainConstraint: ">= 1.18", - NativeToolchainConstraint: ">= 1.21", + ToolchainConstraintTinyGo: ">= 1.18", + ToolchainConstraint: ">= 1.21", }, }, }, diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 71f0f9e85..5107791f6 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -27,13 +27,6 @@ import ( // This makes the experience less confusing as users didn't expect file changes. const TinyGoDefaultBuildCommand = "tinygo build -target=wasi -gc=conservative -o bin/main.wasm ./" -// GoDefaultBuildCommand is a build command compiled into the CLI binary so it -// can be used as a fallback for customer's who have an existing C@E project and -// who don't have a `scripts.build` defined. -// -// NOTE: Only used if `toolchain = "go"` and if Go 1.21+ is installed. -const GoDefaultBuildCommand = "GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" - // GoSourceDirectory represents the source code directory. │ │ const GoSourceDirectory = "." @@ -102,33 +95,39 @@ type Go struct { // Build compiles the user's source code into a Wasm binary. func (g *Go) Build() error { - var noBuildScript bool + var ( + tinygoToolchain bool + toolchainConstraint string + ) if g.build == "" { - g.build = GoDefaultBuildCommand - if g.toolchain == "tinygo" { - g.build = TinyGoDefaultBuildCommand - } - noBuildScript = true - } - - if noBuildScript && g.verbose { - text.Info(g.output, "No [scripts.build] found in fastly.toml. The following default build command for Go will be used: `%s`\n", g.build) + g.build = TinyGoDefaultBuildCommand + tinygoToolchain = true + toolchainConstraint = g.config.ToolchainConstraintTinyGo + text.Info(g.output, "No [scripts.build] found in fastly.toml. Visit https://developer.fastly.com/learning/compute/go/ to learn how to target native Go vs TinyGo.") + text.Break(g.output) + text.Description(g.output, "The following default build command for TinyGo will be used:", g.build) + text.Break(g.output) } - constraint := g.config.NativeToolchainConstraint - - if g.toolchain == "tinygo" { - constraint = g.config.ToolchainConstraint - } else { - text.Info(g.output, "The standard Go compiler %s now supports WASI. To keep using TinyGo set `[scripts.toolchain]` to 'tinygo'.", constraint) + if g.build != "" { + // IMPORTANT: All Fastly starter-kits for Go/TinyGo will have build script. + // + // So we'll need to parse the build script to identify if TinyGo is used so + // we can set the constraints appropriately. + if strings.Contains(g.build, "tinygo build") { + tinygoToolchain = true + toolchainConstraint = g.config.ToolchainConstraintTinyGo + } else { + toolchainConstraint = g.config.ToolchainConstraint + } } g.toolchainConstraint( - "go", `go version go(?P\d[^\s]+)`, constraint, + "go", `go version go(?P\d[^\s]+)`, toolchainConstraint, ) - if g.toolchain == "tinygo" { + if tinygoToolchain { g.toolchainConstraint( "tinygo", `tinygo version (?P\d[^\s]+)`, g.config.TinyGoConstraint, ) diff --git a/pkg/config/config.go b/pkg/config/config.go index 0a2c4e552..5973f1cb0 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -88,14 +88,14 @@ type Go struct { // TinyGoConstraint is the `tinygo` version that we support. TinyGoConstraint string `toml:"tinygo_constraint"` - // ToolchainConstraint is the `go` version that we support with TinyGo. + // ToolchainConstraint is the `go` version that we support with WASI. + ToolchainConstraint string `toml:"toolchain_constraint"` + + // ToolchainConstraintTinyGo is the `go` version that we support with TinyGo. // // We aim for go versions that support go modules by default. // https://go.dev/blog/using-go-modules - ToolchainConstraint string `toml:"toolchain_constraint"` - - // NativeToolchainConstraint is the `go` version that we support with WASI. - NativeToolchainConstraint string `toml:"native_toolchain_constraint"` + ToolchainConstraintTinyGo string `toml:"toolchain_constraint_tinygo"` } // Rust represents Rust C@E language specific configuration. diff --git a/scripts/config.sh b/scripts/config.sh index 60c958fc9..aea066f86 100755 --- a/scripts/config.sh +++ b/scripts/config.sh @@ -18,7 +18,7 @@ kits=( compute-starter-kit-rust-empty compute-starter-kit-rust-static-content compute-starter-kit-rust-websockets - compute-starter-kit-tinygo-default + # compute-starter-kit-tinygo-default compute-starter-kit-typescript ) From 242793a57556415da9a797c79cbc6bb97a321984 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 16 Aug 2023 14:59:55 +0100 Subject: [PATCH 06/22] fix(compute/build): support env vars for Windows --- pkg/commands/compute/build_test.go | 4 ++-- pkg/commands/compute/init.go | 3 ++- pkg/commands/compute/language_go.go | 1 + pkg/commands/compute/language_toolchain.go | 4 +++- pkg/exec/exec.go | 3 ++- 5 files changed, 10 insertions(+), 5 deletions(-) diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index e54250ec4..cb076b7f3 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -264,12 +264,12 @@ func TestBuildGo(t *testing.T) { name = "test" language = "go" [scripts] - build = "GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" + build = "go build -o bin/main.wasm ./" `, wantOutput: []string{ "The Fastly CLI requires a go version '>= 1.21'", "Build script to execute", - "GOARCH=wasm GOOS=wasip1", + "go build -o bin/main.wasm ./", "Creating ./bin directory (for Wasm binary)", "Built package", }, diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 8786fb5c0..a6f30dd2a 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -256,8 +256,9 @@ func (c *InitCommand) Exec(in io.Reader, out io.Writer) (err error) { s := Shell{} command, args := s.Build(postInit) noTimeout := 0 // zero indicates no timeout + noEnvVars := []string{} err := fstexec.Command( - command, args, msg, out, spinner, c.Globals.Flags.Verbose, noTimeout, c.Globals.ErrLog, + command, args, msg, out, spinner, c.Globals.Flags.Verbose, noTimeout, c.Globals.ErrLog, noEnvVars, ) if err != nil { return err diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 5107791f6..6657c711f 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -137,6 +137,7 @@ func (g *Go) Build() error { autoYes: g.autoYes, buildFn: g.Shell.Build, buildScript: g.build, + env: []string{"GOARCH=wasm", "GOOS=wasip1"}, errlog: g.errlog, in: g.input, nonInteractive: g.nonInteractive, diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index cad5b68d0..8b9566811 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -41,6 +41,8 @@ type BuildToolchain struct { buildFn func(string) (string, []string) // buildScript is the [scripts.build] within the fastly.toml manifest. buildScript string + // env are environment variables to be set. + env []string // errlog is an abstraction for recording errors to disk. errlog fsterr.LogInterface // in is the user's terminal stdin stream @@ -195,7 +197,7 @@ func (bt BuildToolchain) handleError(err error) error { // By passing in the spinner and message we can short-circuit the spinner. func (bt BuildToolchain) execCommand(cmd string, args []string, spinMessage string) error { return fstexec.Command( - cmd, args, spinMessage, bt.out, bt.spinner, bt.verbose, bt.timeout, bt.errlog, + cmd, args, spinMessage, bt.out, bt.spinner, bt.verbose, bt.timeout, bt.errlog, bt.env, ) } diff --git a/pkg/exec/exec.go b/pkg/exec/exec.go index 1733e3712..51e76a4da 100644 --- a/pkg/exec/exec.go +++ b/pkg/exec/exec.go @@ -168,11 +168,12 @@ func Command( verbose bool, timeout int, errLog fsterr.LogInterface, + env []string, ) error { s := Streaming{ Command: cmd, Args: args, - Env: os.Environ(), + Env: env, Output: out, Spinner: spinner, SpinnerMessage: spinMessage, From aa48ed694862422fcb12d4abf2f232ece0159ed4 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 16 Aug 2023 16:59:07 +0100 Subject: [PATCH 07/22] fix: switch to older tinygo constraint depending on sdk version --- .fastly/config.toml | 2 +- pkg/commands/compute/build_test.go | 2 +- pkg/commands/compute/language_go.go | 73 ++++++++++++++++++++++++++++- 3 files changed, 73 insertions(+), 4 deletions(-) diff --git a/.fastly/config.toml b/.fastly/config.toml index 3ad4a1713..4623ff1b1 100644 --- a/.fastly/config.toml +++ b/.fastly/config.toml @@ -5,7 +5,7 @@ api_endpoint = "https://api.fastly.com" [language] [language.go] -tinygo_constraint = ">= 0.26.0-0" # NOTE -0 indicates to the CLI's semver package that we accept pre-releases (TinyGo users commonly use pre-releases). +tinygo_constraint = ">= 0.28.1-0" # NOTE -0 indicates to the CLI's semver package that we accept pre-releases (TinyGo users commonly use pre-releases). toolchain_constraint = ">= 1.21" # Go toolchain constraint for use with WASI support. toolchain_constraint_tinygo = ">= 1.18" # Go toolchain constraint for use with TinyGo. diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index cb076b7f3..099077bb8 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -267,7 +267,7 @@ func TestBuildGo(t *testing.T) { build = "go build -o bin/main.wasm ./" `, wantOutput: []string{ - "The Fastly CLI requires a go version '>= 1.21'", + "The Fastly CLI build step requires a go version '>= 1.21'", "Build script to execute", "go build -o bin/main.wasm ./", "Creating ./bin directory (for Wasm binary)", diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 6657c711f..362315160 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -1,8 +1,10 @@ package compute import ( + "bufio" "fmt" "io" + "os" "os/exec" "regexp" "strings" @@ -123,13 +125,20 @@ func (g *Go) Build() error { } } + // IMPORTANT: The Go SDK 0.2.0 bumps the tinygo requirement to 0.28.1 + // + // This means we need to check the go.sum of the user's project for + // `compute-sdk-go` and then parse the version and identify if it's less than + // 0.2.0 version. If it less than, change the TinyGo constraint to 0.26.0 + tinygoConstraint := identifyTinyGoConstraint(g.config.TinyGoConstraint) + g.toolchainConstraint( "go", `go version go(?P\d[^\s]+)`, toolchainConstraint, ) if tinygoToolchain { g.toolchainConstraint( - "tinygo", `tinygo version (?P\d[^\s]+)`, g.config.TinyGoConstraint, + "tinygo", `tinygo version (?P\d[^\s]+)`, tinygoConstraint, ) } @@ -151,6 +160,66 @@ func (g *Go) Build() error { return bt.Build() } +// identifyTinyGoConstraint checks the compute-sdk-go version used by the +// project and if it's less than 0.2.0 we'll change the TinyGo constraint to be +// version 0.26.0 +// +// We do this because the 0.2.0 release of the compute-sdk-go bumps the TinyGo +// version requirement to 0.28.1 and we want to avoid any scenarios where a +// bump in SDK version causes the user's build to break (which would happen for +// users with a pre-existing project who happen to update their CLI version: the +// new CLI version would have a TinyGo constraint that would be higher than +// before and would stop their build from working). +// +// NOTE: The `configConstraint` is the latest CLI application config version. +// If there are any errors trying to parse the go.sum we'll default to the +// config constraint. +func identifyTinyGoConstraint(configConstraint string) string { + moduleName := "github.com/fastly/compute-sdk-go" + version := "" + + f, err := os.Open("go.sum") + if err != nil { + return configConstraint + } + defer f.Close() + + scanner := bufio.NewScanner(f) + for scanner.Scan() { + line := scanner.Text() + parts := strings.Fields(line) + if len(parts) >= 2 && parts[0] == moduleName { + version = strings.TrimPrefix(parts[1], "v") + break + } + } + + if err := scanner.Err(); err != nil { + return configConstraint + } + + if version == "" { + return configConstraint + } + + gosumVersion, err := semver.NewVersion(version) + if err != nil { + return configConstraint + } + + // 0.2.0 introduces the break by bumping the TinyGo minimum version to 0.28.1 + breakingSDKVersion, err := semver.NewVersion("0.2.0") + if err != nil { + return configConstraint + } + + if gosumVersion.LessThan(breakingSDKVersion) { + return ">= 0.26.0-0" + } + + return configConstraint +} + // toolchainConstraint warns the user if the required constraint is not met. // // NOTE: We don't stop the build as their toolchain may compile successfully. @@ -158,7 +227,7 @@ func (g *Go) Build() error { // the opportunity to do something about it if they choose. func (g *Go) toolchainConstraint(toolchain, pattern, constraint string) { if g.verbose { - text.Info(g.output, "The Fastly CLI requires a %s version '%s'. ", toolchain, constraint) + text.Info(g.output, "The Fastly CLI build step requires a %s version '%s'. ", toolchain, constraint) } versionCommand := fmt.Sprintf("%s version", toolchain) From 4782a2f3b0fa9501fa2c951d2604e49e9fcc9494 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 18 Aug 2023 10:15:21 +0100 Subject: [PATCH 08/22] refactor(compute/build): switch to go.mod --- pkg/commands/compute/language_go.go | 34 ++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 8 deletions(-) diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 362315160..c0b020df4 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -127,7 +127,7 @@ func (g *Go) Build() error { // IMPORTANT: The Go SDK 0.2.0 bumps the tinygo requirement to 0.28.1 // - // This means we need to check the go.sum of the user's project for + // This means we need to check the go.mod of the user's project for // `compute-sdk-go` and then parse the version and identify if it's less than // 0.2.0 version. If it less than, change the TinyGo constraint to 0.26.0 tinygoConstraint := identifyTinyGoConstraint(g.config.TinyGoConstraint) @@ -172,13 +172,13 @@ func (g *Go) Build() error { // before and would stop their build from working). // // NOTE: The `configConstraint` is the latest CLI application config version. -// If there are any errors trying to parse the go.sum we'll default to the +// If there are any errors trying to parse the go.mod we'll default to the // config constraint. func identifyTinyGoConstraint(configConstraint string) string { moduleName := "github.com/fastly/compute-sdk-go" version := "" - f, err := os.Open("go.sum") + f, err := os.Open("go.mod") if err != nil { return configConstraint } @@ -188,9 +188,27 @@ func identifyTinyGoConstraint(configConstraint string) string { for scanner.Scan() { line := scanner.Text() parts := strings.Fields(line) - if len(parts) >= 2 && parts[0] == moduleName { - version = strings.TrimPrefix(parts[1], "v") - break + + // go.mod has two separate definition possibilities: + // + // 1. + // require github.com/fastly/compute-sdk-go v0.1.7 + // + // 2. + // require ( + // github.com/fastly/compute-sdk-go v0.1.7 + // ) + if len(parts) >= 2 { + // 1. require [github.com/fastly/compute-sdk-go] v0.1.7 + if parts[1] == moduleName { + version = strings.TrimPrefix(parts[2], "v") + break + } + // 2. [github.com/fastly/compute-sdk-go] v0.1.7 + if parts[0] == moduleName { + version = strings.TrimPrefix(parts[1], "v") + break + } } } @@ -202,7 +220,7 @@ func identifyTinyGoConstraint(configConstraint string) string { return configConstraint } - gosumVersion, err := semver.NewVersion(version) + gomodVersion, err := semver.NewVersion(version) if err != nil { return configConstraint } @@ -213,7 +231,7 @@ func identifyTinyGoConstraint(configConstraint string) string { return configConstraint } - if gosumVersion.LessThan(breakingSDKVersion) { + if gomodVersion.LessThan(breakingSDKVersion) { return ">= 0.26.0-0" } From 7299f6d7d24d5223616a222209afee50392470c1 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 18 Aug 2023 10:18:14 +0100 Subject: [PATCH 09/22] remove(compute/build): remove toolchain setting --- pkg/commands/compute/language_go.go | 3 --- pkg/manifest/file.go | 3 --- 2 files changed, 6 deletions(-) diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index c0b020df4..e1f3d05dc 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -54,7 +54,6 @@ func NewGo( postBuild: fastlyManifest.Scripts.PostBuild, spinner: spinner, timeout: flags.Timeout, - toolchain: fastlyManifest.Scripts.Toolchain, verbose: globals.Verbose(), } } @@ -89,8 +88,6 @@ type Go struct { spinner text.Spinner // timeout is the build execution threshold. timeout int - // toolchain indicates the toolchain used for compiling your program. - toolchain string // verbose indicates if the user set --verbose verbose bool } diff --git a/pkg/manifest/file.go b/pkg/manifest/file.go index 913146940..816accf36 100644 --- a/pkg/manifest/file.go +++ b/pkg/manifest/file.go @@ -194,7 +194,4 @@ type Scripts struct { PostBuild string `toml:"post_build,omitempty"` // PostInit is executed after the init step. PostInit string `toml:"post_init,omitempty"` - // Toolchain indicates the toolchain used for compiling your program. - // Supported languages: Go (allowed inputs: go, tinygo). - Toolchain string `toml:"toolchain,omitempty"` } From 5efa4a6ab3dd48c4d5eb0753a5bec99c3247ab99 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 18 Aug 2023 10:18:50 +0100 Subject: [PATCH 10/22] refactor(compute/build): replace native with standard --- pkg/commands/compute/language_go.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index e1f3d05dc..88831ed1e 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -103,7 +103,7 @@ func (g *Go) Build() error { g.build = TinyGoDefaultBuildCommand tinygoToolchain = true toolchainConstraint = g.config.ToolchainConstraintTinyGo - text.Info(g.output, "No [scripts.build] found in fastly.toml. Visit https://developer.fastly.com/learning/compute/go/ to learn how to target native Go vs TinyGo.") + text.Info(g.output, "No [scripts.build] found in fastly.toml. Visit https://developer.fastly.com/learning/compute/go/ to learn how to target standard Go vs TinyGo.") text.Break(g.output) text.Description(g.output, "The following default build command for TinyGo will be used:", g.build) text.Break(g.output) From 0dadb5a54d5e8f77bcc3870e00dd6f1d4c1f9306 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 18 Aug 2023 10:22:26 +0100 Subject: [PATCH 11/22] Revert "fix(compute/build): support env vars for Windows" This reverts commit 242793a57556415da9a797c79cbc6bb97a321984. --- pkg/commands/compute/build_test.go | 4 ++-- pkg/commands/compute/init.go | 3 +-- pkg/commands/compute/language_go.go | 1 - pkg/commands/compute/language_toolchain.go | 4 +--- pkg/exec/exec.go | 3 +-- 5 files changed, 5 insertions(+), 10 deletions(-) diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index 099077bb8..4228aa90d 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -264,12 +264,12 @@ func TestBuildGo(t *testing.T) { name = "test" language = "go" [scripts] - build = "go build -o bin/main.wasm ./" + build = "GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" `, wantOutput: []string{ "The Fastly CLI build step requires a go version '>= 1.21'", "Build script to execute", - "go build -o bin/main.wasm ./", + "GOARCH=wasm GOOS=wasip1", "Creating ./bin directory (for Wasm binary)", "Built package", }, diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index a6f30dd2a..8786fb5c0 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -256,9 +256,8 @@ func (c *InitCommand) Exec(in io.Reader, out io.Writer) (err error) { s := Shell{} command, args := s.Build(postInit) noTimeout := 0 // zero indicates no timeout - noEnvVars := []string{} err := fstexec.Command( - command, args, msg, out, spinner, c.Globals.Flags.Verbose, noTimeout, c.Globals.ErrLog, noEnvVars, + command, args, msg, out, spinner, c.Globals.Flags.Verbose, noTimeout, c.Globals.ErrLog, ) if err != nil { return err diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 88831ed1e..ace5f5a9e 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -143,7 +143,6 @@ func (g *Go) Build() error { autoYes: g.autoYes, buildFn: g.Shell.Build, buildScript: g.build, - env: []string{"GOARCH=wasm", "GOOS=wasip1"}, errlog: g.errlog, in: g.input, nonInteractive: g.nonInteractive, diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index 8b9566811..cad5b68d0 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -41,8 +41,6 @@ type BuildToolchain struct { buildFn func(string) (string, []string) // buildScript is the [scripts.build] within the fastly.toml manifest. buildScript string - // env are environment variables to be set. - env []string // errlog is an abstraction for recording errors to disk. errlog fsterr.LogInterface // in is the user's terminal stdin stream @@ -197,7 +195,7 @@ func (bt BuildToolchain) handleError(err error) error { // By passing in the spinner and message we can short-circuit the spinner. func (bt BuildToolchain) execCommand(cmd string, args []string, spinMessage string) error { return fstexec.Command( - cmd, args, spinMessage, bt.out, bt.spinner, bt.verbose, bt.timeout, bt.errlog, bt.env, + cmd, args, spinMessage, bt.out, bt.spinner, bt.verbose, bt.timeout, bt.errlog, ) } diff --git a/pkg/exec/exec.go b/pkg/exec/exec.go index 51e76a4da..1733e3712 100644 --- a/pkg/exec/exec.go +++ b/pkg/exec/exec.go @@ -168,12 +168,11 @@ func Command( verbose bool, timeout int, errLog fsterr.LogInterface, - env []string, ) error { s := Streaming{ Command: cmd, Args: args, - Env: env, + Env: os.Environ(), Output: out, Spinner: spinner, SpinnerMessage: spinMessage, From 83340ffdfbe6e1c1c6612c23e984edbd68a65213 Mon Sep 17 00:00:00 2001 From: Integralist Date: Fri, 18 Aug 2023 10:57:11 +0100 Subject: [PATCH 12/22] fix: add env to test build script --- pkg/commands/compute/build_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index 4228aa90d..b46c2008f 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -264,7 +264,7 @@ func TestBuildGo(t *testing.T) { name = "test" language = "go" [scripts] - build = "GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" + build = "env GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" `, wantOutput: []string{ "The Fastly CLI build step requires a go version '>= 1.21'", From ebb7a16668fbeeb581949a53c0b886b7d974d68b Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 29 Aug 2023 15:01:34 +0100 Subject: [PATCH 13/22] feat(manifest): support scripts.env_vars --- pkg/commands/compute/build_test.go | 4 +- pkg/commands/compute/init.go | 20 ++++- pkg/commands/compute/language_go.go | 4 + pkg/commands/compute/language_toolchain.go | 19 ++++- pkg/exec/exec.go | 86 ++++++++++++++-------- pkg/manifest/file.go | 2 + 6 files changed, 96 insertions(+), 39 deletions(-) diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index b46c2008f..d88e4a05b 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -264,11 +264,13 @@ func TestBuildGo(t *testing.T) { name = "test" language = "go" [scripts] - build = "env GOARCH=wasm GOOS=wasip1 go build -o bin/main.wasm ./" + build = "go build -o bin/main.wasm ./" + env_vars = ["GOARCH=wasm", "GOOS=wasip1"] `, wantOutput: []string{ "The Fastly CLI build step requires a go version '>= 1.21'", "Build script to execute", + "Build environment variables set", "GOARCH=wasm GOOS=wasip1", "Creating ./bin directory (for Wasm binary)", "Built package", diff --git a/pkg/commands/compute/init.go b/pkg/commands/compute/init.go index 8786fb5c0..df127b73a 100644 --- a/pkg/commands/compute/init.go +++ b/pkg/commands/compute/init.go @@ -255,10 +255,22 @@ func (c *InitCommand) Exec(in io.Reader, out io.Writer) (err error) { s := Shell{} command, args := s.Build(postInit) - noTimeout := 0 // zero indicates no timeout - err := fstexec.Command( - command, args, msg, out, spinner, c.Globals.Flags.Verbose, noTimeout, c.Globals.ErrLog, - ) + // gosec flagged this: + // G204 (CWE-78): Subprocess launched with function call as argument or cmd arguments + // Disabling as we require the user to provide this command. + // #nosec + // nosemgrep: go.lang.security.audit.dangerous-exec-command.dangerous-exec-command + err := fstexec.Command(fstexec.CommandOpts{ + Args: args, + Command: command, + Env: c.manifest.File.Scripts.EnvVars, + ErrLog: c.Globals.ErrLog, + Output: out, + Spinner: spinner, + SpinnerMessage: msg, + Timeout: 0, // zero indicates no timeout + Verbose: c.Globals.Flags.Verbose, + }) if err != nil { return err } diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index ace5f5a9e..bef123e7b 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -47,6 +47,7 @@ func NewGo( autoYes: globals.Flags.AutoYes, build: fastlyManifest.Scripts.Build, config: globals.Config.Language.Go, + env: fastlyManifest.Scripts.EnvVars, errlog: globals.ErrLog, input: in, nonInteractive: globals.Flags.NonInteractive, @@ -73,6 +74,8 @@ type Go struct { build string // config is the Go specific application configuration. config config.Go + // env is environment variables to be set. + env []string // errlog is an abstraction for recording errors to disk. errlog fsterr.LogInterface // input is the user's terminal stdin stream @@ -143,6 +146,7 @@ func (g *Go) Build() error { autoYes: g.autoYes, buildFn: g.Shell.Build, buildScript: g.build, + env: g.env, errlog: g.errlog, in: g.input, nonInteractive: g.nonInteractive, diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index cad5b68d0..920015865 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -41,6 +41,8 @@ type BuildToolchain struct { buildFn func(string) (string, []string) // buildScript is the [scripts.build] within the fastly.toml manifest. buildScript string + // env is environment variables to be set. + env []string // errlog is an abstraction for recording errors to disk. errlog fsterr.LogInterface // in is the user's terminal stdin stream @@ -69,6 +71,9 @@ func (bt BuildToolchain) Build() error { if bt.verbose { text.Break(bt.out) text.Description(bt.out, "Build script to execute", fmt.Sprintf("%s %s", cmd, strings.Join(args, " "))) + if len(bt.env) > 0 { + text.Description(bt.out, "Build environment variables set", strings.Join(bt.env, " ")) + } } var err error @@ -194,9 +199,17 @@ func (bt BuildToolchain) handleError(err error) error { // This causes the spinner message to be displayed twice with different status. // By passing in the spinner and message we can short-circuit the spinner. func (bt BuildToolchain) execCommand(cmd string, args []string, spinMessage string) error { - return fstexec.Command( - cmd, args, spinMessage, bt.out, bt.spinner, bt.verbose, bt.timeout, bt.errlog, - ) + return fstexec.Command(fstexec.CommandOpts{ + Args: args, + Command: cmd, + Env: bt.env, + ErrLog: bt.errlog, + Output: bt.out, + Spinner: bt.spinner, + SpinnerMessage: spinMessage, + Timeout: bt.timeout, + Verbose: bt.verbose, + }) } // promptForPostBuildContinue ensures the user is happy to continue with the build diff --git a/pkg/exec/exec.go b/pkg/exec/exec.go index 1733e3712..b63b07889 100644 --- a/pkg/exec/exec.go +++ b/pkg/exec/exec.go @@ -23,17 +23,28 @@ const divider = "--------------------------------------------------------------- // compute commands can use this to standardize the flow control for each // compiler toolchain. type Streaming struct { - Args []string - Command string - Env []string - ForceOutput bool - Output io.Writer - Process *os.Process - SignalCh chan os.Signal - Spinner text.Spinner + // Args are the command positional arguments. + Args []string + // Command is the command to be executed. + Command string + // Env is the environment variables to set. + Env []string + // ForceOutput ensures output is displayed (default: only display on error). + ForceOutput bool + // Output is where to write output (e.g. stdout) + Output io.Writer + // Process is the process to terminal if signal received. + Process *os.Process + // SignalCh is a channel handling signal events. + SignalCh chan os.Signal + // Spinner is a specific spinner instance. + Spinner text.Spinner + // SpinnerMessage is the messaging to use. SpinnerMessage string - Timeout time.Duration - Verbose bool + // Timeout is the command timeout. + Timeout time.Duration + // Verbose outputs additional information. + Verbose bool } // MonitorSignals spawns a goroutine that configures signal handling so that @@ -157,35 +168,48 @@ func (s *Streaming) Signal(sig os.Signal) error { return nil } +// CommandOpts are arguments for executing a streaming command. +type CommandOpts struct { + // Args are the command positional arguments. + Args []string + // Command is the command to be executed. + Command string + // Env is the environment variables to set. + Env []string + // ErrLog provides an interface for recording errors to disk. + ErrLog fsterr.LogInterface + // Output is where to write output (e.g. stdout) + Output io.Writer + // Spinner is a specific spinner instance. + Spinner text.Spinner + // SpinnerMessage is the messaging to use. + SpinnerMessage string + // Timeout is the command timeout. + Timeout int + // Verbose outputs additional information. + Verbose bool +} + // Command is an abstraction over a Streaming type. It is used by both the // `compute init` and `compute build` commands to run post init/build scripts. -func Command( - cmd string, - args []string, - spinMessage string, - out io.Writer, - spinner text.Spinner, - verbose bool, - timeout int, - errLog fsterr.LogInterface, -) error { +func Command(opts CommandOpts) error { s := Streaming{ - Command: cmd, - Args: args, - Env: os.Environ(), - Output: out, - Spinner: spinner, - SpinnerMessage: spinMessage, - Verbose: verbose, + Command: opts.Command, + Args: opts.Args, + Env: opts.Env, + Output: opts.Output, + Spinner: opts.Spinner, + SpinnerMessage: opts.SpinnerMessage, + Verbose: opts.Verbose, } - if verbose { + if opts.Verbose { s.ForceOutput = true } - if timeout > 0 { - s.Timeout = time.Duration(timeout) * time.Second + if opts.Timeout > 0 { + s.Timeout = time.Duration(opts.Timeout) * time.Second } if err := s.Exec(); err != nil { - errLog.Add(err) + opts.ErrLog.Add(err) return err } return nil diff --git a/pkg/manifest/file.go b/pkg/manifest/file.go index 816accf36..4400fc295 100644 --- a/pkg/manifest/file.go +++ b/pkg/manifest/file.go @@ -190,6 +190,8 @@ func appendSpecRef(w io.Writer) error { type Scripts struct { // Build is a custom build script. Build string `toml:"build,omitempty"` + // EnvVars contains build related environment variables. + EnvVars []string `toml:"env_vars,omitempty"` // PostBuild is executed after the build step. PostBuild string `toml:"post_build,omitempty"` // PostInit is executed after the init step. From d5d1c0e970793cd161387b269dac57f473e0f15c Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 29 Aug 2023 15:38:30 +0100 Subject: [PATCH 14/22] doc(RELEASE): add comment about config_version --- RELEASE.md | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index c4d13f1ee..15bd5f1c9 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -1,19 +1,19 @@ # Release Process 1. Merge all PRs intended for the release. -2. Rebase latest remote main branch locally (`git pull --rebase origin main`). -3. Ensure all analysis checks and tests are passing (`time TEST_COMPUTE_INIT=1 TEST_COMPUTE_BUILD=1 TEST_COMPUTE_DEPLOY=1 make all`). -4. Ensure goreleaser builds locally (`make release GORELEASER_ARGS="--skip-validate --skip-post-hooks --clean"`). -5. Open a new PR to update CHANGELOG ([example](https://github.com/fastly/cli/pull/273))[1](#note1). -6. Merge CHANGELOG. -7. Rebase latest remote main branch locally (`git pull --rebase origin main`). -8. Tag a new release (`tag=vX.Y.Z && git tag -s $tag -m "$tag" && git push origin $tag`)[2](#note2). -9. Copy/paste CHANGELOG into the [draft release](https://github.com/fastly/cli/releases). -10. Publish draft release. -11. Communicate the release in the relevant Slack channels[3](#note3). +1. Rebase latest remote main branch locally (`git pull --rebase origin main`). +1. Ensure all analysis checks and tests are passing (`time TEST_COMPUTE_INIT=1 TEST_COMPUTE_BUILD=1 TEST_COMPUTE_DEPLOY=1 make all`). +1. Ensure goreleaser builds locally (`make release GORELEASER_ARGS="--skip-validate --skip-post-hooks --clean"`). +1. Open a new PR to update CHANGELOG ([example](https://github.com/fastly/cli/pull/273))[1](#note1). +1. Merge CHANGELOG. +1. Rebase latest remote main branch locally (`git pull --rebase origin main`). +1. Tag a new release (`tag=vX.Y.Z && git tag -s $tag -m "$tag" && git push origin $tag`)[2](#note2). +1. Copy/paste CHANGELOG into the [draft release](https://github.com/fastly/cli/releases). +1. Publish draft release. +1. Communicate the release in the relevant Slack channels[3](#note3). ## Footnotes -1. We utilize [semantic versioning](https://semver.org/) and only include relevant/significant changes within the CHANGELOG. -2. Triggers a [github action](https://github.com/fastly/cli/blob/main/.github/workflows/tag_release.yml) that produces a 'draft' release. -3. Fastly make internal announcements in the Slack channels: `#api-clients`, `#ecp-languages`. +1. We utilize [semantic versioning](https://semver.org/) and only include relevant/significant changes within the CHANGELOG (be sure to document changes to the app config if `config_version` has changed). +1. Triggers a [github action](https://github.com/fastly/cli/blob/main/.github/workflows/tag_release.yml) that produces a 'draft' release. +1. Fastly make internal announcements in the Slack channels: `#api-clients`, `#ecp-languages`. From 96f844bba24e62e26a6f1bff2e5ceb4b7a86e3f6 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 29 Aug 2023 15:39:50 +0100 Subject: [PATCH 15/22] doc(RELEASE): remove internal notes for releasing --- RELEASE.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/RELEASE.md b/RELEASE.md index 15bd5f1c9..93908ea98 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -10,10 +10,8 @@ 1. Tag a new release (`tag=vX.Y.Z && git tag -s $tag -m "$tag" && git push origin $tag`)[2](#note2). 1. Copy/paste CHANGELOG into the [draft release](https://github.com/fastly/cli/releases). 1. Publish draft release. -1. Communicate the release in the relevant Slack channels[3](#note3). ## Footnotes 1. We utilize [semantic versioning](https://semver.org/) and only include relevant/significant changes within the CHANGELOG (be sure to document changes to the app config if `config_version` has changed). 1. Triggers a [github action](https://github.com/fastly/cli/blob/main/.github/workflows/tag_release.yml) that produces a 'draft' release. -1. Fastly make internal announcements in the Slack channels: `#api-clients`, `#ecp-languages`. From 268362e382e705690e425adca4208b325f64752f Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 29 Aug 2023 18:11:22 +0100 Subject: [PATCH 16/22] feat(compute/build): validate wasm binary file --- pkg/commands/compute/build_test.go | 21 +++++-- pkg/commands/compute/language_go.go | 3 +- pkg/commands/compute/language_toolchain.go | 63 ++++++++++++++++++++- pkg/commands/compute/testdata/main.wasm | Bin 0 -> 8 bytes 4 files changed, 80 insertions(+), 7 deletions(-) create mode 100644 pkg/commands/compute/testdata/main.wasm diff --git a/pkg/commands/compute/build_test.go b/pkg/commands/compute/build_test.go index d88e4a05b..d702850e5 100644 --- a/pkg/commands/compute/build_test.go +++ b/pkg/commands/compute/build_test.go @@ -674,8 +674,21 @@ func TestBuildOther(t *testing.T) { // NOTE: Our only requirement is that there be a bin directory. The custom // build script we're using in the test is not going to use any files in the // directory (the script will just `echo` a message). + // + // NOTE: We create a "valid" main.wasm file with a quick shell script. + // + // Previously we set the build script to "touch ./bin/main.wasm" but since + // adding Wasm validation this no longer works as it's an empty file. + // + // So we use the following script to produce a file that LOOKS valid but isn't. + // + // magic="\x00\x61\x73\x6d\x01\x00\x00\x00" + // printf "$magic" > ./pkg/commands/compute/testdata/main.wasm rootdir := testutil.NewEnv(testutil.EnvOpts{ T: t, + Copy: []testutil.FileIO{ + {Src: "./testdata/main.wasm", Dst: "bin/main.wasm"}, + }, Write: []testutil.FileIO{ {Src: "mock content", Dst: "bin/testfile"}, }, @@ -707,7 +720,7 @@ func TestBuildOther(t *testing.T) { manifest_version = 2 name = "test" [scripts] - build = "touch ./bin/main.wasm" + build = "ls ./bin" post_build = "echo doing a post build"`, stdin: "N", wantOutput: []string{ @@ -724,7 +737,7 @@ func TestBuildOther(t *testing.T) { manifest_version = 2 name = "test" [scripts] - build = "touch ./bin/main.wasm" + build = "ls ./bin" post_build = "echo doing a post build"`, stdin: "Y", wantOutput: []string{ @@ -741,7 +754,7 @@ func TestBuildOther(t *testing.T) { name = "test" language = "other" [scripts] - build = "touch ./bin/main.wasm" + build = "ls ./bin" post_build = "echo doing a post build"`, stdin: "Y", wantOutput: []string{ @@ -757,7 +770,7 @@ func TestBuildOther(t *testing.T) { manifest_version = 2 name = "test" [scripts] - build = "touch ./bin/main.wasm" + build = "ls ./bin" post_build = "echo doing a post build with no confirmation prompt && exit 1"`, // force an error so post_build is displayed to validate it was run. wantOutput: []string{ "doing a post build with no confirmation prompt", diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index bef123e7b..9e22425b3 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -108,8 +108,7 @@ func (g *Go) Build() error { toolchainConstraint = g.config.ToolchainConstraintTinyGo text.Info(g.output, "No [scripts.build] found in fastly.toml. Visit https://developer.fastly.com/learning/compute/go/ to learn how to target standard Go vs TinyGo.") text.Break(g.output) - text.Description(g.output, "The following default build command for TinyGo will be used:", g.build) - text.Break(g.output) + text.Description(g.output, "The following default build command for TinyGo will be used", g.build) } if g.build != "" { diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index 920015865..9e699c4f2 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -1,9 +1,11 @@ package compute import ( + "encoding/binary" "fmt" "io" "os" + "strconv" "strings" fsterr "github.com/fastly/cli/pkg/errors" @@ -11,6 +13,9 @@ import ( "github.com/fastly/cli/pkg/text" ) +// https://webassembly.github.io/spec/core/binary/modules.html#binary-module +const wasmBytes = 4 + // DefaultBuildErrorRemediation is the message returned to a user when there is // a build error. var DefaultBuildErrorRemediation = func() string { @@ -143,13 +148,20 @@ func (bt BuildToolchain) Build() error { } } + binWasmPath := "./bin/main.wasm" + // IMPORTANT: The stat check MUST come after the internalPostBuildCallback. // This is because for Rust it needs to move the binary first. - _, err = os.Stat("./bin/main.wasm") + _, err = os.Stat(binWasmPath) if err != nil { return bt.handleError(err) } + // NOTE: The logic for checking the Wasm binary is 'valid' is not exhaustive. + if err := bt.validateWasm(binWasmPath); err != nil { + return err + } + if bt.postBuild != "" { if !bt.autoYes && !bt.nonInteractive { msg := fmt.Sprintf(CustomPostScriptMessage, "build") @@ -184,6 +196,55 @@ func (bt BuildToolchain) Build() error { return nil } +// The encoding of a module starts with a preamble containing a 4-byte magic +// number (the string '\0asm') and a version field. +// +// Reference: +// https://webassembly.github.io/spec/core/binary/modules.html#binary-module +func (bt BuildToolchain) validateWasm(path string) error { + // gosec flagged this: + // G304 (CWE-22): Potential file inclusion via variable + // Disabling as we trust the source of the path variable. + // #nosec + f, err := os.Open(path) + if err != nil { + return bt.handleError(err) + } + defer f.Close() + + // Parse the magic number + magic := make([]byte, wasmBytes) + _, err = f.Read(magic) + if err != nil { + return bt.handleError(err) + } + if len(magic) > 0 && magic[0] == 0x00 { + magic = magic[1:] // Remove the first byte which is a null character "\x00" + } + if string(magic) != "asm" { + return bt.handleError(err) + } + if bt.verbose { + text.Break(bt.out) + text.Description(bt.out, "Wasm module 'magic'", string(magic)) + } + + // Parse the version + versionBytes := make([]byte, wasmBytes) + _, err = f.Read(versionBytes) + if err != nil { + return bt.handleError(err) + } + version := int(binary.LittleEndian.Uint32(versionBytes)) + if version <= 0 { + return bt.handleError(err) + } + if bt.verbose { + text.Description(bt.out, "Wasm module 'version'", strconv.Itoa(version)) + } + return nil +} + func (bt BuildToolchain) handleError(err error) error { return fsterr.RemediationError{ Inner: err, diff --git a/pkg/commands/compute/testdata/main.wasm b/pkg/commands/compute/testdata/main.wasm new file mode 100644 index 0000000000000000000000000000000000000000..d8fc92d022fbf4d1072da17bc8e0840054b51ddc GIT binary patch literal 8 PcmZQbEY4+QU|;|M2ZjMd literal 0 HcmV?d00001 From 5609539a4d095e5ee9c67059f78709ace713f473 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 29 Aug 2023 19:31:26 +0100 Subject: [PATCH 17/22] refactor(config): replace inline value with config value --- .fastly/config.toml | 7 ++++--- pkg/commands/compute/language_go.go | 6 +++--- pkg/config/config.go | 4 ++++ 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/.fastly/config.toml b/.fastly/config.toml index 4623ff1b1..a8cc187ac 100644 --- a/.fastly/config.toml +++ b/.fastly/config.toml @@ -5,9 +5,10 @@ api_endpoint = "https://api.fastly.com" [language] [language.go] -tinygo_constraint = ">= 0.28.1-0" # NOTE -0 indicates to the CLI's semver package that we accept pre-releases (TinyGo users commonly use pre-releases). -toolchain_constraint = ">= 1.21" # Go toolchain constraint for use with WASI support. -toolchain_constraint_tinygo = ">= 1.18" # Go toolchain constraint for use with TinyGo. +tinygo_constraint = ">= 0.28.1-0" # NOTE -0 indicates to the CLI's semver package that we accept pre-releases (TinyGo users commonly use pre-releases). +tinygo_constraint_fallback = ">= 0.26.0-0" # The Fastly Go SDK 0.2.0 requires `tinygo_constraint` but the 0.1.x SDK requires this constraint. +toolchain_constraint = ">= 1.21" # Go toolchain constraint for use with WASI support. +toolchain_constraint_tinygo = ">= 1.18" # Go toolchain constraint for use with TinyGo. [language.rust] toolchain_constraint = ">= 1.56.1" diff --git a/pkg/commands/compute/language_go.go b/pkg/commands/compute/language_go.go index 9e22425b3..cb3409dcd 100644 --- a/pkg/commands/compute/language_go.go +++ b/pkg/commands/compute/language_go.go @@ -129,7 +129,7 @@ func (g *Go) Build() error { // This means we need to check the go.mod of the user's project for // `compute-sdk-go` and then parse the version and identify if it's less than // 0.2.0 version. If it less than, change the TinyGo constraint to 0.26.0 - tinygoConstraint := identifyTinyGoConstraint(g.config.TinyGoConstraint) + tinygoConstraint := identifyTinyGoConstraint(g.config.TinyGoConstraint, g.config.TinyGoConstraintFallback) g.toolchainConstraint( "go", `go version go(?P\d[^\s]+)`, toolchainConstraint, @@ -173,7 +173,7 @@ func (g *Go) Build() error { // NOTE: The `configConstraint` is the latest CLI application config version. // If there are any errors trying to parse the go.mod we'll default to the // config constraint. -func identifyTinyGoConstraint(configConstraint string) string { +func identifyTinyGoConstraint(configConstraint, fallback string) string { moduleName := "github.com/fastly/compute-sdk-go" version := "" @@ -231,7 +231,7 @@ func identifyTinyGoConstraint(configConstraint string) string { } if gomodVersion.LessThan(breakingSDKVersion) { - return ">= 0.26.0-0" + return fallback } return configConstraint diff --git a/pkg/config/config.go b/pkg/config/config.go index 5973f1cb0..8adfd1315 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -88,6 +88,10 @@ type Go struct { // TinyGoConstraint is the `tinygo` version that we support. TinyGoConstraint string `toml:"tinygo_constraint"` + // TinyGoConstraintFallback is a fallback `tinygo` version for users who have + // a pre-existing project with a 0.1.x Fastly Go SDK specified. + TinyGoConstraintFallback string `toml:"tinygo_constraint_fallback"` + // ToolchainConstraint is the `go` version that we support with WASI. ToolchainConstraint string `toml:"toolchain_constraint"` From 9f8d185a4fbcc74fcc45a9a35a7b38d650b0607a Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 29 Aug 2023 19:40:13 +0100 Subject: [PATCH 18/22] refactor(compute/toolchain): move value to constant to avoids gosec G304 --- pkg/commands/compute/language_toolchain.go | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index 9e699c4f2..d2edd1828 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -13,8 +13,13 @@ import ( "github.com/fastly/cli/pkg/text" ) -// https://webassembly.github.io/spec/core/binary/modules.html#binary-module -const wasmBytes = 4 +const ( + // https://webassembly.github.io/spec/core/binary/modules.html#binary-module + wasmBytes = 4 + + // Defining as a constant avoids gosec G304 issue with command execution. + binWasmPath = "./bin/main.wasm" +) // DefaultBuildErrorRemediation is the message returned to a user when there is // a build error. @@ -148,8 +153,6 @@ func (bt BuildToolchain) Build() error { } } - binWasmPath := "./bin/main.wasm" - // IMPORTANT: The stat check MUST come after the internalPostBuildCallback. // This is because for Rust it needs to move the binary first. _, err = os.Stat(binWasmPath) @@ -158,7 +161,7 @@ func (bt BuildToolchain) Build() error { } // NOTE: The logic for checking the Wasm binary is 'valid' is not exhaustive. - if err := bt.validateWasm(binWasmPath); err != nil { + if err := bt.validateWasm(); err != nil { return err } @@ -201,12 +204,8 @@ func (bt BuildToolchain) Build() error { // // Reference: // https://webassembly.github.io/spec/core/binary/modules.html#binary-module -func (bt BuildToolchain) validateWasm(path string) error { - // gosec flagged this: - // G304 (CWE-22): Potential file inclusion via variable - // Disabling as we trust the source of the path variable. - // #nosec - f, err := os.Open(path) +func (bt BuildToolchain) validateWasm() error { + f, err := os.Open(binWasmPath) if err != nil { return bt.handleError(err) } From 80b11a98e4f8b5f6754d8627e86525e593512e32 Mon Sep 17 00:00:00 2001 From: Integralist Date: Tue, 29 Aug 2023 20:05:14 +0100 Subject: [PATCH 19/22] refactor(compute/toolchain): replace string parsing with bytes.Equal --- pkg/commands/compute/language_toolchain.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index d2edd1828..f73292909 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -1,6 +1,7 @@ package compute import ( + "bytes" "encoding/binary" "fmt" "io" @@ -217,15 +218,13 @@ func (bt BuildToolchain) validateWasm() error { if err != nil { return bt.handleError(err) } - if len(magic) > 0 && magic[0] == 0x00 { - magic = magic[1:] // Remove the first byte which is a null character "\x00" - } - if string(magic) != "asm" { + expectedMagic := []byte{0x00, 0x61, 0x73, 0x6d} + if !bytes.Equal(magic, expectedMagic) { return bt.handleError(err) } if bt.verbose { text.Break(bt.out) - text.Description(bt.out, "Wasm module 'magic'", string(magic)) + text.Description(bt.out, "Wasm module 'magic'", fmt.Sprintf("%#v", magic)) } // Parse the version From befafbe3f5abfc9f9b950e9ce060c1c44e811372 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 30 Aug 2023 10:41:24 +0100 Subject: [PATCH 20/22] refactor(compute/toolchain): use Read method from binary package --- pkg/commands/compute/language_toolchain.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index f73292909..62427fa98 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -228,17 +228,12 @@ func (bt BuildToolchain) validateWasm() error { } // Parse the version - versionBytes := make([]byte, wasmBytes) - _, err = f.Read(versionBytes) - if err != nil { - return bt.handleError(err) - } - version := int(binary.LittleEndian.Uint32(versionBytes)) - if version <= 0 { + var version uint32 + if err := binary.Read(f, binary.LittleEndian, &version); err != nil { return bt.handleError(err) } if bt.verbose { - text.Description(bt.out, "Wasm module 'version'", strconv.Itoa(version)) + text.Description(bt.out, "Wasm module 'version'", strconv.FormatUint(uint64(version), 10)) } return nil } From beec623bb479cd29dfe052d9832dd0136e710b52 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 30 Aug 2023 10:55:42 +0100 Subject: [PATCH 21/22] feat(config): support resetting config to static embedded version --- pkg/commands/config/root.go | 7 +++++++ pkg/config/config.go | 8 ++++---- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/pkg/commands/config/root.go b/pkg/commands/config/root.go index 43c583be8..c0f922c64 100644 --- a/pkg/commands/config/root.go +++ b/pkg/commands/config/root.go @@ -6,6 +6,7 @@ import ( "os" "github.com/fastly/cli/pkg/cmd" + "github.com/fastly/cli/pkg/config" "github.com/fastly/cli/pkg/global" "github.com/fastly/cli/pkg/text" ) @@ -16,6 +17,7 @@ type RootCommand struct { cmd.Base location bool + reset bool } // NewRootCommand returns a new command registered in the parent. @@ -24,11 +26,16 @@ func NewRootCommand(parent cmd.Registerer, g *global.Data) *RootCommand { c.Globals = g c.CmdClause = parent.Command("config", "Display the Fastly CLI configuration") c.CmdClause.Flag("location", "Print the location of the CLI configuration file").Short('l').BoolVar(&c.location) + c.CmdClause.Flag("reset", "Reset the config to a version compatible with the current CLI version").Short('r').BoolVar(&c.reset) return &c } // Exec implements the command interface. func (c *RootCommand) Exec(_ io.Reader, out io.Writer) (err error) { + if c.reset { + c.Globals.Config.UseStatic(config.FilePath) + } + if c.location { if c.Globals.Flags.Verbose { text.Break(out) diff --git a/pkg/config/config.go b/pkg/config/config.go index 8adfd1315..b79c3b89a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -139,9 +139,9 @@ type StarterKit struct { Branch string `toml:"branch"` } -// createConfigDir creates the application configuration directory if it +// ensureConfigDirExists creates the application configuration directory if it // doesn't already exist. -func createConfigDir(path string) error { +func ensureConfigDirExists(path string) error { basePath := filepath.Dir(path) return filesystem.MakeDirectoryIfNotExists(basePath) } @@ -258,7 +258,7 @@ func (f *File) Read( f = &staticConfig } - err = createConfigDir(path) + err = ensureConfigDirExists(path) if err != nil { errLog.Add(err) return err @@ -358,7 +358,7 @@ func (f *File) UseStatic(path string) error { f.CLI.Version = revision.SemVer(revision.AppVersion) f.MigrateLegacy() - err = createConfigDir(path) + err = ensureConfigDirExists(path) if err != nil { return err } From 63704ce4c9becaf773b343e10a22edf9a159dda9 Mon Sep 17 00:00:00 2001 From: Integralist Date: Wed, 30 Aug 2023 19:57:39 +0100 Subject: [PATCH 22/22] fix(compute/toolchain): create custom error --- pkg/commands/compute/language_toolchain.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/commands/compute/language_toolchain.go b/pkg/commands/compute/language_toolchain.go index 62427fa98..9902d3434 100644 --- a/pkg/commands/compute/language_toolchain.go +++ b/pkg/commands/compute/language_toolchain.go @@ -220,7 +220,7 @@ func (bt BuildToolchain) validateWasm() error { } expectedMagic := []byte{0x00, 0x61, 0x73, 0x6d} if !bytes.Equal(magic, expectedMagic) { - return bt.handleError(err) + return bt.handleError(fmt.Errorf("unexpected magic: %#v", magic)) } if bt.verbose { text.Break(bt.out)