Create v2 Release (pin + lockstep tags) #3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Create v2 Release (pin + lockstep tags) | |
| # One manual workflow that cuts a full v2 release from main: | |
| # 1. Pre-flight: the modularization gates + the GOWORK=off release-mode build. | |
| # 2. Pin every submodule's cross-module require to the release version and | |
| # commit that in-CI (the commit the tags point at). Deterministic; runs | |
| # scripts/release-prep-pin.sh. | |
| # 3. Push the 16 per-module tags in dependency order, then verify the proxy. | |
| # | |
| # Supersedes the old two-step flow (manual release-prep-pin.sh on a throwaway | |
| # branch + a tag-only workflow). Procedure documented in | |
| # docs/v2-release-runbook.md. Run with dry_run=true first to preview the tags. | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| version: | |
| description: 'Version to tag (e.g. v2.0.0-beta.1). Applied to every submodule.' | |
| required: true | |
| type: string | |
| ref: | |
| description: 'Base ref/SHA to release from.' | |
| required: false | |
| type: string | |
| default: main | |
| dry_run: | |
| description: 'If true, pin and print the tag commands without pushing.' | |
| required: false | |
| type: boolean | |
| default: true | |
| # Default to read-only. Only the tagging job is granted write, so the pre-flight | |
| # job cannot push even though it runs scripts from a dispatched ref. | |
| permissions: | |
| contents: read | |
| jobs: | |
| verify: | |
| name: Pre-flight checks | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| ref: ${{ inputs.ref }} | |
| persist-credentials: false | |
| - run: bash scripts/check-acyclic-deps.sh | |
| - run: bash scripts/check-module-deps.sh | |
| - run: bash scripts/check-single-source.sh | |
| - run: bash scripts/check-siv-placement.sh | |
| - name: Set up mise | |
| uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| # Validates the exact release-mode build (pin + GOWORK=off external | |
| # consumer) in a throwaway, so it runs against the un-pinned ref. | |
| - name: Release-mode build (GOWORK=off external consumer) | |
| run: bash scripts/check-release-mode.sh | |
| tag-and-push: | |
| name: Pin, tag, push | |
| needs: verify | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| env: | |
| VERSION: ${{ inputs.version }} | |
| # Single source of truth for the module list and tag order (mirrors ORDER | |
| # in scripts/check-release-mode.sh and the runbook tag sequence). | |
| MODULE_PATHS: >- | |
| modules/core | |
| modules/ssh modules/httphelper modules/dnshelper | |
| modules/docker modules/packer modules/database modules/opa | |
| modules/aws modules/azure modules/gcp modules/k8s modules/helm | |
| modules/terraform modules/terragrunt modules/teststructure | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 | |
| with: | |
| ref: ${{ inputs.ref }} | |
| fetch-depth: 0 | |
| - name: Validate version | |
| run: | | |
| if [[ ! "$VERSION" =~ ^v2\.[0-9]+\.[0-9]+(-[0-9A-Za-z.]+)?$ ]]; then | |
| echo "::error::version '$VERSION' must look like v2.<minor>.<patch>[-suffix] (e.g. v2.0.0-beta.1)" | |
| exit 1 | |
| fi | |
| - name: Set up mise | |
| uses: jdx/mise-action@5228313ee0372e111a38da051671ca30fc5a96db # v3 | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Configure git | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| # Pin the cross-module requires to the real version and commit in-CI. This | |
| # is the commit the tags point at. It intentionally breaks the go.work | |
| # build (the tags do not exist yet); that only matters until the push. | |
| - name: Pin cross-module requires and commit | |
| run: | | |
| bash scripts/release-prep-pin.sh "$VERSION" | |
| if git diff --quiet; then | |
| echo "no placeholders to pin (ref already pinned to $VERSION)" | |
| else | |
| git commit -am "release-prep: pin cross-module requires to $VERSION" | |
| fi | |
| echo "PINNED_SHA=$(git rev-parse HEAD)" >> "$GITHUB_ENV" | |
| - name: Tag in dependency order | |
| env: | |
| DRY_RUN: ${{ inputs.dry_run }} | |
| run: | | |
| set -e | |
| for path in $MODULE_PATHS; do | |
| tag="${path}/${VERSION}" | |
| if [ "$DRY_RUN" = "true" ]; then | |
| echo "DRY-RUN would tag ${PINNED_SHA:0:12}: $tag" | |
| else | |
| git tag -a "$tag" -m "v2 lockstep release $VERSION" | |
| git push origin "$tag" | |
| echo "pushed $tag" | |
| fi | |
| done | |
| - name: Verify proxy serves each tag | |
| if: ${{ inputs.dry_run == false }} | |
| run: | | |
| # Allow the proxy a moment to populate after push. | |
| sleep 30 | |
| fail=0 | |
| for path in $MODULE_PATHS; do | |
| url="https://proxy.golang.org/github.com/gruntwork-io/terratest/${path}/v2/@v/${VERSION}.info" | |
| code=$(curl -s -o /dev/null -w '%{http_code}' "$url") | |
| if [ "$code" = "200" ]; then | |
| echo " $path: 200" | |
| else | |
| echo "::warning::$path: $code from $url" | |
| fail=1 | |
| fi | |
| done | |
| if [ "$fail" -ne 0 ]; then | |
| echo "::warning::Proxy has not served every tag yet. The tags are already pushed and immutable; the proxy usually populates within a few minutes. Re-run this check if needed." | |
| fi | |
| # One human-facing GitHub Release for the whole version (not 16). Attached | |
| # to the core tag; -beta/-rc suffixes are marked prerelease. | |
| - name: Create GitHub Release | |
| if: ${{ inputs.dry_run == false }} | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| prerelease="" | |
| case "$VERSION" in *-*) prerelease="--prerelease" ;; esac | |
| { | |
| echo "Terratest v2 lockstep release. All 16 submodules are tagged at ${VERSION}." | |
| echo | |
| echo "## Install" | |
| echo | |
| echo '```' | |
| echo "go get github.com/gruntwork-io/terratest/modules/aws/v2@${VERSION}" | |
| echo '```' | |
| echo | |
| echo "## Modules" | |
| echo | |
| echo "All at \`github.com/gruntwork-io/terratest/modules/<name>/v2\`:" | |
| echo | |
| for p in $MODULE_PATHS; do printf '%s ' "${p#modules/}"; done | |
| echo | |
| } > release_notes.md | |
| # shellcheck disable=SC2086 | |
| gh release create "modules/core/${VERSION}" \ | |
| --title "Terratest ${VERSION}" \ | |
| --notes-file release_notes.md \ | |
| $prerelease |