mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
release: forward-port extended stable pipeline
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
name: Full Release Validation
|
||||
run-name: ${{ inputs.dispatch_correlation_id || github.workflow }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -8,6 +9,16 @@ on:
|
||||
required: true
|
||||
default: main
|
||||
type: string
|
||||
dispatch_correlation_id:
|
||||
description: Optional unique dispatch correlation used by release orchestration
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
target_context_ref:
|
||||
description: Optional canonical release branch or tag context for an exact-SHA target
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
provider:
|
||||
description: Provider lane for cross-OS onboarding and the end-to-end agent turn
|
||||
required: false
|
||||
@@ -1082,7 +1093,8 @@ jobs:
|
||||
-f repeat=3 \
|
||||
-f deep_profile=false \
|
||||
-f live_openai_candidate=false \
|
||||
-f fail_on_regression=true
|
||||
-f fail_on_regression=true \
|
||||
-f publish_reports=false
|
||||
|
||||
run_id=""
|
||||
for _ in $(seq 1 60); do
|
||||
@@ -1593,6 +1605,14 @@ jobs:
|
||||
NPM_TELEGRAM_RUN_ID: ${{ needs.npm_telegram.outputs.run_id }}
|
||||
PERFORMANCE_RUN_ID: ${{ needs.performance.outputs.run_id }}
|
||||
PERFORMANCE_CONCLUSION: ${{ needs.performance.outputs.conclusion }}
|
||||
PROVIDER: ${{ inputs.provider }}
|
||||
MODE: ${{ inputs.mode }}
|
||||
TARGET_CONTEXT_REF: ${{ inputs.target_context_ref }}
|
||||
LIVE_SUITE_FILTER: ${{ inputs.live_suite_filter }}
|
||||
CROSS_OS_SUITE_FILTER: ${{ inputs.cross_os_suite_filter }}
|
||||
RELEASE_PACKAGE_SPEC: ${{ inputs.release_package_spec }}
|
||||
PACKAGE_ACCEPTANCE_PACKAGE_SPEC: ${{ inputs.package_acceptance_package_spec }}
|
||||
CODEX_PLUGIN_SPEC: ${{ inputs.codex_plugin_spec }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
manifest_dir="${RUNNER_TEMP}/full-release-validation"
|
||||
@@ -1602,6 +1622,9 @@ jobs:
|
||||
--arg runId "$GITHUB_RUN_ID" \
|
||||
--arg runAttempt "$GITHUB_RUN_ATTEMPT" \
|
||||
--arg workflowRef "$GITHUB_REF_NAME" \
|
||||
--arg workflowSha "$GITHUB_SHA" \
|
||||
--arg workflowFullRef "$GITHUB_REF" \
|
||||
--arg workflowRefType "$GITHUB_REF_TYPE" \
|
||||
--arg targetRef "$TARGET_REF" \
|
||||
--arg targetSha "$TARGET_SHA" \
|
||||
--arg releaseProfile "$RELEASE_PROFILE" \
|
||||
@@ -1613,20 +1636,42 @@ jobs:
|
||||
--arg npmTelegramRunId "$NPM_TELEGRAM_RUN_ID" \
|
||||
--arg performanceRunId "$PERFORMANCE_RUN_ID" \
|
||||
--arg performanceConclusion "$PERFORMANCE_CONCLUSION" \
|
||||
--arg provider "$PROVIDER" \
|
||||
--arg mode "$MODE" \
|
||||
--arg targetContextRef "$TARGET_CONTEXT_REF" \
|
||||
--arg liveSuiteFilter "$LIVE_SUITE_FILTER" \
|
||||
--arg crossOsSuiteFilter "$CROSS_OS_SUITE_FILTER" \
|
||||
--arg releasePackageSpec "$RELEASE_PACKAGE_SPEC" \
|
||||
--arg packageAcceptancePackageSpec "$PACKAGE_ACCEPTANCE_PACKAGE_SPEC" \
|
||||
--arg codexPluginSpec "$CODEX_PLUGIN_SPEC" \
|
||||
'{
|
||||
version: 2,
|
||||
version: 3,
|
||||
workflowName: $workflowName,
|
||||
runId: $runId,
|
||||
runAttempt: $runAttempt,
|
||||
workflowRef: $workflowRef,
|
||||
workflowSha: $workflowSha,
|
||||
workflowFullRef: $workflowFullRef,
|
||||
workflowRefType: $workflowRefType,
|
||||
targetRef: $targetRef,
|
||||
targetSha: $targetSha,
|
||||
releaseProfile: $releaseProfile,
|
||||
rerunGroup: $rerunGroup,
|
||||
runReleaseSoak: $runReleaseSoak,
|
||||
validationInputs: {
|
||||
provider: $provider,
|
||||
mode: $mode,
|
||||
targetContextRef: $targetContextRef,
|
||||
liveSuiteFilter: $liveSuiteFilter,
|
||||
crossOsSuiteFilter: $crossOsSuiteFilter,
|
||||
releasePackageSpec: $releasePackageSpec,
|
||||
packageAcceptancePackageSpec: $packageAcceptancePackageSpec,
|
||||
codexPluginSpec: $codexPluginSpec
|
||||
},
|
||||
controls: {
|
||||
stableSoakRequired: ($releaseProfile == "stable" or $releaseProfile == "full"),
|
||||
performanceBlocking: true
|
||||
performanceBlocking: true,
|
||||
performanceReportPublication: "artifact-only"
|
||||
},
|
||||
childRuns: {
|
||||
normalCi: $normalCiRunId,
|
||||
@@ -1656,3 +1701,4 @@ jobs:
|
||||
name: full-release-validation-${{ github.run_id }}
|
||||
path: ${{ runner.temp }}/full-release-validation
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
name: NPM Telegram Beta E2E
|
||||
run-name: ${{ inputs.dispatch_correlation_id || github.workflow }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -8,6 +9,11 @@ on:
|
||||
required: true
|
||||
default: openclaw@beta
|
||||
type: string
|
||||
dispatch_correlation_id:
|
||||
description: Optional unique dispatch correlation used by release orchestration
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
package_label:
|
||||
description: Optional display label for an artifact-backed package candidate
|
||||
required: false
|
||||
@@ -161,8 +167,8 @@ jobs:
|
||||
set -euo pipefail
|
||||
|
||||
if [[ -z "${PACKAGE_ARTIFACT_NAME// }" ]]; then
|
||||
if [[ ! "${PACKAGE_SPEC}" =~ ^openclaw@(alpha|beta|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-(alpha|beta)\.[1-9][0-9]*)?)$ ]]; then
|
||||
echo "package_spec must be openclaw@alpha, openclaw@beta, openclaw@latest, or an exact OpenClaw release version; got: ${PACKAGE_SPEC}" >&2
|
||||
if [[ ! "${PACKAGE_SPEC}" =~ ^openclaw@(alpha|beta|extended-stable|latest|[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*(-[1-9][0-9]*|-(alpha|beta)\.[1-9][0-9]*)?)$ ]]; then
|
||||
echo "package_spec must be openclaw@alpha, openclaw@beta, openclaw@extended-stable, openclaw@latest, or an exact OpenClaw release version; got: ${PACKAGE_SPEC}" >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
name: OpenClaw NPM Release
|
||||
run-name: ${{ inputs.dispatch_correlation_id || github.workflow }}
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
@@ -7,6 +8,11 @@ on:
|
||||
description: Release tag to publish, or any full 40-character commit SHA for validation-only preflight (for example v2026.3.22 or 0123456789abcdef0123456789abcdef01234567)
|
||||
required: true
|
||||
type: string
|
||||
dispatch_correlation_id:
|
||||
description: Optional unique dispatch correlation used by release orchestration
|
||||
required: false
|
||||
default: ""
|
||||
type: string
|
||||
preflight_only:
|
||||
description: Run validation/build only and skip the gated publish job
|
||||
required: true
|
||||
@@ -184,12 +190,46 @@ jobs:
|
||||
OPENCLAW_LOCAL_CHECK: "0"
|
||||
run: pnpm check:architecture
|
||||
|
||||
# Same-SHA re-runs restore the built outputs so a late preflight failure
|
||||
# does not redo the build and Control UI build; every validation step
|
||||
# still runs against the restored artifacts.
|
||||
- name: Resolve preflight build cache key
|
||||
id: preflight_cache_key
|
||||
run: echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore preflight build outputs
|
||||
id: dist_build_cache
|
||||
uses: actions/cache/restore@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
dist/
|
||||
dist-runtime/
|
||||
packages/*/dist/
|
||||
extensions/*/src/host/**/.bundle.hash
|
||||
extensions/*/src/host/**/*.bundle.js
|
||||
key: ${{ runner.os }}-npm-preflight-dist-v1-${{ github.workflow_sha }}-${{ steps.preflight_cache_key.outputs.sha }}-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
- name: Build
|
||||
if: steps.dist_build_cache.outputs.cache-hit != 'true'
|
||||
run: pnpm build
|
||||
|
||||
- name: Build Control UI
|
||||
if: steps.dist_build_cache.outputs.cache-hit != 'true'
|
||||
run: pnpm ui:build
|
||||
|
||||
- name: Save preflight build outputs
|
||||
if: steps.dist_build_cache.outputs.cache-hit != 'true'
|
||||
continue-on-error: true
|
||||
uses: actions/cache/save@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5
|
||||
with:
|
||||
path: |
|
||||
dist/
|
||||
dist-runtime/
|
||||
packages/*/dist/
|
||||
extensions/*/src/host/**/.bundle.hash
|
||||
extensions/*/src/host/**/*.bundle.js
|
||||
key: ${{ steps.dist_build_cache.outputs.cache-primary-key }}
|
||||
|
||||
- name: Validate release metadata
|
||||
if: ${{ inputs.preflight_run_id == '' }}
|
||||
env:
|
||||
@@ -273,6 +313,7 @@ jobs:
|
||||
name: openclaw-plugin-npm-preflight-${{ inputs.tag }}
|
||||
path: ${{ steps.plugin_npm_preflight.outputs.dir }}
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
|
||||
- name: Generate dependency release evidence
|
||||
id: dependency_evidence
|
||||
@@ -392,6 +433,7 @@ jobs:
|
||||
packageVersion: process.env.PACKAGE_VERSION,
|
||||
tarballName: process.env.TARBALL_NAME,
|
||||
tarballSha256: process.env.TARBALL_SHA256,
|
||||
dependencyTarballs: [],
|
||||
dependencyEvidenceDir: "dependency-evidence",
|
||||
dependencyEvidenceManifest: "dependency-evidence/dependency-evidence-manifest.json",
|
||||
};
|
||||
@@ -424,6 +466,7 @@ jobs:
|
||||
name: openclaw-release-dependency-evidence-${{ inputs.tag }}
|
||||
path: ${{ steps.dependency_evidence.outputs.dir }}
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
|
||||
- name: Upload dependency release evidence tag alias
|
||||
if: ${{ steps.packed_tarball.outputs.release_tag != inputs.tag }}
|
||||
@@ -432,6 +475,7 @@ jobs:
|
||||
name: openclaw-release-dependency-evidence-${{ steps.packed_tarball.outputs.release_tag }}
|
||||
path: ${{ steps.dependency_evidence.outputs.dir }}
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
|
||||
- name: Upload immutable prepared npm publish bundle
|
||||
uses: actions/upload-artifact@v7
|
||||
@@ -446,6 +490,7 @@ jobs:
|
||||
name: openclaw-npm-preflight-${{ inputs.tag }}
|
||||
path: ${{ steps.packed_tarball.outputs.dir }}
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
|
||||
- name: Upload legacy prepared npm publish bundle tag alias
|
||||
if: ${{ steps.packed_tarball.outputs.release_tag != inputs.tag }}
|
||||
@@ -454,6 +499,7 @@ jobs:
|
||||
name: openclaw-npm-preflight-${{ steps.packed_tarball.outputs.release_tag }}
|
||||
path: ${{ steps.packed_tarball.outputs.dir }}
|
||||
if-no-files-found: error
|
||||
overwrite: true
|
||||
|
||||
validate_publish_request:
|
||||
if: ${{ !inputs.preflight_only }}
|
||||
@@ -480,18 +526,26 @@ jobs:
|
||||
RELEASE_TAG: ${{ inputs.tag }}
|
||||
RELEASE_NPM_DIST_TAG: ${{ inputs.npm_dist_tag }}
|
||||
WORKFLOW_REF: ${{ github.ref }}
|
||||
WORKFLOW_SHA: ${{ github.workflow_sha }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
tideclaw_alpha_publish=false
|
||||
extended_stable_publish=false
|
||||
release_publish_workflow=false
|
||||
if [[ "${RELEASE_TAG}" == *"-alpha."* && "${RELEASE_NPM_DIST_TAG}" == "alpha" && "${WORKFLOW_REF}" =~ ^refs/heads/tideclaw/alpha/[0-9]{4}-[0-9]{2}-[0-9]{2}-[0-9]{4}Z$ ]]; then
|
||||
tideclaw_alpha_publish=true
|
||||
fi
|
||||
if [[ "${RELEASE_NPM_DIST_TAG}" == "extended-stable" && "${WORKFLOW_REF}" == refs/heads/extended-stable/* ]]; then
|
||||
extended_stable_publish=true
|
||||
fi
|
||||
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]] && [[ ! "${WORKFLOW_REF}" =~ ^refs/heads/release/[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*$ ]] && [[ "${tideclaw_alpha_publish}" != "true" ]] && [[ "${extended_stable_publish}" != "true" ]]; then
|
||||
echo "Real publish runs must be dispatched from main, release/YYYY.M.PATCH, the exact validated extended-stable branch, or a Tideclaw alpha branch for alpha prereleases. Use preflight_only=true for other branch validation."
|
||||
if [[ "${WORKFLOW_REF}" == "refs/heads/release-publish/${WORKFLOW_SHA}" ]]; then
|
||||
git fetch --no-tags origin +refs/heads/main:refs/remotes/origin/main
|
||||
if git merge-base --is-ancestor "${WORKFLOW_SHA}" origin/main; then
|
||||
release_publish_workflow=true
|
||||
fi
|
||||
fi
|
||||
if [[ "${WORKFLOW_REF}" != "refs/heads/main" ]] && [[ ! "${WORKFLOW_REF}" =~ ^refs/heads/release/[0-9]{4}\.[1-9][0-9]*\.[1-9][0-9]*$ ]] && [[ "${tideclaw_alpha_publish}" != "true" ]] && [[ "${extended_stable_publish}" != "true" ]] && [[ "${release_publish_workflow}" != "true" ]]; then
|
||||
echo "Real publish runs must be dispatched from main, release/YYYY.M.PATCH, an immutable release-publish/<workflow-sha> main ancestor, the exact validated extended-stable branch, or a Tideclaw alpha branch for alpha prereleases. Use preflight_only=true for other branch validation."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
@@ -531,11 +585,8 @@ jobs:
|
||||
echo "Real publish requires full_release_validation_run_id from a successful Full Release Validation run." >&2
|
||||
exit 1
|
||||
fi
|
||||
elif [[ "${RELEASE_NPM_DIST_TAG}" == "extended-stable" && ! "${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "Extended-stable publish requires a positive full_release_validation_run_attempt." >&2
|
||||
exit 1
|
||||
elif [[ -n "${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}" && ! "${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "full_release_validation_run_attempt must be a positive integer when provided." >&2
|
||||
elif [[ ! "${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}" =~ ^[1-9][0-9]*$ ]]; then
|
||||
echo "Real publish with full release validation requires a positive full_release_validation_run_attempt." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "${RELEASE_NPM_DIST_TAG}" == "extended-stable" && -z "${PLUGIN_NPM_RUN_ID// }" ]]; then
|
||||
@@ -694,19 +745,21 @@ jobs:
|
||||
set -euo pipefail
|
||||
EXPECTED_RELEASE_SHA="$(git rev-parse HEAD)"
|
||||
export EXPECTED_RELEASE_SHA
|
||||
if [[ -n "$FULL_RELEASE_VALIDATION_RUN_ATTEMPT" ]]; then
|
||||
run_file="${RUNNER_TEMP}/full-release-validation-run.json"
|
||||
gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${FULL_RELEASE_VALIDATION_RUN_ID}/attempts/${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}" > "$run_file"
|
||||
jq '{workflowName: .name, headBranch: .head_branch, headSha: .head_sha, event, status, conclusion, url: .html_url}' "$run_file" | node scripts/openclaw-npm-extended-stable-release.mjs verify-run
|
||||
run_attempt="$(jq -r '.run_attempt // ""' "$run_file")"
|
||||
if [[ "$run_attempt" != "$FULL_RELEASE_VALIDATION_RUN_ATTEMPT" ]]; then
|
||||
echo "Full Release Validation run ${FULL_RELEASE_VALIDATION_RUN_ID} attempt mismatch: expected ${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}, got ${run_attempt:-<missing>}." >&2
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
RUN_JSON="$(gh run view "$FULL_RELEASE_VALIDATION_RUN_ID" --repo "$GITHUB_REPOSITORY" --json workflowName,headBranch,headSha,event,status,conclusion,url)"
|
||||
printf '%s' "$RUN_JSON" | node scripts/openclaw-npm-extended-stable-release.mjs verify-run
|
||||
run_attempt=""
|
||||
run_file="${RUNNER_TEMP}/full-release-validation-run.json"
|
||||
gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${FULL_RELEASE_VALIDATION_RUN_ID}/attempts/${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}" > "$run_file"
|
||||
jq '{
|
||||
workflowName: .name,
|
||||
headBranch: .head_branch,
|
||||
headSha: .head_sha,
|
||||
event,
|
||||
status,
|
||||
conclusion,
|
||||
url: .html_url
|
||||
}' "$run_file" | node scripts/openclaw-npm-extended-stable-release.mjs verify-run
|
||||
run_attempt="$(jq -r '.run_attempt // ""' "$run_file")"
|
||||
if [[ "$run_attempt" != "$FULL_RELEASE_VALIDATION_RUN_ATTEMPT" ]]; then
|
||||
echo "Full Release Validation run ${FULL_RELEASE_VALIDATION_RUN_ID} attempt mismatch: expected ${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}, got ${run_attempt:-<missing>}." >&2
|
||||
exit 1
|
||||
fi
|
||||
echo "attempt=$run_attempt" >> "$GITHUB_OUTPUT"
|
||||
|
||||
@@ -784,33 +837,27 @@ jobs:
|
||||
FULL_RELEASE_VALIDATION_RUN_ATTEMPT: ${{ steps.full_run.outputs.attempt }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
if [[ -n "$FULL_RELEASE_VALIDATION_RUN_ATTEMPT" ]]; then
|
||||
artifact_name="full-release-validation-${FULL_RELEASE_VALIDATION_RUN_ID}-${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}"
|
||||
artifacts_file="${RUNNER_TEMP}/full-validation-artifacts.json"
|
||||
artifact_name="full-release-validation-${FULL_RELEASE_VALIDATION_RUN_ID}-${FULL_RELEASE_VALIDATION_RUN_ATTEMPT}"
|
||||
artifacts_file="${RUNNER_TEMP}/full-release-validation-artifacts.json"
|
||||
gh api "repos/${GITHUB_REPOSITORY}/actions/runs/${FULL_RELEASE_VALIDATION_RUN_ID}/artifacts?per_page=100" > "$artifacts_file"
|
||||
jq --arg name "$artifact_name" '[.artifacts[] | select(.expired != true and .name == $name)]' "$artifacts_file" > "${RUNNER_TEMP}/full-validation-matches.json"
|
||||
artifact_count="$(jq 'length' "${RUNNER_TEMP}/full-validation-matches.json")"
|
||||
jq --arg name "$artifact_name" '[.artifacts[] | select(.expired != true and .name == $name)]' "$artifacts_file" > "${RUNNER_TEMP}/full-release-validation-matches.json"
|
||||
artifact_count="$(jq 'length' "${RUNNER_TEMP}/full-release-validation-matches.json")"
|
||||
if [[ "$artifact_count" != "1" ]]; then
|
||||
echo "Expected exactly one immutable artifact named ${artifact_name}; found ${artifact_count}." >&2
|
||||
exit 1
|
||||
fi
|
||||
artifact_id="$(jq -er '.[0].id' "${RUNNER_TEMP}/full-validation-matches.json")"
|
||||
artifact_digest="$(jq -er '.[0].digest | strings' "${RUNNER_TEMP}/full-validation-matches.json")"
|
||||
artifact_zip="${RUNNER_TEMP}/full-validation-${artifact_id}.zip"
|
||||
artifact_id="$(jq -er '.[0].id' "${RUNNER_TEMP}/full-release-validation-matches.json")"
|
||||
artifact_digest="$(jq -er '.[0].digest | strings' "${RUNNER_TEMP}/full-release-validation-matches.json")"
|
||||
artifact_zip="${RUNNER_TEMP}/full-release-validation-${artifact_id}.zip"
|
||||
gh api "repos/${GITHUB_REPOSITORY}/actions/artifacts/${artifact_id}/zip" > "$artifact_zip"
|
||||
actual_digest="sha256:$(sha256sum "$artifact_zip" | awk '{print $1}')"
|
||||
if [[ "$actual_digest" != "$artifact_digest" ]]; then
|
||||
echo "Immutable full validation artifact digest mismatch: expected ${artifact_digest}, got ${actual_digest}." >&2
|
||||
echo "Immutable full release validation artifact digest mismatch: expected ${artifact_digest}, got ${actual_digest}." >&2
|
||||
exit 1
|
||||
fi
|
||||
rm -rf full-release-validation
|
||||
mkdir -p full-release-validation
|
||||
unzip -q "$artifact_zip" -d full-release-validation
|
||||
else
|
||||
rm -rf full-release-validation
|
||||
mkdir -p full-release-validation
|
||||
gh run download "$FULL_RELEASE_VALIDATION_RUN_ID" --repo "$GITHUB_REPOSITORY" --name "full-release-validation-${FULL_RELEASE_VALIDATION_RUN_ID}" --dir full-release-validation
|
||||
fi
|
||||
unzip -q "$artifact_zip" -d full-release-validation
|
||||
|
||||
- name: Validate release tag and package metadata
|
||||
if: ${{ inputs.preflight_run_id == '' }}
|
||||
@@ -909,6 +956,7 @@ jobs:
|
||||
export EXPECTED_RELEASE_SHA MANIFEST_FILE
|
||||
node scripts/openclaw-npm-extended-stable-release.mjs verify-manifest
|
||||
RERUN_GROUP="$(jq -r '.rerunGroup // ""' "$MANIFEST_FILE")"
|
||||
RELEASE_PROFILE="$(jq -r '.releaseProfile // ""' "$MANIFEST_FILE")"
|
||||
RUN_RELEASE_SOAK="$(jq -r '.runReleaseSoak // ""' "$MANIFEST_FILE")"
|
||||
PERFORMANCE_BLOCKING="$(jq -r '.controls.performanceBlocking // false' "$MANIFEST_FILE")"
|
||||
if [[ "$RERUN_GROUP" != "all" ]]; then
|
||||
@@ -919,9 +967,15 @@ jobs:
|
||||
echo "Full release validation manifest does not record blocking product performance evidence." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$RELEASE_TAG" != *"-alpha."* && "$RELEASE_TAG" != *"-beta."* && "$RUN_RELEASE_SOAK" != "true" ]]; then
|
||||
echo "Stable releases require Full Release Validation with runReleaseSoak=true." >&2
|
||||
exit 1
|
||||
if [[ "$RELEASE_TAG" != *"-alpha."* && "$RELEASE_TAG" != *"-beta."* ]]; then
|
||||
if [[ "$RELEASE_PROFILE" != "stable" && "$RELEASE_PROFILE" != "full" ]]; then
|
||||
echo "Stable releases require stable or full validation; got $RELEASE_PROFILE." >&2
|
||||
exit 1
|
||||
fi
|
||||
if [[ "$RUN_RELEASE_SOAK" != "true" ]]; then
|
||||
echo "Stable releases require Full Release Validation with runReleaseSoak=true." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
- name: Recheck npm release request
|
||||
|
||||
@@ -66,6 +66,21 @@ env:
|
||||
KOVA_SCENARIO_TIMEOUT_MS: "300000"
|
||||
|
||||
jobs:
|
||||
verify_artifact_only:
|
||||
name: Verify artifact-only report mode
|
||||
if: ${{ github.event_name == 'workflow_dispatch' && inputs.publish_reports == false }}
|
||||
runs-on: ubuntu-24.04
|
||||
steps:
|
||||
- name: Confirm report publication is disabled
|
||||
env:
|
||||
PUBLISH_REPORTS: ${{ inputs.publish_reports }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
[[ "$PUBLISH_REPORTS" == "false" ]] || {
|
||||
echo "Artifact-only performance validation requires publish_reports=false." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
kova:
|
||||
name: ${{ matrix.title }}
|
||||
runs-on: blacksmith-16vcpu-ubuntu-2404
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -42,7 +42,7 @@ env:
|
||||
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
|
||||
NODE_VERSION: "24.15.0"
|
||||
CLAWHUB_REGISTRY: "https://clawhub.ai"
|
||||
CLAWHUB_CLI_PACKAGE: "clawhub@0.21.0"
|
||||
CLAWHUB_CLI_PACKAGE: "clawhub@0.23.1"
|
||||
|
||||
jobs:
|
||||
preview_plugins_clawhub:
|
||||
@@ -63,7 +63,7 @@ jobs:
|
||||
missing_trusted_publisher_matrix: ${{ steps.plan.outputs.missing_trusted_publisher_matrix }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.ref }}
|
||||
@@ -275,7 +275,7 @@ jobs:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
@@ -315,7 +315,7 @@ jobs:
|
||||
plugin: ${{ fromJson(needs.preview_plugins_clawhub.outputs.matrix) }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.ref }}
|
||||
@@ -364,7 +364,7 @@ jobs:
|
||||
run: bash scripts/plugin-clawhub-publish.sh --pack "${PACKAGE_DIR}"
|
||||
|
||||
- name: Upload ClawHub package artifact
|
||||
uses: actions/upload-artifact@v7
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
|
||||
with:
|
||||
name: ${{ matrix.plugin.artifactName }}
|
||||
path: ${{ runner.temp }}/clawhub-package-artifact/*.tgz
|
||||
@@ -387,7 +387,7 @@ jobs:
|
||||
needs:
|
||||
[preview_plugins_clawhub, pack_plugins_clawhub_artifacts, approve_plugins_clawhub_release]
|
||||
if: always() && github.event_name == 'workflow_dispatch' && needs.preview_plugins_clawhub.outputs.has_candidates == 'true' && needs.pack_plugins_clawhub_artifacts.result == 'success' && (inputs.dry_run == true || needs.approve_plugins_clawhub_release.result == 'success')
|
||||
uses: openclaw/clawhub/.github/workflows/package-publish.yml@9d49df109d4ad3dc8a6ecf05d26b39f46d294721
|
||||
uses: openclaw/clawhub/.github/workflows/package-publish.yml@d8096dfc039e86ab942ddf9ef117d04849fd84c1
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
@@ -402,6 +402,7 @@ jobs:
|
||||
dry_run: ${{ inputs.dry_run }}
|
||||
registry: https://clawhub.ai
|
||||
site: https://clawhub.ai
|
||||
family: ${{ contains(fromJson('["@openclaw/acpx","@openclaw/diffs","@openclaw/feishu","@openclaw/qqbot"]'), matrix.plugin.packageName) && 'bundle-plugin' || '' }}
|
||||
tags: ${{ matrix.plugin.publishTag }}
|
||||
source_repo: ${{ github.repository }}
|
||||
source_commit: ${{ needs.preview_plugins_clawhub.outputs.ref_revision }}
|
||||
@@ -414,7 +415,9 @@ jobs:
|
||||
needs: [preview_plugins_clawhub, publish_plugins_clawhub]
|
||||
if: github.event_name == 'workflow_dispatch' && inputs.dry_run != true && needs.preview_plugins_clawhub.outputs.has_candidates == 'true'
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 45
|
||||
permissions:
|
||||
actions: read
|
||||
contents: read
|
||||
strategy:
|
||||
fail-fast: false
|
||||
@@ -422,6 +425,27 @@ jobs:
|
||||
matrix:
|
||||
plugin: ${{ fromJson(needs.preview_plugins_clawhub.outputs.matrix) }}
|
||||
steps:
|
||||
- name: Checkout verification tooling
|
||||
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
ref: ${{ github.sha }}
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Setup Node environment
|
||||
uses: ./.github/actions/setup-node-env
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
install-bun: "false"
|
||||
install-deps: "false"
|
||||
use-actions-cache: "false"
|
||||
|
||||
- name: Download published package input
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
|
||||
with:
|
||||
name: ${{ matrix.plugin.artifactName }}
|
||||
path: ${{ runner.temp }}/clawhub-package-artifact
|
||||
|
||||
- name: Verify published ClawHub package
|
||||
env:
|
||||
CLAWHUB_REGISTRY: ${{ env.CLAWHUB_REGISTRY }}
|
||||
@@ -430,57 +454,9 @@ jobs:
|
||||
PACKAGE_TAG: ${{ matrix.plugin.publishTag }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
node --input-type=module <<'EOF'
|
||||
const registry = (process.env.CLAWHUB_REGISTRY ?? "https://clawhub.ai").replace(/\/+$/, "");
|
||||
const packageName = process.env.PACKAGE_NAME;
|
||||
const packageVersion = process.env.PACKAGE_VERSION;
|
||||
const packageTag = process.env.PACKAGE_TAG;
|
||||
if (!packageName || !packageVersion || !packageTag) {
|
||||
throw new Error("Missing ClawHub package verification env.");
|
||||
}
|
||||
const encodedName = encodeURIComponent(packageName);
|
||||
const encodedVersion = encodeURIComponent(packageVersion);
|
||||
const detailUrl = `${registry}/api/v1/packages/${encodedName}`;
|
||||
const versionUrl = `${detailUrl}/versions/${encodedVersion}`;
|
||||
const artifactUrl = `${versionUrl}/artifact/download`;
|
||||
|
||||
async function fetchWithRetry(url, options = {}) {
|
||||
let lastStatus = "unknown";
|
||||
for (let attempt = 1; attempt <= 12; attempt += 1) {
|
||||
try {
|
||||
const response = await fetch(url, { redirect: "manual", ...options });
|
||||
lastStatus = response.status;
|
||||
if (response.status !== 429 && response.status < 500) {
|
||||
return response;
|
||||
}
|
||||
} catch (error) {
|
||||
lastStatus = error instanceof Error ? error.message : String(error);
|
||||
}
|
||||
await new Promise((resolve) => setTimeout(resolve, attempt * 5000));
|
||||
}
|
||||
throw new Error(`${url} did not stabilize; last status ${lastStatus}.`);
|
||||
}
|
||||
|
||||
const detailResponse = await fetchWithRetry(detailUrl, {
|
||||
headers: { accept: "application/json" },
|
||||
});
|
||||
if (!detailResponse.ok) {
|
||||
throw new Error(`${detailUrl} returned HTTP ${detailResponse.status}.`);
|
||||
}
|
||||
const detail = await detailResponse.json();
|
||||
const tags = detail?.package?.tags ?? {};
|
||||
if (tags[packageTag] !== packageVersion) {
|
||||
throw new Error(
|
||||
`${packageName}: ClawHub tag ${packageTag} points to ${tags[packageTag] ?? "<missing>"}, expected ${packageVersion}.`,
|
||||
);
|
||||
}
|
||||
const versionResponse = await fetchWithRetry(versionUrl);
|
||||
if (!versionResponse.ok) {
|
||||
throw new Error(`${versionUrl} returned HTTP ${versionResponse.status}.`);
|
||||
}
|
||||
const artifactResponse = await fetchWithRetry(artifactUrl, { method: "HEAD" });
|
||||
if (artifactResponse.status < 200 || artifactResponse.status >= 400) {
|
||||
throw new Error(`${artifactUrl} returned HTTP ${artifactResponse.status}.`);
|
||||
}
|
||||
console.log(`${packageName}@${packageVersion} verified on ClawHub.`);
|
||||
EOF
|
||||
node scripts/verify-clawhub-published-artifact.mjs \
|
||||
--expected-artifact-dir "${RUNNER_TEMP}/clawhub-package-artifact" \
|
||||
--package-name "${PACKAGE_NAME}" \
|
||||
--package-version "${PACKAGE_VERSION}" \
|
||||
--publish-tag "${PACKAGE_TAG}" \
|
||||
--registry "${CLAWHUB_REGISTRY}"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user