diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000..322f232 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,6 @@ +# These owners will be the default owners for everything in +# the repo. Unless a later match takes precedence, +# they will be requested for review when someone opens a +# pull request. + +* @hashicorp/terraform-core diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 6e32a8a..6c20668 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -11,3 +11,21 @@ updates: schedule: interval: "daily" labels: ["dependencies"] + + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + labels: + - dependencies + # only update HashiCorp actions, external actions managed by TSCCR + allow: + - dependency-name: hashicorp/* + groups: + github-actions-breaking: + update-types: + - major + github-actions-backward-compatible: + update-types: + - minor + - patch diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b84ce2f..3aa9d02 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ jobs: outputs: go-version: ${{ steps.get-go-version.outputs.go-version }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Determine Go version id: get-go-version run: | @@ -29,10 +29,10 @@ jobs: product-base-version: ${{ steps.set-product-version.outputs.base-product-version }} product-prerelease-version: ${{ steps.set-product-version.outputs.prerelease-product-version }} steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Set Product version id: set-product-version - uses: hashicorp/actions-set-product-version@v1 + uses: hashicorp/actions-set-product-version@d9b52fb778068099ca4c5e28e1ca0fee2544e114 # v2 generate-metadata-file: needs: set-product-version @@ -41,15 +41,15 @@ jobs: filepath: ${{ steps.generate-metadata-file.outputs.filepath }} steps: - name: "Checkout directory" - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Generate metadata file id: generate-metadata-file - uses: hashicorp/actions-generate-metadata@v1 + uses: hashicorp/actions-generate-metadata@fdbc8803a0e53bcbb912ddeee3808329033d6357 # v1.1.1 with: version: ${{ needs.set-product-version.outputs.product-version }} product: ${{ env.PKG_NAME }} repositoryOwner: "hashicorp" - - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 with: name: metadata.json path: ${{ steps.generate-metadata-file.outputs.filepath }} @@ -81,8 +81,8 @@ jobs: fail-fast: true name: Go ${{ needs.get-go-version.outputs.go-version }} ${{ matrix.goos }} ${{ matrix.goarch }} build steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: hashicorp/actions-go-build@v0.1.9 + - uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 + - uses: hashicorp/actions-go-build@37358f6098ef21b09542d84a9814ebb843aa4e3e # v1 env: BASE_VERSION: ${{ needs.set-product-version.outputs.product-base-version }} PRERELEASE_VERSION: ${{ needs.set-product-version.outputs.product-prerelease-version}} @@ -97,10 +97,16 @@ jobs: reproducible: report instructions: | go build -trimpath -ldflags "-s -w" -o "$BIN_PATH" ./cmd/hc-install - + cp LICENSE "$TARGET_DIR/LICENSE.txt" + - name: Copy license file to config_dir # for Linux packages + if: ${{ matrix.goos == 'linux' }} + env: + LICENSE_DIR: ".release/linux/package/usr/share/doc/${{ env.PKG_NAME }}" + run: | + mkdir -p "$LICENSE_DIR" && cp LICENSE "$LICENSE_DIR/LICENSE.txt" - name: Package if: ${{ matrix.goos == 'linux' }} - uses: hashicorp/actions-packaging-linux@v1 + uses: hashicorp/actions-packaging-linux@0596d94121d44bd00463ac9d245efea64ee282d0 # v1.7 with: name: ${{ github.event.repository.name }} description: "hc-install CLI allows installing multiple versions of HashiCorp products in automation" @@ -112,6 +118,7 @@ jobs: binary: "dist/${{ env.PKG_NAME }}" deb_depends: "openssl" rpm_depends: "openssl" + config_dir: ".release/linux/package/" - name: Set Package Names if: ${{ matrix.goos == 'linux' }} @@ -119,13 +126,13 @@ jobs: echo "RPM_PACKAGE=$(basename out/*.rpm)" >> $GITHUB_ENV echo "DEB_PACKAGE=$(basename out/*.deb)" >> $GITHUB_ENV - - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: ${{ matrix.goos == 'linux' }} with: name: ${{ env.RPM_PACKAGE }} path: out/${{ env.RPM_PACKAGE }} - - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 + - uses: actions/upload-artifact@65462800fd760344b1a7b4382951275a0abb4808 # v4.3.3 if: ${{ matrix.goos == 'linux' }} with: name: ${{ env.DEB_PACKAGE }} diff --git a/.github/workflows/nightly-tests.yaml b/.github/workflows/nightly-tests.yaml index 0c16e9b..e95b7dd 100644 --- a/.github/workflows/nightly-tests.yaml +++ b/.github/workflows/nightly-tests.yaml @@ -15,13 +15,13 @@ jobs: - name: Resolve old stable version id: oldstable - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: oldstable - name: Resolve stable version id: stable - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: stable outputs: @@ -43,10 +43,10 @@ jobs: - ${{ needs.resolve-versions.outputs.stable }} steps: - name: Check out code - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Set up Go - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: ${{ matrix.go_version }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1144586..88cc764 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Setup bob - uses: hashicorp/action-setup-bob@v1 + uses: hashicorp/action-setup-bob@37475d2579813f74f3a9f4e86870498c8e560a1c # v2 with: github-token: ${{ secrets.BOB_GITHUB_TOKEN }} @@ -49,7 +49,7 @@ jobs: needs: staging steps: - name: Setup bob - uses: hashicorp/action-setup-bob@v1 + uses: hashicorp/action-setup-bob@37475d2579813f74f3a9f4e86870498c8e560a1c # v2 with: github-token: ${{ secrets.BOB_GITHUB_TOKEN }} diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d39bab3..fac881f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,9 +18,9 @@ jobs: timeout-minutes: 3 steps: - name: Checkout Repo - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Install copywrite - uses: hashicorp/setup-copywrite@v1.1.2 + uses: hashicorp/setup-copywrite@32638da2d4e81d56a0764aa1547882fc4d209636 # v1.1.3 - name: Validate Header Compliance run: copywrite headers --plan @@ -33,13 +33,13 @@ jobs: - name: Resolve old stable version id: oldstable - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: oldstable - name: Resolve stable version id: stable - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: stable outputs: @@ -60,13 +60,13 @@ jobs: - ${{ needs.resolve-versions.outputs.stable }} steps: - name: Set up Go - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: ${{ matrix.go_version }} id: go - name: Check out code into the Go module directory - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Go fmt run: | @@ -98,13 +98,13 @@ jobs: steps: - name: Set up Go - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0 + uses: actions/setup-go@cdcb36043654635271a94b9a6d1392de5bb323a7 # v5.0.1 with: go-version: ${{ matrix.go_version }} id: go - name: Check out code into the Go module directory - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + uses: actions/checkout@0ad4b8fadaa221de15dcec353f45205ec38ea70b # v4.1.4 - name: Unit tests timeout-minutes: 5 diff --git a/README.md b/README.md index 6e78b5a..0d55191 100644 --- a/README.md +++ b/README.md @@ -14,55 +14,55 @@ the library in ad-hoc or CI shell scripting outside of Go. `hc-install` does **not**: - - Determine suitable installation path based on target system. e.g. in `/usr/bin` or `/usr/local/bin` on Unix based system. - - Deal with execution of installed binaries (via service files or otherwise). - - Upgrade existing binaries on your system. - - Add nor link downloaded binaries to your `$PATH`. +- Determine suitable installation path based on target system. e.g. in `/usr/bin` or `/usr/local/bin` on Unix based system. +- Deal with execution of installed binaries (via service files or otherwise). +- Upgrade existing binaries on your system. +- Add nor link downloaded binaries to your `$PATH`. ## API The `Installer` offers a few high-level methods: - - `Ensure(context.Context, []src.Source)` to find, install, or build a product version - - `Install(context.Context, []src.Installable)` to install a product version +- `Ensure(context.Context, []src.Source)` to find, install, or build a product version +- `Install(context.Context, []src.Installable)` to install a product version ### Sources The `Installer` methods accept number of different `Source` types. Each comes with different trade-offs described below. - - `fs.{AnyVersion,ExactVersion,Version}` - Finds a binary in `$PATH` (or additional paths) - - **Pros:** - - This is most convenient when you already have the product installed on your system +- `fs.{AnyVersion,ExactVersion,Version}` - Finds a binary in `$PATH` (or additional paths) + - **Pros:** + - This is most convenient when you already have the product installed on your system which you already manage. - - **Cons:** - - Only relies on a single version, expects _you_ to manage the installation - - _Not recommended_ for any environment where product installation is not controlled or managed by you (e.g. default GitHub Actions image managed by GitHub) - - `releases.{LatestVersion,ExactVersion}` - Downloads, verifies & installs any known product from `releases.hashicorp.com` - - **Pros:** - - Fast and reliable way of obtaining any pre-built version of any product - - Allows installation of enterprise versions - - **Cons:** - - Installation may consume some bandwidth, disk space and a little time - - Potentially less stable builds (see `checkpoint` below) - - `checkpoint.LatestVersion` - Downloads, verifies & installs any known product available in HashiCorp Checkpoint - - **Pros:** - - Checkpoint typically contains only product versions considered stable - - **Cons:** - - Installation may consume some bandwidth, disk space and a little time - - Currently doesn't allow installation of old versions or enterprise versions (see `releases` above) - - `build.GitRevision` - Clones raw source code and builds the product from it - - **Pros:** - - Useful for catching bugs and incompatibilities as early as possible (prior to product release). - - **Cons:** - - Building from scratch can consume significant amount of time & resources (CPU, memory, bandwith, disk space) - - There are no guarantees that build instructions will always be up-to-date - - There's increased likelihood of build containing bugs prior to release - - Any CI builds relying on this are likely to be fragile + - **Cons:** + - Only relies on a single version, expects _you_ to manage the installation + - _Not recommended_ for any environment where product installation is not controlled or managed by you (e.g. default GitHub Actions image managed by GitHub) +- `releases.{LatestVersion,ExactVersion}` - Downloads, verifies & installs any known product from `releases.hashicorp.com` + - **Pros:** + - Fast and reliable way of obtaining any pre-built version of any product + - Allows installation of enterprise versions + - **Cons:** + - Installation may consume some bandwidth, disk space and a little time + - Potentially less stable builds (see `checkpoint` below) +- `checkpoint.LatestVersion` - Downloads, verifies & installs any known product available in HashiCorp Checkpoint + - **Pros:** + - Checkpoint typically contains only product versions considered stable + - **Cons:** + - Installation may consume some bandwidth, disk space and a little time + - Currently doesn't allow installation of old versions or enterprise versions (see `releases` above) +- `build.GitRevision` - Clones raw source code and builds the product from it + - **Pros:** + - Useful for catching bugs and incompatibilities as early as possible (prior to product release). + - **Cons:** + - Building from scratch can consume significant amount of time & resources (CPU, memory, bandwidth, disk space) + - There are no guarantees that build instructions will always be up-to-date + - There's increased likelihood of build containing bugs prior to release + - Any CI builds relying on this are likely to be fragile ## Example Usage -See examples at https://pkg.go.dev/github.com/hashicorp/hc-install#example-Installer. +See examples at . ## CLI @@ -70,9 +70,9 @@ In addition to the Go library, which is the intended primary use case of `hc-ins The CLI comes with some trade-offs: - - more limited interface compared to the flexible Go API (installs specific versions of products via `releases.ExactVersion`) - - minimal environment pre-requisites (no need to compile Go code) - - see ["hc-install is not a package manager"](https://github.com/hashicorp/hc-install#hc-install-is-not-a-package-manager) +- more limited interface compared to the flexible Go API (installs specific versions of products via `releases.ExactVersion`) +- minimal environment pre-requisites (no need to compile Go code) +- see ["hc-install is not a package manager"](https://github.com/hashicorp/hc-install#hc-install-is-not-a-package-manager) ### Installation @@ -82,7 +82,7 @@ Given that one of the key roles of the CLI/library is integrity checking, you sh [Homebrew](https://brew.sh) -``` +```sh brew install hashicorp/tap/hc-install ``` @@ -102,19 +102,23 @@ You can follow the instructions in the [Official Packaging Guide](https://www.ha ### Usage -``` +```text Usage: hc-install install [options] -version This command installs a HashiCorp product. Options: -version [REQUIRED] Version of product to install. - -path Path to directory where the product will be installed. Defaults - to current working directory. + -path Path to directory where the product will be installed. + Defaults to current working directory. + -log-file Path to file where logs will be written. /dev/stdout + or /dev/stderr can be used to log to STDOUT/STDERR. ``` + ```sh hc-install install -version 1.3.7 terraform ``` -``` + +```sh hc-install: will install terraform@1.3.7 installed terraform@1.3.7 to /current/working/dir/terraform ``` diff --git a/build/git_revision.go b/build/git_revision.go index 2cd9f41..ae36e5d 100644 --- a/build/git_revision.go +++ b/build/git_revision.go @@ -6,9 +6,10 @@ package build import ( "context" "fmt" - "io/ioutil" + "io" "log" "os" + "path/filepath" "time" "github.com/go-git/go-git/v5" @@ -23,7 +24,7 @@ var ( defaultCloneTimeout = 5 * time.Minute defaultBuildTimeout = 25 * time.Minute - discardLogger = log.New(ioutil.Discard, "", 0) + discardLogger = log.New(io.Discard, "", 0) ) // GitRevision installs a particular git revision by cloning @@ -101,7 +102,7 @@ func (gr *GitRevision) Build(ctx context.Context) (string, error) { gr.pathsToRemove = make([]string, 0) } - repoDir, err := ioutil.TempDir("", + repoDir, err := os.MkdirTemp("", fmt.Sprintf("hc-install-build-%s", gr.Product.Name)) if err != nil { return "", err @@ -160,7 +161,7 @@ func (gr *GitRevision) Build(ctx context.Context) (string, error) { } installDir := gr.InstallDir if installDir == "" { - tmpDir, err := ioutil.TempDir("", + tmpDir, err := os.MkdirTemp("", fmt.Sprintf("hc-install-%s-%s", gr.Product.Name, head.Hash())) if err != nil { return "", err @@ -169,11 +170,47 @@ func (gr *GitRevision) Build(ctx context.Context) (string, error) { gr.pathsToRemove = append(gr.pathsToRemove, installDir) } + // copy license file on best effort basis + dstLicensePath := filepath.Join(installDir, "LICENSE.txt") + srcLicensePath := filepath.Join(repoDir, "LICENSE.txt") + altSrcLicensePath := filepath.Join(repoDir, "LICENSE") + if _, err := os.Stat(srcLicensePath); err == nil { + err = gr.copyLicenseFile(srcLicensePath, dstLicensePath) + if err != nil { + return "", err + } + } else if _, err := os.Stat(altSrcLicensePath); err == nil { + err = gr.copyLicenseFile(altSrcLicensePath, dstLicensePath) + if err != nil { + return "", err + } + } + gr.log().Printf("building %s (timeout: %s)", gr.Product.Name, buildTimeout) defer gr.log().Printf("building of %s finished", gr.Product.Name) return bi.Build.Build(buildCtx, repoDir, installDir, gr.Product.BinaryName()) } +func (gr *GitRevision) copyLicenseFile(srcPath, dstPath string) error { + src, err := os.Open(srcPath) + if err != nil { + return err + } + defer src.Close() + dst, err := os.Create(dstPath) + if err != nil { + return err + } + defer dst.Close() + n, err := io.Copy(dst, src) + if err != nil { + return err + } + gr.log().Printf("license file copied from %q to %q (%d bytes)", + srcPath, dstPath, n) + return nil +} + func (gr *GitRevision) Remove(ctx context.Context) error { if gr.pathsToRemove != nil { for _, path := range gr.pathsToRemove { diff --git a/build/git_revision_test.go b/build/git_revision_test.go index 2da0a25..400e424 100644 --- a/build/git_revision_test.go +++ b/build/git_revision_test.go @@ -6,6 +6,8 @@ package build import ( "context" "fmt" + "os" + "path/filepath" "testing" "github.com/hashicorp/go-version" @@ -32,7 +34,15 @@ func TestGitRevision_terraform(t *testing.T) { if err != nil { t.Fatal(err) } - t.Cleanup(func() { gr.Remove(ctx) }) + + licensePath := filepath.Join(filepath.Dir(execPath), "LICENSE.txt") + t.Cleanup(func() { + gr.Remove(ctx) + // check if license was deleted + if _, err := os.Stat(licensePath); !os.IsNotExist(err) { + t.Fatalf("license file not deleted at %q: %s", licensePath, err) + } + }) v, err := product.Terraform.GetVersion(ctx, execPath) if err != nil { @@ -47,6 +57,11 @@ func TestGitRevision_terraform(t *testing.T) { t.Fatalf("versions don't match (expected: %s, installed: %s)", latestConstraint, v) } + + // check if license was copied + if _, err := os.Stat(licensePath); err != nil { + t.Fatalf("expected license file not found at %q: %s", licensePath, err) + } } func TestGitRevision_consul(t *testing.T) { diff --git a/checkpoint/latest_version.go b/checkpoint/latest_version.go index 2cd5379..7a8aa3d 100644 --- a/checkpoint/latest_version.go +++ b/checkpoint/latest_version.go @@ -6,7 +6,7 @@ package checkpoint import ( "context" "fmt" - "io/ioutil" + "io" "log" "os" "path/filepath" @@ -24,7 +24,7 @@ import ( var ( defaultTimeout = 30 * time.Second - discardLogger = log.New(ioutil.Discard, "", 0) + discardLogger = log.New(io.Discard, "", 0) ) // LatestVersion installs the latest version known to Checkpoint @@ -101,7 +101,7 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) { if dstDir == "" { var err error dirName := fmt.Sprintf("%s_*", lv.Product.Name) - dstDir, err = ioutil.TempDir("", dirName) + dstDir, err = os.MkdirTemp("", dirName) if err != nil { return "", err } @@ -126,9 +126,9 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) { if lv.ArmoredPublicKey != "" { d.ArmoredPublicKey = lv.ArmoredPublicKey } - zipFilePath, err := d.DownloadAndUnpack(ctx, pv, dstDir, "") - if zipFilePath != "" { - lv.pathsToRemove = append(lv.pathsToRemove, zipFilePath) + up, err := d.DownloadAndUnpack(ctx, pv, dstDir, "") + if up != nil { + lv.pathsToRemove = append(lv.pathsToRemove, up.PathsToRemove...) } if err != nil { return "", err diff --git a/checkpoint/latest_version_test.go b/checkpoint/latest_version_test.go index ffc6a4c..4172a97 100644 --- a/checkpoint/latest_version_test.go +++ b/checkpoint/latest_version_test.go @@ -6,6 +6,8 @@ package checkpoint import ( "context" "fmt" + "os" + "path/filepath" "testing" "github.com/hashicorp/go-version" @@ -34,7 +36,15 @@ func TestLatestVersion(t *testing.T) { if err != nil { t.Fatal(err) } - t.Cleanup(func() { lv.Remove(ctx) }) + + licensePath := filepath.Join(filepath.Dir(execPath), "LICENSE.txt") + t.Cleanup(func() { + lv.Remove(ctx) + // check if license was deleted + if _, err := os.Stat(licensePath); !os.IsNotExist(err) { + t.Fatalf("license file not deleted at %q: %s", licensePath, err) + } + }) v, err := product.Terraform.GetVersion(ctx, execPath) if err != nil { @@ -49,6 +59,11 @@ func TestLatestVersion(t *testing.T) { t.Fatalf("versions don't match (expected: %s, installed: %s)", latestConstraint, v) } + + // check if license was copied + if _, err := os.Stat(licensePath); err != nil { + t.Fatalf("expected license file not found at %q: %s", licensePath, err) + } } func TestLatestVersionValidate(t *testing.T) { diff --git a/cmd/hc-install/cmd_install.go b/cmd/hc-install/cmd_install.go index bd0f682..eb61493 100644 --- a/cmd/hc-install/cmd_install.go +++ b/cmd/hc-install/cmd_install.go @@ -7,6 +7,8 @@ import ( "context" "flag" "fmt" + "io" + "log" "os" "runtime" "strings" @@ -37,8 +39,10 @@ Usage: hc-install install [options] -version This command installs a HashiCorp product. Options: -version [REQUIRED] Version of product to install. - -path Path to directory where the product will be installed. Defaults - to current working directory. + -path Path to directory where the product will be installed. + Defaults to current working directory. + -log-file Path to file where logs will be written. /dev/stdout + or /dev/stderr can be used to log to STDOUT/STDERR. ` return strings.TrimSpace(helpText) } @@ -47,12 +51,14 @@ func (c *InstallCommand) Run(args []string) int { var ( version string installDirPath string + logFilePath string ) fs := flag.NewFlagSet("install", flag.ExitOnError) fs.Usage = func() { c.Ui.Output(c.Help()) } fs.StringVar(&version, "version", "", "version of product to install") fs.StringVar(&installDirPath, "path", "", "path to directory where production will be installed") + fs.StringVar(&logFilePath, "log-file", "", "path to file where logs will be written") if err := fs.Parse(args); err != nil { return 1 @@ -83,7 +89,17 @@ Option flags must be provided before the positional argument`) installDirPath = cwd } - installedPath, err := c.install(product, version, installDirPath) + logger := log.New(io.Discard, "", 0) + if logFilePath != "" { + f, err := os.OpenFile(logFilePath, os.O_WRONLY|os.O_APPEND|os.O_CREATE, 0644) + if err != nil { + c.Ui.Error(fmt.Sprintf("unable to log into %q: %s", logFilePath, err)) + return 1 + } + logger = log.New(f, "[DEBUG] ", log.LstdFlags|log.Lshortfile|log.Lmicroseconds) + } + + installedPath, err := c.install(product, version, installDirPath, logger) if err != nil { msg := fmt.Sprintf("failed to install %s@%s: %v", product, version, err) c.Ui.Error(msg) @@ -94,7 +110,7 @@ Option flags must be provided before the positional argument`) return 0 } -func (c *InstallCommand) install(project, tag, installDirPath string) (string, error) { +func (c *InstallCommand) install(project, tag, installDirPath string, logger *log.Logger) (string, error) { msg := fmt.Sprintf("hc-install: will install %s@%s", project, tag) c.Ui.Info(msg) @@ -103,6 +119,7 @@ func (c *InstallCommand) install(project, tag, installDirPath string) (string, e return "", fmt.Errorf("invalid version: %w", err) } i := hci.NewInstaller() + i.SetLogger(logger) source := &releases.ExactVersion{ Product: product.Product{ diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 23ce140..b406406 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -6,8 +6,8 @@ Releases are made on a reasonably regular basis by the maintainers (HashiCorp st Release process: - 1. Update [`version/VERSION`](https://github.com/hashicorp/hc-install/blob/main/version/VERSION) to remove `-dev` suffix and set it to the intended version to be released - 1. Wait for [`build` workflow](https://github.com/hashicorp/hc-install/actions/workflows/build.yml) to finish - 1. Run the Release workflow with the appropriate version (matching the one in `version/VERSION`) & SHA (long one). - 1. Wait for a message in the Slack channel saying that authorisation is needed to promote artifacts to production. Click on the link and approve. - 1. Once notified that promotion is successful, go to https://github.com/hashicorp/crt-workflows-common/actions/workflows/promote-production-packaging.yml, locate the hc-install promote-production-packaging workflow, and approve. +1. Update [`version/VERSION`](https://github.com/hashicorp/hc-install/blob/main/version/VERSION) to remove `-dev` suffix and set it to the intended version to be released +1. Wait for [`build` workflow](https://github.com/hashicorp/hc-install/actions/workflows/build.yml) to finish +1. Run the Release workflow with the appropriate version (matching the one in `version/VERSION`) & SHA (long one). +1. Wait for a message in the Slack channel saying that authorisation is needed to promote artifacts to production. Click on the link and approve. +1. Once notified that promotion is successful, go to , locate the hc-install promote-production-packaging workflow, and approve. diff --git a/fs/fs.go b/fs/fs.go index 216df2c..ac6f5cf 100644 --- a/fs/fs.go +++ b/fs/fs.go @@ -4,14 +4,14 @@ package fs import ( - "io/ioutil" + "io" "log" "time" ) var ( defaultTimeout = 10 * time.Second - discardLogger = log.New(ioutil.Discard, "", 0) + discardLogger = log.New(io.Discard, "", 0) ) type fileCheckFunc func(path string) error diff --git a/fs/fs_test.go b/fs/fs_test.go index 1d82c98..99238c4 100644 --- a/fs/fs_test.go +++ b/fs/fs_test.go @@ -54,7 +54,7 @@ func TestVersion(t *testing.T) { t.Setenv("PATH", p) ev := releases.ExactVersion{ Product: product.Terraform, - Version: version.Must(version.NewVersion("1.0.0")), + Version: version.Must(version.NewVersion("1.1.0")), InstallDir: p, } ev.SetLogger(testutil.TestLogger()) @@ -67,7 +67,7 @@ func TestVersion(t *testing.T) { // Version matches constraint v := &Version{ Product: product.Terraform, - Constraints: version.MustConstraints(version.NewConstraint(">= 1.0")), + Constraints: version.MustConstraints(version.NewConstraint(">= 1.1")), } v.SetLogger(testutil.TestLogger()) if _, err := v.Find(ctx); err != nil { @@ -97,7 +97,7 @@ func TestVersion(t *testing.T) { } // Version mismatches constraint - v.Constraints = version.MustConstraints(version.NewConstraint("> 1.0")) + v.Constraints = version.MustConstraints(version.NewConstraint("> 1.1")) if _, err := v.Find(ctx); err == nil { t.Fatal("expecting error") } diff --git a/fs/fs_unix.go b/fs/fs_unix.go index eebd98b..5aed844 100644 --- a/fs/fs_unix.go +++ b/fs/fs_unix.go @@ -16,9 +16,7 @@ import ( func lookupDirs(extraDirs []string) []string { pathVar := os.Getenv("PATH") dirs := filepath.SplitList(pathVar) - for _, ep := range extraDirs { - dirs = append(dirs, ep) - } + dirs = append(dirs, extraDirs...) return dirs } diff --git a/go.mod b/go.mod index 39927e2..ea8cd1e 100644 --- a/go.mod +++ b/go.mod @@ -3,8 +3,8 @@ module github.com/hashicorp/hc-install go 1.18 require ( - github.com/ProtonMail/go-crypto v1.1.0-alpha.0 - github.com/go-git/go-git/v5 v5.11.0 + github.com/ProtonMail/go-crypto v1.1.0-alpha.2 + github.com/go-git/go-git/v5 v5.12.0 github.com/google/go-cmp v0.6.0 github.com/hashicorp/cli v1.1.6 github.com/hashicorp/go-checkpoint v0.5.0 @@ -12,7 +12,7 @@ require ( github.com/hashicorp/go-multierror v1.1.1 github.com/hashicorp/go-version v1.6.0 github.com/hashicorp/logutils v1.0.0 - golang.org/x/mod v0.15.0 + golang.org/x/mod v0.17.0 ) require ( @@ -43,14 +43,14 @@ require ( github.com/mitchellh/reflectwalk v1.0.0 // indirect github.com/pjbgf/sha1cd v0.3.0 // indirect github.com/posener/complete v1.2.3 // indirect - github.com/sergi/go-diff v1.1.0 // indirect + github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect github.com/shopspring/decimal v1.2.0 // indirect - github.com/skeema/knownhosts v1.2.1 // indirect + github.com/skeema/knownhosts v1.2.2 // indirect github.com/spf13/cast v1.3.1 // indirect github.com/xanzy/ssh-agent v0.3.3 // indirect - golang.org/x/crypto v0.17.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/crypto v0.21.0 // indirect + golang.org/x/net v0.23.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/tools v0.13.0 // indirect gopkg.in/warnings.v0 v0.1.2 // indirect ) diff --git a/go.sum b/go.sum index bb1fcb9..164d94b 100644 --- a/go.sum +++ b/go.sum @@ -9,8 +9,8 @@ github.com/Masterminds/sprig/v3 v3.2.3/go.mod h1:rXcFaZ2zZbLRJv/xSysmlgIM1u11eBa github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= github.com/Microsoft/go-winio v0.6.1 h1:9/kr64B9VUZrLm5YYwbGtUJnMgqWVOdUAXu6Migciow= github.com/Microsoft/go-winio v0.6.1/go.mod h1:LRdKpFKfdobln8UmuiYcKPot9D2v6svN5+sAH+4kjUM= -github.com/ProtonMail/go-crypto v1.1.0-alpha.0 h1:nHGfwXmFvJrSR9xu8qL7BkO4DqTHXE9N5vPhgY2I+j0= -github.com/ProtonMail/go-crypto v1.1.0-alpha.0/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= +github.com/ProtonMail/go-crypto v1.1.0-alpha.2 h1:bkyFVUP+ROOARdgCiJzNQo2V2kiB97LyUpzH9P6Hrlg= +github.com/ProtonMail/go-crypto v1.1.0-alpha.2/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI= github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= @@ -29,14 +29,14 @@ github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= -github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY= +github.com/gliderlabs/ssh v0.3.7 h1:iV3Bqi942d9huXnzEF2Mt+CY9gLu8DNM4Obd+8bODRE= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= github.com/go-git/go-billy/v5 v5.5.0 h1:yEY4yhzCDuMGSv83oGxiBotRzhwhNr8VZyphhiu+mTU= github.com/go-git/go-billy/v5 v5.5.0/go.mod h1:hmexnoNsr2SJU1Ju67OaNz5ASJY3+sHgFRpCtpDCKow= github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= -github.com/go-git/go-git/v5 v5.11.0 h1:XIZc1p+8YzypNr34itUfSvYJcv+eYdTnTvOZ2vD3cA4= -github.com/go-git/go-git/v5 v5.11.0/go.mod h1:6GFcX2P3NM7FPBfpePbpLd21XxsgdAt+lKqXmCUiUCY= +github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys= +github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE= github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= @@ -95,20 +95,20 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/posener/complete v1.2.3 h1:NP0eAhjcjImqslEwo/1hq7gpajME0fTLTezBKDqfXqo= github.com/posener/complete v1.2.3/go.mod h1:WZIdtGGp+qx0sLrYKtIRAruyNpv6hFCicSgv7Sy7s/s= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/sergi/go-diff v1.1.0 h1:we8PVUC3FE2uYfodKH/nBHMSetSfHDR6scGdBi+erh0= -github.com/sergi/go-diff v1.1.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= +github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= -github.com/skeema/knownhosts v1.2.1 h1:SHWdIUa82uGZz+F+47k8SY4QhhI291cXCpopT1lK2AQ= -github.com/skeema/knownhosts v1.2.1/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= +github.com/skeema/knownhosts v1.2.2 h1:Iug2P4fLmDw9f41PB6thxUkNUkJzB5i+1/exaj40L3A= +github.com/skeema/knownhosts v1.2.2/go.mod h1:xYbVRSPxqBZFrdmDyMmsOs+uX1UZC3nTN3ThzgDxUwo= github.com/spf13/cast v1.3.1 h1:nFm6S0SMdyzrzcmThSipiEubIDy8WEXKNZ0UOgiRpng= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM= github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -116,18 +116,18 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= -golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k= -golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= -golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= +golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= +golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E= @@ -143,12 +143,12 @@ golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= +golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -167,7 +167,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntN gopkg.in/warnings.v0 v0.1.2 h1:wFXVbFY8DY5/xOe1ECiWdKCzZlxgshcYVNkBHstARME= gopkg.in/warnings.v0 v0.1.2/go.mod h1:jksf8JmL6Qr/oQM2OXTHunEvvTAsrWBLb6OOjuVWRNI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/installer.go b/installer.go index 6c704ee..01c1fde 100644 --- a/installer.go +++ b/installer.go @@ -6,7 +6,7 @@ package install import ( "context" "fmt" - "io/ioutil" + "io" "log" "github.com/hashicorp/go-multierror" @@ -23,7 +23,7 @@ type Installer struct { type RemoveFunc func(ctx context.Context) error func NewInstaller() *Installer { - discardLogger := log.New(ioutil.Discard, "", 0) + discardLogger := log.New(io.Discard, "", 0) return &Installer{ logger: discardLogger, } diff --git a/internal/build/go_build.go b/internal/build/go_build.go index 504bf45..6eef755 100644 --- a/internal/build/go_build.go +++ b/internal/build/go_build.go @@ -7,7 +7,7 @@ import ( "bytes" "context" "fmt" - "io/ioutil" + "io" "log" "os" "os/exec" @@ -17,7 +17,7 @@ import ( "golang.org/x/mod/modfile" ) -var discardLogger = log.New(ioutil.Discard, "", 0) +var discardLogger = log.New(io.Discard, "", 0) // GoBuild represents a Go builder (to run "go build") type GoBuild struct { @@ -161,7 +161,7 @@ type CleanupFunc func(context.Context) func guessRequiredGoVersion(repoDir string) (*version.Version, bool) { goEnvFile := filepath.Join(repoDir, ".go-version") if fi, err := os.Stat(goEnvFile); err == nil && !fi.IsDir() { - b, err := ioutil.ReadFile(goEnvFile) + b, err := os.ReadFile(goEnvFile) if err != nil { return nil, false } @@ -174,7 +174,7 @@ func guessRequiredGoVersion(repoDir string) (*version.Version, bool) { goModFile := filepath.Join(repoDir, "go.mod") if fi, err := os.Stat(goModFile); err == nil && !fi.IsDir() { - b, err := ioutil.ReadFile(goModFile) + b, err := os.ReadFile(goModFile) if err != nil { return nil, false } diff --git a/internal/releasesjson/checksum_downloader.go b/internal/releasesjson/checksum_downloader.go index 843de8c..59dd1a1 100644 --- a/internal/releasesjson/checksum_downloader.go +++ b/internal/releasesjson/checksum_downloader.go @@ -55,7 +55,7 @@ func (cd *ChecksumDownloader) DownloadAndVerifyChecksums(ctx context.Context) (C client := httpclient.NewHTTPClient() sigURL := fmt.Sprintf("%s/%s/%s/%s", cd.BaseURL, url.PathEscape(cd.ProductVersion.Name), - url.PathEscape(cd.ProductVersion.RawVersion), + url.PathEscape(cd.ProductVersion.Version.String()), url.PathEscape(sigFilename)) cd.Logger.Printf("downloading signature from %s", sigURL) @@ -76,7 +76,7 @@ func (cd *ChecksumDownloader) DownloadAndVerifyChecksums(ctx context.Context) (C shasumsURL := fmt.Sprintf("%s/%s/%s/%s", cd.BaseURL, url.PathEscape(cd.ProductVersion.Name), - url.PathEscape(cd.ProductVersion.RawVersion), + url.PathEscape(cd.ProductVersion.Version.String()), url.PathEscape(cd.ProductVersion.SHASUMS)) cd.Logger.Printf("downloading checksums from %s", shasumsURL) diff --git a/internal/releasesjson/downloader.go b/internal/releasesjson/downloader.go index 146c1cf..a1139b5 100644 --- a/internal/releasesjson/downloader.go +++ b/internal/releasesjson/downloader.go @@ -10,7 +10,6 @@ import ( "crypto/sha256" "fmt" "io" - "io/ioutil" "log" "net/http" "net/url" @@ -29,14 +28,18 @@ type Downloader struct { BaseURL string } -func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, binDir string, licenseDir string) (zipFilePath string, err error) { +type UnpackedProduct struct { + PathsToRemove []string +} + +func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, binDir string, licenseDir string) (up *UnpackedProduct, err error) { if len(pv.Builds) == 0 { - return "", fmt.Errorf("no builds found for %s %s", pv.Name, pv.Version) + return nil, fmt.Errorf("no builds found for %s %s", pv.Name, pv.Version) } pb, ok := pv.Builds.FilterBuild(runtime.GOOS, runtime.GOARCH, "zip") if !ok { - return "", fmt.Errorf("no ZIP archive found for %s %s %s/%s", + return nil, fmt.Errorf("no ZIP archive found for %s %s %s/%s", pv.Name, pv.Version, runtime.GOOS, runtime.GOARCH) } @@ -50,12 +53,12 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, } verifiedChecksums, err := v.DownloadAndVerifyChecksums(ctx) if err != nil { - return "", err + return nil, err } var ok bool verifiedChecksum, ok = verifiedChecksums[pb.Filename] if !ok { - return "", fmt.Errorf("no checksum found for %q", pb.Filename) + return nil, fmt.Errorf("no checksum found for %q", pb.Filename) } } @@ -63,16 +66,17 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, archiveURL := pb.URL if d.BaseURL != "" { - // ensure that absolute download links from mocked responses - // are still pointing to the mock server if one is set + // If custom URL is set, use that instead of the one from the JSON. + // Also ensures that absolute download links from mocked responses + // are still pointing to the mock server if one is set. baseURL, err := url.Parse(d.BaseURL) if err != nil { - return "", err + return nil, err } u, err := url.Parse(archiveURL) if err != nil { - return "", err + return nil, err } u.Scheme = baseURL.Scheme u.Host = baseURL.Host @@ -83,15 +87,15 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, req, err := http.NewRequestWithContext(ctx, http.MethodGet, archiveURL, nil) if err != nil { - return "", fmt.Errorf("failed to create request for %q: %w", archiveURL, err) + return nil, fmt.Errorf("failed to create request for %q: %w", archiveURL, err) } resp, err := client.Do(req) if err != nil { - return "", err + return nil, err } if resp.StatusCode != 200 { - return "", fmt.Errorf("failed to download ZIP archive from %q: %s", archiveURL, resp.Status) + return nil, fmt.Errorf("failed to download ZIP archive from %q: %s", archiveURL, resp.Status) } defer resp.Body.Close() @@ -100,19 +104,22 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, contentType := resp.Header.Get("content-type") if !contentTypeIsZip(contentType) { - return "", fmt.Errorf("unexpected content-type: %s (expected any of %q)", + return nil, fmt.Errorf("unexpected content-type: %s (expected any of %q)", contentType, zipMimeTypes) } expectedSize := resp.ContentLength - pkgFile, err := ioutil.TempFile("", pb.Filename) + pkgFile, err := os.CreateTemp("", pb.Filename) if err != nil { - return "", err + return nil, err } defer pkgFile.Close() pkgFilePath, err := filepath.Abs(pkgFile.Name()) + up = &UnpackedProduct{} + up.PathsToRemove = append(up.PathsToRemove, pkgFilePath) + d.Logger.Printf("copying %q (%d bytes) to %s", pb.Filename, expectedSize, pkgFile.Name()) var bytesCopied int64 @@ -123,12 +130,12 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, bytesCopied, err = io.Copy(h, r) if err != nil { - return "", err + return nil, err } calculatedSum := h.Sum(nil) if !bytes.Equal(calculatedSum, verifiedChecksum) { - return pkgFilePath, fmt.Errorf( + return up, fmt.Errorf( "checksum mismatch (expected: %x, got: %x)", verifiedChecksum, calculatedSum, ) @@ -136,14 +143,14 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, } else { bytesCopied, err = io.Copy(pkgFile, pkgReader) if err != nil { - return pkgFilePath, err + return up, err } } d.Logger.Printf("copied %d bytes to %s", bytesCopied, pkgFile.Name()) if expectedSize != 0 && bytesCopied != int64(expectedSize) { - return pkgFilePath, fmt.Errorf( + return up, fmt.Errorf( "unexpected size (downloaded: %d, expected: %d)", bytesCopied, expectedSize, ) @@ -151,7 +158,7 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, r, err := zip.OpenReader(pkgFile.Name()) if err != nil { - return pkgFilePath, err + return up, err } defer r.Close() @@ -163,7 +170,7 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, } srcFile, err := f.Open() if err != nil { - return pkgFilePath, err + return up, err } // Determine the appropriate destination file path @@ -174,20 +181,25 @@ func (d *Downloader) DownloadAndUnpack(ctx context.Context, pv *ProductVersion, d.Logger.Printf("unpacking %s to %s", f.Name, dstDir) dstPath := filepath.Join(dstDir, f.Name) + + if isLicenseFile(f.Name) { + up.PathsToRemove = append(up.PathsToRemove, dstPath) + } + dstFile, err := os.Create(dstPath) if err != nil { - return pkgFilePath, err + return up, err } _, err = io.Copy(dstFile, srcFile) if err != nil { - return pkgFilePath, err + return up, err } srcFile.Close() dstFile.Close() } - return pkgFilePath, nil + return up, nil } // The production release site uses consistent single mime type @@ -207,11 +219,13 @@ func contentTypeIsZip(contentType string) bool { return false } -// Enterprise products have a few additional license files -// that need to be extracted to a separate directory +// Product archives may have a few license files +// which may be extracted to a separate directory +// and may need to be tracked for later cleanup. var licenseFiles = []string{ "EULA.txt", "TermsOfEvaluation.txt", + "LICENSE.txt", } func isLicenseFile(filename string) bool { diff --git a/internal/releasesjson/product_version.go b/internal/releasesjson/product_version.go index 99b811a..94152b1 100644 --- a/internal/releasesjson/product_version.go +++ b/internal/releasesjson/product_version.go @@ -9,8 +9,7 @@ import "github.com/hashicorp/go-version" // "consul 0.5.1". A ProductVersion may have one or more builds. type ProductVersion struct { Name string `json:"name"` - RawVersion string `json:"version"` - Version *version.Version `json:"-"` + Version *version.Version `json:"version"` SHASUMS string `json:"shasums,omitempty"` SHASUMSSig string `json:"shasums_signature,omitempty"` SHASUMSSigs []string `json:"shasums_signatures,omitempty"` diff --git a/internal/releasesjson/releases.go b/internal/releasesjson/releases.go index 755019f..4c0bab0 100644 --- a/internal/releasesjson/releases.go +++ b/internal/releasesjson/releases.go @@ -7,7 +7,7 @@ import ( "context" "encoding/json" "fmt" - "io/ioutil" + "io" "log" "net/http" "net/url" @@ -55,7 +55,7 @@ type Releases struct { func NewReleases() *Releases { return &Releases{ - logger: log.New(ioutil.Discard, "", 0), + logger: log.New(io.Discard, "", 0), BaseURL: defaultBaseURL, } } @@ -95,7 +95,7 @@ func (r *Releases) ListProductVersions(ctx context.Context, productName string) r.logger.Printf("received %s", resp.Status) - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } @@ -153,7 +153,7 @@ func (r *Releases) GetProductVersion(ctx context.Context, product string, versio r.logger.Printf("received %s", resp.Status) - body, err := ioutil.ReadAll(resp.Body) + body, err := io.ReadAll(resp.Body) if err != nil { return nil, err } diff --git a/internal/releasesjson/releases_test.go b/internal/releasesjson/releases_test.go index aaa6768..ed76dcb 100644 --- a/internal/releasesjson/releases_test.go +++ b/internal/releasesjson/releases_test.go @@ -46,7 +46,7 @@ func TestGetProductVersion_includesEnterpriseBuild(t *testing.T) { testEntVersion.String()) } - if version.RawVersion != testEntVersion.Original() { + if version.Version.String() != testEntVersion.Original() { t.Fatalf("Expected version %q, got %q", testEntVersion.String(), version.Version.String()) } } diff --git a/internal/testutil/logger.go b/internal/testutil/logger.go index 2d214b2..451f822 100644 --- a/internal/testutil/logger.go +++ b/internal/testutil/logger.go @@ -4,7 +4,7 @@ package testutil import ( - "io/ioutil" + "io" "log" "os" "testing" @@ -14,5 +14,5 @@ func TestLogger() *log.Logger { if testing.Verbose() { return log.New(os.Stdout, "", log.LstdFlags|log.Lshortfile) } - return log.New(ioutil.Discard, "", 0) + return log.New(io.Discard, "", 0) } diff --git a/releases/exact_version.go b/releases/exact_version.go index e42f4d2..179f0b4 100644 --- a/releases/exact_version.go +++ b/releases/exact_version.go @@ -6,7 +6,6 @@ package releases import ( "context" "fmt" - "io/ioutil" "log" "os" "path/filepath" @@ -37,7 +36,10 @@ type ExactVersion struct { // instead of built-in pubkey to verify signature of downloaded checksums ArmoredPublicKey string - apiBaseURL string + // ApiBaseURL is an optional field that specifies a custom URL to download the product from. + // If ApiBaseURL is set, the product will be downloaded from this base URL instead of the default site. + // Note: The directory structure of the custom URL must match the HashiCorp releases site (including the index.json files). + ApiBaseURL string logger *log.Logger pathsToRemove []string } @@ -93,7 +95,7 @@ func (ev *ExactVersion) Install(ctx context.Context) (string, error) { if dstDir == "" { var err error dirName := fmt.Sprintf("%s_*", ev.Product.Name) - dstDir, err = ioutil.TempDir("", dirName) + dstDir, err = os.MkdirTemp("", dirName) if err != nil { return "", err } @@ -103,8 +105,8 @@ func (ev *ExactVersion) Install(ctx context.Context) (string, error) { ev.log().Printf("will install into dir at %s", dstDir) rels := rjson.NewReleases() - if ev.apiBaseURL != "" { - rels.BaseURL = ev.apiBaseURL + if ev.ApiBaseURL != "" { + rels.BaseURL = ev.ApiBaseURL } rels.SetLogger(ev.log()) installVersion := ev.Version @@ -125,17 +127,17 @@ func (ev *ExactVersion) Install(ctx context.Context) (string, error) { if ev.ArmoredPublicKey != "" { d.ArmoredPublicKey = ev.ArmoredPublicKey } - if ev.apiBaseURL != "" { - d.BaseURL = ev.apiBaseURL + if ev.ApiBaseURL != "" { + d.BaseURL = ev.ApiBaseURL } licenseDir := "" if ev.Enterprise != nil { licenseDir = ev.Enterprise.LicenseDir } - zipFilePath, err := d.DownloadAndUnpack(ctx, pv, dstDir, licenseDir) - if zipFilePath != "" { - ev.pathsToRemove = append(ev.pathsToRemove, zipFilePath) + up, err := d.DownloadAndUnpack(ctx, pv, dstDir, licenseDir) + if up != nil { + ev.pathsToRemove = append(ev.pathsToRemove, up.PathsToRemove...) } if err != nil { return "", err diff --git a/releases/latest_version.go b/releases/latest_version.go index 9893b22..c4888f4 100644 --- a/releases/latest_version.go +++ b/releases/latest_version.go @@ -6,7 +6,6 @@ package releases import ( "context" "fmt" - "io/ioutil" "log" "os" "path/filepath" @@ -37,7 +36,10 @@ type LatestVersion struct { // instead of built-in pubkey to verify signature of downloaded checksums ArmoredPublicKey string - apiBaseURL string + // ApiBaseURL is an optional field that specifies a custom URL to download the product from. + // If ApiBaseURL is set, the product will be downloaded from this base URL instead of the default site. + // Note: The directory structure of the custom URL must match the HashiCorp releases site (including the index.json files). + ApiBaseURL string logger *log.Logger pathsToRemove []string } @@ -89,7 +91,7 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) { if dstDir == "" { var err error dirName := fmt.Sprintf("%s_*", lv.Product.Name) - dstDir, err = ioutil.TempDir("", dirName) + dstDir, err = os.MkdirTemp("", dirName) if err != nil { return "", err } @@ -99,8 +101,8 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) { lv.log().Printf("will install into dir at %s", dstDir) rels := rjson.NewReleases() - if lv.apiBaseURL != "" { - rels.BaseURL = lv.apiBaseURL + if lv.ApiBaseURL != "" { + rels.BaseURL = lv.ApiBaseURL } rels.SetLogger(lv.log()) versions, err := rels.ListProductVersions(ctx, lv.Product.Name) @@ -126,16 +128,16 @@ func (lv *LatestVersion) Install(ctx context.Context) (string, error) { if lv.ArmoredPublicKey != "" { d.ArmoredPublicKey = lv.ArmoredPublicKey } - if lv.apiBaseURL != "" { - d.BaseURL = lv.apiBaseURL + if lv.ApiBaseURL != "" { + d.BaseURL = lv.ApiBaseURL } licenseDir := "" if lv.Enterprise != nil { licenseDir = lv.Enterprise.LicenseDir } - zipFilePath, err := d.DownloadAndUnpack(ctx, versionToInstall, dstDir, licenseDir) - if zipFilePath != "" { - lv.pathsToRemove = append(lv.pathsToRemove, zipFilePath) + up, err := d.DownloadAndUnpack(ctx, versionToInstall, dstDir, licenseDir) + if up != nil { + lv.pathsToRemove = append(lv.pathsToRemove, up.PathsToRemove...) } if err != nil { return "", err diff --git a/releases/releases.go b/releases/releases.go index 7bef49b..a24db6c 100644 --- a/releases/releases.go +++ b/releases/releases.go @@ -4,7 +4,7 @@ package releases import ( - "io/ioutil" + "io" "log" "time" ) @@ -12,5 +12,5 @@ import ( var ( defaultInstallTimeout = 30 * time.Second defaultListTimeout = 10 * time.Second - discardLogger = log.New(ioutil.Discard, "", 0) + discardLogger = log.New(io.Discard, "", 0) ) diff --git a/releases/releases_test.go b/releases/releases_test.go index f0844b9..22e20c4 100644 --- a/releases/releases_test.go +++ b/releases/releases_test.go @@ -6,7 +6,7 @@ package releases import ( "context" "fmt" - "io/ioutil" + "io" "os" "path/filepath" "testing" @@ -61,7 +61,7 @@ func TestLatestVersion_basic(t *testing.T) { lv := &LatestVersion{ Product: product.Terraform, ArmoredPublicKey: getTestPubKey(t), - apiBaseURL: testutil.NewTestServer(t, mockApiRoot).URL, + ApiBaseURL: testutil.NewTestServer(t, mockApiRoot).URL, } lv.SetLogger(testutil.TestLogger()) @@ -95,7 +95,7 @@ func TestLatestVersion_prereleases(t *testing.T) { Product: product.Terraform, IncludePrereleases: true, ArmoredPublicKey: getTestPubKey(t), - apiBaseURL: testutil.NewTestServer(t, mockApiRoot).URL, + ApiBaseURL: testutil.NewTestServer(t, mockApiRoot).URL, } lv.SetLogger(testutil.TestLogger()) @@ -125,7 +125,7 @@ func TestLatestVersion_prereleases(t *testing.T) { func TestExactVersion(t *testing.T) { testutil.EndToEndTest(t) - versionToInstall := version.Must(version.NewVersion("0.14.0")) + versionToInstall := version.Must(version.NewVersion("1.8.2")) ev := &ExactVersion{ Product: product.Terraform, Version: versionToInstall, @@ -139,7 +139,14 @@ func TestExactVersion(t *testing.T) { t.Fatal(err) } - t.Cleanup(func() { ev.Remove(ctx) }) + licensePath := filepath.Join(filepath.Dir(execPath), "LICENSE.txt") + t.Cleanup(func() { + ev.Remove(ctx) + // check if license was deleted + if _, err := os.Stat(licensePath); !os.IsNotExist(err) { + t.Fatalf("license file not deleted at %q: %s", licensePath, err) + } + }) t.Logf("exec path of installed: %s", execPath) @@ -152,13 +159,18 @@ func TestExactVersion(t *testing.T) { t.Fatalf("versions don't match (expected: %s, installed: %s)", versionToInstall, v) } + + // check if license was copied + if _, err := os.Stat(licensePath); err != nil { + t.Fatalf("expected license file not found at %q: %s", licensePath, err) + } } func BenchmarkExactVersion(b *testing.B) { mockApiRoot := filepath.Join("testdata", "mock_api_tf_0_14_with_prereleases") for i := 0; i < b.N; i++ { - installDir, err := ioutil.TempDir("", fmt.Sprintf("%s_%d", "terraform", i)) + installDir, err := os.MkdirTemp("", fmt.Sprintf("%s_%d", "terraform", i)) if err != nil { b.Fatal(err) } @@ -167,7 +179,7 @@ func BenchmarkExactVersion(b *testing.B) { Product: product.Terraform, Version: version.Must(version.NewVersion("0.14.11")), ArmoredPublicKey: getTestPubKey(b), - apiBaseURL: testutil.NewTestServer(b, mockApiRoot).URL, + ApiBaseURL: testutil.NewTestServer(b, mockApiRoot).URL, InstallDir: installDir, } ev.SetLogger(testutil.TestLogger()) @@ -183,7 +195,7 @@ func BenchmarkExactVersion(b *testing.B) { func getTestPubKey(t testing.TB) string { f, err := os.Open(filepath.Join("testdata", "2FCA0A85.pub")) - b, err := ioutil.ReadAll(f) + b, err := io.ReadAll(f) if err != nil { t.Fatal(err) } diff --git a/releases/testdata/mock_api_tf_0_14_with_prereleases/terraform/index.json b/releases/testdata/mock_api_tf_0_14_with_prereleases/terraform/index.json index d8b975d..ace99c3 100644 --- a/releases/testdata/mock_api_tf_0_14_with_prereleases/terraform/index.json +++ b/releases/testdata/mock_api_tf_0_14_with_prereleases/terraform/index.json @@ -612,6 +612,14 @@ "filename": "terraform_0.15.0-rc2_darwin_amd64.zip", "url": "https://releases.hashicorp.com/terraform/0.15.0-rc2/terraform_0.15.0-rc2_darwin_amd64.zip" }, + { + "name": "terraform", + "version": "0.15.0-rc2", + "os": "darwin", + "arch": "arm64", + "filename": "terraform_0.15.0-rc2_darwin_arm64.zip", + "url": "https://releases.hashicorp.com/terraform/0.15.0-rc2/terraform_0.15.0-rc2_darwin_arm64.zip" + }, { "name": "terraform", "version": "0.15.0-rc2", diff --git a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS index 0b14d58..ee61b23 100644 --- a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS +++ b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS @@ -1,3 +1,4 @@ -518baaa2b8926bf704d5f72f50631b46f598fb883da6691dd5523091ed54bae3 terraform_0.15.0-rc2_darwin_amd64.zip -d4ede4731c2d5f30d786cb9a28004d77037b0bc25e3343e82536509b4dd8d13c terraform_0.15.0-rc2_linux_amd64.zip -eb6c292c28058fd0aea75ef1a14cda16fa817c3e5bd0df08cd74d565eb556bcf terraform_0.15.0-rc2_windows_amd64.zip +d432b9722de43e89bb1568344b47c707348025d809765817ece2e46cd0d7b24d terraform_0.15.0-rc2_darwin_amd64.zip +6b6bf2497aefbef79076bde41a0718b72e9adabb3e33fafc45e9494546199e43 terraform_0.15.0-rc2_darwin_arm64.zip +44dfce5c083a9187393262a5071e21e55d1c38dc4bd2a6c5284ae7924974be8a terraform_0.15.0-rc2_linux_amd64.zip +14a5acf8b7dd8c6947e6af633e7962f0d4974c4ac0eb0fcefb1ff43db829ea1f terraform_0.15.0-rc2_windows_amd64.zip diff --git a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.2FCA0A85.sig b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.2FCA0A85.sig index 6f19c35..2ea641c 100644 Binary files a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.2FCA0A85.sig and b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.2FCA0A85.sig differ diff --git a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.sig b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.sig index 6f19c35..2ea641c 100644 Binary files a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.sig and b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_SHA256SUMS.sig differ diff --git a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_darwin_amd64.zip b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_darwin_amd64.zip index 1b4c109..c57ed01 100644 Binary files a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_darwin_amd64.zip and b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_darwin_amd64.zip differ diff --git a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_darwin_arm64.zip b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_darwin_arm64.zip new file mode 100644 index 0000000..95522bc Binary files /dev/null and b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_darwin_arm64.zip differ diff --git a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_linux_amd64.zip b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_linux_amd64.zip index cd87d20..8ef84c1 100644 Binary files a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_linux_amd64.zip and b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_linux_amd64.zip differ diff --git a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_windows_amd64.zip b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_windows_amd64.zip index de95037..6890b64 100644 Binary files a/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_windows_amd64.zip and b/releases/testdata/mock_terraform_builds/0.15.0-rc2/terraform_0.15.0-rc2_windows_amd64.zip differ diff --git a/releases/testdata/terraform/main.go b/releases/testdata/terraform/main.go index 554c0c6..979cf61 100644 --- a/releases/testdata/terraform/main.go +++ b/releases/testdata/terraform/main.go @@ -7,7 +7,7 @@ import ( "encoding/json" "flag" "fmt" - "io/ioutil" + "io" "log" "os" "runtime" @@ -98,7 +98,7 @@ func (c *VersionCommand) Run(args []string) int { func defaultFlagSet(name string) *flag.FlagSet { f := flag.NewFlagSet(name, flag.ContinueOnError) - f.SetOutput(ioutil.Discard) + f.SetOutput(io.Discard) f.Usage = func() {} return f } diff --git a/version/VERSION b/version/VERSION index 844f6a9..faef31a 100644 --- a/version/VERSION +++ b/version/VERSION @@ -1 +1 @@ -0.6.3 +0.7.0