Release Agent #217
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: Release Agent | |
| on: | |
| workflow_dispatch: | |
| inputs: | |
| packageVersion: | |
| required: true | |
| description: 'Package version number (3.x.x)' | |
| default: "" | |
| type: string | |
| packageBuildNo: | |
| required: true | |
| description: 'Package build number' | |
| default: "1" | |
| type: string | |
| releaseBranch: | |
| description: 'Release branch to build from (release-3.x.x)' | |
| required: true | |
| type: string | |
| tagRelease: | |
| description: 'Add tag for release (v3.x.x)' | |
| default: false | |
| type: boolean | |
| githubRelease: | |
| description: 'Draft release (v3.x.x) on GitHub' | |
| type: boolean | |
| default: false | |
| createPullRequest: | |
| description: 'Create pull request into main (required if release branch has diverged from main)' | |
| default: false | |
| type: boolean | |
| publishPackages: | |
| description: 'Publish packages to nginx repo' | |
| default: false | |
| type: boolean | |
| uploadUrl: | |
| description: 'Location to publish packages to' | |
| required: false | |
| default: "https://up-ap.nginx.com" | |
| type: string | |
| assertionDoc: | |
| description: 'Generate assertion document' | |
| default: false | |
| type: boolean | |
| env: | |
| NFPM_VERSION: 'v2.35.3' | |
| GOPROXY: "https://${{ secrets.ARTIFACTORY_USER }}:${{ secrets.ARTIFACTORY_TOKEN }}@${{ secrets.ARTIFACTORY_URL_PROD }}" | |
| defaults: | |
| run: | |
| shell: bash | |
| concurrency: | |
| group: ${{ github.ref_name }}-release | |
| cancel-in-progress: true | |
| permissions: | |
| contents: read | |
| jobs: | |
| vars: | |
| name: Set workflow variables | |
| runs-on: ubuntu-22.04 | |
| outputs: | |
| tag_release: ${{steps.vars.outputs.tag_release }} | |
| github_release: ${{steps.vars.outputs.github_release }} | |
| publish_packages: ${{steps.vars.outputs.publish_packages }} | |
| create_pull_request: ${{steps.vars.outputs.create_pull_request }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| with: | |
| ref: ${{ inputs.releaseBranch }} | |
| - name: Set variables | |
| id: vars | |
| run: | | |
| echo "tag_release=${{ inputs.tagRelease }}" >> $GITHUB_OUTPUT | |
| echo "github_release=${{ inputs.githubRelease }}" >> $GITHUB_OUTPUT | |
| echo "publish_packages=${{ inputs.publishPackages }}" >> $GITHUB_OUTPUT | |
| echo "create_pull_request=${{ inputs.createPullRequest }}" >> $GITHUB_OUTPUT | |
| cat $GITHUB_OUTPUT | |
| release-draft: | |
| name: Update Release Draft | |
| runs-on: ubuntu-22.04 | |
| needs: [vars] | |
| permissions: | |
| contents: write # Needed to create draft release | |
| outputs: | |
| release_id: ${{ steps.vars.outputs.RELEASE_ID }} | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| if: ${{ needs.vars.outputs.github_release == 'true' }} | |
| with: | |
| ref: ${{ inputs.releaseBranch }} | |
| - name: Create Draft Release | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| if: ${{ needs.vars.outputs.github_release == 'true' }} | |
| id: release | |
| env: | |
| version: ${{ inputs.packageVersion }} | |
| with: | |
| script: | | |
| const ref = context.ref.split("/")[2] | |
| const {version} = process.env | |
| console.log(`The release version is v${version}`) | |
| const releases = (await github.rest.repos.listReleases({ | |
| owner: context.payload.repository.owner.login, | |
| repo: context.payload.repository.name, | |
| per_page: 100, | |
| })).data | |
| const latest_release = (await github.rest.repos.getLatestRelease({ | |
| owner: context.payload.repository.owner.login, | |
| repo: context.payload.repository.name, | |
| })).data.tag_name | |
| console.log(`The latest release was ${latest_release}`) | |
| if (latest_release === "v"+version) { | |
| core.setFailed(`A published release already exists for ${latest_release}`) | |
| } else { | |
| const draft = releases.find((r) => r.draft && r.tag_name === "v"+version) | |
| const draft_found = !(draft === undefined) | |
| let release | |
| if (draft_found){ | |
| console.log("Draft release already exists. Deleting current draft release and recreating it") | |
| release = (await github.rest.repos.deleteRelease({ | |
| owner: context.payload.repository.owner.login, | |
| repo: context.payload.repository.name, | |
| release_id: draft.id, | |
| })) | |
| } | |
| const release_notes = (await github.rest.repos.generateReleaseNotes({ | |
| owner: context.payload.repository.owner.login, | |
| repo: context.payload.repository.name, | |
| tag_name: "v"+version, | |
| previous_tag_name: latest_release, | |
| target_commitish: ref, | |
| })) | |
| const footer = ` | |
| ## Resources | |
| - Documentation -- https://github.com/nginx/agent#readme | |
| ` | |
| release = (await github.rest.repos.createRelease({ | |
| owner: context.payload.repository.owner.login, | |
| repo: context.payload.repository.name, | |
| tag_name: "v"+version, | |
| target_commitish: ref, | |
| name: "v"+version, | |
| body: release_notes.data.body + footer, | |
| draft: true, | |
| })) | |
| console.log(`Release created: ${release.data.html_url}`) | |
| console.log(`Release ID: ${release.data.id}`) | |
| console.log(`Release notes: ${release_notes.data.body}`) | |
| console.log(`Release Upload URL: ${release.data.upload_url}`) | |
| return { | |
| version: version, | |
| release_id: release.data.id, | |
| release_upload_url: release.data.upload_url, | |
| } | |
| } | |
| - name: Set Environment Variables | |
| id: vars | |
| if: ${{ needs.vars.outputs.github_release == 'true' }} | |
| run: | | |
| echo "RELEASE_ID=$(echo '${{steps.release.outputs.result}}' | jq -r '.release_id')" >> $GITHUB_OUTPUT | |
| cat $GITHUB_OUTPUT | |
| tag-release: | |
| name: Tag Release | |
| runs-on: ubuntu-22.04 | |
| needs: [vars,release-draft] | |
| permissions: | |
| contents: write | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| if: ${{ needs.vars.outputs.tag_release == 'true' }} | |
| with: | |
| ref: ${{ inputs.releaseBranch }} | |
| - name: Tag release | |
| if: ${{ needs.vars.outputs.tag_release == 'true' }} | |
| run: | | |
| git config --global user.name 'github-actions' | |
| git config --global user.email '41898282+github-actions[bot]@users.noreply.github.com' | |
| git tag -a "v${{ inputs.packageVersion }}" -m "CI Autogenerated" | |
| git push origin "v${{ inputs.packageVersion }}" | |
| build-and-upload-packages: | |
| name: Build and upload release packages | |
| runs-on: ubuntu-22.04-amd64 | |
| needs: [vars,release-draft,tag-release] | |
| permissions: | |
| id-token: write | |
| contents: write # Needed to update a release | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| with: | |
| ref: ${{ inputs.releaseBranch }} | |
| - name: Setup go | |
| uses: actions/setup-go@4dc6199c7b1a012772edbd06daecab0f50c9053c # v6.1.0 | |
| with: | |
| go-version-file: 'go.mod' | |
| cache: false | |
| - name: Setup package build environment | |
| run: | | |
| go mod download | |
| go install github.com/goreleaser/nfpm/v2/cmd/nfpm@${{ env.NFPM_VERSION }} | |
| sudo apt-get update | |
| sudo apt-get install -y gpgv1 monkeysphere | |
| make install-tools | |
| export PATH=$PATH:~/go/bin | |
| nfpm --version | |
| - name: Set the VERSION environment variable | |
| run: echo VERSION=v${{ inputs.packageVersion }} >> $GITHUB_ENV | |
| - name: Build Packages | |
| env: | |
| GPG_KEY: ${{ secrets.INDIGO_GPG_AGENT }} | |
| NFPM_SIGNING_KEY_FILE: .key.asc | |
| VERSION: ${{ env.VERSION }} | |
| PACKAGE_BUILD: ${{ inputs.packageBuildNo }} | |
| run: | | |
| export PATH=$PATH:~/go/bin | |
| echo "$GPG_KEY" | base64 --decode > ${NFPM_SIGNING_KEY_FILE} | |
| make package | |
| find build/ -type f -name "nginx-agent*" | |
| - name: Archive AMD64 Binaries | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 | |
| with: | |
| name: nginx-agent-binaries-${{ inputs.packageVersion }}-amd64 | |
| path: | | |
| build/amd64/nginx-agent | |
| build/amd64/nginx-agent.sha256 | |
| build/amd64/nginx-agent.buildstart | |
| build/amd64/nginx-agent.buildend | |
| - name: Archive ARM64 Binaries | |
| uses: actions/upload-artifact@330a01c490aca151604b8cf639adc76d48f6c5d4 # v5.0.0 | |
| with: | |
| name: nginx-agent-binaries-${{ inputs.packageVersion }}-arm64 | |
| path: | | |
| build/arm64/nginx-agent | |
| build/arm64/nginx-agent.sha256 | |
| build/arm64/nginx-agent.buildstart | |
| build/arm64/nginx-agent.buildend | |
| - name: List artifacts | |
| run: | | |
| echo "Run ID: ${{ github.run_id }}" | |
| echo "Run Number: ${{ github.run_number }}" | |
| echo "nginx-agent-binaries-${{ inputs.packageVersion }}-arm64" | |
| find build/arm64 -type f -name "nginx-agent*" | |
| echo "nginx-agent-binaries-${{ inputs.packageVersion }}-amd64" | |
| find build/amd64 -type f -name "nginx-agent*" | |
| - name: Get Id Token | |
| if: ${{ inputs.publishPackages == true }} | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| id: idtoken | |
| with: | |
| script: | | |
| let id_token = await core.getIDToken() | |
| core.setOutput('id_token', id_token) | |
| - name: Upload Release Packages to NGINX repo | |
| if: ${{ inputs.publishPackages == true }} | |
| env: | |
| TOKEN: ${{ steps.idtoken.outputs.id_token }} | |
| UPLOAD_URL: ${{ inputs.uploadUrl }} | |
| run: | | |
| make release | |
| assertion-document: | |
| name: Build and Generate Assertion Document | |
| needs: [build-and-upload-packages] | |
| if : ${{ inputs.assertionDoc == true }} | |
| uses: ./.github/workflows/assertion.yml | |
| permissions: | |
| id-token: write | |
| contents: read | |
| with: | |
| packageVersion: ${{ inputs.packageVersion }} | |
| runId: ${{ github.run_id }} | |
| secrets: | |
| ARTIFACTORY_USER: ${{ secrets.ARTIFACTORY_USER }} | |
| ARTIFACTORY_TOKEN: ${{ secrets.ARTIFACTORY_TOKEN }} | |
| ARTIFACTORY_URL: ${{ secrets.ARTIFACTORY_URL }} | |
| merge-release: | |
| if: ${{ needs.vars.outputs.create_pull_request == 'true' }} | |
| name: Merge release branch back into main branch | |
| runs-on: ubuntu-22.04 | |
| needs: [vars,tag-release] | |
| permissions: | |
| pull-requests: write | |
| steps: | |
| - name: Checkout Repository | |
| uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0 | |
| with: | |
| ref: ${{ inputs.releaseBranch }} | |
| - name: Create Pull Request | |
| uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 | |
| with: | |
| script: | | |
| const { repo, owner } = context.repo; | |
| const result = await github.rest.pulls.create({ | |
| title: 'Merge ${{ inputs.releaseBranch }} back into main', | |
| owner, | |
| repo, | |
| head: '${{ inputs.releaseBranch }}', | |
| base: 'main', | |
| body: [ | |
| 'This PR was auto-generated by the release workflow.', | |
| 'NOTE: DO NOT squash commits when merging!', | |
| ].join('\n') | |
| }); |