From 5eedd2ca8b6ea3ccbd004b07bcaace9d52b00ad1 Mon Sep 17 00:00:00 2001 From: Adam Bovill Date: Sun, 14 Jan 2024 09:21:58 +0000 Subject: [PATCH] feat(prerelease): adds prerelease action that works on pull requests --- prerelease/README.md | 104 +++++++++++++++++++++++ prerelease/action.yaml | 189 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 293 insertions(+) create mode 100644 prerelease/README.md create mode 100644 prerelease/action.yaml diff --git a/prerelease/README.md b/prerelease/README.md new file mode 100644 index 0000000..e346794 --- /dev/null +++ b/prerelease/README.md @@ -0,0 +1,104 @@ +# GitHub Action: Prerelease Terraform Module + + + +## Description + +< GitHub Action to compute a prerelease version based on the latest release version and the number of commits since the latest release. This will also generate a docker tag based on the computed version if the label `prerelease` is specified on the PR. + + + +## Configuration + +### Step1: Set any [Semantic Release Configuration](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/configuration.md#configuration) in your repository. + +### Step2: [Add Secrets](https://help.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets) in your repository for the [Semantic Release Authentication](https://github.com/semantic-release/semantic-release/blob/master/docs/usage/ci-configuration.md#authentication) Environment Variables. + +### Step3: Add a [Workflow File](https://help.github.com/en/articles/workflow-syntax-for-github-actions) to your repository to create custom automated processes. + +## Usage + +```yaml +steps: + - name: Action semantic release + uses: open-turo/actions-tf/prerelease@v3 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} +``` + +**IMPORTANT**: `GITHUB_TOKEN` does not have the required permissions to operate on protected branches. +If you are using this action for protected branches, replace `GITHUB_TOKEN` +with [Personal Access Token](https://help.github.com/en/github/authenticating-to-github/creating-a-personal-access-token-for-the-command-line). +If using the `@semantic-release/git` plugin for protected branches, avoid persisting credentials as part +of `actions/checkout@v4` by setting the parameter `persist-credentials: false`. This credential does not have the +required permission to operate on protected branches. + + + +## Inputs + +| parameter | description | required | default | +| --- | --- | --- | --- | +| checkout-repo | Perform checkout as first step of action | `false` | true | +| create-prerelease | Whether semantic-release should create a prerelease or do a dry run. This can be useful to set to true when a prerelease requires pushing artifacts semantic-release is in charge of generating | `false` | false | +| docker-config-file | Path to the docker config file (defaults to .docker-config.json) Must contain imageName, may contain dockerfile. | `false` | .docker-config.json | +| dockerhub-user | username for dockerhub | `true` | | +| dockerhub-password | password for dockerhub | `true` | | +| github-token | GitHub token that can checkout the repository as well as create tags/releases against it. e.g. 'secrets.GITHUB_TOKEN' | `true` | | +| extra-plugins | Extra plugins for pre-install. You can also specify specifying version range for the extra plugins if you prefer. Defaults to install @open-turo/semantic-release-config. | `false` | @open-turo/semantic-release-config | +| artifactory-username | Artifactory user name usually secrets.ARTIFACTORY_USERNAME | `true` | | +| artifactory-auth-token | Artifactory auth token usually secrets.ARTIFACTORY_AUTH_TOKEN | `true` | | + + + +## Outputs + +| parameter | description | +| --- | --- | +| new-release-published | Whether a new release was published | +| new-release-version | Version of the new release | +| new-release-major-version | Major version of the new release | +| image-name | Docker image name | +| image-with-tag | Full image with tag - : | +| pull-request-number | Pull request number | +| run-url | URL to the GHA run | + + + +## Runs + +This action is a `composite` action. + + + + + + +## Additional Examples + +### using output parameters example + +```yaml +jobs: + build: + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 + - name: Release + uses: open-turo/actions-tf/prerelease@v3 + id: semantic # Need an `id` for output variables + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Do something when a new release published + if: steps.semantic.outputs.new-release-published == 'true' + run: | + echo ${{ steps.semantic.outputs.new-release-version }} + echo ${{ steps.semantic.outputs.new-release-major-version }} +``` + +## Notes + +- By default, this action will perform actions/checkout as its first step. diff --git a/prerelease/action.yaml b/prerelease/action.yaml new file mode 100644 index 0000000..536acd1 --- /dev/null +++ b/prerelease/action.yaml @@ -0,0 +1,189 @@ +name: GitHub Action Release and Publish Prerelease Module +description: GitHub Action to compute a prerelease version based on the latest release version and the number of commits since the latest release. +inputs: + checkout-repo: + required: false + description: Perform checkout as first step of action + default: "true" + create-prerelease: + required: false + description: Whether semantic-release should create a prerelease or do a dry run. This can be useful to set to true when a prerelease requires pushing artifacts semantic-release is in charge of generating + default: "true" + github-token: + required: true + description: GitHub token that can checkout the repository as well as create tags/releases against it. e.g. 'secrets.GITHUB_TOKEN' + extra-plugins: + required: false + description: Extra plugins for pre-install. You can also specify specifying version range for the extra plugins if you prefer. Defaults to install @open-turo/semantic-release-config. + default: | + @open-turo/semantic-release-config +outputs: + new-release-published: + description: Whether a new release was published + value: ${{ steps.prerelease.outputs.new-release-published }} + new-release-version: + description: Version of the new release + value: ${{ steps.prerelease.outputs.new-release-version }} + new-release-major-version: + description: Major version of the new release + value: ${{ steps.prerelease.outputs.new-release-major_version }} + pull-request-number: + description: Pull request number + value: ${{ steps.PR.outputs.number }} + run-url: + description: URL to the GHA run + value: ${{ steps.vars.outputs.run-url }} + +runs: + using: composite + steps: + - name: Dump GitHub context + env: + GITHUB_CONTEXT: ${{ toJSON(github) }} + shell: bash + run: | + echo "::group::Github Context" + echo "$GITHUB_CONTEXT" + echo "::endgroup::" + + - name: Set vars + id: source-vars + shell: bash + env: + event_name: ${{ github.event_name }} + dispatch_client_payload_ref: ${{ github.event.client_payload.ref }} + dispatch_client_payload_sha: ${{ github.event.client_payload.sha }} + push_ref_name: ${{ github.ref_name }} + push_sha: ${{ github.sha }} + pull_request_ref_name: ${{ github.event.pull_request.head.ref }} + pull_request_sha: ${{ github.event.pull_request.head.sha }} + run: | + echo "event_name=$event_name" + + if [ "$event_name" == "push" ]; then + branch=$push_ref_name + sha=$push_sha + elif [ "$event_name" == "repository_dispatch" ]; then + branch=$dispatch_client_payload_ref + sha=$dispatch_client_payload_sha + elif [ "$event_name" == "pull_request" ]; then + branch=$pull_request_ref_name + sha=$pull_request_sha + else + echo "::error::Unsupported event type '$event_name'" + exit 1 + fi + + echo "branch=$branch" + echo "branch=$branch" >> $GITHUB_OUTPUT + + echo "sha=$sha" + echo "sha=$sha" >> $GITHUB_OUTPUT + + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + ref: ${{ steps.source-vars.outputs.branch }} + + # Find PR + - uses: 8BitJonny/gh-get-current-pr@2.2.0 + id: PR + with: + sha: ${{ steps.source-vars.outputs.sha }} + + - id: check-pr + shell: bash + run: | + if [ -z "${{ steps.PR.outputs.number }}" ]; then + echo "pr_found=false" >> $GITHUB_OUTPUT + echo "has_prerelease_label=false" >> $GITHUB_OUTPUT + else + echo "pr_found=true" >> $GITHUB_OUTPUT + echo "has_prerelease_label=${{ contains(toJSON(fromJSON(steps.PR.outputs.pr).labels.*.name), 'prerelease') }}" >> $GITHUB_OUTPUT + fi + git branch + echo "branch: ${{ steps.source-vars.outputs.branch }}" + + - if: steps.check-pr.outputs.pr_found != 'true' + shell: bash + run: echo "PR does not exist for branch (${{ steps.source-vars.outputs.branch }}) - ignoring" + + - if: steps.check-pr.outputs.has_prerelease_label == 'true' + shell: bash + run: | + echo "Your PR number is ${{ steps.PR.outputs.number }}" + echo "::debug::labels.contains('prerelease'): ${{ contains(toJSON(fromJSON(steps.PR.outputs.pr).labels.*.name), 'prerelease') }}" + + # Compute next release + - uses: open-turo/action-setup-tools@v1 + if: steps.check-pr.outputs.has_prerelease_label == 'true' + + - name: Prerelease + id: prerelease + uses: open-turo/actions-release/semantic-release@v4 + if: steps.check-pr.outputs.has_prerelease_label == 'true' + env: + GITHUB_TOKEN: ${{ inputs.github-token }} + ORG_GRADLE_PROJECT_artifactoryAuthToken: ${{ inputs.artifactory-auth-token }} + ORG_GRADLE_PROJECT_artifactoryUsername: ${{ inputs.artifactory-username }} + with: + branches: '["main", {"name": "${{ steps.source-vars.outputs.branch }}","channel": "next","prerelease": "pr-${{ steps.PR.outputs.number }}.${{ github.run_number }}.${{ github.run_attempt }}"}]' + dry-run: ${{ inputs.create-prerelease == 'false' }} + override-github-ref-name: ${{ steps.source-vars.outputs.branch }} + override-github-sha: ${{ steps.source-vars.outputs.sha }} + extra-plugins: ${{ inputs.extra-plugins }} + + - id: vars + if: steps.check-pr.outputs.has_prerelease_label == 'true' + shell: bash + run: | + echo "version=${{ steps.prerelease.outputs.new-release-version }}" >> $GITHUB_OUTPUT + echo "run-url=https://github.com/$GITHUB_REPOSITORY/actions/runs/$GITHUB_RUN_ID" >> "$GITHUB_OUTPUT" + + - name: Add new version to summary + shell: bash + if: steps.prerelease.outputs.new-release-published == 'true' + env: + NEW_VERSION: ${{ steps.vars.outputs.version }} + DOCKER_IMAGE: ${{ steps.build-docker.outputs.image-with-tag }} + run: | + echo "::notice::new version: \`${NEW_VERSION}\`" + echo "#### New version: \`${NEW_VERSION}\`" >> $GITHUB_STEP_SUMMARY + echo "#### Docekr image: \`${DOCKER_IMAGE}\`" >> $GITHUB_STEP_SUMMARY + + - name: Add no new version to summary + shell: bash + if: steps.prerelease.outputs.new-release-published != 'true' + run: | + echo "::notice::no new version" + echo "### New version: 'NONE" >> $GITHUB_STEP_SUMMARY + + - name: Check for release notes comment + uses: peter-evans/find-comment@v2 + id: fc-prerelease + if: steps.prerelease.outputs.new-release-published == 'true' + with: + issue-number: ${{ steps.PR.outputs.number }} + comment-author: "github-actions[bot]" + body-includes: "" + + - name: Delete previous release note + if: steps.fc-prerelease.outputs.comment-id != '' + uses: jungwinter/comment@v1 + with: + type: delete + comment_id: ${{ steps.fc-prerelease.outputs.comment-id }} + token: ${{ inputs.github-token }} + + - name: Upsert build version + if: steps.prerelease.outputs.new-release-published == 'true' + uses: peter-evans/create-or-update-comment@v1 + with: + issue-number: ${{ steps.PR.outputs.number }} + body: | + + ## Prerelease build + + **Build version:** `${{ steps.vars.outputs.version }}` + + [Build output](${{ steps.vars.outputs.run-url }})