From 1400b8a4916d13242b19cae630b080c644c3842c Mon Sep 17 00:00:00 2001 From: Agustin Bettati Date: Thu, 18 Apr 2024 09:29:27 +0200 Subject: [PATCH] chore: Refactor release steps ensuring tag is created before running tests and creating release (#2154) * initial structure * fix: use github output * fix: ensure tag step uses latest commit from master * fix: handle properly string value of output value * rename initial step for processing inputs * add new input for commit workflow * simplify conditionals by using cancelled() and contains(needs.*.result, 'failure') * add FAQ section in releasing docs * fix link to workflow --- .github/workflows/release.yml | 115 +++++++++++++++++++++------------- RELEASING.md | 16 +++++ 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6d297266f6..0503319962 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,5 +1,5 @@ name: 'New Release' -run-name: 'Release ${{ inputs.version_number }}' +run-name: 'Release ${{ inputs.version_number }} (skip tests: ${{ inputs.skip_tests }}, use existing tag: ${{ inputs.use_existing_tag}})' # Used for creating a new release. This workflow will run qa acceptance tests, create a new tag, and generate the release with GoReleaser. on: @@ -9,38 +9,43 @@ on: description: 'Version number (e.g., v1.0.0, v1.0.0-pre, v1.0.0-pre1)' required: true skip_tests: - description: 'Skip QA acceptance tests, define value to `true` to explicitly skip' + description: 'Set value to `true` to skip QA acceptance tests, default is `false`' + default: 'false' use_existing_tag: - description: 'Set value to `true` to use an existing tag for this release version, default is `false`' + description: 'Set value to `true` to use an existing tag for the release process, default is `false`' + default: 'false' jobs: + release-config: + runs-on: ubuntu-latest + outputs: + creates_new_tag: ${{ steps.evaluate_inputs.outputs.creates_new_tag }} + is_official_release: ${{ steps.evaluate_inputs.outputs.is_official_release }} + runs_tests: ${{ steps.evaluate_inputs.outputs.runs_tests }} + steps: + - id: evaluate_inputs + run: | + { + echo "creates_new_tag=$(if [ '${{ inputs.use_existing_tag }}' = 'true' ]; then echo 'false'; else echo 'true'; fi)" + echo "is_official_release=$(if echo '${{ inputs.version_number }}' | grep -q 'pre'; then echo 'false'; else echo 'true'; fi)" + echo "runs_tests=$(if [ '${{ inputs.skip_tests }}' = 'true' ]; then echo 'false'; else echo 'true'; fi)" + } >> "$GITHUB_OUTPUT" + validate-version-input: runs-on: ubuntu-latest steps: - name: Validation of version format run: | - echo "${{ inputs.version_number }}" | grep -P '^v\d+\.\d+\.\d+(-pre[A-Za-z0-9-]*)?$' + echo "${{ inputs.version_number }}" | grep -P '^v\d+\.\d+\.\d+(-pre[A-Za-z0-9-]*)?$' - run-qa-acceptance-tests: - needs: [ validate-version-input ] - # QA acceptance tests are skipped when explicit input parameter is used - # As this job may be skipped following jobs require using 'always()' to make sure they are still run - if: needs.validate-version-input.result == 'success' && inputs.skip_tests != 'true' - secrets: inherit - uses: ./.github/workflows/acceptance-tests.yml - with: - atlas_cloud_env: "qa" - ref: ${{ inputs.use_existing_tag == 'true' && inputs.version_number || github.ref }} - update-examples-reference-in-docs: - needs: [ validate-version-input, run-qa-acceptance-tests ] + needs: [ release-config, validate-version-input ] if: >- - always() - && inputs.use_existing_tag != 'true' - && !contains(inputs.version_number, 'pre') - && needs.validate-version-input.result == 'success' - && (needs.run-qa-acceptance-tests.result == 'skipped' || needs.run-qa-acceptance-tests.result == 'success') + !cancelled() + && !contains(needs.*.result, 'failure') + && needs.release-config.outputs.creates_new_tag == 'true' + && needs.release-config.outputs.is_official_release == 'true' uses: ./.github/workflows/run-script-and-commit.yml with: script_call: './scripts/update-examples-reference-in-docs.sh ${{inputs.version_number}}' @@ -52,13 +57,12 @@ jobs: passphrase: ${{ secrets.APIX_BOT_PASSPHRASE }} update-changelog-header: - needs: [ validate-version-input, run-qa-acceptance-tests, update-examples-reference-in-docs ] + needs: [ release-config, validate-version-input, update-examples-reference-in-docs ] if: >- - always() - && inputs.use_existing_tag != 'true' - && !contains(inputs.version_number, 'pre') - && needs.validate-version-input.result == 'success' - && (needs.run-qa-acceptance-tests.result == 'skipped' || needs.run-qa-acceptance-tests.result == 'success') + !cancelled() + && !contains(needs.*.result, 'failure') + && needs.release-config.outputs.creates_new_tag == 'true' + && needs.release-config.outputs.is_official_release == 'true' uses: ./.github/workflows/run-script-and-commit.yml with: script_call: './scripts/update-changelog-header-for-release.sh ${{inputs.version_number}}' @@ -68,24 +72,19 @@ jobs: remote: https://svc-apix-bot:${{ secrets.APIX_BOT_PAT }}@github.com/${{ github.repository }} gpg_private_key: ${{ secrets.APIX_BOT_GPG_PRIVATE_KEY }} passphrase: ${{ secrets.APIX_BOT_PASSPHRASE }} - - release: + + create-tag: runs-on: ubuntu-latest - needs: [ validate-version-input, run-qa-acceptance-tests, update-examples-reference-in-docs, update-changelog-header ] - # Release is skipped if there are failures in previous steps - if: >- - always() - && needs.validate-version-input.result == 'success' - && (needs.run-qa-acceptance-tests.result == 'skipped' || needs.run-qa-acceptance-tests.result == 'success') - && (needs.update-examples-reference-in-docs.result == 'skipped' || needs.update-examples-reference-in-docs.result == 'success') - && (needs.update-changelog-header.result == 'skipped' || needs.update-changelog-header.result == 'success') - steps: + needs: [ release-config, validate-version-input, update-examples-reference-in-docs, update-changelog-header ] + if: >- + !cancelled() + && !contains(needs.*.result, 'failure') + && needs.release-config.outputs.creates_new_tag == 'true' + steps: - name: Checkout uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 with: - ref: ${{ inputs.use_existing_tag == 'true' && inputs.version_number || 'master' }} - - name: Unshallow - run: git fetch --prune --unshallow + ref: 'master' - name: Get the latest commit SHA id: get-sha run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" @@ -96,7 +95,31 @@ jobs: commit_sha: ${{ steps.get-sha.outputs.sha }} gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} gpg_passphrase: ${{ secrets.PASSPHRASE }} - tag_exists_error: ${{ inputs.use_existing_tag != 'true' }} + + run-qa-acceptance-tests: + needs: [ release-config, validate-version-input, update-examples-reference-in-docs, update-changelog-header, create-tag ] + if: >- + !cancelled() + && !contains(needs.*.result, 'failure') + && needs.release-config.outputs.runs_tests == 'true' + secrets: inherit + uses: ./.github/workflows/acceptance-tests.yml + with: + atlas_cloud_env: "qa" + ref: ${{ inputs.version_number }} + + release: + runs-on: ubuntu-latest + needs: [ validate-version-input, update-examples-reference-in-docs, update-changelog-header, create-tag, run-qa-acceptance-tests ] + # Release is skipped if there are failures in previous steps + if: >- + !cancelled() + && !contains(needs.*.result, 'failure') + steps: + - name: Checkout + uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 + with: + ref: ${{ inputs.version_number }} - name: Set up Go uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 with: @@ -117,9 +140,13 @@ jobs: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} jira-release-version: - if: ${{ !contains(inputs.version_number, 'pre') }} - needs: [ release ] runs-on: ubuntu-latest + needs: [ release-config, release ] + # if release job is skipped, cancelled, or failed we do not run this job + if: >- + !cancelled() + && needs.release.result == 'success' + && needs.release-config.outputs.is_official_release == 'true' steps: - uses: actions/checkout@9bb56186c3b09b4f86b1c65136769dd318469633 - uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 diff --git a/RELEASING.md b/RELEASING.md index 84d07b214a..a636adb663 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -28,3 +28,19 @@ Pre-releases are not needed for a regular release process, but they can be gener - You will see the release in the [GitHub Release page](https://github.com/mongodb/terraform-provider-mongodbatlas/releases) once the [release action](.github/workflows/release.yml) has completed. HashiCorp has a process in place that will retrieve the latest release from the GitHub repository and add the binaries to the HashiCorp Terraform Registry (more details [here](https://developer.hashicorp.com/terraform/registry/providers/publishing#webhooks)). - **CDKTF Update - Only for major release, i.e. the left most version digit increment (see this [comment](https://github.com/cdktf/cdktf-repository-manager/pull/202#issuecomment-1602562201))**: Once the provider has been released, we need to update the provider version in our CDKTF. Raise a PR against [cdktf/cdktf-repository-manager](https://github.com/cdktf/cdktf-repository-manager). - Example PR: [#183](https://github.com/cdktf/cdktf-repository-manager/pull/183) + +## FAQ + +**What happens if a release execution fails to create the tag but generated automatic commits into master?** + +All steps before creating the tag are idempotent, meaning you can run the process again and no additional commits will be generated in the second run. + +**What happens if a release execution creates a tag but fails during acceptance tests or creating the release (go releaser step)?** + +Once a tag has been created in a previous execution, you can make use of the input `Using an existing tag` to run a new release process. + +Depending on the nature of the failure, you may want to introduce new changes into the current release. In this case you must: +- Delete the existing tag. +- Incorporate any new fixes into master. +- Manually trigger the [Generate Changelog workflow](https://github.com/mongodb/terraform-provider-mongodbatlas/actions/workflows/generate-changelog.yml) to remove the current header and including any new entries that have been merged. This will run automatically if you have merged PRs after deleting the tag. +- Trigger a new release process, this will create a tag that includes your latest fixes.