From 0c23584c2c04d2aac3cc04ef1b719b58e74eafb8 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Sat, 2 May 2026 00:05:25 +0100 Subject: [PATCH] ci: run Telegram package E2E in full release validation --- .github/workflows/full-release-validation.yml | 33 ++++++++---- .github/workflows/npm-telegram-beta-e2e.yml | 24 ++++++++- docs/ci.md | 2 +- docs/reference/RELEASING.md | 30 ++++++----- docs/reference/full-release-validation.md | 53 ++++++++++--------- .../package-acceptance-workflow.test.ts | 11 ++++ 6 files changed, 104 insertions(+), 49 deletions(-) diff --git a/.github/workflows/full-release-validation.yml b/.github/workflows/full-release-validation.yml index b1128de43b9..53337ab836f 100644 --- a/.github/workflows/full-release-validation.yml +++ b/.github/workflows/full-release-validation.yml @@ -59,7 +59,7 @@ on: default: "" type: string npm_telegram_package_spec: - description: Optional published package spec for the post-publish Telegram E2E lane + description: Optional published package spec for the package Telegram E2E lane required: false default: "" type: string @@ -69,7 +69,7 @@ on: default: "" type: string npm_telegram_provider_mode: - description: Provider mode for the optional post-publish Telegram E2E lane + description: Provider mode for the package Telegram E2E lane required: false default: mock-openai type: choice @@ -77,7 +77,7 @@ on: - mock-openai - live-frontier npm_telegram_scenario: - description: Optional comma-separated Telegram scenario ids for the post-publish lane + description: Optional comma-separated Telegram scenario ids for the package Telegram lane required: false default: "" type: string @@ -127,6 +127,7 @@ jobs: CHILD_WORKFLOW_REF: ${{ github.ref_name }} NPM_TELEGRAM_PACKAGE_SPEC: ${{ inputs.npm_telegram_package_spec }} EVIDENCE_PACKAGE_SPEC: ${{ inputs.evidence_package_spec }} + RELEASE_PROFILE: ${{ inputs.release_profile }} RERUN_GROUP: ${{ inputs.rerun_group }} LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }} run: | @@ -156,9 +157,11 @@ jobs: echo "- Release/live/Docker/package/QA: skipped by rerun group" fi if [[ -n "${NPM_TELEGRAM_PACKAGE_SPEC// }" ]]; then - echo "- Post-publish Telegram E2E: \`${NPM_TELEGRAM_PACKAGE_SPEC}\`" + echo "- Published-package Telegram E2E: \`${NPM_TELEGRAM_PACKAGE_SPEC}\`" + elif [[ "$RERUN_GROUP" == "all" && "$RELEASE_PROFILE" == "full" ]]; then + echo "- Package Telegram E2E: release package artifact from \`OpenClaw Release Checks\`" else - echo "- Post-publish Telegram E2E: skipped because no published package spec was provided" + echo "- Package Telegram E2E: skipped unless \`release_profile=full\` or \`npm_telegram_package_spec\` is provided" fi if [[ -n "${EVIDENCE_PACKAGE_SPEC// }" ]]; then echo "- Private evidence package proof: \`${EVIDENCE_PACKAGE_SPEC}\`" @@ -474,9 +477,9 @@ jobs: dispatch_and_wait openclaw-release-checks.yml "${args[@]}" npm_telegram: - name: Run post-publish Telegram E2E - needs: [resolve_target] - if: inputs.npm_telegram_package_spec != '' && contains(fromJSON('["all","npm-telegram"]'), inputs.rerun_group) + name: Run package Telegram E2E + needs: [resolve_target, release_checks] + if: ${{ always() && contains(fromJSON('["all","npm-telegram"]'), inputs.rerun_group) && (inputs.npm_telegram_package_spec != '' || (inputs.rerun_group == 'all' && inputs.release_profile == 'full')) }} runs-on: ubuntu-24.04 timeout-minutes: 120 outputs: @@ -491,6 +494,7 @@ jobs: CHILD_WORKFLOW_REF: ${{ github.ref_name }} TARGET_SHA: ${{ needs.resolve_target.outputs.sha }} PACKAGE_SPEC: ${{ inputs.npm_telegram_package_spec }} + RELEASE_CHECKS_RUN_ID: ${{ needs.release_checks.outputs.run_id }} PROVIDER_MODE: ${{ inputs.npm_telegram_provider_mode }} SCENARIO: ${{ inputs.npm_telegram_scenario }} run: | @@ -498,7 +502,18 @@ jobs: before_json="$(gh run list --workflow npm-telegram-beta-e2e.yml --event workflow_dispatch --limit 100 --json databaseId --jq '[.[].databaseId]')" - args=(-f package_spec="$PACKAGE_SPEC" -f harness_ref="$TARGET_SHA" -f provider_mode="$PROVIDER_MODE") + args=(-f package_spec="${PACKAGE_SPEC:-openclaw@beta}" -f harness_ref="$TARGET_SHA" -f provider_mode="$PROVIDER_MODE") + if [[ -z "${PACKAGE_SPEC// }" ]]; then + if [[ -z "${RELEASE_CHECKS_RUN_ID// }" ]]; then + echo "Full release Telegram requires either npm_telegram_package_spec or a release_checks child run with the release-package-under-test artifact." >&2 + exit 1 + fi + args+=( + -f package_artifact_name=release-package-under-test + -f package_artifact_run_id="$RELEASE_CHECKS_RUN_ID" + -f package_label="full-release-${TARGET_SHA:0:12}" + ) + fi if [[ -n "${SCENARIO// }" ]]; then args+=(-f scenario="$SCENARIO") fi diff --git a/.github/workflows/npm-telegram-beta-e2e.yml b/.github/workflows/npm-telegram-beta-e2e.yml index dcc102e27c1..b8e25f5c6db 100644 --- a/.github/workflows/npm-telegram-beta-e2e.yml +++ b/.github/workflows/npm-telegram-beta-e2e.yml @@ -18,6 +18,11 @@ on: required: false default: "" type: string + package_artifact_run_id: + description: Advanced run id containing package_artifact_name; blank downloads from this run + required: false + default: "" + type: string harness_ref: description: Source ref for the private QA harness; defaults to the dispatched workflow ref required: false @@ -42,7 +47,12 @@ on: required: true type: string package_artifact_name: - description: Optional package-under-test artifact from the current workflow run + description: Optional package-under-test artifact from the current or specified workflow run + required: false + default: "" + type: string + package_artifact_run_id: + description: Optional run id containing package_artifact_name required: false default: "" type: string @@ -93,6 +103,7 @@ jobs: timeout-minutes: 60 environment: qa-live-shared permissions: + actions: read contents: read env: DOCKER_BUILD_SUMMARY: "false" @@ -169,12 +180,21 @@ jobs: fi - name: Download package-under-test artifact - if: inputs.package_artifact_name != '' + if: inputs.package_artifact_name != '' && inputs.package_artifact_run_id == '' uses: actions/download-artifact@v8 with: name: ${{ inputs.package_artifact_name }} path: .artifacts/telegram-package-under-test + - name: Download package-under-test artifact from release run + if: inputs.package_artifact_name != '' && inputs.package_artifact_run_id != '' + uses: actions/download-artifact@v8 + with: + name: ${{ inputs.package_artifact_name }} + path: .artifacts/telegram-package-under-test + run-id: ${{ inputs.package_artifact_run_id }} + github-token: ${{ github.token }} + - name: Run package Telegram E2E id: run_lane shell: bash diff --git a/docs/ci.md b/docs/ci.md index d52a7703bab..915df398513 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -110,7 +110,7 @@ pnpm test:perf:groups:compare .artifacts/test-perf/baseline-before.json .artifac ## Full Release Validation -`Full Release Validation` is the manual umbrella workflow for "run everything before release." It accepts a branch, tag, or full commit SHA, dispatches the manual `CI` workflow with that target, dispatches `Plugin Prerelease` for release-only plugin/package/static/Docker proof, and dispatches `OpenClaw Release Checks` for install smoke, package acceptance, Docker release-path suites, live/E2E, OpenWebUI, QA Lab parity, Matrix, and Telegram lanes. It can also run the post-publish `NPM Telegram Beta E2E` workflow when a published package spec is provided. +`Full Release Validation` is the manual umbrella workflow for "run everything before release." It accepts a branch, tag, or full commit SHA, dispatches the manual `CI` workflow with that target, dispatches `Plugin Prerelease` for release-only plugin/package/static/Docker proof, and dispatches `OpenClaw Release Checks` for install smoke, package acceptance, Docker release-path suites, live/E2E, OpenWebUI, QA Lab parity, Matrix, and Telegram lanes. With `rerun_group=all` and `release_profile=full`, it also runs `NPM Telegram Beta E2E` against the `release-package-under-test` artifact from release checks. After publishing, pass `npm_telegram_package_spec` to rerun the same Telegram package lane against the published npm package. See [Full release validation](/reference/full-release-validation) for the stage matrix, exact workflow job names, profile differences, artifacts, and diff --git a/docs/reference/RELEASING.md b/docs/reference/RELEASING.md index 4fcba825475..c461fe7a742 100644 --- a/docs/reference/RELEASING.md +++ b/docs/reference/RELEASING.md @@ -102,8 +102,10 @@ the maintainer-only release runbook. tag, or full commit SHA, dispatches manual `CI`, and dispatches `OpenClaw Release Checks` for install smoke, package acceptance, Docker release-path suites, live/E2E, OpenWebUI, QA Lab parity, Matrix, and Telegram - lanes. Provide `npm_telegram_package_spec` only after a package has been - published and the post-publish Telegram E2E should run too. Provide + lanes. With `release_profile=full` and `rerun_group=all`, it also runs package + Telegram E2E against the `release-package-under-test` artifact from release + checks. Provide `npm_telegram_package_spec` after publishing when the same + Telegram E2E should prove the published npm package too. Provide `evidence_package_spec` when the private evidence report should prove that the validation matches a published npm package without forcing Telegram E2E. Example: @@ -247,14 +249,16 @@ gh workflow run full-release-validation.yml \ ``` The workflow resolves the target ref, dispatches manual `CI` with -`target_ref=`, dispatches `OpenClaw Release Checks`, and -optionally dispatches standalone post-publish Telegram E2E when -`npm_telegram_package_spec` is set. `OpenClaw Release Checks` then fans out -install smoke, cross-OS release checks, live/E2E Docker release-path coverage, -Package Acceptance with Telegram package QA, QA Lab parity, live Matrix, and -live Telegram. A full run is only acceptable when the `Full Release Validation` -summary shows `normal_ci` and `release_checks` as successful, and any optional -`npm_telegram` child is either successful or intentionally skipped. The final +`target_ref=`, dispatches `OpenClaw Release Checks`, and dispatches +standalone package Telegram E2E when `release_profile=full` with +`rerun_group=all` or when `npm_telegram_package_spec` is set. `OpenClaw Release +Checks` then fans out install smoke, cross-OS release checks, live/E2E Docker +release-path coverage, Package Acceptance with Telegram package QA, QA Lab +parity, live Matrix, and live Telegram. A full run is only acceptable when the +`Full Release Validation` +summary shows `normal_ci` and `release_checks` as successful. In full/all mode, +the `npm_telegram` child must also be successful; outside full/all it is skipped +unless a published `npm_telegram_package_spec` was provided. The final verifier summary includes slowest-job tables for each child run, so the release manager can see the current critical path without downloading logs. See [Full release validation](/reference/full-release-validation) for the @@ -305,6 +309,7 @@ gh workflow run full-release-validation.yml \ -f ref=release/YYYY.M.D \ -f provider=openai \ -f mode=both \ + -f release_profile=full \ -f evidence_package_spec=openclaw@YYYY.M.D-beta.N \ -f npm_telegram_package_spec=openclaw@YYYY.M.D-beta.N \ -f npm_telegram_provider_mode=mock-openai @@ -322,8 +327,9 @@ For bounded recovery, pass `rerun_group` to the umbrella. `all` is the real release-candidate run, `ci` runs only the normal CI child, `plugin-prerelease` runs only the release-only plugin child, `release-checks` runs every release box, and the narrower release groups are `install-smoke`, `cross-os`, -`live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, and `npm-telegram` when the -standalone package Telegram lane is supplied. +`live-e2e`, `package`, `qa`, `qa-parity`, `qa-live`, and `npm-telegram`. +Focused `npm-telegram` reruns require `npm_telegram_package_spec`; full/all runs +with `release_profile=full` use the release-checks package artifact. ### Vitest diff --git a/docs/reference/full-release-validation.md b/docs/reference/full-release-validation.md index 15383efce56..d2249ef85c2 100644 --- a/docs/reference/full-release-validation.md +++ b/docs/reference/full-release-validation.md @@ -29,14 +29,14 @@ when validating an older release branch or tag. ## Top-level stages -| Stage | Details | -| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Target resolution | **Job:** `Resolve target ref`
**Child workflow:** none
**Proves:** resolves the release branch, tag, or full commit SHA and records selected inputs.
**Rerun:** rerun the umbrella if this fails. | -| Vitest and normal CI | **Job:** `Run normal full CI`
**Child workflow:** `CI`
**Proves:** manual full CI graph against the target ref, including Linux Node lanes, bundled plugin shards, channel contracts, Node 22 compatibility, `check`, `check-additional`, build smoke, docs checks, Python skills, Windows, macOS, Control UI i18n, and Android via the umbrella.
**Rerun:** `rerun_group=ci`. | -| Plugin prerelease | **Job:** `Run plugin prerelease validation`
**Child workflow:** `Plugin Prerelease`
**Proves:** release-only plugin static checks, agentic plugin coverage, full extension batch shards, and plugin prerelease Docker lanes.
**Rerun:** `rerun_group=plugin-prerelease`. | -| Release checks | **Job:** `Run release/live/Docker/QA validation`
**Child workflow:** `OpenClaw Release Checks`
**Proves:** install smoke, cross-OS package checks, live/E2E suites, Docker release-path chunks, Package Acceptance, QA Lab parity, live Matrix, and live Telegram.
**Rerun:** `rerun_group=release-checks` or a narrower release-checks handle. | -| Post-publish Telegram | **Job:** `Run post-publish Telegram E2E`
**Child workflow:** `NPM Telegram Beta E2E`
**Proves:** optional published-package Telegram proof when `npm_telegram_package_spec` is set.
**Rerun:** `rerun_group=npm-telegram`. | -| Umbrella verifier | **Job:** `Verify full validation`
**Child workflow:** none
**Proves:** re-checks recorded child run conclusions and appends slowest-job tables from child workflows.
**Rerun:** rerun only this job after rerunning a failed child to green. | +| Stage | Details | +| -------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| Target resolution | **Job:** `Resolve target ref`
**Child workflow:** none
**Proves:** resolves the release branch, tag, or full commit SHA and records selected inputs.
**Rerun:** rerun the umbrella if this fails. | +| Vitest and normal CI | **Job:** `Run normal full CI`
**Child workflow:** `CI`
**Proves:** manual full CI graph against the target ref, including Linux Node lanes, bundled plugin shards, channel contracts, Node 22 compatibility, `check`, `check-additional`, build smoke, docs checks, Python skills, Windows, macOS, Control UI i18n, and Android via the umbrella.
**Rerun:** `rerun_group=ci`. | +| Plugin prerelease | **Job:** `Run plugin prerelease validation`
**Child workflow:** `Plugin Prerelease`
**Proves:** release-only plugin static checks, agentic plugin coverage, full extension batch shards, and plugin prerelease Docker lanes.
**Rerun:** `rerun_group=plugin-prerelease`. | +| Release checks | **Job:** `Run release/live/Docker/QA validation`
**Child workflow:** `OpenClaw Release Checks`
**Proves:** install smoke, cross-OS package checks, live/E2E suites, Docker release-path chunks, Package Acceptance, QA Lab parity, live Matrix, and live Telegram.
**Rerun:** `rerun_group=release-checks` or a narrower release-checks handle. | +| Package Telegram | **Job:** `Run package Telegram E2E`
**Child workflow:** `NPM Telegram Beta E2E`
**Proves:** artifact-backed Telegram package proof for `rerun_group=all` with `release_profile=full`, or published-package Telegram proof when `npm_telegram_package_spec` is set.
**Rerun:** `rerun_group=npm-telegram` with `npm_telegram_package_spec`. | +| Umbrella verifier | **Job:** `Verify full validation`
**Child workflow:** none
**Proves:** re-checks recorded child run conclusions and appends slowest-job tables from child workflows.
**Rerun:** rerun only this job after rerunning a failed child to green. | For `ref=main` and `rerun_group=all`, a newer umbrella supersedes an older one. When the parent is cancelled, its monitor cancels any child workflow it already @@ -84,9 +84,12 @@ commands with package artifact and image reuse inputs when available. ## Release profiles -`release_profile` only controls live/provider breadth inside release checks. It -does not remove normal full CI, Plugin Prerelease, install smoke, package -acceptance, QA Lab, or Docker release-path chunks. +`release_profile` mostly controls live/provider breadth inside release checks. +It does not remove normal full CI, Plugin Prerelease, install smoke, package +acceptance, QA Lab, or Docker release-path chunks. `full` also makes the +umbrella run package Telegram E2E against the release package artifact when +`rerun_group=all`, so a full pre-publish candidate does not silently skip that +Telegram package lane. | Profile | Intended use | Included live/provider coverage | | --------- | --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | @@ -113,20 +116,20 @@ uses the broader OpenCode Go model shards instead. Use `rerun_group` to avoid repeating unrelated release boxes: -| Handle | Scope | -| ------------------- | ------------------------------------------------- | -| `all` | All Full Release Validation stages. | -| `ci` | Manual full CI child only. | -| `plugin-prerelease` | Plugin Prerelease child only. | -| `release-checks` | All OpenClaw Release Checks stages. | -| `install-smoke` | Install Smoke through release checks. | -| `cross-os` | Cross-OS release checks. | -| `live-e2e` | Repo/live E2E and Docker release-path validation. | -| `package` | Package Acceptance. | -| `qa` | QA parity plus QA live lanes. | -| `qa-parity` | QA parity lanes and report only. | -| `qa-live` | QA live Matrix and Telegram only. | -| `npm-telegram` | Optional post-publish Telegram E2E only. | +| Handle | Scope | +| ------------------- | --------------------------------------------------------------------- | +| `all` | All Full Release Validation stages. | +| `ci` | Manual full CI child only. | +| `plugin-prerelease` | Plugin Prerelease child only. | +| `release-checks` | All OpenClaw Release Checks stages. | +| `install-smoke` | Install Smoke through release checks. | +| `cross-os` | Cross-OS release checks. | +| `live-e2e` | Repo/live E2E and Docker release-path validation. | +| `package` | Package Acceptance. | +| `qa` | QA parity plus QA live lanes. | +| `qa-parity` | QA parity lanes and report only. | +| `qa-live` | QA live Matrix and Telegram only. | +| `npm-telegram` | Published-package Telegram E2E; requires `npm_telegram_package_spec`. | Use `live_suite_filter` with `rerun_group=live-e2e` when one live suite failed. Valid filter ids are defined in the reusable live/E2E workflow, including diff --git a/test/scripts/package-acceptance-workflow.test.ts b/test/scripts/package-acceptance-workflow.test.ts index 47a6fb07434..779a6e135eb 100644 --- a/test/scripts/package-acceptance-workflow.test.ts +++ b/test/scripts/package-acceptance-workflow.test.ts @@ -39,6 +39,7 @@ describe("package acceptance workflow", () => { it("offers bounded product profiles and can run Telegram against the resolved artifact", () => { const workflow = readFileSync(PACKAGE_ACCEPTANCE_WORKFLOW, "utf8"); + const npmTelegramWorkflow = readFileSync(NPM_TELEGRAM_WORKFLOW, "utf8"); expect(workflow).toContain("suite_profile:"); expect(workflow).toContain("published_upgrade_survivor_baseline:"); @@ -64,6 +65,10 @@ describe("package acceptance workflow", () => { expect(workflow).toContain( "package_label: openclaw@${{ needs.resolve_package.outputs.package_version }}", ); + expect(npmTelegramWorkflow).toContain("package_artifact_run_id:"); + expect(npmTelegramWorkflow).toContain("Download package-under-test artifact from release run"); + expect(npmTelegramWorkflow).toContain("run-id: ${{ inputs.package_artifact_run_id }}"); + expect(npmTelegramWorkflow).toContain("github-token: ${{ github.token }}"); expect(workflow).toContain( "package_source_sha: ${{ steps.resolve.outputs.package_source_sha }}", ); @@ -449,6 +454,12 @@ describe("package artifact reuse", () => { 'gh workflow run npm-telegram-beta-e2e.yml --ref "$CHILD_WORKFLOW_REF" "${args[@]}"', ); expect(workflow).toContain('-f harness_ref="$TARGET_SHA"'); + expect(workflow).toContain("needs: [resolve_target, release_checks]"); + expect(workflow).toContain("inputs.rerun_group == 'all' && inputs.release_profile == 'full'"); + expect(workflow).toContain("RELEASE_CHECKS_RUN_ID: ${{ needs.release_checks.outputs.run_id }}"); + expect(workflow).toContain("-f package_artifact_name=release-package-under-test"); + expect(workflow).toContain('-f package_artifact_run_id="$RELEASE_CHECKS_RUN_ID"'); + expect(workflow).toContain('-f package_label="full-release-${TARGET_SHA:0:12}"'); expect(workflow).toContain("child_rerun_group=all"); expect(workflow).toContain('-f rerun_group="$child_rerun_group"'); expect(workflow).toContain('args+=(-f live_suite_filter="$LIVE_SUITE_FILTER")');