Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 15 additions & 27 deletions .github/workflows/release-extension.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,36 +10,13 @@ name: Release Lambda Extension
# patch on top of upstream v119 -> Tero-Datadog-Extension-119:2
#
# Tag "v119" to release, "v119.2" to release a patch and assert it lands on 2.
# A tag push is the only automated way in. upstream-release-watch.yml pushes the
# tag; publishing lives here and nowhere else.
on:
push:
tags:
- "v[0-9]+"
- "v[0-9]+.[0-9]+"
# Called by upstream-release-watch.yml. A tag pushed with GITHUB_TOKEN does not
# trigger another workflow, so the watch job invokes this one directly instead
# of relying on a tag push. github.event_name is the caller's event, so a
# scheduled watch run does NOT get the -dev suffix — it is a real release.
workflow_call:
inputs:
version:
description: "Upstream version to release, e.g. 119 or 119.2 (patch optional)"
required: true
type: string
regions:
description: "Comma-separated AWS regions. Empty publishes to DEFAULT_REGIONS."
required: false
default: ""
type: string
architectures:
description: "Architectures to build and publish"
required: false
default: "amd64,arm64"
type: string
dry_run:
description: "Dry run - build but don't publish to AWS"
required: false
default: false
type: boolean
workflow_dispatch:
inputs:
version:
Expand All @@ -65,6 +42,13 @@ on:
required: false
default: false
type: boolean
# Defaults true here so a manual run cannot overwrite a real release by
# accident. Untick it to publish prod layer names by hand.
dev:
description: "Append -dev to the layer name"
required: false
default: true
type: boolean

permissions:
id-token: write
Expand Down Expand Up @@ -262,8 +246,12 @@ jobs:
COMPATIBLE_ARCH="arm64"
fi

# Add -dev suffix for workflow_dispatch (manual) runs
if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
# Driven by an explicit input, not github.event_name: inside a called
# workflow event_name is the CALLER's event, so keying off it made a
# manual run of upstream-release-watch publish -dev names while
# reporting a release. Tag pushes leave the input empty, so they are
# never -dev.
if [ "${{ inputs.dev }}" = "true" ]; then
DEV_SUFFIX="-dev"
else
DEV_SUFFIX=""
Expand Down
52 changes: 46 additions & 6 deletions .github/workflows/upstream-release-watch.yml
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,53 @@ jobs:
"git checkout -b chore/upstream-v${UPSTREAM_VERSION} && git merge v${UPSTREAM_VERSION}" \
'```' )"

release:
name: Release v${{ needs.check.outputs.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' || inputs.release)
uses: ./.github/workflows/release-extension.yml
with:
version: ${{ needs.check.outputs.upstream_version }}
secrets: inherit
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."
36 changes: 29 additions & 7 deletions Releasing.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,19 @@ Replace:
- **Name:** `AWS_ROLE_ARN`
- **Value:** Your role ARN

### Step 4: Add a tag-push token

Upstream Release Watch pushes the release tag, and a tag pushed with the default
`GITHUB_TOKEN` does not trigger another workflow. Without this secret the watch
tags and nothing publishes.

1. Create a fine-grained PAT (or GitHub App token) with **Contents: write** on
this repository

2. Add it as a secret:
- **Name:** `RELEASE_TAG_TOKEN`
- **Value:** The token

## Versioning

Releases track DataDog's upstream releases. Upstream publishes `v<N>` tags, so a
Expand Down Expand Up @@ -133,17 +146,24 @@ be triggered by hand. It compares DataDog's latest release with two things: the
version `main` contains (recorded in `.upstream-version`) and whether
`Tero-Datadog-Extension-<N>` is published.

| State | What the watch does |
| ----------------------------------------- | ------------------------------------ |
| `main` is behind upstream | Opens a PR merging upstream `v<N>` |
| `main` is level, `v<N>` not published | Publishes `v<N>` to all regions |
| Both level | Nothing |
| State | What the watch does |
| ------------------------------------- | ---------------------------------- |
| `main` is behind upstream | Opens a PR merging upstream `v<N>` |
| `main` is level, `v<N>` not published | Pushes tag `v<N>` |
| Both level | Nothing |

The watch never publishes. It pushes the tag, and the tag triggers **Release
Lambda Extension** — publishing lives in one place, on one trigger.

A release therefore only happens after a human merged the upstream PR and CI was
green. When the merge conflicts the watch opens an issue instead of a PR, because
resolving an upstream merge needs judgement — stale lock entries and API changes
that only clippy catches.

If the tag already exists but the layer is still unpublished, the watch fails
loudly rather than re-tagging: a tag can only trigger a release once, so that
state means a tagged release failed and needs a look.

To check parity without publishing, run it by hand with `release` unticked.

`.upstream-version` is the record of what `main` contains. The merge PR bumps it;
Expand Down Expand Up @@ -190,8 +210,10 @@ publishing to a region the account has not enabled fails the job. Add them to

4. After completion, find the Layer ARNs in the workflow summary

Manual runs append `-dev` to the layer name, so they never overwrite a real
release.
Manual runs tick `dev` by default, which appends `-dev` to the layer name so they
cannot overwrite a real release. Untick it to publish prod names by hand.

Tag pushes and watch-driven releases always publish prod names.

## Layer Naming Convention

Expand Down
Loading