From b3962cf6f2d2d68992bc9d9a81dd0a352d54d847 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 11:35:14 +0530 Subject: [PATCH 01/15] ci: add weekly upstream release check automation Add a cron workflow that runs weekly to detect new releases in the upstream open-telemetry/opentelemetry-lambda repo and automatically triggers the release-prepare workflow when new tags are found. - release-check-upstream.yml: weekly cron + manual trigger - upstream-releases.json: tracks last-processed upstream tag per language - release-prepare.yml: workflow for creating prepare PRs - ci/release-prepare.sh: script that updates changelog, versions, and tracking file --- .github/upstream-releases.json | 5 + .github/workflows/release-check-upstream.yml | 138 +++++++++++++++++++ .github/workflows/release-prepare.yml | 127 +++++++++++++++++ ci/release-prepare.sh | 135 ++++++++++++++++++ 4 files changed, 405 insertions(+) create mode 100644 .github/upstream-releases.json create mode 100644 .github/workflows/release-check-upstream.yml create mode 100644 .github/workflows/release-prepare.yml create mode 100755 ci/release-prepare.sh diff --git a/.github/upstream-releases.json b/.github/upstream-releases.json new file mode 100644 index 0000000..9cebd71 --- /dev/null +++ b/.github/upstream-releases.json @@ -0,0 +1,5 @@ +{ + "java": "layer-javaagent/0.19.0", + "nodejs": "layer-nodejs/0.21.0", + "python": "layer-python/0.19.0" +} diff --git a/.github/workflows/release-check-upstream.yml b/.github/workflows/release-check-upstream.yml new file mode 100644 index 0000000..b1a3083 --- /dev/null +++ b/.github/workflows/release-check-upstream.yml @@ -0,0 +1,138 @@ +name: Check Upstream Releases + +on: + schedule: + - cron: '7 9 * * 1' + workflow_dispatch: + +permissions: + contents: read + actions: write + +jobs: + check: + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Check for new upstream releases + env: + GH_TOKEN: ${{ github.token }} + run: | + set -euo pipefail + + UPSTREAM="https://github.com/open-telemetry/opentelemetry-lambda.git" + TRACKING_FILE=".github/upstream-releases.json" + + declare -A TAG_PREFIX=( + [java]="layer-javaagent" + [nodejs]="layer-nodejs" + [python]="layer-python" + ) + + semver_gt() { + local lhs="$1" rhs="$2" + if [[ "${lhs}" == "${rhs}" ]]; then + return 1 + fi + local IFS='.' + read -ra L <<< "${lhs}" + read -ra R <<< "${rhs}" + for i in 0 1 2; do + if (( ${L[$i]:-0} > ${R[$i]:-0} )); then + return 0 + elif (( ${L[$i]:-0} < ${R[$i]:-0} )); then + return 1 + fi + done + return 1 + } + + minor_bump() { + local ver="$1" + local IFS='.' + read -ra parts <<< "${ver}" + echo "${parts[0]}.$(( parts[1] + 1 )).0" + } + + latest_upstream_tag() { + local prefix="$1" + git ls-remote --tags "${UPSTREAM}" "refs/tags/${prefix}/*" \ + | sed 's|.*refs/tags/||' \ + | grep -v '\^{}' \ + | sort -t/ -k2 -V \ + | tail -1 + } + + TRIGGERED=() + + for LANGUAGE in java nodejs python; do + PREFIX="${TAG_PREFIX[${LANGUAGE}]}" + + echo "--- Checking ${LANGUAGE} (prefix: ${PREFIX}) ---" + + LATEST_UPSTREAM=$(latest_upstream_tag "${PREFIX}") + if [[ -z "${LATEST_UPSTREAM}" ]]; then + echo "WARNING: No upstream tags found for ${PREFIX}" + continue + fi + echo "Latest upstream: ${LATEST_UPSTREAM}" + + LAST_PROCESSED=$(jq -r ".${LANGUAGE}" "${TRACKING_FILE}") + echo "Last processed: ${LAST_PROCESSED}" + + if [[ "${LATEST_UPSTREAM}" == "${LAST_PROCESSED}" ]]; then + echo "No new release for ${LANGUAGE}" + continue + fi + + UPSTREAM_VER="${LATEST_UPSTREAM#"${PREFIX}/"}" + PROCESSED_VER="${LAST_PROCESSED#"${PREFIX}/"}" + if ! semver_gt "${UPSTREAM_VER}" "${PROCESSED_VER}"; then + echo "Upstream ${UPSTREAM_VER} is not newer than ${PROCESSED_VER}" + continue + fi + + echo "New release detected: ${LATEST_UPSTREAM} > ${LAST_PROCESSED}" + + EXISTING_BRANCH=$( + git ls-remote --heads origin "refs/heads/prepare-${LANGUAGE}-v*" \ + | head -1 || true + ) + if [[ -n "${EXISTING_BRANCH}" ]]; then + echo "Skipping ${LANGUAGE}: prepare branch already exists" + continue + fi + + LATEST_TAG=$( + git tag -l "${LANGUAGE}-v*" \ + | sort -V \ + | tail -1 + ) + if [[ -z "${LATEST_TAG}" ]]; then + echo "ERROR: No existing tags for ${LANGUAGE}" + continue + fi + CURRENT_VER="${LATEST_TAG#"${LANGUAGE}"-v}" + NEXT_VER=$(minor_bump "${CURRENT_VER}") + echo "Version bump: ${CURRENT_VER} -> ${NEXT_VER}" + + echo "Triggering release-prepare for ${LANGUAGE} v${NEXT_VER}" + gh workflow run release-prepare.yml \ + -f language="${LANGUAGE}" \ + -f version="${NEXT_VER}" \ + -f otel_lambda_tag="${LATEST_UPSTREAM}" + + TRIGGERED+=("${LANGUAGE}-v${NEXT_VER}") + done + + if [[ ${#TRIGGERED[@]} -gt 0 ]]; then + echo "" + echo "=== Triggered releases ===" + printf ' %s\n' "${TRIGGERED[@]}" + else + echo "" + echo "=== No new releases detected ===" + fi diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml new file mode 100644 index 0000000..42c5200 --- /dev/null +++ b/.github/workflows/release-prepare.yml @@ -0,0 +1,127 @@ +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 }} + OTEL_LAMBDA_TAG: ${{ inputs.otel_lambda_tag }} + 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: + fetch-depth: 0 + submodules: true + + - name: Check release tag and branch do 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 + if git ls-remote --heads origin "${BRANCH}" | grep -q .; then + echo "::error::Branch ${BRANCH} already exists on remote" + 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 \ + .github/upstream-releases.json \ + 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 + run: git push origin "${BRANCH}" + + - name: Ensure release label exists + env: + GH_TOKEN: ${{ github.token }} + run: | + gh label create release \ + --color "0075ca" \ + --description "Release PR" \ + 2>/dev/null || true + + - name: Create pull request + env: + GH_TOKEN: ${{ github.token }} + 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/ci/release-prepare.sh b/ci/release-prepare.sh new file mode 100755 index 0000000..59514a8 --- /dev/null +++ b/ci/release-prepare.sh @@ -0,0 +1,135 @@ +#!/bin/bash + +set -euo pipefail + +: "${LANGUAGE:?LANGUAGE is required (java, nodejs, or python)}" +: "${VERSION:?VERSION is required (e.g. 1.41.0)}" +: "${OTEL_LAMBDA_TAG:?OTEL_LAMBDA_TAG is required (e.g. layer-python/0.19.0)}" + +VERSION_DASHED="v${VERSION//./-}" +TAG="${LANGUAGE}-v${VERSION}" +RELEASE_BRANCH="release-${TAG}" +DATE="$(date +%Y-%m-%d)" + +LAYER_DATA="${LANGUAGE}/layer-data.sh" +TEMPLATE="${LANGUAGE}/sample-apps/template.yaml" +TRACKING_FILE=".github/upstream-releases.json" + +cleanup() { find . -maxdepth 3 -name '*.bak' -delete; } +trap cleanup EXIT + +OLD_VERSION_DASHED=$(grep '^VERSION=' "${LAYER_DATA}" | cut -d= -f2) +if [[ -z "${OLD_VERSION_DASHED}" ]]; then + echo "ERROR: could not extract VERSION from ${LAYER_DATA}" >&2 + exit 1 +fi + +# --- Update CHANGELOG.md --- + +cat > /tmp/changelog_block.md <&2 + exit 1 +fi +sed -i.bak "/^All notable changes/r /tmp/changelog_block.md" CHANGELOG.md + +# --- Update layer-data.sh --- + +sed -i.bak "s|^VERSION=.*|VERSION=${VERSION_DASHED}|" "${LAYER_DATA}" + +sed -i.bak \ + "s|tree/[^/]*/\{0,1\}${LANGUAGE}|tree/${RELEASE_BRANCH}/${LANGUAGE}|" \ + "${LAYER_DATA}" + +# --- Update template.yaml --- + +sed -i.bak "s|${OLD_VERSION_DASHED}|${VERSION_DASHED}|g" "${TEMPLATE}" + +# --- Detect component versions from submodule --- + +COLLECTOR_VERSION=$(grep "go.opentelemetry.io/collector/otelcol v" \ + opentelemetry-lambda/collector/go.mod | awk '{print $2}') +if [[ -z "${COLLECTOR_VERSION}" ]]; then + echo "ERROR: could not extract COLLECTOR_VERSION from collector/go.mod" >&2 + exit 1 +fi + +case "${LANGUAGE}" in + python) + SDK_VERSION=$(grep "^opentelemetry-sdk==" \ + opentelemetry-lambda/python/src/otel/otel_sdk/requirements.txt \ + | cut -d= -f3) + INSTRUMENTATION_VERSION=$(grep "^opentelemetry-distro==" \ + opentelemetry-lambda/python/src/otel/otel_sdk/requirements.txt \ + | cut -d= -f3) + if [[ -z "${SDK_VERSION}" ]]; then + echo "ERROR: could not extract opentelemetry-sdk version from requirements.txt" >&2 + exit 1 + fi + if [[ -z "${INSTRUMENTATION_VERSION}" ]]; then + echo "ERROR: could not extract opentelemetry-distro version from requirements.txt" >&2 + exit 1 + fi + ;; + nodejs) + SDK_VERSION=v$(grep -A5 '"node_modules/@opentelemetry/sdk-trace-node"' \ + opentelemetry-lambda/nodejs/package-lock.json \ + | grep '"version"' | grep -o '[0-9][0-9.]*' | head -1) + if [[ "${SDK_VERSION}" == "v" ]]; then + echo "ERROR: could not extract @opentelemetry/sdk-trace-node version from package-lock.json" >&2 + exit 1 + fi + ;; + java) + SDK_VERSION=$(grep 'opentelemetry-javaagent:' \ + opentelemetry-lambda/java/dependencyManagement/build.gradle.kts \ + | grep -o '[0-9][0-9.]*' | head -1) + if [[ -z "${SDK_VERSION}" ]]; then + echo "ERROR: could not extract opentelemetry-javaagent version from build.gradle.kts" >&2 + exit 1 + fi + ;; +esac + +# --- Update root README.md --- + +sed -i.bak \ + "s|release-${LANGUAGE}-v[0-9][0-9.]*/${LANGUAGE}|release-${LANGUAGE}-v${VERSION}/${LANGUAGE}|g" \ + README.md + +case "${LANGUAGE}" in + python) + sed -i.bak "/Python layer/s|SDK \`v[^\`]*\`|SDK \`v${SDK_VERSION}\`|" README.md + sed -i.bak "/Python layer/s|instrumentation \`v[^\`]*\`|instrumentation \`v${INSTRUMENTATION_VERSION}\`|" README.md + sed -i.bak "/Python layer/s|Collector \`v[^\`]*\`|Collector \`${COLLECTOR_VERSION}\`|" README.md + ;; + nodejs) + sed -i.bak "/NodeJS layer/s|SDK \`v[^\`]*\`|SDK \`${SDK_VERSION}\`|" README.md + sed -i.bak "/NodeJS layer/s|Collector \`v[^\`]*\`|Collector \`${COLLECTOR_VERSION}\`|" README.md + ;; + java) + sed -i.bak "/Java wrapper/s|Java \`v[^\`]*\`|Java \`v${SDK_VERSION}\`|" README.md + sed -i.bak "/Java wrapper/s|Collector \`v[^\`]*\`|Collector \`${COLLECTOR_VERSION}\`|" README.md + ;; +esac + +# --- Update upstream tracking file --- + +TMP_TRACKING=$(mktemp) +jq --arg lang "${LANGUAGE}" --arg tag "${OTEL_LAMBDA_TAG}" \ + '.[$lang] = $tag' "${TRACKING_FILE}" > "${TMP_TRACKING}" +mv "${TMP_TRACKING}" "${TRACKING_FILE}" + +echo "Release preparation complete for ${TAG}" From eaf8a55e1b715d4fdf4a8794bbf0ebbb265b7319 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 13:00:51 +0530 Subject: [PATCH 02/15] ci: add dry_run and language filter inputs to upstream check Adds workflow_dispatch inputs for testing: - dry_run (default: true): detect releases without triggering prepare - language: optionally check only one language --- .github/workflows/release-check-upstream.yml | 38 ++++++++++++++++---- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/.github/workflows/release-check-upstream.yml b/.github/workflows/release-check-upstream.yml index b1a3083..ffe6a20 100644 --- a/.github/workflows/release-check-upstream.yml +++ b/.github/workflows/release-check-upstream.yml @@ -4,6 +4,21 @@ on: schedule: - cron: '7 9 * * 1' workflow_dispatch: + inputs: + dry_run: + description: "If true, detect releases but don't trigger prepare workflow" + required: false + type: boolean + default: true + language: + description: "Only check this language (leave empty to check all)" + required: false + type: choice + options: + - '' + - java + - nodejs + - python permissions: contents: read @@ -20,6 +35,8 @@ jobs: - name: Check for new upstream releases env: GH_TOKEN: ${{ github.token }} + DRY_RUN: ${{ inputs.dry_run || 'false' }} + FILTER_LANGUAGE: ${{ inputs.language || '' }} run: | set -euo pipefail @@ -68,7 +85,12 @@ jobs: TRIGGERED=() - for LANGUAGE in java nodejs python; do + LANGUAGES=(java nodejs python) + if [[ -n "${FILTER_LANGUAGE}" ]]; then + LANGUAGES=("${FILTER_LANGUAGE}") + fi + + for LANGUAGE in "${LANGUAGES[@]}"; do PREFIX="${TAG_PREFIX[${LANGUAGE}]}" echo "--- Checking ${LANGUAGE} (prefix: ${PREFIX}) ---" @@ -119,11 +141,15 @@ jobs: NEXT_VER=$(minor_bump "${CURRENT_VER}") echo "Version bump: ${CURRENT_VER} -> ${NEXT_VER}" - echo "Triggering release-prepare for ${LANGUAGE} v${NEXT_VER}" - gh workflow run release-prepare.yml \ - -f language="${LANGUAGE}" \ - -f version="${NEXT_VER}" \ - -f otel_lambda_tag="${LATEST_UPSTREAM}" + if [[ "${DRY_RUN}" == "true" ]]; then + echo "[DRY RUN] Would trigger release-prepare for ${LANGUAGE} v${NEXT_VER} with tag ${LATEST_UPSTREAM}" + else + echo "Triggering release-prepare for ${LANGUAGE} v${NEXT_VER}" + gh workflow run release-prepare.yml \ + -f language="${LANGUAGE}" \ + -f version="${NEXT_VER}" \ + -f otel_lambda_tag="${LATEST_UPSTREAM}" + fi TRIGGERED+=("${LANGUAGE}-v${NEXT_VER}") done From 2d9aadabc9899353f7490d9763a700c15be7e4a1 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 13:53:40 +0530 Subject: [PATCH 03/15] ci: add submodule tag and commit reference to prepare PR body Includes clickable links to the upstream opentelemetry-lambda tag and commit SHA in the PR description so reviewers can see exactly what the layers will be built from. --- .github/workflows/release-prepare.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml index 42c5200..8a4385f 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -70,10 +70,12 @@ jobs: run: git checkout -b "${BRANCH}" - name: Update submodule to otel-lambda release + id: submodule run: | cd opentelemetry-lambda git fetch --tags origin git checkout "${{ inputs.otel_lambda_tag }}" + echo "commit=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" cd .. - name: Run prepare script @@ -107,11 +109,16 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | + SUBMODULE_COMMIT="${{ steps.submodule.outputs.commit }}" + UPSTREAM_REPO="https://github.com/open-telemetry/opentelemetry-lambda" 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 }}\` + ### Submodule reference + + - **Tag:** [\`${{ inputs.otel_lambda_tag }}\`](${UPSTREAM_REPO}/releases/tag/${{ inputs.otel_lambda_tag }}) + - **Commit:** [\`${SUBMODULE_COMMIT:0:12}\`](${UPSTREAM_REPO}/commit/${SUBMODULE_COMMIT}) ### Pre-merge checklist From d268c96b3a5f1598af03570fed6a02da489acf87 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 17 Jul 2026 08:28:46 +0000 Subject: [PATCH 04/15] feat: prepare release java v2.20.0 --- .github/upstream-releases.json | 2 +- CHANGELOG.md | 10 ++++++++++ README.md | 2 +- java/layer-data.sh | 4 ++-- java/sample-apps/template.yaml | 32 ++++++++++++++++---------------- opentelemetry-lambda | 2 +- 6 files changed, 31 insertions(+), 21 deletions(-) diff --git a/.github/upstream-releases.json b/.github/upstream-releases.json index 9cebd71..3af3ca0 100644 --- a/.github/upstream-releases.json +++ b/.github/upstream-releases.json @@ -1,5 +1,5 @@ { - "java": "layer-javaagent/0.19.0", + "java": "layer-javaagent/0.20.0", "nodejs": "layer-nodejs/0.21.0", "python": "layer-python/0.19.0" } diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ee4c04..7d197f9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. +## [java-v2.20.0] + +### Released 2026-07-17 + +### Changed + +- TODO: fill in changelog + +[java-v2.20.0]: https://github.com/SumoLogic/sumologic-otel-lambda/releases/tag/java-v2.20.0 + ## [python-v1.40.0] ### Released 2026-04-09 diff --git a/README.md b/README.md index ee9d859..69dac3c 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ `sumologic-otel-lambda` publishes preconfigured [OpenTelemetry Lambda](https://github.com/open-telemetry/opentelemetry-lambda) layers which provide instrumentation for AWS Lambda functions. Released `sumologic-otel-lambda` layers are available: -- Java wrapper layer contains OpenTelemetry Java `v2.19.0` and OpenTelemetry Collector `v0.132.0`. Please see list of [lambda layers](https://github.com/SumoLogic/sumologic-otel-lambda/blob/release-java-v2.19.0/java/README.md). +- Java wrapper layer contains OpenTelemetry Java `v2.27.0` and OpenTelemetry Collector `v0.151.0`. Please see list of [lambda layers](https://github.com/SumoLogic/sumologic-otel-lambda/blob/release-java-v2.20.0/java/README.md). - NodeJS layer contains OpenTelemetry JavaScript SDK `v2.2.0` and OpenTelemetry Collector `v0.138.0`. Please see list of [lambda layers](https://github.com/SumoLogic/sumologic-otel-lambda/blob/release-nodejs-v2.0.2/nodejs/README.md). diff --git a/java/layer-data.sh b/java/layer-data.sh index c7dd820..00a4ee7 100755 --- a/java/layer-data.sh +++ b/java/layer-data.sh @@ -4,6 +4,6 @@ OFFICIAL_LAYER_NAME=sumologic-otel-lambda-java ARCHITECTURE_AMD=x86_64 ARCHITECTURE_ARM=arm64 RUNTIMES='java8.al2 java11 java17 java21' -DESCRIPTION='Sumo Logic OTEL Collector and Java Lambda Layer https://github.com/SumoLogic/sumologic-otel-lambda/tree/release-java-2.19.0/java' +DESCRIPTION='Sumo Logic OTEL Collector and Java Lambda Layer https://github.com/SumoLogic/sumologic-otel-lambda/tree/release-java-v2.20.0/java' LICENSE=Apache-2.0 -VERSION=v2-19-0 +VERSION=v2-20-0 diff --git a/java/sample-apps/template.yaml b/java/sample-apps/template.yaml index cb1a368..139cc03 100644 --- a/java/sample-apps/template.yaml +++ b/java/sample-apps/template.yaml @@ -49,34 +49,34 @@ Outputs: Mappings: RegionMap: ap-northeast-1: - layer: "arn:aws:lambda:ap-northeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:ap-northeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" ap-northeast-2: - layer: "arn:aws:lambda:ap-northeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:ap-northeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" ap-south-1: - layer: "arn:aws:lambda:ap-south-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:ap-south-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" ap-southeast-1: - layer: "arn:aws:lambda:ap-southeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:ap-southeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" ap-southeast-2: - layer: "arn:aws:lambda:ap-southeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:ap-southeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" ca-central-1: - layer: "arn:aws:lambda:ca-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:ca-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" eu-central-1: - layer: "arn:aws:lambda:eu-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:eu-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" eu-north-1: - layer: "arn:aws:lambda:eu-north-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:eu-north-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" eu-west-1: - layer: "arn:aws:lambda:eu-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:eu-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" eu-west-2: - layer: "arn:aws:lambda:eu-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:eu-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" eu-west-3: - layer: "arn:aws:lambda:eu-west-3:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:eu-west-3:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" sa-east-1: - layer: "arn:aws:lambda:sa-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:sa-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" us-east-1: - layer: "arn:aws:lambda:us-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:us-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" us-east-2: - layer: "arn:aws:lambda:us-east-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:us-east-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" us-west-1: - layer: "arn:aws:lambda:us-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:us-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" us-west-2: - layer: "arn:aws:lambda:us-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" + layer: "arn:aws:lambda:us-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" diff --git a/opentelemetry-lambda b/opentelemetry-lambda index c0ac4ce..247d46c 160000 --- a/opentelemetry-lambda +++ b/opentelemetry-lambda @@ -1 +1 @@ -Subproject commit c0ac4ce0bc0f33b07d7fa73b5fda734400625704 +Subproject commit 247d46c7e19d38ef5ca5e126c828827cb77c55ed From 4dba72e175032df18362554c0d1e703223b64c6f Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 14:09:57 +0530 Subject: [PATCH 05/15] ci: add post-merge release workflows - release-tag.yml: creates and pushes tag when prepare PR is merged - release-finalize.yml: creates release branch with ARN tables after release build succeeds - release-publish.yml: promotes pre-release to full release when release branch PR is merged - ci/release-finalize.sh: extracts ARN tables from pre-release body and updates language README --- .github/workflows/release-finalize.yml | 98 ++++++++++++++++++++++ .github/workflows/release-publish.yml | 41 +++++++++ .github/workflows/release-tag.yml | 49 +++++++++++ ci/release-finalize.sh | 110 +++++++++++++++++++++++++ 4 files changed, 298 insertions(+) create mode 100644 .github/workflows/release-finalize.yml create mode 100644 .github/workflows/release-publish.yml create mode 100644 .github/workflows/release-tag.yml create mode 100755 ci/release-finalize.sh diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml new file mode 100644 index 0000000..5fcc8bc --- /dev/null +++ b/.github/workflows/release-finalize.yml @@ -0,0 +1,98 @@ +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: + 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 + run: git push origin "${{ steps.parse.outputs.release_branch }}" + + - name: Create pull request + env: + GH_TOKEN: ${{ github.token }} + 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-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..3cbe39d --- /dev/null +++ b/.github/workflows/release-tag.yml @@ -0,0 +1,49 @@ +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: + 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 }} + run: | + git tag -m "${TAG}" "${TAG}" + git push origin "${TAG}" diff --git a/ci/release-finalize.sh b/ci/release-finalize.sh new file mode 100755 index 0000000..5d82074 --- /dev/null +++ b/ci/release-finalize.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +set -euo pipefail + +: "${TAG:?TAG is required (e.g. python-v1.41.0)}" +: "${LANGUAGE:?LANGUAGE is required (java, nodejs, or python)}" +: "${VERSION:?VERSION is required (e.g. 1.41.0)}" + +README="${LANGUAGE}/README.md" + +gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ + --jq '.body' > /tmp/release_body.md + +python3 - "${README}" "${TAG}" "${VERSION}" /tmp/release_body.md <<'PYEOF' +import re +import sys + +readme_path = sys.argv[1] +tag = sys.argv[2] +version = sys.argv[3] +release_body_path = sys.argv[4] + +with open(release_body_path) as f: + body = f.read() + +def extract_table(text, heading_fragment): + lines = text.splitlines() + capture = False + table_lines = [] + for line in lines: + if heading_fragment.lower() in line.lower(): + capture = True + continue + if capture: + if line.startswith("##"): + break + if line.strip(): + table_lines.append(line) + return "\n".join(table_lines) + +amd64_table = extract_table(body, "AMD64 Lambda Layers List") +arm64_table = extract_table(body, "ARM64 Lambda Layers List") + +if not amd64_table: + print("ERROR: Could not extract AMD64 table from pre-release body", + file=sys.stderr) + sys.exit(1) +if not arm64_table: + print("ERROR: Could not extract ARM64 table from pre-release body", + file=sys.stderr) + sys.exit(1) + +with open(readme_path) as f: + content = f.read() + +if "unreleased version" not in content: + print(f"ERROR: 'unreleased version' not found in {readme_path}", + file=sys.stderr) + sys.exit(1) + +content = re.sub( + r"unreleased version", + f"v{version}", + content, + count=1, +) + +def replace_section(text, heading, new_table): + lines = text.splitlines() + result = [] + skip = False + found = False + for line in lines: + if line.strip().startswith("##") and heading.lower() in line.lower(): + found = True + result.append(line) + result.append("") + result.append(new_table) + result.append("") + skip = True + continue + if skip: + if line.strip().startswith("##"): + skip = False + result.append(line) + continue + result.append(line) + if not found: + print(f"ERROR: heading '{heading}' not found in {readme_path}", + file=sys.stderr) + sys.exit(1) + return "\n".join(result) + +content = replace_section(content, "AMD64 Lambda Layers List", amd64_table) +content = replace_section(content, "ARM64 Lambda Layers List", arm64_table) + +content = re.sub( + r"releases/download/[^/]+/", + f"releases/download/{tag}/", + content, +) + +if not content.endswith("\n"): + content += "\n" + +with open(readme_path, "w") as f: + f.write(content) + +print(f"Updated {readme_path} with ARN tables for {tag}") +PYEOF From 987cdddae7ede17a2f251342ed143fbb7204d76d Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 14:30:34 +0530 Subject: [PATCH 06/15] ci: use per-language files to avoid merge conflicts - Add /version.txt for version tracking (replaces git tag lookup) - Split .github/upstream-releases.json into per-language .txt files - Use changelog fragments (changelog/.md) instead of directly editing CHANGELOG.md in prepare PRs - Assemble changelog into CHANGELOG.md post-merge in release-tag.yml - Add release-tag, release-finalize, release-publish workflows Each prepare PR now only touches its own language's files, so multiple language releases can be in-flight simultaneously without conflicts. --- .github/upstream-release-java.txt | 1 + .github/upstream-release-nodejs.txt | 1 + .github/upstream-release-python.txt | 1 + .github/upstream-releases.json | 5 - .github/workflows/release-check-upstream.yml | 18 +-- .github/workflows/release-finalize.yml | 98 +++++++++++++++++ .github/workflows/release-prepare.yml | 5 +- .github/workflows/release-publish.yml | 41 +++++++ .github/workflows/release-tag.yml | 67 +++++++++++ changelog/.gitkeep | 0 ci/release-finalize.sh | 110 +++++++++++++++++++ ci/release-prepare.sh | 28 ++--- java/version.txt | 1 + nodejs/version.txt | 1 + python/version.txt | 1 + 15 files changed, 343 insertions(+), 35 deletions(-) create mode 100644 .github/upstream-release-java.txt create mode 100644 .github/upstream-release-nodejs.txt create mode 100644 .github/upstream-release-python.txt delete mode 100644 .github/upstream-releases.json create mode 100644 .github/workflows/release-finalize.yml create mode 100644 .github/workflows/release-publish.yml create mode 100644 .github/workflows/release-tag.yml create mode 100644 changelog/.gitkeep create mode 100755 ci/release-finalize.sh create mode 100644 java/version.txt create mode 100644 nodejs/version.txt create mode 100644 python/version.txt diff --git a/.github/upstream-release-java.txt b/.github/upstream-release-java.txt new file mode 100644 index 0000000..db81268 --- /dev/null +++ b/.github/upstream-release-java.txt @@ -0,0 +1 @@ +layer-javaagent/0.19.0 diff --git a/.github/upstream-release-nodejs.txt b/.github/upstream-release-nodejs.txt new file mode 100644 index 0000000..93cb677 --- /dev/null +++ b/.github/upstream-release-nodejs.txt @@ -0,0 +1 @@ +layer-nodejs/0.21.0 diff --git a/.github/upstream-release-python.txt b/.github/upstream-release-python.txt new file mode 100644 index 0000000..5841364 --- /dev/null +++ b/.github/upstream-release-python.txt @@ -0,0 +1 @@ +layer-python/0.19.0 diff --git a/.github/upstream-releases.json b/.github/upstream-releases.json deleted file mode 100644 index 9cebd71..0000000 --- a/.github/upstream-releases.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "java": "layer-javaagent/0.19.0", - "nodejs": "layer-nodejs/0.21.0", - "python": "layer-python/0.19.0" -} diff --git a/.github/workflows/release-check-upstream.yml b/.github/workflows/release-check-upstream.yml index ffe6a20..60c0680 100644 --- a/.github/workflows/release-check-upstream.yml +++ b/.github/workflows/release-check-upstream.yml @@ -29,8 +29,6 @@ jobs: runs-on: ubuntu-22.04 steps: - uses: actions/checkout@v4 - with: - fetch-depth: 0 - name: Check for new upstream releases env: @@ -41,7 +39,6 @@ jobs: set -euo pipefail UPSTREAM="https://github.com/open-telemetry/opentelemetry-lambda.git" - TRACKING_FILE=".github/upstream-releases.json" declare -A TAG_PREFIX=( [java]="layer-javaagent" @@ -102,7 +99,8 @@ jobs: fi echo "Latest upstream: ${LATEST_UPSTREAM}" - LAST_PROCESSED=$(jq -r ".${LANGUAGE}" "${TRACKING_FILE}") + TRACKING_FILE=".github/upstream-release-${LANGUAGE}.txt" + LAST_PROCESSED=$(cat "${TRACKING_FILE}" | tr -d '[:space:]') echo "Last processed: ${LAST_PROCESSED}" if [[ "${LATEST_UPSTREAM}" == "${LAST_PROCESSED}" ]]; then @@ -128,16 +126,12 @@ jobs: continue fi - LATEST_TAG=$( - git tag -l "${LANGUAGE}-v*" \ - | sort -V \ - | tail -1 - ) - if [[ -z "${LATEST_TAG}" ]]; then - echo "ERROR: No existing tags for ${LANGUAGE}" + VERSION_FILE="${LANGUAGE}/version.txt" + CURRENT_VER=$(cat "${VERSION_FILE}" | tr -d '[:space:]') + if [[ -z "${CURRENT_VER}" ]]; then + echo "ERROR: could not read version from ${VERSION_FILE}" continue fi - CURRENT_VER="${LATEST_TAG#"${LANGUAGE}"-v}" NEXT_VER=$(minor_bump "${CURRENT_VER}") echo "Version bump: ${CURRENT_VER} -> ${NEXT_VER}" diff --git a/.github/workflows/release-finalize.yml b/.github/workflows/release-finalize.yml new file mode 100644 index 0000000..5fcc8bc --- /dev/null +++ b/.github/workflows/release-finalize.yml @@ -0,0 +1,98 @@ +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: + 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 + run: git push origin "${{ steps.parse.outputs.release_branch }}" + + - name: Create pull request + env: + GH_TOKEN: ${{ github.token }} + 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 index 8a4385f..1fbf07a 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -84,8 +84,9 @@ jobs: - name: Commit changes run: | git add \ - .github/upstream-releases.json \ - CHANGELOG.md \ + ".github/upstream-release-${LANGUAGE}.txt" \ + "changelog/${LANGUAGE}-v${VERSION}.md" \ + "${LANGUAGE}/version.txt" \ README.md \ "${LANGUAGE}/layer-data.sh" \ "${LANGUAGE}/sample-apps/template.yaml" \ 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..c6d26ec --- /dev/null +++ b/.github/workflows/release-tag.yml @@ -0,0 +1,67 @@ +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: + 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: Assemble changelog fragment + env: + TAG: ${{ steps.parse.outputs.tag }} + run: | + FRAGMENT="changelog/${TAG}.md" + if [[ -f "${FRAGMENT}" ]]; then + if grep -q '^All notable changes' CHANGELOG.md; then + sed -i "/^All notable changes/r ${FRAGMENT}" CHANGELOG.md + rm "${FRAGMENT}" + git add CHANGELOG.md "${FRAGMENT}" + git commit -m "docs: add ${TAG} changelog entry" + else + echo "WARNING: could not find anchor in CHANGELOG.md, skipping assembly" + fi + else + echo "No changelog fragment found for ${TAG}, skipping" + fi + + - name: Create and push tag + env: + TAG: ${{ steps.parse.outputs.tag }} + run: | + git tag -m "${TAG}" "${TAG}" + git push origin main "${TAG}" diff --git a/changelog/.gitkeep b/changelog/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/ci/release-finalize.sh b/ci/release-finalize.sh new file mode 100755 index 0000000..5d82074 --- /dev/null +++ b/ci/release-finalize.sh @@ -0,0 +1,110 @@ +#!/bin/bash + +set -euo pipefail + +: "${TAG:?TAG is required (e.g. python-v1.41.0)}" +: "${LANGUAGE:?LANGUAGE is required (java, nodejs, or python)}" +: "${VERSION:?VERSION is required (e.g. 1.41.0)}" + +README="${LANGUAGE}/README.md" + +gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ + --jq '.body' > /tmp/release_body.md + +python3 - "${README}" "${TAG}" "${VERSION}" /tmp/release_body.md <<'PYEOF' +import re +import sys + +readme_path = sys.argv[1] +tag = sys.argv[2] +version = sys.argv[3] +release_body_path = sys.argv[4] + +with open(release_body_path) as f: + body = f.read() + +def extract_table(text, heading_fragment): + lines = text.splitlines() + capture = False + table_lines = [] + for line in lines: + if heading_fragment.lower() in line.lower(): + capture = True + continue + if capture: + if line.startswith("##"): + break + if line.strip(): + table_lines.append(line) + return "\n".join(table_lines) + +amd64_table = extract_table(body, "AMD64 Lambda Layers List") +arm64_table = extract_table(body, "ARM64 Lambda Layers List") + +if not amd64_table: + print("ERROR: Could not extract AMD64 table from pre-release body", + file=sys.stderr) + sys.exit(1) +if not arm64_table: + print("ERROR: Could not extract ARM64 table from pre-release body", + file=sys.stderr) + sys.exit(1) + +with open(readme_path) as f: + content = f.read() + +if "unreleased version" not in content: + print(f"ERROR: 'unreleased version' not found in {readme_path}", + file=sys.stderr) + sys.exit(1) + +content = re.sub( + r"unreleased version", + f"v{version}", + content, + count=1, +) + +def replace_section(text, heading, new_table): + lines = text.splitlines() + result = [] + skip = False + found = False + for line in lines: + if line.strip().startswith("##") and heading.lower() in line.lower(): + found = True + result.append(line) + result.append("") + result.append(new_table) + result.append("") + skip = True + continue + if skip: + if line.strip().startswith("##"): + skip = False + result.append(line) + continue + result.append(line) + if not found: + print(f"ERROR: heading '{heading}' not found in {readme_path}", + file=sys.stderr) + sys.exit(1) + return "\n".join(result) + +content = replace_section(content, "AMD64 Lambda Layers List", amd64_table) +content = replace_section(content, "ARM64 Lambda Layers List", arm64_table) + +content = re.sub( + r"releases/download/[^/]+/", + f"releases/download/{tag}/", + content, +) + +if not content.endswith("\n"): + content += "\n" + +with open(readme_path, "w") as f: + f.write(content) + +print(f"Updated {readme_path} with ARN tables for {tag}") +PYEOF diff --git a/ci/release-prepare.sh b/ci/release-prepare.sh index 59514a8..4db4438 100755 --- a/ci/release-prepare.sh +++ b/ci/release-prepare.sh @@ -13,7 +13,8 @@ DATE="$(date +%Y-%m-%d)" LAYER_DATA="${LANGUAGE}/layer-data.sh" TEMPLATE="${LANGUAGE}/sample-apps/template.yaml" -TRACKING_FILE=".github/upstream-releases.json" +VERSION_FILE="${LANGUAGE}/version.txt" +TRACKING_FILE=".github/upstream-release-${LANGUAGE}.txt" cleanup() { find . -maxdepth 3 -name '*.bak' -delete; } trap cleanup EXIT @@ -24,10 +25,10 @@ if [[ -z "${OLD_VERSION_DASHED}" ]]; then exit 1 fi -# --- Update CHANGELOG.md --- - -cat > /tmp/changelog_block.md < "changelog/${TAG}.md" < /tmp/changelog_block.md <&2 - exit 1 -fi -sed -i.bak "/^All notable changes/r /tmp/changelog_block.md" CHANGELOG.md +# --- Update version.txt --- + +echo "${VERSION}" > "${VERSION_FILE}" + +# --- Update upstream tracking (per-language file, no conflicts) --- + +echo "${OTEL_LAMBDA_TAG}" > "${TRACKING_FILE}" # --- Update layer-data.sh --- @@ -125,11 +128,4 @@ case "${LANGUAGE}" in ;; esac -# --- Update upstream tracking file --- - -TMP_TRACKING=$(mktemp) -jq --arg lang "${LANGUAGE}" --arg tag "${OTEL_LAMBDA_TAG}" \ - '.[$lang] = $tag' "${TRACKING_FILE}" > "${TMP_TRACKING}" -mv "${TMP_TRACKING}" "${TRACKING_FILE}" - echo "Release preparation complete for ${TAG}" diff --git a/java/version.txt b/java/version.txt new file mode 100644 index 0000000..ef0f38a --- /dev/null +++ b/java/version.txt @@ -0,0 +1 @@ +2.19.0 diff --git a/nodejs/version.txt b/nodejs/version.txt new file mode 100644 index 0000000..e9307ca --- /dev/null +++ b/nodejs/version.txt @@ -0,0 +1 @@ +2.0.2 diff --git a/python/version.txt b/python/version.txt new file mode 100644 index 0000000..32b7211 --- /dev/null +++ b/python/version.txt @@ -0,0 +1 @@ +1.40.0 From 788e13dde9b43f5d2fdbf49d082a9574f2bed704 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 14:39:35 +0530 Subject: [PATCH 07/15] ci: improve prepare PR description with post-merge automation details Explains the full automated pipeline that runs after merge: tag creation, changelog assembly (fragment removed), release build, pre-release, release branch PR, and final promotion. --- .github/workflows/release-prepare.yml | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml index 1fbf07a..7e9f569 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -114,7 +114,8 @@ jobs: UPSTREAM_REPO="https://github.com/open-telemetry/opentelemetry-lambda" gh pr create \ --title "feat: prepare release ${LANGUAGE} v${VERSION}" \ - --body "Automated release preparation for \`${LANGUAGE}-v${VERSION}\`. + --body "$(cat < Date: Fri, 17 Jul 2026 14:45:48 +0530 Subject: [PATCH 08/15] ci: consolidate tracking into version.txt Remove separate .github/upstream-release-*.txt files. Each language's version.txt now contains both pieces of info: line 1: our version (e.g. 2.19.0) line 2: upstream tag it was built from (e.g. layer-javaagent/0.19.0) This is the only per-language file the cron needs to read. --- .github/upstream-release-java.txt | 1 - .github/upstream-release-nodejs.txt | 1 - .github/upstream-release-python.txt | 1 - .github/workflows/release-check-upstream.yml | 19 ++++++++++--------- .github/workflows/release-prepare.yml | 1 - ci/release-prepare.sh | 9 ++------- java/version.txt | 1 + nodejs/version.txt | 1 + python/version.txt | 1 + 9 files changed, 15 insertions(+), 20 deletions(-) delete mode 100644 .github/upstream-release-java.txt delete mode 100644 .github/upstream-release-nodejs.txt delete mode 100644 .github/upstream-release-python.txt diff --git a/.github/upstream-release-java.txt b/.github/upstream-release-java.txt deleted file mode 100644 index db81268..0000000 --- a/.github/upstream-release-java.txt +++ /dev/null @@ -1 +0,0 @@ -layer-javaagent/0.19.0 diff --git a/.github/upstream-release-nodejs.txt b/.github/upstream-release-nodejs.txt deleted file mode 100644 index 93cb677..0000000 --- a/.github/upstream-release-nodejs.txt +++ /dev/null @@ -1 +0,0 @@ -layer-nodejs/0.21.0 diff --git a/.github/upstream-release-python.txt b/.github/upstream-release-python.txt deleted file mode 100644 index 5841364..0000000 --- a/.github/upstream-release-python.txt +++ /dev/null @@ -1 +0,0 @@ -layer-python/0.19.0 diff --git a/.github/workflows/release-check-upstream.yml b/.github/workflows/release-check-upstream.yml index 60c0680..56156a6 100644 --- a/.github/workflows/release-check-upstream.yml +++ b/.github/workflows/release-check-upstream.yml @@ -99,9 +99,16 @@ jobs: fi echo "Latest upstream: ${LATEST_UPSTREAM}" - TRACKING_FILE=".github/upstream-release-${LANGUAGE}.txt" - LAST_PROCESSED=$(cat "${TRACKING_FILE}" | tr -d '[:space:]') - echo "Last processed: ${LAST_PROCESSED}" + VERSION_FILE="${LANGUAGE}/version.txt" + CURRENT_VER=$(sed -n '1p' "${VERSION_FILE}" | tr -d '[:space:]') + LAST_PROCESSED=$(sed -n '2p' "${VERSION_FILE}" | tr -d '[:space:]') + echo "Current version: ${CURRENT_VER}" + echo "Last processed upstream: ${LAST_PROCESSED}" + + if [[ -z "${CURRENT_VER}" || -z "${LAST_PROCESSED}" ]]; then + echo "ERROR: could not read version.txt for ${LANGUAGE}" + continue + fi if [[ "${LATEST_UPSTREAM}" == "${LAST_PROCESSED}" ]]; then echo "No new release for ${LANGUAGE}" @@ -126,12 +133,6 @@ jobs: continue fi - VERSION_FILE="${LANGUAGE}/version.txt" - CURRENT_VER=$(cat "${VERSION_FILE}" | tr -d '[:space:]') - if [[ -z "${CURRENT_VER}" ]]; then - echo "ERROR: could not read version from ${VERSION_FILE}" - continue - fi NEXT_VER=$(minor_bump "${CURRENT_VER}") echo "Version bump: ${CURRENT_VER} -> ${NEXT_VER}" diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml index 7e9f569..e800c93 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -84,7 +84,6 @@ jobs: - name: Commit changes run: | git add \ - ".github/upstream-release-${LANGUAGE}.txt" \ "changelog/${LANGUAGE}-v${VERSION}.md" \ "${LANGUAGE}/version.txt" \ README.md \ diff --git a/ci/release-prepare.sh b/ci/release-prepare.sh index 4db4438..b03c30c 100755 --- a/ci/release-prepare.sh +++ b/ci/release-prepare.sh @@ -14,7 +14,6 @@ DATE="$(date +%Y-%m-%d)" LAYER_DATA="${LANGUAGE}/layer-data.sh" TEMPLATE="${LANGUAGE}/sample-apps/template.yaml" VERSION_FILE="${LANGUAGE}/version.txt" -TRACKING_FILE=".github/upstream-release-${LANGUAGE}.txt" cleanup() { find . -maxdepth 3 -name '*.bak' -delete; } trap cleanup EXIT @@ -40,13 +39,9 @@ cat > "changelog/${TAG}.md" < "${VERSION_FILE}" - -# --- Update upstream tracking (per-language file, no conflicts) --- - -echo "${OTEL_LAMBDA_TAG}" > "${TRACKING_FILE}" +printf '%s\n%s\n' "${VERSION}" "${OTEL_LAMBDA_TAG}" > "${VERSION_FILE}" # --- Update layer-data.sh --- diff --git a/java/version.txt b/java/version.txt index ef0f38a..69077b2 100644 --- a/java/version.txt +++ b/java/version.txt @@ -1 +1,2 @@ 2.19.0 +layer-javaagent/0.19.0 diff --git a/nodejs/version.txt b/nodejs/version.txt index e9307ca..33768c3 100644 --- a/nodejs/version.txt +++ b/nodejs/version.txt @@ -1 +1,2 @@ 2.0.2 +layer-nodejs/0.21.0 diff --git a/python/version.txt b/python/version.txt index 32b7211..0ddbf39 100644 --- a/python/version.txt +++ b/python/version.txt @@ -1 +1,2 @@ 1.40.0 +layer-python/0.19.0 From 64be132485925b0ceadc5155c3680863741dcdfd Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 16:59:18 +0530 Subject: [PATCH 09/15] ci: harden automated release workflow Make release preparation conflict-aware and ensure post-merge builds, changelog assembly, finalization, and promotion run reliably. --- .github/workflows/release-build-java.yml | 57 ++++++++- .github/workflows/release-build-nodejs.yml | 57 ++++++++- .github/workflows/release-build-python.yml | 57 ++++++++- .github/workflows/release-check-upstream.yml | 34 +++--- .github/workflows/release-finalize.yml | 86 ++++++++++---- .github/workflows/release-prepare.yml | 80 ++++++++----- .github/workflows/release-publish.yml | 9 ++ .github/workflows/release-tag.yml | 66 ++++++++--- ci/release-finalize.sh | 15 ++- ci/release-prepare.sh | 5 +- docs/release.md | 117 ++++++++++++++----- java/version.txt | 4 +- nodejs/version.txt | 4 +- python/version.txt | 4 +- 14 files changed, 449 insertions(+), 146 deletions(-) diff --git a/.github/workflows/release-build-java.yml b/.github/workflows/release-build-java.yml index 90ad6d3..d99cb53 100644 --- a/.github/workflows/release-build-java.yml +++ b/.github/workflows/release-build-java.yml @@ -4,9 +4,29 @@ on: push: tags: - 'java-v[0-9]+.[0-9]+.[0-9]+' + workflow_dispatch: + +permissions: + actions: write + contents: write + id-token: write jobs: + validate-tag: + runs-on: ubuntu-22.04 + steps: + - name: Validate release tag + env: + TAG: ${{ github.ref_name }} + run: | + if [[ "${{ github.ref_type }}" != "tag" ]] || \ + ! [[ "${TAG}" =~ ^java-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::Run this workflow from a java-vX.Y.Z tag" + exit 1 + fi + build-release-artifacts: + needs: validate-tag uses: ./.github/workflows/build-artifacts.yml with: BUILD_COMMAND: make build-java @@ -27,9 +47,27 @@ jobs: name: Create Release runs-on: ubuntu-22.04 steps: - - name: Extract tag - id: extract_tag - run: echo "::set-output name=tag::$(echo ${GITHUB_REF#refs/tags/java-v})" + - uses: actions/checkout@v4 + with: + ref: ${{ github.ref_name }} + + - name: Extract release details + id: release + env: + TAG: ${{ github.ref_name }} + run: | + echo "version=${TAG#java-v}" >> "$GITHUB_OUTPUT" + python3 - "${TAG}" >> "$GITHUB_ENV" <<'PY' + import sys + + tag = sys.argv[1] + lines = open("CHANGELOG.md").read().splitlines() + start = next(i for i, line in enumerate(lines) if line == f"## [{tag}]") + end = next((i for i in range(start + 1, len(lines)) if lines[i].startswith("## [")), len(lines)) + print("RELEASE_CHANGELOG<> "$GITHUB_OUTPUT" + python3 - "${TAG}" >> "$GITHUB_ENV" <<'PY' + import sys + + tag = sys.argv[1] + lines = open("CHANGELOG.md").read().splitlines() + start = next(i for i, line in enumerate(lines) if line == f"## [{tag}]") + end = next((i for i in range(start + 1, len(lines)) if lines[i].startswith("## [")), len(lines)) + print("RELEASE_CHANGELOG<> "$GITHUB_OUTPUT" + python3 - "${TAG}" >> "$GITHUB_ENV" <<'PY' + import sys + + tag = sys.argv[1] + lines = open("CHANGELOG.md").read().splitlines() + start = next(i for i, line in enumerate(lines) if line == f"## [{tag}]") + end = next((i for i in range(start + 1, len(lines)) if lines[i].startswith("## [")), len(lines)) + print("RELEASE_CHANGELOG<- - github.event.workflow_run.conclusion == 'success' runs-on: ubuntu-22.04 steps: - - name: Extract tag and language + - name: Extract release details id: parse + env: + TAG: ${{ inputs.tag }} run: | - TAG="${{ github.event.workflow_run.head_branch }}" - LANGUAGE="${TAG%%-v*}" - VERSION="${TAG#"${LANGUAGE}"-v}" - RELEASE_BRANCH="release-${TAG}" + if ! [[ "${TAG}" =~ ^(java|nodejs|python)-v([0-9]+\.[0-9]+\.[0-9]+)$ ]]; then + echo "::error::Unexpected release tag: ${TAG}" + exit 1 + fi + + LANGUAGE="${BASH_REMATCH[1]}" + VERSION="${BASH_REMATCH[2]}" echo "tag=${TAG}" >> "$GITHUB_OUTPUT" echo "language=${LANGUAGE}" >> "$GITHUB_OUTPUT" echo "version=${VERSION}" >> "$GITHUB_OUTPUT" - echo "release_branch=${RELEASE_BRANCH}" \ - >> "$GITHUB_OUTPUT" + echo "release_branch=release-${TAG}" >> "$GITHUB_OUTPUT" + + - name: Check for existing release pull request + id: existing + env: + GH_TOKEN: ${{ github.token }} + RELEASE_BRANCH: ${{ steps.parse.outputs.release_branch }} + run: | + PR_URL=$(gh pr list \ + --repo "${GITHUB_REPOSITORY}" \ + --state all \ + --base main \ + --head "${RELEASE_BRANCH}" \ + --json url \ + --jq '.[0].url // empty') + if [[ -n "${PR_URL}" ]]; then + echo "Release pull request already exists or was completed: ${PR_URL}" + echo "skip=true" >> "$GITHUB_OUTPUT" + else + echo "skip=false" >> "$GITHUB_OUTPUT" + fi - uses: actions/checkout@v4 + if: steps.existing.outputs.skip != 'true' with: ref: main fetch-depth: 0 - name: Configure git + if: steps.existing.outputs.skip != 'true' run: | git config user.name "github-actions[bot]" git config user.email \ "github-actions[bot]@users.noreply.github.com" - name: Create release branch + if: steps.existing.outputs.skip != 'true' + env: + RELEASE_BRANCH: ${{ steps.parse.outputs.release_branch }} run: | - git checkout -b \ - "${{ steps.parse.outputs.release_branch }}" + if git ls-remote --exit-code --heads origin "${RELEASE_BRANCH}"; then + echo "::error::Branch ${RELEASE_BRANCH} exists without an open PR" + exit 1 + fi + git checkout -b "${RELEASE_BRANCH}" - name: Update README with ARN tables + if: steps.existing.outputs.skip != 'true' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} TAG: ${{ steps.parse.outputs.tag }} @@ -56,8 +91,10 @@ jobs: run: ./ci/release-finalize.sh - uses: actions/setup-node@v4 + if: steps.existing.outputs.skip != 'true' - name: Format markdown tables + if: steps.existing.outputs.skip != 'true' env: LANGUAGE: ${{ steps.parse.outputs.language }} run: | @@ -65,25 +102,24 @@ jobs: ./node_modules/.bin/markdown-table-formatter \ "${LANGUAGE}/README.md" - - name: Commit changes + - name: Commit and push release branch + if: steps.existing.outputs.skip != 'true' env: TAG: ${{ steps.parse.outputs.tag }} LANGUAGE: ${{ steps.parse.outputs.language }} + RELEASE_BRANCH: ${{ steps.parse.outputs.release_branch }} run: | git add "${LANGUAGE}/README.md" - git commit -m \ - "docs: update ${LANGUAGE} layer ARNs for ${TAG}" - - - name: Push release branch - run: git push origin "${{ steps.parse.outputs.release_branch }}" + git commit -m "docs: update ${LANGUAGE} layer ARNs for ${TAG}" + git push origin "${RELEASE_BRANCH}" - name: Create pull request + if: steps.existing.outputs.skip != 'true' env: GH_TOKEN: ${{ github.token }} TAG: ${{ steps.parse.outputs.tag }} LANGUAGE: ${{ steps.parse.outputs.language }} - RELEASE_BRANCH: >- - ${{ steps.parse.outputs.release_branch }} + RELEASE_BRANCH: ${{ steps.parse.outputs.release_branch }} run: | REPO="${GITHUB_REPOSITORY}" BODY="Updates \`${LANGUAGE}/README.md\` with layer ARNs " diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml index e800c93..892a8c3 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -27,6 +27,10 @@ permissions: contents: write pull-requests: write +concurrency: + group: release-prepare-${{ inputs.language }} + cancel-in-progress: false + jobs: prepare: runs-on: ubuntu-22.04 @@ -36,18 +40,42 @@ jobs: OTEL_LAMBDA_TAG: ${{ inputs.otel_lambda_tag }} BRANCH: prepare-${{ inputs.language }}-v${{ inputs.version }} steps: - - name: Validate version format + - name: Validate inputs run: | - if ! [[ "${{ inputs.version }}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + if ! [[ "${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 + case "${LANGUAGE}" in + java) EXPECTED_PREFIX="layer-javaagent/" ;; + nodejs) EXPECTED_PREFIX="layer-nodejs/" ;; + python) EXPECTED_PREFIX="layer-python/" ;; + *) + echo "::error::Unsupported language: ${LANGUAGE}" + exit 1 + ;; + esac + + if [[ "${OTEL_LAMBDA_TAG}" != "${EXPECTED_PREFIX}"* ]]; then + echo "::error::${LANGUAGE} requires an upstream tag starting with ${EXPECTED_PREFIX}" + exit 1 + fi + - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: true + - name: Verify upstream release tag exists + run: | + if ! git ls-remote --exit-code --tags \ + https://github.com/open-telemetry/opentelemetry-lambda.git \ + "refs/tags/${OTEL_LAMBDA_TAG}" >/dev/null; then + echo "::error::Upstream tag ${OTEL_LAMBDA_TAG} does not exist" + exit 1 + fi + - name: Check release tag and branch do not already exist run: | TAG="${LANGUAGE}-v${VERSION}" @@ -69,15 +97,6 @@ jobs: - name: Create branch run: git checkout -b "${BRANCH}" - - name: Update submodule to otel-lambda release - id: submodule - run: | - cd opentelemetry-lambda - git fetch --tags origin - git checkout "${{ inputs.otel_lambda_tag }}" - echo "commit=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" - cd .. - - name: Run prepare script run: ./ci/release-prepare.sh @@ -86,10 +105,9 @@ jobs: git add \ "changelog/${LANGUAGE}-v${VERSION}.md" \ "${LANGUAGE}/version.txt" \ - README.md \ "${LANGUAGE}/layer-data.sh" \ "${LANGUAGE}/sample-apps/template.yaml" \ - opentelemetry-lambda + README.md COMMIT_MSG="feat: prepare release ${LANGUAGE} v${VERSION}" git commit -m "${COMMIT_MSG}" @@ -109,34 +127,42 @@ jobs: env: GH_TOKEN: ${{ github.token }} run: | - SUBMODULE_COMMIT="${{ steps.submodule.outputs.commit }}" UPSTREAM_REPO="https://github.com/open-telemetry/opentelemetry-lambda" gh pr create \ --title "feat: prepare release ${LANGUAGE} v${VERSION}" \ --body "$(cat <> "$GITHUB_OUTPUT" + echo "language=${LANGUAGE}" >> "$GITHUB_OUTPUT" - uses: actions/checkout@v4 with: @@ -41,27 +54,50 @@ jobs: git config user.email \ "github-actions[bot]@users.noreply.github.com" + - name: Check release state + id: state + env: + TAG: ${{ steps.parse.outputs.tag }} + run: | + if git rev-parse "refs/tags/${TAG}" >/dev/null 2>&1; then + echo "Tag ${TAG} already exists; skipping changelog assembly" + echo "tag_exists=true" >> "$GITHUB_OUTPUT" + else + echo "tag_exists=false" >> "$GITHUB_OUTPUT" + fi + - name: Assemble changelog fragment + if: steps.state.outputs.tag_exists != 'true' env: TAG: ${{ steps.parse.outputs.tag }} run: | FRAGMENT="changelog/${TAG}.md" - if [[ -f "${FRAGMENT}" ]]; then - if grep -q '^All notable changes' CHANGELOG.md; then - sed -i "/^All notable changes/r ${FRAGMENT}" CHANGELOG.md - rm "${FRAGMENT}" - git add CHANGELOG.md "${FRAGMENT}" - git commit -m "docs: add ${TAG} changelog entry" - else - echo "WARNING: could not find anchor in CHANGELOG.md, skipping assembly" - fi - else - echo "No changelog fragment found for ${TAG}, skipping" + if [[ ! -f "${FRAGMENT}" ]]; then + echo "::error::Missing changelog fragment ${FRAGMENT}" + exit 1 fi + if ! grep -q '^All notable changes' CHANGELOG.md; then + echo "::error::Could not find changelog insertion anchor" + exit 1 + fi + + sed -i "/^All notable changes/r ${FRAGMENT}" CHANGELOG.md + rm "${FRAGMENT}" - - name: Create and push tag + - name: Commit changelog and create tag + if: steps.state.outputs.tag_exists != 'true' env: TAG: ${{ steps.parse.outputs.tag }} run: | + git add CHANGELOG.md "changelog/${TAG}.md" + git commit -m "release: ${TAG}" git tag -m "${TAG}" "${TAG}" - git push origin main "${TAG}" + git push --atomic origin main "${TAG}" + + - name: Dispatch release build + env: + GH_TOKEN: ${{ github.token }} + LANGUAGE: ${{ steps.parse.outputs.language }} + TAG: ${{ steps.parse.outputs.tag }} + run: | + gh workflow run "release-build-${LANGUAGE}.yml" --ref "${TAG}" diff --git a/ci/release-finalize.sh b/ci/release-finalize.sh index 5d82074..1e1af73 100755 --- a/ci/release-finalize.sh +++ b/ci/release-finalize.sh @@ -53,17 +53,16 @@ if not arm64_table: with open(readme_path) as f: content = f.read() -if "unreleased version" not in content: - print(f"ERROR: 'unreleased version' not found in {readme_path}", +title_pattern = re.compile( + r"^(# .*?)(?:unreleased version|v\d+\.\d+\.\d+)(.*)$", + re.MULTILINE, +) +if not title_pattern.search(content): + print(f"ERROR: release version not found in title of {readme_path}", file=sys.stderr) sys.exit(1) -content = re.sub( - r"unreleased version", - f"v{version}", - content, - count=1, -) +content = title_pattern.sub(rf"\g<1>v{version}\g<2>", content, count=1) def replace_section(text, heading, new_table): lines = text.splitlines() diff --git a/ci/release-prepare.sh b/ci/release-prepare.sh index b03c30c..e3d1837 100755 --- a/ci/release-prepare.sh +++ b/ci/release-prepare.sh @@ -39,9 +39,10 @@ cat > "changelog/${TAG}.md" < "${VERSION_FILE}" +printf 'current_version=%s\nupstream_release_tag=%s\n' \ + "${VERSION}" "${OTEL_LAMBDA_TAG}" > "${VERSION_FILE}" # --- Update layer-data.sh --- diff --git a/docs/release.md b/docs/release.md index 0ba3c8d..a8e7924 100644 --- a/docs/release.md +++ b/docs/release.md @@ -1,46 +1,99 @@ # Releasing guide -Perform the following steps in order to release new versions: +Release preparation and publication are automated with GitHub Actions. Java, +NodeJS, and Python preparation pull requests may be open at the same time. -1. Prepare and merge PR with following changes: +## Release metadata - - update [changelog](../CHANGELOG.md) - - in [README.md](../README.md) update version of the latest lambda layers - - update `/layer-data.sh` - - update `/sample-apps/template.yaml` +Each language has a `/version.txt` file with named values: -1. Create and push new tag: +```text +current_version=1.41.0 +upstream_release_tag=layer-python/0.20.0 +``` - Pushing new tag will trigger job which will create a pre-release draft. +- `current_version` is the latest Sumo Logic release for that language. +- `upstream_release_tag` is the upstream OpenTelemetry Lambda release detected + for that language. - ```bash - export LANGUAGE= # Possible values: java, nodejs, or python - export TAG=${LANGUAGE}-vx.y.z - git checkout main - git pull - git tag -m "${TAG}" "${TAG}" - git push origin "${TAG}" - ``` +The upstream tag prefixes are: -1. Prepare release branch +- Java: `layer-javaagent/` +- NodeJS: `layer-nodejs/` +- Python: `layer-python/` - - branch out: +Submodule pinning is not part of this automation yet. The selected upstream tag +is recorded as release metadata, but the prepare workflow does not change the +`opentelemetry-lambda` gitlink. - ```bash - git checkout -b "release-${TAG}" - ``` +## Prepare a release - - in specific language README.md (e.g. python/README.md) - - set a version as `x.y.z` (`unreleased version` in title) - - update Layer ARNs tables (look at pre-release draft) - - update Container Layer links with dependencies (look at pre-release draft) - - in [README.md](../README.md) update version of the latest lambda layers - - push branch: +The `Check Upstream Releases` workflow runs weekly and can also be dispatched +manually. It compares the latest language-specific upstream tag with +`upstream_release_tag` and dispatches `Release Prepare` when it finds a newer +release. - ```bash - git push -u origin "release-${TAG}" - ``` +`Release Prepare` can also be dispatched directly with: -1. Create [new release][releases] based on generated pre-release draft. +- `language`: `java`, `nodejs`, or `python` +- `version`: the next release version without a `v` prefix +- `otel_lambda_tag`: the matching language-specific upstream tag -[releases]: https://github.com/SumoLogic/sumologic-otel-lambda/releases +The workflow opens `prepare--v` with these changes: + +- `changelog/-v.md` +- `/version.txt` +- `/layer-data.sh` +- `/sample-apps/template.yaml` +- root `README.md` + +The changelog fragment prevents concurrent release preparations from editing +`CHANGELOG.md`. Before merging the pull request: + +1. Replace the fragment's TODO with the release changes. +2. Verify the named values in `/version.txt`. +3. Verify the layer version in `/layer-data.sh`. +4. Verify the layer version in `/sample-apps/template.yaml`. +5. Verify the root README release link and component versions. +6. Resolve any normal pull-request conflict, including a shared root README + conflict caused by another release merged on the same day. + +Only one open prepare pull request is allowed per language. An open Java +prepare pull request does not block NodeJS or Python preparation. + +## Automatic post-merge flow + +Merging a prepare pull request triggers the following sequence: + +1. `Release Tag` serializes changes to `main` across all languages. +2. It inserts `changelog/-v.md` at the top of + `CHANGELOG.md` and deletes the fragment. +3. It commits the assembled changelog and creates + `-v` at that commit. +4. It explicitly dispatches the matching language build workflow at the tag. + The dispatch-capable build workflows must already be present on `main` before + the first automated release is merged. +5. The build workflow creates artifacts, publishes Lambda layers, and creates + a GitHub pre-release containing the reviewed changelog and layer ARN tables. +6. A successful build opens `release--v`, updating the + language README with the published ARN tables and release download links. +7. Merging that release pull request promotes the pre-release to a full, + latest GitHub release. + +Finalization is idempotent: rerunning a successful release build does not open +a duplicate release pull request, and promoting an already published release +succeeds without changing it again. + +## Recovery + +- If preparation fails, correct the input or workflow issue and dispatch + `Release Prepare` again. +- If changelog assembly fails, restore or correct the expected fragment or the + `All notable changes` anchor before rerunning the merge-triggered workflow. +- If a tag exists but its build did not start, dispatch the matching + `release-build-.yml` workflow using the release tag as its ref. +- If ARN finalization fails, dispatch `release-finalize.yml` with the release + tag after correcting the failure. + +Do not manually publish the GitHub pre-release before the generated release +pull request has merged. diff --git a/java/version.txt b/java/version.txt index 69077b2..6939b30 100644 --- a/java/version.txt +++ b/java/version.txt @@ -1,2 +1,2 @@ -2.19.0 -layer-javaagent/0.19.0 +current_version=2.19.0 +upstream_release_tag=layer-javaagent/0.19.0 diff --git a/nodejs/version.txt b/nodejs/version.txt index 33768c3..15162ab 100644 --- a/nodejs/version.txt +++ b/nodejs/version.txt @@ -1,2 +1,2 @@ -2.0.2 -layer-nodejs/0.21.0 +current_version=2.0.2 +upstream_release_tag=layer-nodejs/0.21.0 diff --git a/python/version.txt b/python/version.txt index 0ddbf39..1ec435c 100644 --- a/python/version.txt +++ b/python/version.txt @@ -1,2 +1,2 @@ -1.40.0 -layer-python/0.19.0 +current_version=1.40.0 +upstream_release_tag=layer-python/0.19.0 From bdf666008a15add17c9bf6ebeef711a1814d98d7 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 18:01:21 +0530 Subject: [PATCH 10/15] ci: simplify release finalization Keep the established language build workflows unchanged while making release branches title-only review artifacts and leaving final promotion as a manual step. --- .github/workflows/release-build-java.yml | 57 ++------------ .github/workflows/release-build-nodejs.yml | 57 ++------------ .github/workflows/release-build-python.yml | 57 ++------------ .github/workflows/release-finalize.yml | 78 +++---------------- .github/workflows/release-prepare.yml | 6 +- .github/workflows/release-publish.yml | 50 ------------ ci/release-finalize.sh | 89 +++------------------- docs/release.md | 35 +++++---- 8 files changed, 63 insertions(+), 366 deletions(-) delete mode 100644 .github/workflows/release-publish.yml diff --git a/.github/workflows/release-build-java.yml b/.github/workflows/release-build-java.yml index d99cb53..90ad6d3 100644 --- a/.github/workflows/release-build-java.yml +++ b/.github/workflows/release-build-java.yml @@ -4,29 +4,9 @@ on: push: tags: - 'java-v[0-9]+.[0-9]+.[0-9]+' - workflow_dispatch: - -permissions: - actions: write - contents: write - id-token: write jobs: - validate-tag: - runs-on: ubuntu-22.04 - steps: - - name: Validate release tag - env: - TAG: ${{ github.ref_name }} - run: | - if [[ "${{ github.ref_type }}" != "tag" ]] || \ - ! [[ "${TAG}" =~ ^java-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then - echo "::error::Run this workflow from a java-vX.Y.Z tag" - exit 1 - fi - build-release-artifacts: - needs: validate-tag uses: ./.github/workflows/build-artifacts.yml with: BUILD_COMMAND: make build-java @@ -47,27 +27,9 @@ jobs: name: Create Release runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v4 - with: - ref: ${{ github.ref_name }} - - - name: Extract release details - id: release - env: - TAG: ${{ github.ref_name }} - run: | - echo "version=${TAG#java-v}" >> "$GITHUB_OUTPUT" - python3 - "${TAG}" >> "$GITHUB_ENV" <<'PY' - import sys - - tag = sys.argv[1] - lines = open("CHANGELOG.md").read().splitlines() - start = next(i for i, line in enumerate(lines) if line == f"## [{tag}]") - end = next((i for i in range(start + 1, len(lines)) if lines[i].startswith("## [")), len(lines)) - print("RELEASE_CHANGELOG<> "$GITHUB_OUTPUT" - python3 - "${TAG}" >> "$GITHUB_ENV" <<'PY' - import sys - - tag = sys.argv[1] - lines = open("CHANGELOG.md").read().splitlines() - start = next(i for i, line in enumerate(lines) if line == f"## [{tag}]") - end = next((i for i in range(start + 1, len(lines)) if lines[i].startswith("## [")), len(lines)) - print("RELEASE_CHANGELOG<> "$GITHUB_OUTPUT" - python3 - "${TAG}" >> "$GITHUB_ENV" <<'PY' - import sys - - tag = sys.argv[1] - lines = open("CHANGELOG.md").read().splitlines() - start = next(i for i, line in enumerate(lines) if line == f"## [{tag}]") - end = next((i for i in range(start + 1, len(lines)) if lines[i].startswith("## [")), len(lines)) - print("RELEASE_CHANGELOG<> "$GITHUB_OUTPUT" echo "release_branch=release-${TAG}" >> "$GITHUB_OUTPUT" - - name: Check for existing release pull request - id: existing - env: - GH_TOKEN: ${{ github.token }} - RELEASE_BRANCH: ${{ steps.parse.outputs.release_branch }} - run: | - PR_URL=$(gh pr list \ - --repo "${GITHUB_REPOSITORY}" \ - --state all \ - --base main \ - --head "${RELEASE_BRANCH}" \ - --json url \ - --jq '.[0].url // empty') - if [[ -n "${PR_URL}" ]]; then - echo "Release pull request already exists or was completed: ${PR_URL}" - echo "skip=true" >> "$GITHUB_OUTPUT" - else - echo "skip=false" >> "$GITHUB_OUTPUT" - fi - - uses: actions/checkout@v4 - if: steps.existing.outputs.skip != 'true' with: ref: main fetch-depth: 0 - name: Configure git - if: steps.existing.outputs.skip != 'true' run: | git config user.name "github-actions[bot]" git config user.email \ "github-actions[bot]@users.noreply.github.com" - name: Create release branch - if: steps.existing.outputs.skip != 'true' + id: branch env: RELEASE_BRANCH: ${{ steps.parse.outputs.release_branch }} run: | if git ls-remote --exit-code --heads origin "${RELEASE_BRANCH}"; then - echo "::error::Branch ${RELEASE_BRANCH} exists without an open PR" - exit 1 + echo "Release branch ${RELEASE_BRANCH} already exists" + echo "exists=true" >> "$GITHUB_OUTPUT" + else + git checkout -b "${RELEASE_BRANCH}" + echo "exists=false" >> "$GITHUB_OUTPUT" fi - git checkout -b "${RELEASE_BRANCH}" - - name: Update README with ARN tables - if: steps.existing.outputs.skip != 'true' + - name: Update language README title + if: steps.branch.outputs.exists != 'true' 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 - if: steps.existing.outputs.skip != 'true' - - - name: Format markdown tables - if: steps.existing.outputs.skip != 'true' - 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 and push release branch - if: steps.existing.outputs.skip != 'true' + - name: Push release branch + if: steps.branch.outputs.exists != 'true' env: TAG: ${{ steps.parse.outputs.tag }} LANGUAGE: ${{ steps.parse.outputs.language }} RELEASE_BRANCH: ${{ steps.parse.outputs.release_branch }} run: | git add "${LANGUAGE}/README.md" - git commit -m "docs: update ${LANGUAGE} layer ARNs for ${TAG}" + git commit -m "docs: update ${LANGUAGE} README for ${TAG}" git push origin "${RELEASE_BRANCH}" - - - name: Create pull request - if: steps.existing.outputs.skip != 'true' - env: - GH_TOKEN: ${{ github.token }} - 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 index 892a8c3..7fbf1e0 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -160,9 +160,9 @@ jobs: 2. **Tag created** — \`${LANGUAGE}-v${VERSION}\` is created from the assembled changelog commit 3. **Release build dispatched** — the matching language workflow runs at the release tag 4. **Layers published** — layer artifacts are built and published to supported AWS regions - 5. **Pre-release created** — GitHub receives the reviewed changelog, ARN tables, and artifacts - 6. **Release PR created** — \`release-${LANGUAGE}-v${VERSION}\` updates \`${LANGUAGE}/README.md\` with published ARNs - 7. **Release promoted** — merging that release PR converts the pre-release to a full release + 5. **Pre-release created** — GitHub receives generated release notes, ARN tables, and artifacts + 6. **Release branch pushed** — \`release-${LANGUAGE}-v${VERSION}\` updates the version in the title of \`${LANGUAGE}/README.md\`; no PR is opened + 7. **Manual promotion** — after reviewing the pre-release and release branch, promote the pre-release from the GitHub Releases page BODY )" \ --base main \ diff --git a/.github/workflows/release-publish.yml b/.github/workflows/release-publish.yml deleted file mode 100644 index fac50ef..0000000 --- a/.github/workflows/release-publish.yml +++ /dev/null @@ -1,50 +0,0 @@ -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: | - IS_PRERELEASE=$(gh release view "${TAG}" \ - --repo "${{ github.repository }}" \ - --json isPrerelease \ - --jq '.isPrerelease') - if [[ "${IS_PRERELEASE}" == "false" ]]; then - echo "Release ${TAG} is already published" - exit 0 - fi - - gh release edit "${TAG}" \ - --repo "${{ github.repository }}" \ - --prerelease=false \ - --latest diff --git a/ci/release-finalize.sh b/ci/release-finalize.sh index 1e1af73..74e5df7 100755 --- a/ci/release-finalize.sh +++ b/ci/release-finalize.sh @@ -2,53 +2,26 @@ set -euo pipefail -: "${TAG:?TAG is required (e.g. python-v1.41.0)}" : "${LANGUAGE:?LANGUAGE is required (java, nodejs, or python)}" : "${VERSION:?VERSION is required (e.g. 1.41.0)}" -README="${LANGUAGE}/README.md" +if [[ ! "${LANGUAGE}" =~ ^(java|nodejs|python)$ ]]; then + echo "ERROR: Unsupported language: ${LANGUAGE}" >&2 + exit 1 +fi +if [[ ! "${VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "ERROR: Invalid version: ${VERSION}" >&2 + exit 1 +fi -gh api "repos/${GITHUB_REPOSITORY}/releases/tags/${TAG}" \ - --jq '.body' > /tmp/release_body.md +README="${LANGUAGE}/README.md" -python3 - "${README}" "${TAG}" "${VERSION}" /tmp/release_body.md <<'PYEOF' +python3 - "${README}" "${VERSION}" <<'PYEOF' import re import sys readme_path = sys.argv[1] -tag = sys.argv[2] -version = sys.argv[3] -release_body_path = sys.argv[4] - -with open(release_body_path) as f: - body = f.read() - -def extract_table(text, heading_fragment): - lines = text.splitlines() - capture = False - table_lines = [] - for line in lines: - if heading_fragment.lower() in line.lower(): - capture = True - continue - if capture: - if line.startswith("##"): - break - if line.strip(): - table_lines.append(line) - return "\n".join(table_lines) - -amd64_table = extract_table(body, "AMD64 Lambda Layers List") -arm64_table = extract_table(body, "ARM64 Lambda Layers List") - -if not amd64_table: - print("ERROR: Could not extract AMD64 table from pre-release body", - file=sys.stderr) - sys.exit(1) -if not arm64_table: - print("ERROR: Could not extract ARM64 table from pre-release body", - file=sys.stderr) - sys.exit(1) +version = sys.argv[2] with open(readme_path) as f: content = f.read() @@ -64,46 +37,8 @@ if not title_pattern.search(content): content = title_pattern.sub(rf"\g<1>v{version}\g<2>", content, count=1) -def replace_section(text, heading, new_table): - lines = text.splitlines() - result = [] - skip = False - found = False - for line in lines: - if line.strip().startswith("##") and heading.lower() in line.lower(): - found = True - result.append(line) - result.append("") - result.append(new_table) - result.append("") - skip = True - continue - if skip: - if line.strip().startswith("##"): - skip = False - result.append(line) - continue - result.append(line) - if not found: - print(f"ERROR: heading '{heading}' not found in {readme_path}", - file=sys.stderr) - sys.exit(1) - return "\n".join(result) - -content = replace_section(content, "AMD64 Lambda Layers List", amd64_table) -content = replace_section(content, "ARM64 Lambda Layers List", arm64_table) - -content = re.sub( - r"releases/download/[^/]+/", - f"releases/download/{tag}/", - content, -) - -if not content.endswith("\n"): - content += "\n" - with open(readme_path, "w") as f: f.write(content) -print(f"Updated {readme_path} with ARN tables for {tag}") +print(f"Updated {readme_path} title to v{version}") PYEOF diff --git a/docs/release.md b/docs/release.md index a8e7924..9ce2b87 100644 --- a/docs/release.md +++ b/docs/release.md @@ -73,16 +73,23 @@ Merging a prepare pull request triggers the following sequence: 4. It explicitly dispatches the matching language build workflow at the tag. The dispatch-capable build workflows must already be present on `main` before the first automated release is merged. -5. The build workflow creates artifacts, publishes Lambda layers, and creates - a GitHub pre-release containing the reviewed changelog and layer ARN tables. -6. A successful build opens `release--v`, updating the - language README with the published ARN tables and release download links. -7. Merging that release pull request promotes the pre-release to a full, - latest GitHub release. - -Finalization is idempotent: rerunning a successful release build does not open -a duplicate release pull request, and promoting an already published release -succeeds without changing it again. +5. The build workflow identifies the previous tag for the same language and + asks GitHub to generate release notes for that tag range. It creates + artifacts, publishes Lambda layers, and creates a GitHub pre-release with + those generated notes and the layer ARN tables. The reviewed changelog + fragment remains the source for the repository `CHANGELOG.md`. +6. A successful build creates and pushes `release--v`. + That branch updates the language README title from `unreleased version` (or + its previous version) to the new version. No pull request is opened for this + branch. +7. Review the pre-release and the pushed release branch. The GitHub release + remains a pre-release. +8. When ready to publish, open the pre-release on the GitHub Releases page, + edit it, clear the pre-release setting, mark it as the latest release, and + publish it. + +Finalization is idempotent: rerunning it does not recreate an existing release +branch. Final promotion is a manual GitHub UI step. ## Recovery @@ -92,8 +99,8 @@ succeeds without changing it again. `All notable changes` anchor before rerunning the merge-triggered workflow. - If a tag exists but its build did not start, dispatch the matching `release-build-.yml` workflow using the release tag as its ref. -- If ARN finalization fails, dispatch `release-finalize.yml` with the release - tag after correcting the failure. +- If release-branch finalization fails, dispatch `release-finalize.yml` with + the release tag after correcting the failure. -Do not manually publish the GitHub pre-release before the generated release -pull request has merged. +Do not promote the pre-release before the pre-release contents and generated +release branch have been reviewed. From 95c042f62e3d66c417a8bdf73552a9bf854f5e90 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 18:21:05 +0530 Subject: [PATCH 11/15] ci: update prep release behavior --- .github/workflows/release-prepare.yml | 11 ++++---- .github/workflows/release-tag.yml | 9 ------ ci/release-prepare.sh | 28 +++++++++++++++++++ docs/release.md | 40 ++++++++++----------------- 4 files changed, 49 insertions(+), 39 deletions(-) diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml index 7fbf1e0..8584948 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -107,6 +107,7 @@ jobs: "${LANGUAGE}/version.txt" \ "${LANGUAGE}/layer-data.sh" \ "${LANGUAGE}/sample-apps/template.yaml" \ + "${LANGUAGE}/README.md" \ README.md COMMIT_MSG="feat: prepare release ${LANGUAGE} v${VERSION}" git commit -m "${COMMIT_MSG}" @@ -143,6 +144,7 @@ jobs: - \`${LANGUAGE}/version.txt\` — records the current release version and upstream release tag - \`${LANGUAGE}/layer-data.sh\` — updates the layer version and release branch link - \`${LANGUAGE}/sample-apps/template.yaml\` — updates the sample layer version + - \`${LANGUAGE}/README.md\` — updates the release version in the title - \`README.md\` — updates the latest layer link and detected component versions - \`changelog/${LANGUAGE}-v${VERSION}.md\` — adds the release changelog fragment @@ -151,6 +153,7 @@ jobs: - [ ] Replace the TODO in \`changelog/${LANGUAGE}-v${VERSION}.md\` with the release changes - [ ] Verify \`${LANGUAGE}/version.txt\` metadata - [ ] Verify \`${LANGUAGE}/layer-data.sh\` and \`${LANGUAGE}/sample-apps/template.yaml\` + - [ ] Verify the version in the title of \`${LANGUAGE}/README.md\` - [ ] Verify \`README.md\` component versions and release link - [ ] Approve this PR @@ -158,11 +161,9 @@ jobs: 1. **Changelog assembled** — the fragment is inserted into \`CHANGELOG.md\` and deleted 2. **Tag created** — \`${LANGUAGE}-v${VERSION}\` is created from the assembled changelog commit - 3. **Release build dispatched** — the matching language workflow runs at the release tag - 4. **Layers published** — layer artifacts are built and published to supported AWS regions - 5. **Pre-release created** — GitHub receives generated release notes, ARN tables, and artifacts - 6. **Release branch pushed** — \`release-${LANGUAGE}-v${VERSION}\` updates the version in the title of \`${LANGUAGE}/README.md\`; no PR is opened - 7. **Manual promotion** — after reviewing the pre-release and release branch, promote the pre-release from the GitHub Releases page + 3. **Release tag pushed** — the tag is pushed after changelog assembly + 4. **Build remains separate** — the unchanged release-build workflow is tag-push-only and is not automatically started by the GitHub token used here + 5. **Manual promotion** — after the existing release build creates the pre-release, review and promote it from the GitHub Releases page BODY )" \ --base main \ diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index 526a187..ef59e71 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -6,7 +6,6 @@ on: branches: [main] permissions: - actions: write contents: write pull-requests: read @@ -93,11 +92,3 @@ jobs: git commit -m "release: ${TAG}" git tag -m "${TAG}" "${TAG}" git push --atomic origin main "${TAG}" - - - name: Dispatch release build - env: - GH_TOKEN: ${{ github.token }} - LANGUAGE: ${{ steps.parse.outputs.language }} - TAG: ${{ steps.parse.outputs.tag }} - run: | - gh workflow run "release-build-${LANGUAGE}.yml" --ref "${TAG}" diff --git a/ci/release-prepare.sh b/ci/release-prepare.sh index e3d1837..0dca927 100755 --- a/ci/release-prepare.sh +++ b/ci/release-prepare.sh @@ -14,6 +14,7 @@ DATE="$(date +%Y-%m-%d)" LAYER_DATA="${LANGUAGE}/layer-data.sh" TEMPLATE="${LANGUAGE}/sample-apps/template.yaml" VERSION_FILE="${LANGUAGE}/version.txt" +LANGUAGE_README="${LANGUAGE}/README.md" cleanup() { find . -maxdepth 3 -name '*.bak' -delete; } trap cleanup EXIT @@ -102,6 +103,33 @@ case "${LANGUAGE}" in ;; esac +# --- Update language README.md --- + +python3 - "${LANGUAGE_README}" "${VERSION}" <<'PYEOF' +import re +import sys + +readme_path = sys.argv[1] +version = sys.argv[2] + +with open(readme_path) as f: + content = f.read() + +pattern = re.compile( + r"^(# .*?)(?:unreleased version|v\d+\.\d+\.\d+)(.*)$", + re.MULTILINE, +) +if not pattern.search(content): + print(f"ERROR: release version not found in title of {readme_path}", + file=sys.stderr) + sys.exit(1) + +content = pattern.sub(rf"\g<1>v{version}\g<2>", content, count=1) + +with open(readme_path, "w") as f: + f.write(content) +PYEOF + # --- Update root README.md --- sed -i.bak \ diff --git a/docs/release.md b/docs/release.md index 9ce2b87..21f56c8 100644 --- a/docs/release.md +++ b/docs/release.md @@ -45,6 +45,7 @@ The workflow opens `prepare--v` with these changes: - `/version.txt` - `/layer-data.sh` - `/sample-apps/template.yaml` +- `/README.md` - root `README.md` The changelog fragment prevents concurrent release preparations from editing @@ -54,8 +55,9 @@ The changelog fragment prevents concurrent release preparations from editing 2. Verify the named values in `/version.txt`. 3. Verify the layer version in `/layer-data.sh`. 4. Verify the layer version in `/sample-apps/template.yaml`. -5. Verify the root README release link and component versions. -6. Resolve any normal pull-request conflict, including a shared root README +5. Verify the version in the title of `/README.md`. +6. Verify the root README release link and component versions. +7. Resolve any normal pull-request conflict, including a shared root README conflict caused by another release merged on the same day. Only one open prepare pull request is allowed per language. An open Java @@ -70,26 +72,17 @@ Merging a prepare pull request triggers the following sequence: `CHANGELOG.md` and deletes the fragment. 3. It commits the assembled changelog and creates `-v` at that commit. -4. It explicitly dispatches the matching language build workflow at the tag. - The dispatch-capable build workflows must already be present on `main` before - the first automated release is merged. -5. The build workflow identifies the previous tag for the same language and - asks GitHub to generate release notes for that tag range. It creates - artifacts, publishes Lambda layers, and creates a GitHub pre-release with - those generated notes and the layer ARN tables. The reviewed changelog - fragment remains the source for the repository `CHANGELOG.md`. -6. A successful build creates and pushes `release--v`. - That branch updates the language README title from `unreleased version` (or - its previous version) to the new version. No pull request is opened for this - branch. -7. Review the pre-release and the pushed release branch. The GitHub release - remains a pre-release. -8. When ready to publish, open the pre-release on the GitHub Releases page, +4. It pushes the release tag. Because this push uses `GITHUB_TOKEN`, it does + not automatically start the unchanged tag-push-only release-build workflow. +5. Start the existing release-build workflow through the repository's current + release procedure. It creates artifacts, publishes Lambda layers, and + creates a GitHub pre-release containing the ARN tables and release artifacts. +6. Review the pre-release. The GitHub release remains a pre-release. +7. When ready to publish, open the pre-release on the GitHub Releases page, edit it, clear the pre-release setting, mark it as the latest release, and publish it. -Finalization is idempotent: rerunning it does not recreate an existing release -branch. Final promotion is a manual GitHub UI step. +Final promotion is a manual GitHub UI step. ## Recovery @@ -97,10 +90,7 @@ branch. Final promotion is a manual GitHub UI step. `Release Prepare` again. - If changelog assembly fails, restore or correct the expected fragment or the `All notable changes` anchor before rerunning the merge-triggered workflow. -- If a tag exists but its build did not start, dispatch the matching - `release-build-.yml` workflow using the release tag as its ref. -- If release-branch finalization fails, dispatch `release-finalize.yml` with - the release tag after correcting the failure. +- If a tag exists but its build did not start, use the repository's current + release procedure to start the existing tag-push-only build workflow. -Do not promote the pre-release before the pre-release contents and generated -release branch have been reviewed. +Do not promote the pre-release before its contents have been reviewed. From 53821bd7e1fc9b7d31d64495aaf9bbddd56321e4 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 18:28:02 +0530 Subject: [PATCH 12/15] Revert "feat: prepare release java v2.20.0" This reverts commit d268c96b --- CHANGELOG.md | 10 ---------- README.md | 2 +- java/layer-data.sh | 4 ++-- java/sample-apps/template.yaml | 32 ++++++++++++++++---------------- opentelemetry-lambda | 2 +- 5 files changed, 20 insertions(+), 30 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7d197f9..0ee4c04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,16 +2,6 @@ All notable changes to this project will be documented in this file. -## [java-v2.20.0] - -### Released 2026-07-17 - -### Changed - -- TODO: fill in changelog - -[java-v2.20.0]: https://github.com/SumoLogic/sumologic-otel-lambda/releases/tag/java-v2.20.0 - ## [python-v1.40.0] ### Released 2026-04-09 diff --git a/README.md b/README.md index 69dac3c..ee9d859 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ `sumologic-otel-lambda` publishes preconfigured [OpenTelemetry Lambda](https://github.com/open-telemetry/opentelemetry-lambda) layers which provide instrumentation for AWS Lambda functions. Released `sumologic-otel-lambda` layers are available: -- Java wrapper layer contains OpenTelemetry Java `v2.27.0` and OpenTelemetry Collector `v0.151.0`. Please see list of [lambda layers](https://github.com/SumoLogic/sumologic-otel-lambda/blob/release-java-v2.20.0/java/README.md). +- Java wrapper layer contains OpenTelemetry Java `v2.19.0` and OpenTelemetry Collector `v0.132.0`. Please see list of [lambda layers](https://github.com/SumoLogic/sumologic-otel-lambda/blob/release-java-v2.19.0/java/README.md). - NodeJS layer contains OpenTelemetry JavaScript SDK `v2.2.0` and OpenTelemetry Collector `v0.138.0`. Please see list of [lambda layers](https://github.com/SumoLogic/sumologic-otel-lambda/blob/release-nodejs-v2.0.2/nodejs/README.md). diff --git a/java/layer-data.sh b/java/layer-data.sh index 00a4ee7..c7dd820 100755 --- a/java/layer-data.sh +++ b/java/layer-data.sh @@ -4,6 +4,6 @@ OFFICIAL_LAYER_NAME=sumologic-otel-lambda-java ARCHITECTURE_AMD=x86_64 ARCHITECTURE_ARM=arm64 RUNTIMES='java8.al2 java11 java17 java21' -DESCRIPTION='Sumo Logic OTEL Collector and Java Lambda Layer https://github.com/SumoLogic/sumologic-otel-lambda/tree/release-java-v2.20.0/java' +DESCRIPTION='Sumo Logic OTEL Collector and Java Lambda Layer https://github.com/SumoLogic/sumologic-otel-lambda/tree/release-java-2.19.0/java' LICENSE=Apache-2.0 -VERSION=v2-20-0 +VERSION=v2-19-0 diff --git a/java/sample-apps/template.yaml b/java/sample-apps/template.yaml index 139cc03..cb1a368 100644 --- a/java/sample-apps/template.yaml +++ b/java/sample-apps/template.yaml @@ -49,34 +49,34 @@ Outputs: Mappings: RegionMap: ap-northeast-1: - layer: "arn:aws:lambda:ap-northeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:ap-northeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" ap-northeast-2: - layer: "arn:aws:lambda:ap-northeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:ap-northeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" ap-south-1: - layer: "arn:aws:lambda:ap-south-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:ap-south-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" ap-southeast-1: - layer: "arn:aws:lambda:ap-southeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:ap-southeast-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" ap-southeast-2: - layer: "arn:aws:lambda:ap-southeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:ap-southeast-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" ca-central-1: - layer: "arn:aws:lambda:ca-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:ca-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" eu-central-1: - layer: "arn:aws:lambda:eu-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:eu-central-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" eu-north-1: - layer: "arn:aws:lambda:eu-north-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:eu-north-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" eu-west-1: - layer: "arn:aws:lambda:eu-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:eu-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" eu-west-2: - layer: "arn:aws:lambda:eu-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:eu-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" eu-west-3: - layer: "arn:aws:lambda:eu-west-3:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:eu-west-3:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" sa-east-1: - layer: "arn:aws:lambda:sa-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:sa-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" us-east-1: - layer: "arn:aws:lambda:us-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:us-east-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" us-east-2: - layer: "arn:aws:lambda:us-east-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:us-east-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" us-west-1: - layer: "arn:aws:lambda:us-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:us-west-1:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" us-west-2: - layer: "arn:aws:lambda:us-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-20-0:1" + layer: "arn:aws:lambda:us-west-2:663229565520:layer:sumologic-otel-lambda-java-x86_64-v2-19-0:1" diff --git a/opentelemetry-lambda b/opentelemetry-lambda index 247d46c..e285846 160000 --- a/opentelemetry-lambda +++ b/opentelemetry-lambda @@ -1 +1 @@ -Subproject commit 247d46c7e19d38ef5ca5e126c828827cb77c55ed +Subproject commit e285846f398b9b5d7b88f63402f1cec89c19ce95 From a06d51499736e4e84df83ac4109d3df9e7faa19d Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 18:51:44 +0530 Subject: [PATCH 13/15] ci: add submodule checkout --- .github/workflows/release-prepare.yml | 21 ++++++++++++++++----- docs/release.md | 19 +++++++++++++------ 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml index 8584948..1f86feb 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -97,6 +97,14 @@ jobs: - name: Create branch run: git checkout -b "${BRANCH}" + - name: Pin opentelemetry-lambda release + id: submodule + run: | + git -C opentelemetry-lambda fetch --tags origin + git -C opentelemetry-lambda checkout --detach "${OTEL_LAMBDA_TAG}" + echo "commit=$(git -C opentelemetry-lambda rev-parse HEAD)" \ + >> "$GITHUB_OUTPUT" + - name: Run prepare script run: ./ci/release-prepare.sh @@ -108,7 +116,8 @@ jobs: "${LANGUAGE}/layer-data.sh" \ "${LANGUAGE}/sample-apps/template.yaml" \ "${LANGUAGE}/README.md" \ - README.md + README.md \ + opentelemetry-lambda COMMIT_MSG="feat: prepare release ${LANGUAGE} v${VERSION}" git commit -m "${COMMIT_MSG}" @@ -134,10 +143,10 @@ jobs: --body "$(cat <-v` with these changes: - `/sample-apps/template.yaml` - `/README.md` - root `README.md` +- `opentelemetry-lambda` gitlink The changelog fragment prevents concurrent release preparations from editing `CHANGELOG.md`. Before merging the pull request: @@ -57,11 +58,17 @@ The changelog fragment prevents concurrent release preparations from editing 4. Verify the layer version in `/sample-apps/template.yaml`. 5. Verify the version in the title of `/README.md`. 6. Verify the root README release link and component versions. -7. Resolve any normal pull-request conflict, including a shared root README - conflict caused by another release merged on the same day. +7. Verify that `opentelemetry-lambda` points to the upstream tag and commit SHA + listed in the pull request. +8. Resolve any normal pull-request conflict, including the shared root README + or submodule gitlink conflicts caused by another release merged first. Keep + the upstream pin selected for the pull request being merged, then recheck the + generated component versions. Only one open prepare pull request is allowed per language. An open Java -prepare pull request does not block NodeJS or Python preparation. +prepare pull request does not block NodeJS or Python preparation. Concurrent +language releases may point the shared submodule at different commits, so the +later pull request may require conflict resolution before merge. ## Automatic post-merge flow From 88f82cc20a976e3dc54faba09d4243fc8af0f285 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Fri, 17 Jul 2026 19:25:57 +0530 Subject: [PATCH 14/15] ci: add automated release workflow dispatch --- .github/workflows/release-build-java.yml | 1 + .github/workflows/release-build-nodejs.yml | 1 + .github/workflows/release-build-python.yml | 1 + .github/workflows/release-prepare.yml | 6 +++--- .github/workflows/release-tag.yml | 8 ++++++++ docs/release.md | 14 ++++++++------ 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/workflows/release-build-java.yml b/.github/workflows/release-build-java.yml index 90ad6d3..fb8a916 100644 --- a/.github/workflows/release-build-java.yml +++ b/.github/workflows/release-build-java.yml @@ -4,6 +4,7 @@ on: push: tags: - 'java-v[0-9]+.[0-9]+.[0-9]+' + workflow_dispatch: jobs: build-release-artifacts: diff --git a/.github/workflows/release-build-nodejs.yml b/.github/workflows/release-build-nodejs.yml index 4e76fbd..8aca4f3 100644 --- a/.github/workflows/release-build-nodejs.yml +++ b/.github/workflows/release-build-nodejs.yml @@ -4,6 +4,7 @@ on: push: tags: - 'nodejs-v[0-9]+.[0-9]+.[0-9]+' + workflow_dispatch: jobs: build-release-artifacts: diff --git a/.github/workflows/release-build-python.yml b/.github/workflows/release-build-python.yml index 2aa9f8e..d6ef32f 100644 --- a/.github/workflows/release-build-python.yml +++ b/.github/workflows/release-build-python.yml @@ -4,6 +4,7 @@ on: push: tags: - 'python-v[0-9]+.[0-9]+.[0-9]+' + workflow_dispatch: jobs: build-release-artifacts: diff --git a/.github/workflows/release-prepare.yml b/.github/workflows/release-prepare.yml index 1f86feb..b88d92d 100644 --- a/.github/workflows/release-prepare.yml +++ b/.github/workflows/release-prepare.yml @@ -172,9 +172,9 @@ jobs: 1. **Changelog assembled** — the fragment is inserted into \`CHANGELOG.md\` and deleted 2. **Tag created** — \`${LANGUAGE}-v${VERSION}\` is created from the assembled changelog commit - 3. **Release tag pushed** — the tag is pushed after changelog assembly - 4. **Build remains separate** — the unchanged release-build workflow is tag-push-only and is not automatically started by the GitHub token used here - 5. **Manual promotion** — after the existing release build creates the pre-release, review and promote it from the GitHub Releases page + 3. **Release build dispatched** — the matching language build workflow is started at the new tag + 4. **Pre-release created** — artifacts are built, Lambda layers are published, and a GitHub pre-release is created + 5. **Manual promotion** — review and promote the pre-release from the GitHub Releases page BODY )" \ --base main \ diff --git a/.github/workflows/release-tag.yml b/.github/workflows/release-tag.yml index ef59e71..36bdcbf 100644 --- a/.github/workflows/release-tag.yml +++ b/.github/workflows/release-tag.yml @@ -6,6 +6,7 @@ on: branches: [main] permissions: + actions: write contents: write pull-requests: read @@ -92,3 +93,10 @@ jobs: git commit -m "release: ${TAG}" git tag -m "${TAG}" "${TAG}" git push --atomic origin main "${TAG}" + + - name: Dispatch release build + env: + GH_TOKEN: ${{ github.token }} + LANGUAGE: ${{ steps.parse.outputs.language }} + TAG: ${{ steps.parse.outputs.tag }} + run: gh workflow run "release-build-${LANGUAGE}.yml" --ref "${TAG}" diff --git a/docs/release.md b/docs/release.md index 90d1723..6e2cd85 100644 --- a/docs/release.md +++ b/docs/release.md @@ -79,10 +79,11 @@ Merging a prepare pull request triggers the following sequence: `CHANGELOG.md` and deletes the fragment. 3. It commits the assembled changelog and creates `-v` at that commit. -4. It pushes the release tag. Because this push uses `GITHUB_TOKEN`, it does - not automatically start the unchanged tag-push-only release-build workflow. -5. Start the existing release-build workflow through the repository's current - release procedure. It creates artifacts, publishes Lambda layers, and +4. It atomically pushes `main` and the release tag, then explicitly dispatches + the matching `release-build-.yml` workflow at that tag. Explicit + dispatch is required because tag pushes made with `GITHUB_TOKEN` do not + start downstream push-triggered workflows. +5. The release-build workflow creates artifacts, publishes Lambda layers, and creates a GitHub pre-release containing the ARN tables and release artifacts. 6. Review the pre-release. The GitHub release remains a pre-release. 7. When ready to publish, open the pre-release on the GitHub Releases page, @@ -97,7 +98,8 @@ Final promotion is a manual GitHub UI step. `Release Prepare` again. - If changelog assembly fails, restore or correct the expected fragment or the `All notable changes` anchor before rerunning the merge-triggered workflow. -- If a tag exists but its build did not start, use the repository's current - release procedure to start the existing tag-push-only build workflow. +- If a tag exists but its build did not start or must be retried, dispatch the + matching `release-build-.yml` workflow with the existing release + tag as its ref. Do not promote the pre-release before its contents have been reviewed. From 24abc757a19d2180192402151c8bd9d440f214c8 Mon Sep 17 00:00:00 2001 From: Shubham Gupta Date: Mon, 20 Jul 2026 15:14:33 +0530 Subject: [PATCH 15/15] ci: add validation in workflow dispatch (cherry picked from commit 84a087feae88afae4a4f112c8a81a9b04d086254) --- .github/workflows/release-build-java.yml | 11 +++++++++++ .github/workflows/release-build-nodejs.yml | 11 +++++++++++ .github/workflows/release-build-python.yml | 11 +++++++++++ 3 files changed, 33 insertions(+) diff --git a/.github/workflows/release-build-java.yml b/.github/workflows/release-build-java.yml index fb8a916..f00abd9 100644 --- a/.github/workflows/release-build-java.yml +++ b/.github/workflows/release-build-java.yml @@ -7,7 +7,18 @@ on: workflow_dispatch: jobs: + validate-ref: + runs-on: ubuntu-22.04 + steps: + - name: Ensure ref is a release tag + run: | + if ! [[ "${GITHUB_REF_NAME}" =~ ^java-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::This workflow must be dispatched from a release tag (java-vX.Y.Z), not '${GITHUB_REF_NAME}'" + exit 1 + fi + build-release-artifacts: + needs: validate-ref uses: ./.github/workflows/build-artifacts.yml with: BUILD_COMMAND: make build-java diff --git a/.github/workflows/release-build-nodejs.yml b/.github/workflows/release-build-nodejs.yml index 8aca4f3..724c936 100644 --- a/.github/workflows/release-build-nodejs.yml +++ b/.github/workflows/release-build-nodejs.yml @@ -7,7 +7,18 @@ on: workflow_dispatch: jobs: + validate-ref: + runs-on: ubuntu-22.04 + steps: + - name: Ensure ref is a release tag + run: | + if ! [[ "${GITHUB_REF_NAME}" =~ ^nodejs-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::This workflow must be dispatched from a release tag (nodejs-vX.Y.Z), not '${GITHUB_REF_NAME}'" + exit 1 + fi + build-release-artifacts: + needs: validate-ref uses: ./.github/workflows/build-artifacts.yml with: BUILD_COMMAND: make build-nodejs diff --git a/.github/workflows/release-build-python.yml b/.github/workflows/release-build-python.yml index d6ef32f..bcda08d 100644 --- a/.github/workflows/release-build-python.yml +++ b/.github/workflows/release-build-python.yml @@ -7,7 +7,18 @@ on: workflow_dispatch: jobs: + validate-ref: + runs-on: ubuntu-22.04 + steps: + - name: Ensure ref is a release tag + run: | + if ! [[ "${GITHUB_REF_NAME}" =~ ^python-v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "::error::This workflow must be dispatched from a release tag (python-vX.Y.Z), not '${GITHUB_REF_NAME}'" + exit 1 + fi + build-release-artifacts: + needs: validate-ref uses: ./.github/workflows/build-artifacts.yml with: BUILD_COMMAND: make build-python