From e5452a9c574c77e6cca5e261326ab7679e0dcf58 Mon Sep 17 00:00:00 2001 From: Peter Steinberger Date: Tue, 28 Apr 2026 03:51:56 +0100 Subject: [PATCH] ci: speed up release validation --- .agents/skills/openclaw-testing/SKILL.md | 14 ++- .github/workflows/full-release-validation.yml | 44 +++++++++ .../openclaw-live-and-e2e-checks-reusable.yml | 83 +++++++++++++++- .github/workflows/openclaw-release-checks.yml | 95 ++++++++++++++++++- docs/ci.md | 31 ++++-- docs/reference/RELEASING.md | 19 +++- scripts/test-live-shard.mjs | 4 + 7 files changed, 267 insertions(+), 23 deletions(-) diff --git a/.agents/skills/openclaw-testing/SKILL.md b/.agents/skills/openclaw-testing/SKILL.md index 27e64269af4..c37401c5b85 100644 --- a/.agents/skills/openclaw-testing/SKILL.md +++ b/.agents/skills/openclaw-testing/SKILL.md @@ -123,13 +123,19 @@ gh workflow run full-release-validation.yml \ --ref main \ -f ref= \ -f provider=openai \ - -f mode=both + -f mode=both \ + -f release_profile=stable ``` Run the workflow itself from the trusted current ref, normally `--ref main`; child workflows are dispatched from that same ref even when `ref` points at an older release branch or tag. Full Release Validation has no separate child workflow ref input; choose the trusted harness by choosing the workflow run ref. +Use `release_profile=minimum|stable|full` to control live/provider breadth: +`minimum` keeps the fastest OpenAI/core release-critical set, `stable` adds the +stable provider/backend set, and `full` adds the broad advisory provider/media +matrix. The parent verifier job appends slowest-job tables for child runs; rerun +only that verifier after a child rerun turns green. If a full run is already active on a newer `origin/main`, prefer watching that run over dispatching a duplicate. If you accidentally dispatch a stale duplicate, @@ -198,11 +204,15 @@ gh workflow run openclaw-release-checks.yml \ -f ref= \ -f provider=openai \ -f mode=both \ + -f release_profile=stable \ -f rerun_group=all ``` Release-check rerun groups are `all`, `install-smoke`, `cross-os`, `live-e2e`, `package`, `qa`, `qa-parity`, and `qa-live`. +`OpenClaw Release Checks` uses the trusted workflow ref to resolve the selected +ref once as `release-package-under-test` and passes that artifact into both +release-path Docker live/E2E checks and Package Acceptance. The release QA parity box is internally split into candidate and baseline lane jobs, followed by a report job that downloads both artifacts and runs @@ -288,6 +298,8 @@ job: - `native-live-extensions-media` - `native-live-extensions-media-audio` - `native-live-extensions-media-music` +- `native-live-extensions-media-music-google` +- `native-live-extensions-media-music-minimax` - `native-live-extensions-media-video` Use `node scripts/test-live-shard.mjs --list` to see the exact files diff --git a/.github/workflows/full-release-validation.yml b/.github/workflows/full-release-validation.yml index 556b0e9cdee..24e9c7cf94a 100644 --- a/.github/workflows/full-release-validation.yml +++ b/.github/workflows/full-release-validation.yml @@ -26,6 +26,15 @@ on: - fresh - upgrade - both + release_profile: + description: Release coverage profile for live/Docker/provider breadth + required: false + default: full + type: choice + options: + - minimum + - stable + - full rerun_group: description: Validation group to run required: false @@ -239,6 +248,7 @@ jobs: CHILD_WORKFLOW_REF: ${{ github.ref_name }} PROVIDER: ${{ inputs.provider }} MODE: ${{ inputs.mode }} + RELEASE_PROFILE: ${{ inputs.release_profile }} RERUN_GROUP: ${{ inputs.rerun_group }} run: | set -euo pipefail @@ -304,6 +314,7 @@ jobs: echo "- Target SHA: \`${TARGET_SHA}\`" echo "- Provider: \`${PROVIDER}\`" echo "- Cross-OS mode: \`${MODE}\`" + echo "- Release profile: \`${RELEASE_PROFILE}\`" echo "- Rerun group: \`${RERUN_GROUP}\`" } >> "$GITHUB_STEP_SUMMARY" @@ -316,6 +327,7 @@ jobs: -f ref="$TARGET_SHA" \ -f provider="$PROVIDER" \ -f mode="$MODE" \ + -f release_profile="$RELEASE_PROFILE" \ -f rerun_group="$child_rerun_group" npm_telegram: @@ -490,6 +502,34 @@ jobs: fi } + summarize_child_timing() { + local label="$1" + local run_id="$2" + if [[ -z "${run_id// }" ]]; then + return 0 + fi + + { + echo + echo "### Slowest jobs: ${label}" + echo + gh run view "$run_id" --json jobs --jq ' + def ts: fromdateiso8601; + "| Job | Result | Minutes |", + "| --- | --- | ---: |", + ([.jobs[] + | select(.startedAt != "0001-01-01T00:00:00Z" and .completedAt != "0001-01-01T00:00:00Z") + | . + {durationMin: ((((.completedAt | ts) - (.startedAt | ts)) / 60) * 10 | round / 10)} + | {name, conclusion, durationMin}] + | sort_by(.durationMin) + | reverse + | .[0:10] + | map("| `" + (.name | gsub("\\|"; "\\|")) + "` | `" + ((.conclusion // "") | tostring) + "` | " + (.durationMin | tostring) + " |") + | .[]) + ' || echo "_Unable to summarize jobs for run ${run_id}._" + } >> "$GITHUB_STEP_SUMMARY" + } + failed=0 if [[ "$NORMAL_CI_RESULT" == "skipped" && -z "${NORMAL_CI_RUN_ID// }" ]]; then @@ -510,4 +550,8 @@ jobs: check_child "npm_telegram" "$NPM_TELEGRAM_RUN_ID" 1 || failed=1 fi + summarize_child_timing "normal_ci" "$NORMAL_CI_RUN_ID" + summarize_child_timing "release_checks" "$RELEASE_CHECKS_RUN_ID" + summarize_child_timing "npm_telegram" "$NPM_TELEGRAM_RUN_ID" + exit "$failed" diff --git a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml index d0515fd9db3..802754fb63e 100644 --- a/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml +++ b/.github/workflows/openclaw-live-and-e2e-checks-reusable.yml @@ -63,6 +63,15 @@ on: required: false default: "" type: string + release_test_profile: + description: Release coverage profile for live/Docker/provider breadth + required: false + default: full + type: choice + options: + - minimum + - stable + - full workflow_call: inputs: ref: @@ -124,6 +133,11 @@ on: required: false default: "" type: string + release_test_profile: + description: Release coverage profile for live/Docker/provider breadth + required: false + default: full + type: string secrets: OPENAI_API_KEY: required: false @@ -1208,22 +1222,31 @@ jobs: include: - provider_label: Anthropic providers: anthropic + profiles: stable full - provider_label: Google providers: google + profiles: stable full - provider_label: MiniMax providers: minimax + profiles: stable full - provider_label: OpenAI providers: openai + profiles: minimum stable full - provider_label: OpenCode providers: opencode-go + profiles: full - provider_label: OpenRouter providers: openrouter + profiles: full - provider_label: xAI providers: xai + profiles: full - provider_label: Z.ai providers: zai + profiles: full - provider_label: Fireworks providers: fireworks + profiles: full env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} @@ -1261,12 +1284,14 @@ jobs: OPENCLAW_VITEST_MAX_WORKERS: "2" steps: - name: Checkout selected ref + if: contains(matrix.profiles, inputs.release_test_profile) uses: actions/checkout@v6 with: ref: ${{ needs.validate_selected_ref.outputs.selected_sha }} fetch-depth: 1 - name: Setup Node environment + if: contains(matrix.profiles, inputs.release_test_profile) uses: ./.github/actions/setup-node-env with: node-version: ${{ env.NODE_VERSION }} @@ -1274,9 +1299,11 @@ jobs: install-bun: "true" - name: Hydrate live auth/profile inputs + if: contains(matrix.profiles, inputs.release_test_profile) run: bash scripts/ci-hydrate-live-auth.sh - name: Validate provider credential + if: contains(matrix.profiles, inputs.release_test_profile) shell: bash run: | set -euo pipefail @@ -1311,6 +1338,7 @@ jobs: esac - name: Run Docker live model sweep + if: contains(matrix.profiles, inputs.release_test_profile) run: pnpm test:docker:live-models validate_live_models_docker_targeted: @@ -1485,156 +1513,196 @@ jobs: timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: native-live-src-gateway-core label: Native live gateway core command: node scripts/test-live-shard.mjs native-live-src-gateway-core timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: minimum stable full - suite_id: native-live-src-gateway-profiles-anthropic label: Native live gateway profiles Anthropic command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=anthropic node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: native-live-src-gateway-profiles-google label: Native live gateway profiles Google command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=google node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: native-live-src-gateway-profiles-minimax label: Native live gateway profiles MiniMax command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=minimax,minimax-portal node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: native-live-src-gateway-profiles-openai label: Native live gateway profiles OpenAI command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=openai node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: minimum stable full - suite_id: native-live-src-gateway-profiles-fireworks label: Native live gateway profiles Fireworks command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=fireworks node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-src-gateway-profiles-deepseek label: Native live gateway profiles DeepSeek command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=deepseek node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-src-gateway-profiles-opencode-go - label: Native live gateway profiles OpenCode Go + label: Native live gateway profiles OpenCode Go deep command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full + - suite_id: native-live-src-gateway-profiles-opencode-go-smoke + label: Native live gateway profiles OpenCode Go smoke + command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=opencode-go OPENCLAW_LIVE_GATEWAY_SMOKE=1 OPENCLAW_LIVE_GATEWAY_MAX_MODELS=1 node scripts/test-live-shard.mjs native-live-src-gateway-profiles + timeout_minutes: 45 + needs_ffmpeg: false + profile_env_only: false + profiles: stable - suite_id: native-live-src-gateway-profiles-openrouter label: Native live gateway profiles OpenRouter command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=openrouter node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-src-gateway-profiles-xai label: Native live gateway profiles xAI command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=xai node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-src-gateway-profiles-zai label: Native live gateway profiles Z.ai command: OPENCLAW_LIVE_GATEWAY_PROVIDERS=zai node scripts/test-live-shard.mjs native-live-src-gateway-profiles timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-src-gateway-backends label: Native live gateway backends command: node scripts/test-live-shard.mjs native-live-src-gateway-backends timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: native-live-test label: Native live test harnesses command: node scripts/test-live-shard.mjs native-live-test timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: native-live-extensions-a-k label: Native live plugins A-K command: node scripts/test-live-shard.mjs native-live-extensions-a-k timeout_minutes: 90 needs_ffmpeg: true profile_env_only: false + profiles: full - suite_id: native-live-extensions-l-n label: Native live plugins L-N command: node scripts/test-live-shard.mjs native-live-extensions-l-n timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-extensions-openai label: Native live OpenAI plugin command: node scripts/test-live-shard.mjs native-live-extensions-openai timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: minimum stable full - suite_id: native-live-extensions-o-z-other label: Native live plugins O-Z other command: node scripts/test-live-shard.mjs native-live-extensions-o-z-other timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-extensions-xai label: Native live xAI plugin command: node scripts/test-live-shard.mjs native-live-extensions-xai timeout_minutes: 90 needs_ffmpeg: false profile_env_only: false + profiles: full - suite_id: native-live-extensions-media-audio label: Native live media audio plugins command: node scripts/test-live-shard.mjs native-live-extensions-media-audio timeout_minutes: 90 needs_ffmpeg: true profile_env_only: false - - suite_id: native-live-extensions-media-music - label: Native live media music plugins - command: node scripts/test-live-shard.mjs native-live-extensions-media-music + profiles: full + - suite_id: native-live-extensions-media-music-google + label: Native live media music Google + command: OPENCLAW_LIVE_MUSIC_GENERATION_PROVIDERS=google node scripts/test-live-shard.mjs native-live-extensions-media-music-google timeout_minutes: 90 needs_ffmpeg: true profile_env_only: false + profiles: full + - suite_id: native-live-extensions-media-music-minimax + label: Native live media music MiniMax + command: OPENCLAW_LIVE_MUSIC_GENERATION_PROVIDERS=minimax node scripts/test-live-shard.mjs native-live-extensions-media-music-minimax + timeout_minutes: 90 + needs_ffmpeg: true + profile_env_only: false + profiles: full - suite_id: native-live-extensions-media-video label: Native live media video plugins command: node scripts/test-live-shard.mjs native-live-extensions-media-video timeout_minutes: 90 needs_ffmpeg: true profile_env_only: false + profiles: full - suite_id: live-gateway-docker label: Docker live gateway command: pnpm test:docker:live-gateway timeout_minutes: 120 needs_ffmpeg: false profile_env_only: false + profiles: minimum stable full - suite_id: live-cli-backend-docker label: Docker live CLI backend command: pnpm test:docker:live-cli-backend timeout_minutes: 120 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: live-acp-bind-docker label: Docker live ACP bind command: pnpm test:docker:live-acp-bind timeout_minutes: 120 needs_ffmpeg: false profile_env_only: false + profiles: stable full - suite_id: live-codex-harness-docker label: Docker live Codex harness command: pnpm test:docker:live-codex-harness timeout_minutes: 120 needs_ffmpeg: false profile_env_only: false + profiles: stable full env: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} @@ -1685,12 +1753,14 @@ jobs: OPENCLAW_VITEST_MAX_WORKERS: "2" steps: - name: Checkout selected ref + if: contains(matrix.profiles, inputs.release_test_profile) uses: actions/checkout@v6 with: ref: ${{ needs.validate_selected_ref.outputs.selected_sha }} fetch-depth: 1 - name: Setup Node environment + if: contains(matrix.profiles, inputs.release_test_profile) uses: ./.github/actions/setup-node-env with: node-version: ${{ env.NODE_VERSION }} @@ -1698,10 +1768,11 @@ jobs: install-bun: "true" - name: Hydrate live auth/profile inputs + if: contains(matrix.profiles, inputs.release_test_profile) run: bash scripts/ci-hydrate-live-auth.sh - name: Install live media dependencies - if: matrix.needs_ffmpeg + if: matrix.needs_ffmpeg && contains(matrix.profiles, inputs.release_test_profile) shell: bash run: | set -euo pipefail @@ -1720,6 +1791,7 @@ jobs: ffmpeg -version | head -1 - name: Configure suite-specific env + if: contains(matrix.profiles, inputs.release_test_profile) shell: bash run: | set -euo pipefail @@ -1766,4 +1838,5 @@ jobs: esac - name: Run ${{ matrix.label }} + if: contains(matrix.profiles, inputs.release_test_profile) run: ${{ matrix.command }} diff --git a/.github/workflows/openclaw-release-checks.yml b/.github/workflows/openclaw-release-checks.yml index 98e0b81330b..1cc5238b276 100644 --- a/.github/workflows/openclaw-release-checks.yml +++ b/.github/workflows/openclaw-release-checks.yml @@ -25,6 +25,15 @@ on: - fresh - upgrade - both + release_profile: + description: Release coverage profile for live/Docker/provider breadth + required: false + default: full + type: choice + options: + - minimum + - stable + - full rerun_group: description: Release check group to run required: false @@ -61,6 +70,7 @@ jobs: sha: ${{ steps.ref.outputs.sha }} provider: ${{ steps.inputs.outputs.provider }} mode: ${{ steps.inputs.outputs.mode }} + release_profile: ${{ steps.inputs.outputs.release_profile }} rerun_group: ${{ steps.inputs.outputs.rerun_group }} steps: - name: Require main or release workflow ref for release checks @@ -120,6 +130,7 @@ jobs: RELEASE_REF_INPUT: ${{ inputs.ref }} RELEASE_PROVIDER_INPUT: ${{ inputs.provider }} RELEASE_MODE_INPUT: ${{ inputs.mode }} + RELEASE_PROFILE_INPUT: ${{ inputs.release_profile }} RELEASE_RERUN_GROUP_INPUT: ${{ inputs.rerun_group }} run: | set -euo pipefail @@ -127,6 +138,7 @@ jobs: printf 'ref=%s\n' "$RELEASE_REF_INPUT" printf 'provider=%s\n' "$RELEASE_PROVIDER_INPUT" printf 'mode=%s\n' "$RELEASE_MODE_INPUT" + printf 'release_profile=%s\n' "$RELEASE_PROFILE_INPUT" printf 'rerun_group=%s\n' "$RELEASE_RERUN_GROUP_INPUT" } >> "$GITHUB_OUTPUT" @@ -136,6 +148,7 @@ jobs: RELEASE_SHA: ${{ steps.ref.outputs.sha }} RELEASE_PROVIDER: ${{ inputs.provider }} RELEASE_MODE: ${{ inputs.mode }} + RELEASE_PROFILE: ${{ inputs.release_profile }} RELEASE_RERUN_GROUP: ${{ inputs.rerun_group }} run: | { @@ -145,10 +158,75 @@ jobs: echo "- Validated SHA: \`${RELEASE_SHA}\`" echo "- Cross-OS provider: \`${RELEASE_PROVIDER}\`" echo "- Cross-OS mode: \`${RELEASE_MODE}\`" + echo "- Release profile: \`${RELEASE_PROFILE}\`" echo "- Rerun group: \`${RELEASE_RERUN_GROUP}\`" echo "- This run will execute cross-OS release validation, install smoke, QA Lab parity, Matrix, and Telegram lanes, and the non-Parallels Docker/live/openwebui coverage from the CI migration plan." } >> "$GITHUB_STEP_SUMMARY" + prepare_release_package: + name: Prepare release package artifact + needs: [resolve_target] + if: contains(fromJSON('["all","live-e2e","package"]'), needs.resolve_target.outputs.rerun_group) + runs-on: blacksmith-32vcpu-ubuntu-2404 + timeout-minutes: 60 + permissions: + contents: read + outputs: + artifact_name: ${{ steps.artifact.outputs.name }} + package_sha256: ${{ steps.package.outputs.sha256 }} + package_version: ${{ steps.package.outputs.package_version }} + steps: + - name: Checkout trusted workflow ref + uses: actions/checkout@v6 + with: + ref: ${{ github.ref_name }} + fetch-depth: 0 + + - name: Set artifact metadata + id: artifact + run: echo "name=release-package-under-test" >> "$GITHUB_OUTPUT" + + - name: Setup Node environment + uses: ./.github/actions/setup-node-env + with: + node-version: ${{ env.NODE_VERSION }} + pnpm-version: ${{ env.PNPM_VERSION }} + install-bun: "true" + install-deps: "false" + + - name: Resolve release package artifact + id: package + shell: bash + env: + PACKAGE_REF: ${{ needs.resolve_target.outputs.ref }} + run: | + set -euo pipefail + node scripts/resolve-openclaw-package-candidate.mjs \ + --source ref \ + --package-ref "$PACKAGE_REF" \ + --output-dir .artifacts/docker-e2e-package \ + --output-name openclaw-current.tgz \ + --metadata .artifacts/docker-e2e-package/package-candidate.json \ + --github-output "$GITHUB_OUTPUT" + digest="$(node -p "JSON.parse(require('fs').readFileSync('.artifacts/docker-e2e-package/package-candidate.json', 'utf8')).sha256")" + version="$(node -p "JSON.parse(require('fs').readFileSync('.artifacts/docker-e2e-package/package-candidate.json', 'utf8')).version")" + { + echo "## Release package artifact" + echo + echo "- Artifact: \`release-package-under-test\`" + echo "- Package ref: \`$PACKAGE_REF\`" + echo "- SHA-256: \`$digest\`" + echo "- Version: \`$version\`" + } >> "$GITHUB_STEP_SUMMARY" + + - name: Upload release package artifact + uses: actions/upload-artifact@v7 + with: + name: release-package-under-test + path: .artifacts/docker-e2e-package/openclaw-current.tgz + retention-days: 14 + if-no-files-found: error + install_smoke_release_checks: needs: [resolve_target] if: contains(fromJSON('["all","install-smoke"]'), needs.resolve_target.outputs.rerun_group) @@ -177,7 +255,7 @@ jobs: OPENCLAW_DISCORD_SMOKE_CHANNEL_ID: ${{ secrets.OPENCLAW_DISCORD_SMOKE_CHANNEL_ID }} live_and_e2e_release_checks: - needs: [resolve_target] + needs: [resolve_target, prepare_release_package] if: contains(fromJSON('["all","live-e2e"]'), needs.resolve_target.outputs.rerun_group) permissions: actions: read @@ -189,8 +267,11 @@ jobs: ref: ${{ needs.resolve_target.outputs.ref }} include_repo_e2e: true include_release_path_suites: true - include_openwebui: true + include_openwebui: ${{ needs.resolve_target.outputs.release_profile != 'minimum' }} include_live_suites: true + release_test_profile: ${{ needs.resolve_target.outputs.release_profile }} + package_artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }} + package_artifact_run_id: ${{ github.run_id }} secrets: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} OPENAI_BASE_URL: ${{ secrets.OPENAI_BASE_URL }} @@ -239,7 +320,7 @@ jobs: package_acceptance_release_checks: name: Run package acceptance - needs: [resolve_target] + needs: [resolve_target, prepare_release_package] if: contains(fromJSON('["all","package"]'), needs.resolve_target.outputs.rerun_group) permissions: actions: read @@ -249,8 +330,10 @@ jobs: uses: ./.github/workflows/package-acceptance.yml with: workflow_ref: ${{ github.ref_name }} - source: ref - package_ref: ${{ needs.resolve_target.outputs.ref }} + source: artifact + artifact_run_id: ${{ github.run_id }} + artifact_name: ${{ needs.prepare_release_package.outputs.artifact_name }} + package_sha256: ${{ needs.prepare_release_package.outputs.package_sha256 }} suite_profile: custom docker_lanes: bundled-channel-deps-compat plugins-offline telegram_mode: mock-openai @@ -608,6 +691,7 @@ jobs: summary: name: Verify release checks needs: + - prepare_release_package - install_smoke_release_checks - cross_os_release_checks - live_and_e2e_release_checks @@ -627,6 +711,7 @@ jobs: set -euo pipefail failed=0 for item in \ + "prepare_release_package=${{ needs.prepare_release_package.result }}" \ "install_smoke_release_checks=${{ needs.install_smoke_release_checks.result }}" \ "cross_os_release_checks=${{ needs.cross_os_release_checks.result }}" \ "live_and_e2e_release_checks=${{ needs.live_and_e2e_release_checks.result }}" \ diff --git a/docs/ci.md b/docs/ci.md index 58cdb0695e5..5448a9bc23d 100644 --- a/docs/ci.md +++ b/docs/ci.md @@ -14,10 +14,14 @@ manual `CI` workflow with that target, 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. The umbrella records the dispatched child run ids, and the final -`Verify full validation` job re-checks the current child run conclusions. If a -child workflow is rerun and turns green, rerun only the parent verifier job to -refresh the umbrella result. +provided. `release_profile=minimum|stable|full` controls the live/provider +breadth passed into release checks: `minimum` keeps the fastest OpenAI/core +release-critical lanes, `stable` adds the stable provider/backend set, and +`full` runs the broad advisory provider/media matrix. The umbrella records the +dispatched child run ids, and the final `Verify full validation` job re-checks +the current child run conclusions and appends slowest-job tables for each child +run. If a child workflow is rerun and turns green, rerun only the parent +verifier job to refresh the umbrella result and timing summary. For recovery, `Full Release Validation` and `OpenClaw Release Checks` both accept `rerun_group`. Use `all` for a release candidate, `ci` for only the @@ -33,12 +37,19 @@ runs it as named shards (`native-live-src-agents`, `native-live-src-gateway-backends`, `native-live-test`, `native-live-extensions-a-k`, `native-live-extensions-l-n`, `native-live-extensions-openai`, `native-live-extensions-o-z-other`, -`native-live-extensions-xai`, and split media audio/music/video shards) through -`scripts/test-live-shard.mjs` instead of one serial job. That keeps the same -file coverage while making slow live provider failures easier to rerun and -diagnose. The aggregate `native-live-extensions-o-z` and -`native-live-extensions-media` shard names remain valid for manual one-shot -reruns. +`native-live-extensions-xai`, split media audio/video shards, and +provider-filtered music shards) through `scripts/test-live-shard.mjs` instead +of one serial job. That keeps the same file coverage while making slow live +provider failures easier to rerun and diagnose. The aggregate +`native-live-extensions-o-z`, `native-live-extensions-media`, and +`native-live-extensions-media-music` shard names remain valid for manual +one-shot reruns. + +`OpenClaw Release Checks` uses the trusted workflow ref to resolve the selected +ref once into a `release-package-under-test` tarball, then passes that artifact +to both the live/E2E release-path Docker workflow and the package acceptance +shard. That keeps the package bytes consistent across release boxes and avoids +repacking the same candidate in multiple child jobs. `Package Acceptance` is the side-run workflow for validating a package artifact without blocking the release workflow. It resolves one candidate from a diff --git a/docs/reference/RELEASING.md b/docs/reference/RELEASING.md index bc2b11976fb..ef089833a50 100644 --- a/docs/reference/RELEASING.md +++ b/docs/reference/RELEASING.md @@ -237,6 +237,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 ``` @@ -248,12 +249,25 @@ 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. +`npm_telegram` child is either successful or intentionally skipped. 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. Child workflows are dispatched from the trusted ref that runs `Full Release Validation`, normally `--ref main`, even when the target `ref` points at an older release branch or tag. There is no separate Full Release Validation workflow-ref input; choose the trusted harness by choosing the workflow run ref. +Use `release_profile` to select live/provider breadth: + +- `minimum`: fastest release-critical OpenAI/core live and Docker path +- `stable`: minimum plus stable provider/backend coverage for release approval +- `full`: stable plus broad advisory provider/media coverage + +`OpenClaw Release Checks` uses the trusted workflow ref to resolve the target +ref once as `release-package-under-test` and reuses that artifact in both +release-path Docker checks and Package Acceptance. This keeps all +package-facing boxes on the same bytes and avoids repeated package builds. + Use these variants depending on release stage: ```bash @@ -262,7 +276,8 @@ gh workflow run full-release-validation.yml \ --ref main \ -f ref=release/YYYY.M.D \ -f provider=openai \ - -f mode=both + -f mode=both \ + -f release_profile=stable # Validate an exact pushed commit. gh workflow run full-release-validation.yml \ diff --git a/scripts/test-live-shard.mjs b/scripts/test-live-shard.mjs index c8634c3db98..aadb60d5658 100644 --- a/scripts/test-live-shard.mjs +++ b/scripts/test-live-shard.mjs @@ -19,6 +19,8 @@ export const RELEASE_LIVE_TEST_SHARDS = Object.freeze([ "native-live-extensions-xai", "native-live-extensions-media-audio", "native-live-extensions-media-music", + "native-live-extensions-media-music-google", + "native-live-extensions-media-music-minimax", "native-live-extensions-media-video", ]); @@ -184,6 +186,8 @@ export function selectLiveShardFiles(shard, files = collectAllLiveTestFiles()) { case "native-live-extensions-media-audio": return files.filter(isExtensionMediaAudioLiveTest); case "native-live-extensions-media-music": + case "native-live-extensions-media-music-google": + case "native-live-extensions-media-music-minimax": return files.filter(isExtensionMediaMusicLiveTest); case "native-live-extensions-media-video": return files.filter(isExtensionMediaVideoLiveTest);