Repository navigation
Upstream Release Watch #50
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: Upstream Release Watch | |
| # Keeps the fork level with DataDog's released version. | |
| # | |
| # Upstream publishes a v<N> GitHub release. Two things have to be true for us to | |
| # match it: main must contain upstream v<N>, and Tero-Datadog-Extension-<N> must | |
| # be published. This job checks both daily and whenever an upstream-version | |
| # update lands on main, then moves whichever one is behind: | |
| # | |
| # main is behind -> open a PR merging upstream v<N> | |
| # main is level, unreleased -> tag v<N>, which publishes and verifies the matrix | |
| # source and full matrix level -> nothing to do | |
| # | |
| # The version main contains is recorded in .upstream-version. The merge PR bumps | |
| # it, so releasing only ever happens after a human merged and CI was green. | |
| on: | |
| push: | |
| branches: | |
| - main | |
| paths: | |
| - .upstream-version | |
| schedule: | |
| # Daily at 13:00 UTC. Upstream cuts a release roughly monthly, so this is | |
| # about noticing within a day rather than racing. | |
| - cron: "0 13 * * *" | |
| workflow_dispatch: | |
| inputs: | |
| release: | |
| description: "Publish a release when main is level with upstream but unreleased" | |
| required: false | |
| default: true | |
| type: boolean | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| issues: write | |
| id-token: write | |
| jobs: | |
| check: | |
| name: Check upstream release | |
| runs-on: ubuntu-22.04 | |
| outputs: | |
| upstream_version: ${{ steps.compare.outputs.upstream_version }} | |
| merged_version: ${{ steps.compare.outputs.merged_version }} | |
| needs_merge: ${{ steps.compare.outputs.needs_merge }} | |
| needs_release: ${{ steps.compare.outputs.needs_release }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Configure AWS credentials | |
| uses: aws-actions/configure-aws-credentials@v4 | |
| with: | |
| role-to-assume: ${{ secrets.AWS_ROLE_ARN }} | |
| aws-region: us-east-1 | |
| - name: Compare upstream release with our state | |
| id: compare | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| set -euo pipefail | |
| UPSTREAM=$(gh release view \ | |
| --repo DataDog/datadog-lambda-extension \ | |
| --json tagName --jq '.tagName' | sed 's/^v//') | |
| if [[ ! "$UPSTREAM" =~ ^[0-9]+$ ]]; then | |
| echo "::error::Upstream latest release '$UPSTREAM' is not a plain version" | |
| exit 1 | |
| fi | |
| MERGED=$(tr -d '[:space:]' < .upstream-version) | |
| echo "Upstream released: v$UPSTREAM | main contains: v$MERGED" | |
| NEEDS_MERGE=false | |
| NEEDS_RELEASE=false | |
| if [ "$MERGED" -lt "$UPSTREAM" ]; then | |
| NEEDS_MERGE=true | |
| else | |
| # A release is complete only when both architectures exist with a | |
| # public policy in every supported region. | |
| if ! ./scripts/verify_release_matrix.sh "$UPSTREAM" 1; then | |
| NEEDS_RELEASE=true | |
| fi | |
| fi | |
| { | |
| echo "upstream_version=$UPSTREAM" | |
| echo "merged_version=$MERGED" | |
| echo "needs_merge=$NEEDS_MERGE" | |
| echo "needs_release=$NEEDS_RELEASE" | |
| } >> "$GITHUB_OUTPUT" | |
| { | |
| echo "## Upstream release watch" | |
| echo "" | |
| echo "| | Version |" | |
| echo "|---|---|" | |
| echo "| DataDog released | v$UPSTREAM |" | |
| echo "| main contains | v$MERGED |" | |
| echo "" | |
| if [ "$NEEDS_MERGE" = true ]; then | |
| echo "main is behind — opening a merge PR." | |
| elif [ "$NEEDS_RELEASE" = true ]; then | |
| echo "main is level with upstream but v$UPSTREAM is not published." | |
| else | |
| echo "Source and the complete production matrix are in parity. Nothing to do." | |
| fi | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| merge: | |
| name: Open upstream merge PR | |
| runs-on: ubuntu-22.04 | |
| needs: check | |
| if: needs.check.outputs.needs_merge == 'true' | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Merge upstream release | |
| id: merge | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| UPSTREAM_VERSION: ${{ needs.check.outputs.upstream_version }} | |
| run: | | |
| set -euo pipefail | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| BRANCH="chore/upstream-v${UPSTREAM_VERSION}" | |
| if git ls-remote --exit-code --heads origin "$BRANCH" >/dev/null 2>&1; then | |
| echo "Branch $BRANCH already exists; a merge is already in flight." | |
| exit 0 | |
| fi | |
| git remote add upstream https://github.com/DataDog/datadog-lambda-extension.git | |
| git fetch --tags upstream "v${UPSTREAM_VERSION}" | |
| git checkout -b "$BRANCH" | |
| if ! git merge --no-edit "v${UPSTREAM_VERSION}"; then | |
| CONFLICTS=$(git diff --name-only --diff-filter=U) | |
| git merge --abort | |
| echo "conflicts<<EOF" >> "$GITHUB_OUTPUT" | |
| echo "$CONFLICTS" >> "$GITHUB_OUTPUT" | |
| echo "EOF" >> "$GITHUB_OUTPUT" | |
| echo "conflicted=true" >> "$GITHUB_OUTPUT" | |
| exit 0 | |
| fi | |
| echo "$UPSTREAM_VERSION" > .upstream-version | |
| git commit -am "chore: record upstream v${UPSTREAM_VERSION}" --allow-empty | |
| git push origin "$BRANCH" | |
| echo "conflicted=false" >> "$GITHUB_OUTPUT" | |
| - name: Open pull request | |
| if: steps.merge.outputs.conflicted == 'false' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| UPSTREAM_VERSION: ${{ needs.check.outputs.upstream_version }} | |
| run: | | |
| set -euo pipefail | |
| gh pr create \ | |
| --base main \ | |
| --head "chore/upstream-v${UPSTREAM_VERSION}" \ | |
| --title "chore: merge upstream v${UPSTREAM_VERSION}" \ | |
| --body "$(printf '%s\n' \ | |
| "## Overview" \ | |
| "" \ | |
| "Merges DataDog upstream \`v${UPSTREAM_VERSION}\` and records it in \`.upstream-version\`." \ | |
| "Opened automatically by Upstream Release Watch." \ | |
| "" \ | |
| "## Testing" \ | |
| "" \ | |
| "CI must be green before merge. Once this lands, the watch publishes" \ | |
| "and verifies \`Tero-Datadog-Extension-${UPSTREAM_VERSION}\` in every supported" \ | |
| "region, then opens a separate consumer-template promotion PR." )" | |
| # A conflicted merge needs judgement — stale lock entries and API breakage | |
| # that only clippy catches. Report it and let a human drive. | |
| - name: Report conflicts | |
| if: steps.merge.outputs.conflicted == 'true' | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| UPSTREAM_VERSION: ${{ needs.check.outputs.upstream_version }} | |
| CONFLICTS: ${{ steps.merge.outputs.conflicts }} | |
| run: | | |
| set -euo pipefail | |
| TITLE="Upstream v${UPSTREAM_VERSION} merge has conflicts" | |
| if gh issue list --state open --search "$TITLE in:title" --json title \ | |
| --jq '.[].title' | grep -qxF "$TITLE"; then | |
| echo "Issue already open." | |
| exit 0 | |
| fi | |
| gh issue create --title "$TITLE" --body "$(printf '%s\n' \ | |
| "Merging upstream \`v${UPSTREAM_VERSION}\` into main conflicts, so no PR was opened." \ | |
| "" \ | |
| "Conflicted files:" \ | |
| "" \ | |
| '```' \ | |
| "$CONFLICTS" \ | |
| '```' \ | |
| "" \ | |
| "Resolve locally, then set \`.upstream-version\` to ${UPSTREAM_VERSION}:" \ | |
| "" \ | |
| '```bash' \ | |
| "git remote add upstream https://github.com/DataDog/datadog-lambda-extension.git" \ | |
| "git fetch --tags upstream v${UPSTREAM_VERSION}" \ | |
| "git checkout -b chore/upstream-v${UPSTREAM_VERSION} && git merge v${UPSTREAM_VERSION}" \ | |
| '```' )" | |
| # Tagging IS the release: pushing v<N> triggers release-extension.yml, which | |
| # owns publishing. There is deliberately no second path from here. | |
| # | |
| # The push needs RELEASE_TAG_TOKEN (a PAT or GitHub App token with | |
| # contents:write). A tag pushed with the default GITHUB_TOKEN does not trigger | |
| # another workflow, so with GITHUB_TOKEN the tag would land and nothing would | |
| # publish. | |
| tag: | |
| name: Tag v${{ needs.check.outputs.upstream_version }} | |
| runs-on: ubuntu-22.04 | |
| needs: check | |
| if: | | |
| needs.check.outputs.needs_release == 'true' | |
| && (github.event_name == 'schedule' || github.event_name == 'push' || inputs.release) | |
| permissions: | |
| contents: write | |
| steps: | |
| - uses: actions/checkout@v4 | |
| with: | |
| # Checked out with the PAT so the tag push below is attributed to it | |
| # and triggers the release workflow. | |
| token: ${{ secrets.RELEASE_TAG_TOKEN }} | |
| - name: Tag the release | |
| env: | |
| GH_TOKEN: ${{ secrets.RELEASE_TAG_TOKEN }} | |
| UPSTREAM_VERSION: ${{ needs.check.outputs.upstream_version }} | |
| run: | | |
| set -euo pipefail | |
| TAG="v${UPSTREAM_VERSION}" | |
| # The tag already existing means a previous release was tagged but did | |
| # not publish, so re-tagging cannot retry it. Fail loudly rather than | |
| # leave the fork silently behind. | |
| if git ls-remote --exit-code --tags origin "refs/tags/${TAG}" >/dev/null 2>&1; then | |
| echo "::error::$TAG is already tagged but Tero-Datadog-Extension-${UPSTREAM_VERSION} is not published." | |
| echo "::error::Re-run Release Lambda Extension for $UPSTREAM_VERSION with dev unticked, then check why the tagged run failed." | |
| exit 1 | |
| fi | |
| git config user.name "github-actions[bot]" | |
| git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | |
| git tag "$TAG" | |
| git push origin "$TAG" | |
| gh release create "$TAG" \ | |
| --title "$TAG" \ | |
| --notes "Tracks [DataDog ${TAG}](https://github.com/DataDog/datadog-lambda-extension/releases/tag/${TAG}). Publishes \`Tero-Datadog-Extension-${UPSTREAM_VERSION}\` and \`Tero-Datadog-Extension-${UPSTREAM_VERSION}-ARM\`." | |
| echo "::notice::Pushed $TAG. Release Lambda Extension takes over from here." |