From 56615ff31d9f1ed5cb2f8cab21986038ce210763 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Thu, 18 Jun 2026 15:16:15 +0530 Subject: [PATCH] ci: add release automation --- .github/workflows/release-finalize.yml | 106 ++++++++++++++++++++ .github/workflows/release-prepare.yml | 128 +++++++++++++++++++++++++ .github/workflows/release-publish.yml | 41 ++++++++ .github/workflows/release-tag.yml | 54 +++++++++++ 4 files changed, 329 insertions(+) create mode 100644 .github/workflows/release-finalize.yml create mode 100644 .github/workflows/release-prepare.yml create mode 100644 .github/workflows/release-publish.yml create mode 100644 .github/workflows/release-tag.yml diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml new file mode 100644 index 0000000..cbdd0e6 --- /dev/null +++ b/.github/workflows/release-finalize.yml @@ -0,0 +1,106 @@ +name: Release Finalize + +on: + workflow_run: + workflows: + - "Release Build - Java" + - "Release Build - NodeJS" + - "Release Build - Python" + types: [completed] + +permissions: + contents: write + pull-requests: write + +jobs: + finalize: + if: >- + github.event.workflow_run.conclusion == 'success' + runs-on: ubuntu-22.04 + steps: + - name: Extract tag and language + id: parse + run: | + TAG="${{ github.event.workflow_run.head_branch }}" + LANGUAGE="${TAG%%-v*}" + VERSION="${TAG#"${LANGUAGE}"-v}" + RELEASE_BRANCH="release-${TAG}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + echo "language=${LANGUAGE}" >> "$GITHUB_OUTPUT" + echo "version=${VERSION}" >> "$GITHUB_OUTPUT" + echo "release_branch=${RELEASE_BRANCH}" \ + >> "$GITHUB_OUTPUT" + + - uses: actions/checkout@v4 + with: + persist-credentials: false + ref: main + fetch-depth: 0 + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email \ + "github-actions[bot]@users.noreply.github.com" + + - name: Create release branch + run: | + git checkout -b \ + "${{ steps.parse.outputs.release_branch }}" + + - name: Update README with ARN tables + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.parse.outputs.tag }} + LANGUAGE: ${{ steps.parse.outputs.language }} + VERSION: ${{ steps.parse.outputs.version }} + run: ./ci/release-finalize.sh + + - uses: actions/setup-node@v4 + + - name: Format markdown tables + env: + LANGUAGE: ${{ steps.parse.outputs.language }} + run: | + npm install --no-save markdown-table-formatter + ./node_modules/.bin/markdown-table-formatter \ + "${LANGUAGE}/README.md" + + - name: Commit changes + env: + TAG: ${{ steps.parse.outputs.tag }} + LANGUAGE: ${{ steps.parse.outputs.language }} + run: | + git add "${LANGUAGE}/README.md" + git commit -m \ + "docs: update ${LANGUAGE} layer ARNs for ${TAG}" + + - name: Push release branch + env: + REMOTE: >- + https://x-access-token:${{ secrets.RELEASE_PAT + }}@github.com/${{ github.repository }} + run: | + git remote set-url origin "${REMOTE}" + git push origin \ + "${{ steps.parse.outputs.release_branch }}" + + - name: Create pull request + env: + GH_TOKEN: ${{ secrets.RELEASE_PAT }} + TAG: ${{ steps.parse.outputs.tag }} + LANGUAGE: ${{ steps.parse.outputs.language }} + RELEASE_BRANCH: >- + ${{ steps.parse.outputs.release_branch }} + run: | + REPO="${GITHUB_REPOSITORY}" + BODY="Updates \`${LANGUAGE}/README.md\` with layer ARNs " + BODY+="from the [pre-release]" + BODY+="(https://github.com/${REPO}/releases/tag/${TAG})." + BODY+=$'\n\n' + BODY+="Merging promotes the pre-release to a full release." + gh pr create \ + --title "docs: release ${TAG}" \ + --body "${BODY}" \ + --base main \ + --head "${RELEASE_BRANCH}" diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml new file mode 100644 index 0000000..98031ee --- /dev/null +++ b/.github/workflows/release-prepare.yml @@ -0,0 +1,128 @@ +name: Release Prepare + +on: + workflow_dispatch: + inputs: + language: + description: "Language to release" + required: true + type: choice + options: + - java + - nodejs + - python + version: + description: "Version (e.g. 1.41.0)" + required: true + type: string + otel_lambda_tag: + description: >- + opentelemetry-lambda release tag to pin the submodule to + (e.g. layer-python/0.19.0, layer-nodejs/0.21.0, + layer-javaagent/0.19.0) + required: true + type: string + +permissions: + contents: write + pull-requests: write + +jobs: + prepare: + runs-on: ubuntu-22.04 + env: + LANGUAGE: ${{ inputs.language }} + VERSION: ${{ inputs.version }} + BRANCH: prepare-${{ inputs.language }}-v${{ inputs.version }} + steps: + - name: Validate version format + run: | + if ! [[ "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::Version must be semver without v prefix (e.g. 1.41.0)" + exit 1 + fi + + - uses: actions/checkout@v4 + with: + persist-credentials: false + fetch-depth: 0 + submodules: true + + - name: Check release tag does not already exist + run: | + TAG="${LANGUAGE}-v${VERSION}" + if git tag --list "${TAG}" | grep -q .; then + echo "::error::Tag ${TAG} already exists" + exit 1 + fi + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email \ + "github-actions[bot]@users.noreply.github.com" + + - name: Create branch + run: git checkout -b "${BRANCH}" + + - name: Update submodule to otel-lambda release + run: | + cd opentelemetry-lambda + git fetch --tags origin + git checkout "${{ inputs.otel_lambda_tag }}" + cd .. + + - name: Run prepare script + run: ./ci/release-prepare.sh + + - name: Commit changes + run: | + git add \ + CHANGELOG.md \ + README.md \ + "${LANGUAGE}/layer-data.sh" \ + "${LANGUAGE}/sample-apps/template.yaml" \ + opentelemetry-lambda + COMMIT_MSG="feat: prepare release ${LANGUAGE} v${VERSION}" + git commit -m "${COMMIT_MSG}" + + - name: Push branch + env: + REMOTE: >- + https://x-access-token:${{ secrets.RELEASE_PAT + }}@github.com/${{ github.repository }} + run: | + git remote set-url origin "${REMOTE}" + git push origin "${BRANCH}" + + - name: Ensure release label exists + env: + GH_TOKEN: ${{ secrets.RELEASE_PAT }} + run: | + gh label create release \ + --color "0075ca" \ + --description "Release PR" \ + 2>/dev/null || true + + - name: Create pull request + env: + GH_TOKEN: ${{ secrets.RELEASE_PAT }} + run: | + gh pr create \ + --title "feat: prepare release ${LANGUAGE} v${VERSION}" \ + --body "Automated release preparation for \`${LANGUAGE}-v${VERSION}\`. + + opentelemetry-lambda submodule pinned to: \`${{ inputs.otel_lambda_tag }}\` + + ### Pre-merge checklist + + - [ ] Review CHANGELOG.md entry + - [ ] Verify \`${LANGUAGE}/layer-data.sh\` version + - [ ] Verify \`${LANGUAGE}/sample-apps/template.yaml\` version + - [ ] Verify README.md component versions + - [ ] Approve this PR + + Merging will create tag \`${LANGUAGE}-v${VERSION}\` and trigger the release build." \ + --base main \ + --head "${BRANCH}" \ + --label release diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml new file mode 100644 index 0000000..1a4ac8a --- /dev/null +++ b/.github/workflows/release-publish.yml @@ -0,0 +1,41 @@ +name: Release Publish + +on: + pull_request: + types: [closed] + branches: [main] + +permissions: + contents: write + +jobs: + publish: + if: >- + github.event.pull_request.merged == true && + (startsWith( + github.event.pull_request.head.ref, + 'release-java-v') || + startsWith( + github.event.pull_request.head.ref, + 'release-nodejs-v') || + startsWith( + github.event.pull_request.head.ref, + 'release-python-v')) + runs-on: ubuntu-22.04 + steps: + - name: Extract tag from branch name + id: parse + run: | + BRANCH="${{ github.event.pull_request.head.ref }}" + TAG="${BRANCH#release-}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + + - name: Promote pre-release to full release + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + TAG: ${{ steps.parse.outputs.tag }} + run: | + gh release edit "${TAG}" \ + --repo "${{ github.repository }}" \ + --prerelease=false \ + --latest diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml new file mode 100644 index 0000000..ddee1c7 --- /dev/null +++ b/.github/workflows/release-tag.yml @@ -0,0 +1,54 @@ +name: Release Tag + +on: + pull_request: + types: [closed] + branches: [main] + +permissions: + contents: write + +jobs: + create-tag: + if: >- + github.event.pull_request.merged == true && + (startsWith( + github.event.pull_request.head.ref, + 'prepare-java-v') || + startsWith( + github.event.pull_request.head.ref, + 'prepare-nodejs-v') || + startsWith( + github.event.pull_request.head.ref, + 'prepare-python-v')) + runs-on: ubuntu-22.04 + steps: + - name: Extract tag from branch name + id: parse + run: | + BRANCH="${{ github.event.pull_request.head.ref }}" + TAG="${BRANCH#prepare-}" + echo "tag=${TAG}" >> "$GITHUB_OUTPUT" + + - uses: actions/checkout@v4 + with: + persist-credentials: false + ref: main + fetch-depth: 0 + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email \ + "github-actions[bot]@users.noreply.github.com" + + - name: Create and push tag + env: + TAG: ${{ steps.parse.outputs.tag }} + REMOTE: >- + https://x-access-token:${{ secrets.RELEASE_PAT + }}@github.com/${{ github.repository }} + run: | + git tag -m "${TAG}" "${TAG}" + git remote set-url origin "${REMOTE}" + git push origin "${TAG}"