mirror of
https://github.com/nexu-io/open-design.git
synced 2026-10-27 09:51:12 +01:00
perf(release): add proof-gated hot transaction
This commit is contained in:
@@ -7,6 +7,10 @@ inputs:
|
||||
identity-digest:
|
||||
description: Canonical content identity digest for the shared Closure build
|
||||
required: true
|
||||
handoff-enabled:
|
||||
description: Upload the cross-runner contribution artifact
|
||||
required: false
|
||||
default: "true"
|
||||
min-shell-version:
|
||||
description: Frozen initial Shell compatibility declaration for this channel
|
||||
required: true
|
||||
@@ -37,7 +41,7 @@ runs:
|
||||
RELEASE_CLOSURE_BUILD_DIGEST: ${{ inputs.identity-digest }}
|
||||
RELEASE_CLOSURE_BUILD_KIND: shared
|
||||
RELEASE_CLOSURE_BUILD_TOKEN: shared
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-build/closure-shared/shared-contribution.json
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-closure/shared/shared-contribution.json
|
||||
RELEASE_CLOSURE_MATERIALIZE: "false"
|
||||
RELEASE_VERSION: ${{ inputs.release-version }}
|
||||
run: pnpm exec tools-release resolve-closure-build
|
||||
@@ -58,7 +62,8 @@ runs:
|
||||
--json > "$build_dir/build.json"
|
||||
contribution_path="$(jq -er '.contributionPath' "$build_dir/build.json")"
|
||||
blob_root="$(jq -er '.blobRoot' "$build_dir/build.json")"
|
||||
cp "$contribution_path" "$build_dir/shared-contribution.json"
|
||||
mkdir -p "$RUNNER_TEMP/release-closure/shared"
|
||||
cp "$contribution_path" "$RUNNER_TEMP/release-closure/shared/shared-contribution.json"
|
||||
cp -R "$blob_root" "$build_dir/blobs"
|
||||
|
||||
- name: Register immutable shared Closure build
|
||||
@@ -70,7 +75,7 @@ runs:
|
||||
RELEASE_CLOSURE_BUILD_DIGEST: ${{ inputs.identity-digest }}
|
||||
RELEASE_CLOSURE_BUILD_KIND: shared
|
||||
RELEASE_CLOSURE_BUILD_TOKEN: shared
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-build/closure-shared/shared-contribution.json
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-closure/shared/shared-contribution.json
|
||||
run: pnpm exec tools-release register-closure-build
|
||||
|
||||
- name: Publish verified shared Closure blobs
|
||||
@@ -79,7 +84,7 @@ runs:
|
||||
env:
|
||||
RELEASE_CHANNEL: ${{ inputs.channel }}
|
||||
RELEASE_CLOSURE_BLOB_ROOT: ${{ runner.temp }}/release-build/closure-shared/blobs
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-build/closure-shared/shared-contribution.json
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-closure/shared/shared-contribution.json
|
||||
RELEASE_CLOSURE_CONTRIBUTION_KIND: shared
|
||||
RELEASE_CLOSURE_PUBLICATION_JSON_PATH: ${{ runner.temp }}/release-build/closure-shared/publication.json
|
||||
RELEASE_CLOSURE_BUILD_DIGEST: ${{ inputs.identity-digest }}
|
||||
@@ -90,10 +95,11 @@ runs:
|
||||
run: pnpm exec tools-release publish-closure-contribution
|
||||
|
||||
- name: Upload shared Closure contract and acceptance blobs
|
||||
if: ${{ inputs.handoff-enabled == 'true' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: open-design-${{ inputs.channel }}-closure-shared
|
||||
path: |
|
||||
${{ runner.temp }}/release-build/closure-shared/shared-contribution.json
|
||||
${{ runner.temp }}/release-closure/shared/shared-contribution.json
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
name: Stage exact release metadata
|
||||
description: Merge one Closure graph, publish immutable metadata, and stage its run-scoped acceptance feed
|
||||
|
||||
inputs:
|
||||
exact-name:
|
||||
required: true
|
||||
release-version:
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
acceptance_latest_url:
|
||||
value: ${{ steps.acceptance_feed.outputs.latest_url }}
|
||||
release_state:
|
||||
value: ${{ steps.distribute.outputs.release_state }}
|
||||
version_metadata_url:
|
||||
value: ${{ steps.distribute.outputs.version_metadata_url }}
|
||||
mac_arm64_url:
|
||||
value: ${{ steps.distribute.outputs.mac_arm64_url }}
|
||||
mac_x64_url:
|
||||
value: ${{ steps.distribute.outputs.mac_x64_url }}
|
||||
win_x64_url:
|
||||
value: ${{ steps.distribute.outputs.win_x64_url }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Merge the sole version-wide Standalone graph
|
||||
shell: bash
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$RUNNER_TEMP/release-closure"
|
||||
pnpm exec tools-release merge-closure-distribution \
|
||||
"$RUNNER_TEMP/release-closure/shared/shared-contribution.json" \
|
||||
"$RUNNER_TEMP/release-closure/targets/darwin-arm64/target-contribution.json" \
|
||||
"$RUNNER_TEMP/release-closure/targets/darwin-x64/target-contribution.json" \
|
||||
"$RUNNER_TEMP/release-closure/targets/win32-x64/target-contribution.json" \
|
||||
--output "$RUNNER_TEMP/release-closure/closure-distribution.json"
|
||||
|
||||
- name: Accept the N-1 Shell preflight boundary
|
||||
shell: bash
|
||||
run: pnpm exec tools-release verify-closure-preflight --channel "${{ inputs.exact-name }}" --manifest "$RUNNER_TEMP/release-closure/closure-distribution.json" --release-version "${{ inputs.release-version }}"
|
||||
|
||||
- name: Distribute staged exact metadata
|
||||
id: distribute
|
||||
uses: ./.github/actions/release/publish-metadata
|
||||
with:
|
||||
enable_mac_arm64: true
|
||||
enable_mac_x64: true
|
||||
enable_win_x64: true
|
||||
mac_arm64_result: success
|
||||
mac_x64_result: success
|
||||
win_x64_result: success
|
||||
|
||||
- name: Stage run-scoped mutable acceptance feed
|
||||
id: acceptance_feed
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_ACCEPTANCE_FEED_PREFIX: ${{ inputs.exact-name }}/acceptance/runs/${{ github.run_id }}-${{ github.run_attempt }}
|
||||
RELEASE_METADATA_PATH: ${{ runner.temp }}/release-metadata/metadata.json
|
||||
RELEASE_VERSION: ${{ inputs.release-version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
pnpm exec tools-release stage-acceptance-feed
|
||||
origin="${RELEASE_PUBLIC_ORIGIN%/}"
|
||||
echo "latest_url=$origin/$RELEASE_ACCEPTANCE_FEED_PREFIX/latest/metadata.json" >> "$GITHUB_OUTPUT"
|
||||
@@ -4,6 +4,10 @@ description: Project immutable Shell and Closure registry content into one exact
|
||||
inputs:
|
||||
artifact-id:
|
||||
required: true
|
||||
handoff-enabled:
|
||||
description: Upload cross-runner projection artifacts
|
||||
required: false
|
||||
default: "true"
|
||||
channel:
|
||||
required: true
|
||||
closure-identity-digest:
|
||||
@@ -35,7 +39,7 @@ runs:
|
||||
RELEASE_CLOSURE_BUILD_DIGEST: ${{ inputs.closure-identity-digest }}
|
||||
RELEASE_CLOSURE_BUILD_KIND: target
|
||||
RELEASE_CLOSURE_BUILD_TOKEN: target-${{ inputs.platform }}
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-projection/${{ inputs.target }}/target-contribution.json
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-closure/targets/${{ inputs.platform }}/target-contribution.json
|
||||
RELEASE_CLOSURE_MATERIALIZE: "false"
|
||||
RELEASE_PUBLIC_ORIGIN: ${{ inputs.public-origin }}
|
||||
RELEASE_VERSION: ${{ inputs.release-version }}
|
||||
@@ -75,7 +79,7 @@ runs:
|
||||
RELEASE_CLOSURE_BUILD_DIGEST: ${{ inputs.closure-identity-digest }}
|
||||
RELEASE_CLOSURE_BUILD_KIND: target
|
||||
RELEASE_CLOSURE_BUILD_TOKEN: target-${{ inputs.platform }}
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-projection/${{ inputs.target }}/target-contribution.json
|
||||
RELEASE_CLOSURE_CONTRIBUTION_JSON_PATH: ${{ runner.temp }}/release-closure/targets/${{ inputs.platform }}/target-contribution.json
|
||||
RELEASE_CLOSURE_CONTRIBUTION_KIND: target
|
||||
RELEASE_CLOSURE_PUBLICATION_JSON_PATH: ${{ runner.temp }}/release-projection/${{ inputs.target }}/closure-publication.json
|
||||
RELEASE_CLOSURE_REMOTE_PROJECTION: "true"
|
||||
@@ -126,6 +130,7 @@ runs:
|
||||
}));
|
||||
|
||||
- name: Upload ${{ inputs.target }} publish manifest
|
||||
if: ${{ inputs.handoff-enabled == 'true' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: open-design-${{ inputs.channel }}-${{ inputs.artifact-id }}-publish-manifest
|
||||
@@ -133,13 +138,15 @@ runs:
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload ${{ inputs.target }} Standalone contribution
|
||||
if: ${{ inputs.handoff-enabled == 'true' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: open-design-${{ inputs.channel }}-closure-${{ inputs.platform }}
|
||||
path: ${{ runner.temp }}/release-projection/${{ inputs.target }}/target-contribution.json
|
||||
path: ${{ runner.temp }}/release-closure/targets/${{ inputs.platform }}/target-contribution.json
|
||||
if-no-files-found: error
|
||||
|
||||
- name: Upload ${{ inputs.target }} projection result
|
||||
if: ${{ inputs.handoff-enabled == 'true' }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: open-design-${{ inputs.channel }}-${{ inputs.target }}-build-result
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
name: Activate accepted public release
|
||||
description: Project reusable credentials and atomically activate one accepted exact release
|
||||
|
||||
inputs:
|
||||
channel:
|
||||
required: true
|
||||
commit:
|
||||
required: true
|
||||
metadata-url:
|
||||
required: true
|
||||
public-origin:
|
||||
required: true
|
||||
release-version:
|
||||
required: true
|
||||
reuse-json:
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
activated_at:
|
||||
value: ${{ steps.completed.outputs.activated_at }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Project reusable public acceptance credentials
|
||||
if: ${{ inputs.reuse-json != '{}' }}
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_COMMIT: ${{ inputs.commit }}
|
||||
RELEASE_METADATA_URL: ${{ inputs.metadata-url }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_CREDENTIAL_DIR: ${{ runner.temp }}/public-acceptance
|
||||
RELEASE_PUBLIC_ACCEPTANCE_REUSE_JSON: ${{ inputs.reuse-json }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_WORK_DIR: ${{ runner.temp }}/public-acceptance-projection
|
||||
run: pnpm exec tools-release project-public-acceptance
|
||||
|
||||
- name: Activate accepted immutable exact metadata with CAS
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_ACTIVATION_WORK_DIR: ${{ runner.temp }}/release-activation
|
||||
RELEASE_CHANNEL: ${{ inputs.channel }}
|
||||
RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-activation/outputs.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_CREDENTIAL_DIR: ${{ runner.temp }}/public-acceptance
|
||||
RELEASE_PUBLIC_ORIGIN: ${{ inputs.public-origin }}
|
||||
RELEASE_VERSION: ${{ inputs.release-version }}
|
||||
run: pnpm exec tools-release activate-public-release
|
||||
|
||||
- name: Read back activated exact public feed
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_LATEST_METADATA_URL: ${{ inputs.public-origin }}/${{ inputs.channel }}/latest/metadata.json
|
||||
RELEASE_METADATA_URL: ${{ inputs.metadata-url }}
|
||||
RELEASE_PUBLIC_FEED_REPORT_PATH: ${{ runner.temp }}/release-activation/public-feed-observation.json
|
||||
run: pnpm exec tools-release observe-public-feed
|
||||
|
||||
- name: Publish activation summary
|
||||
shell: bash
|
||||
run: |
|
||||
{
|
||||
echo "## Accepted exact activation"
|
||||
echo ""
|
||||
echo "- version: \`${{ inputs.release-version }}\`"
|
||||
echo "- commit: \`${{ inputs.commit }}\`"
|
||||
echo "- mac_arm64/mac_x64/win_x64 public artifact smoke: \`success\`"
|
||||
echo "- latest CAS and public readback: \`success\`"
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
|
||||
- name: Record activation completion
|
||||
id: completed
|
||||
uses: actions/github-script@v8
|
||||
with:
|
||||
script: core.setOutput("activated_at", new Date().toISOString())
|
||||
@@ -0,0 +1,88 @@
|
||||
name: Execute public content acceptance
|
||||
description: Re-download, install, smoke, and attest one immutable public target
|
||||
|
||||
inputs:
|
||||
artifact-dir:
|
||||
required: true
|
||||
channel:
|
||||
required: true
|
||||
commit:
|
||||
required: true
|
||||
metadata-url:
|
||||
required: true
|
||||
mutable-metadata-url:
|
||||
required: true
|
||||
namespace:
|
||||
required: true
|
||||
os:
|
||||
required: true
|
||||
public-origin:
|
||||
required: true
|
||||
release-version:
|
||||
required: true
|
||||
target:
|
||||
required: true
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v5
|
||||
with:
|
||||
version: 10.33.2
|
||||
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24.18.0
|
||||
cache: pnpm
|
||||
cache-dependency-path: pnpm-lock.yaml
|
||||
|
||||
- name: Install dependencies
|
||||
shell: bash
|
||||
run: pnpm install --frozen-lockfile
|
||||
|
||||
- name: Re-download immutable public ${{ inputs.target }} artifacts
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_COMMIT: ${{ inputs.commit }}
|
||||
RELEASE_METADATA_URL: ${{ inputs.metadata-url }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_BUILD_JSON_PATH: ${{ runner.temp }}/public-feedback/build.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_DOWNLOAD_DIR: ${{ runner.temp }}/public-feedback/tools-pack/out/${{ inputs.os }}/namespaces/${{ inputs.namespace }}/${{ inputs.artifact-dir }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_PLAN_PATH: ${{ runner.temp }}/public-feedback/plan.json
|
||||
RELEASE_PUBLIC_ORIGIN: ${{ inputs.public-origin }}
|
||||
RELEASE_TARGET: ${{ inputs.target }}
|
||||
RELEASE_VERSION: ${{ inputs.release-version }}
|
||||
run: pnpm exec tools-release prepare-public-acceptance
|
||||
|
||||
- name: Smoke immutable public ${{ inputs.target }} install and online Closure cold start
|
||||
shell: bash
|
||||
working-directory: e2e
|
||||
env:
|
||||
OD_PACKAGED_E2E_BUILD_JSON_PATH: ${{ runner.temp }}/public-feedback/build.json
|
||||
OD_PACKAGED_E2E_MAC: ${{ inputs.os == 'mac' && '1' || '' }}
|
||||
OD_PACKAGED_E2E_MAC_SMOKE_LANES: shell
|
||||
OD_PACKAGED_E2E_MAC_SMOKE_PROFILE: core
|
||||
OD_PACKAGED_E2E_NAMESPACE: ${{ inputs.namespace }}
|
||||
OD_PACKAGED_E2E_RELEASE_CHANNEL: ${{ inputs.channel }}
|
||||
OD_PACKAGED_E2E_RELEASE_VERSION: ${{ inputs.release-version }}
|
||||
OD_PACKAGED_E2E_REPORT_DIR: ${{ runner.temp }}/public-feedback/report
|
||||
OD_PACKAGED_E2E_SHELL_SMOKE_PROOF: public-immutable-artifacts
|
||||
OD_PACKAGED_E2E_TOOLS_PACK_DIR: ${{ runner.temp }}/public-feedback/tools-pack
|
||||
# Exercise the final reusable-Shell contract: an empty Store discovers
|
||||
# mutable latest, then Standalone resolves its exact immutable sibling.
|
||||
OD_STANDALONE_METADATA_URL: ${{ inputs.mutable-metadata-url }}
|
||||
OD_PACKAGED_E2E_WIN: ${{ inputs.os == 'win' && '1' || '' }}
|
||||
OD_PACKAGED_E2E_WIN_SMOKE_LANES: shell
|
||||
OD_PACKAGED_E2E_WIN_SMOKE_PROFILE: core
|
||||
OD_TOOLS_PACK_EMBEDDED_CONFIG_ONLY: "1"
|
||||
run: pnpm exec tsx scripts/release-smoke.ts ${{ inputs.os }} specs/${{ inputs.os }}.spec.ts
|
||||
|
||||
- name: Issue public ${{ inputs.target }} acceptance credential
|
||||
shell: bash
|
||||
env:
|
||||
RELEASE_PUBLIC_ACCEPTANCE_CREDENTIAL_PATH: ${{ runner.temp }}/public-feedback/${{ inputs.target }}.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_PLAN_PATH: ${{ runner.temp }}/public-feedback/plan.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_SMOKE_SUMMARY_PATH: ${{ runner.temp }}/public-feedback/report/summary.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_SUITE_RESULT_PATH: ${{ runner.temp }}/public-feedback/report/suite-result.json
|
||||
run: pnpm exec tools-release issue-public-acceptance
|
||||
@@ -0,0 +1,127 @@
|
||||
name: Plan public content acceptance
|
||||
description: Resolve the sole reusable public-acceptance execution topology
|
||||
|
||||
inputs:
|
||||
acceptance-matrix:
|
||||
required: true
|
||||
content-identities:
|
||||
required: true
|
||||
|
||||
outputs:
|
||||
acceptance_count:
|
||||
value: ${{ steps.selection.outputs.acceptance_count }}
|
||||
acceptance_matrix:
|
||||
value: ${{ steps.selection.outputs.acceptance_matrix }}
|
||||
mac_arm64_closure:
|
||||
value: ${{ steps.identities.outputs.mac_arm64_closure }}
|
||||
mac_arm64_run:
|
||||
value: ${{ steps.selection.outputs.mac_arm64_run }}
|
||||
mac_arm64_semantic:
|
||||
value: ${{ steps.mac_arm64.outputs.hash }}
|
||||
mac_arm64_shell:
|
||||
value: ${{ steps.identities.outputs.mac_arm64_shell }}
|
||||
mac_x64_closure:
|
||||
value: ${{ steps.identities.outputs.mac_x64_closure }}
|
||||
mac_x64_run:
|
||||
value: ${{ steps.selection.outputs.mac_x64_run }}
|
||||
mac_x64_semantic:
|
||||
value: ${{ steps.mac_x64.outputs.hash }}
|
||||
mac_x64_shell:
|
||||
value: ${{ steps.identities.outputs.mac_x64_shell }}
|
||||
reuse_json:
|
||||
value: ${{ steps.selection.outputs.reuse_json }}
|
||||
win_x64_closure:
|
||||
value: ${{ steps.identities.outputs.win_x64_closure }}
|
||||
win_x64_run:
|
||||
value: ${{ steps.selection.outputs.win_x64_run }}
|
||||
win_x64_semantic:
|
||||
value: ${{ steps.win_x64.outputs.hash }}
|
||||
win_x64_shell:
|
||||
value: ${{ steps.identities.outputs.win_x64_shell }}
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
steps:
|
||||
- name: Resolve acceptance content identities
|
||||
id: identities
|
||||
uses: actions/github-script@v8
|
||||
env:
|
||||
CONTENT_IDENTITIES: ${{ inputs.content-identities }}
|
||||
with:
|
||||
script: |
|
||||
const identities = JSON.parse(process.env.CONTENT_IDENTITIES || "{}");
|
||||
const targets = ["mac_arm64", "mac_x64", "win_x64"];
|
||||
const digest = /^sha256:[0-9a-f]{64}$/;
|
||||
const enabled = targets.every((target) => digest.test(identities[target]?.closure || "") && digest.test(identities[target]?.shell || ""));
|
||||
core.setOutput("enabled", String(enabled));
|
||||
for (const target of targets) {
|
||||
core.setOutput(`${target}_closure`, identities[target]?.closure || "");
|
||||
core.setOutput(`${target}_shell`, identities[target]?.shell || "");
|
||||
}
|
||||
|
||||
- name: Probe mac_arm64 public acceptance proof
|
||||
id: mac_arm64
|
||||
if: ${{ steps.identities.outputs.enabled == 'true' }}
|
||||
uses: ./.github/actions/hash-skip
|
||||
env:
|
||||
HASH_SKIP_EXTRA_CLOSURE: ${{ steps.identities.outputs.mac_arm64_closure }}
|
||||
HASH_SKIP_EXTRA_SHELL: ${{ steps.identities.outputs.mac_arm64_shell }}
|
||||
with:
|
||||
hash_skip: release.public-acceptance.mac
|
||||
|
||||
- name: Probe mac_x64 public acceptance proof
|
||||
id: mac_x64
|
||||
if: ${{ steps.identities.outputs.enabled == 'true' }}
|
||||
uses: ./.github/actions/hash-skip
|
||||
env:
|
||||
HASH_SKIP_EXTRA_CLOSURE: ${{ steps.identities.outputs.mac_x64_closure }}
|
||||
HASH_SKIP_EXTRA_SHELL: ${{ steps.identities.outputs.mac_x64_shell }}
|
||||
with:
|
||||
hash_skip: release.public-acceptance.mac
|
||||
|
||||
- name: Probe win_x64 public acceptance proof
|
||||
id: win_x64
|
||||
if: ${{ steps.identities.outputs.enabled == 'true' }}
|
||||
uses: ./.github/actions/hash-skip
|
||||
env:
|
||||
HASH_SKIP_EXTRA_CLOSURE: ${{ steps.identities.outputs.win_x64_closure }}
|
||||
HASH_SKIP_EXTRA_SHELL: ${{ steps.identities.outputs.win_x64_shell }}
|
||||
with:
|
||||
hash_skip: release.public-acceptance.win
|
||||
|
||||
- name: Select public acceptance topology
|
||||
id: selection
|
||||
uses: actions/github-script@v8
|
||||
env:
|
||||
ACCEPTANCE_MATRIX: ${{ inputs.acceptance-matrix }}
|
||||
CONTENT_IDENTITIES: ${{ inputs.content-identities }}
|
||||
CONTENT_IDENTITIES_ENABLED: ${{ steps.identities.outputs.enabled }}
|
||||
MAC_ARM64_HASH: ${{ steps.mac_arm64.outputs.hash }}
|
||||
MAC_ARM64_REUSE: ${{ steps.mac_arm64.outputs.skip }}
|
||||
MAC_X64_HASH: ${{ steps.mac_x64.outputs.hash }}
|
||||
MAC_X64_REUSE: ${{ steps.mac_x64.outputs.skip }}
|
||||
WIN_X64_HASH: ${{ steps.win_x64.outputs.hash }}
|
||||
WIN_X64_REUSE: ${{ steps.win_x64.outputs.skip }}
|
||||
with:
|
||||
script: |
|
||||
const matrix = JSON.parse(process.env.ACCEPTANCE_MATRIX);
|
||||
const identities = JSON.parse(process.env.CONTENT_IDENTITIES || "{}");
|
||||
const enabled = process.env.CONTENT_IDENTITIES_ENABLED === "true";
|
||||
const proof = {
|
||||
mac_arm64: { hash: process.env.MAC_ARM64_HASH, reuse: process.env.MAC_ARM64_REUSE === "true" },
|
||||
mac_x64: { hash: process.env.MAC_X64_HASH, reuse: process.env.MAC_X64_REUSE === "true" },
|
||||
win_x64: { hash: process.env.WIN_X64_HASH, reuse: process.env.WIN_X64_REUSE === "true" },
|
||||
};
|
||||
const include = matrix.include.filter(({ target }) => !enabled || !proof[target].reuse).map((entry) => ({
|
||||
...entry,
|
||||
closure_identity_digest: identities[entry.target]?.closure || "",
|
||||
semantic_digest: enabled ? proof[entry.target].hash : "",
|
||||
shell_identity_digest: identities[entry.target]?.shell || "",
|
||||
}));
|
||||
const reuse = Object.fromEntries(matrix.include.filter(({ target }) => enabled && proof[target].reuse).map(({ target }) => [target, proof[target].hash]));
|
||||
core.setOutput("acceptance_count", String(include.length));
|
||||
core.setOutput("acceptance_matrix", JSON.stringify({ include }));
|
||||
core.setOutput("reuse_json", JSON.stringify(reuse));
|
||||
for (const target of ["mac_arm64", "mac_x64", "win_x64"]) {
|
||||
core.setOutput(`${target}_run`, String(include.some((entry) => entry.target === target) && enabled));
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
"shell"
|
||||
],
|
||||
"hashPaths": [
|
||||
".github/workflows/distribution-exact-accept.yml",
|
||||
".github/actions/release/public-acceptance/execute/action.yml",
|
||||
"e2e/lib/desktop",
|
||||
"e2e/lib/vitest",
|
||||
"e2e/scripts/release-smoke.ts",
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
"shell"
|
||||
],
|
||||
"hashPaths": [
|
||||
".github/workflows/distribution-exact-accept.yml",
|
||||
".github/actions/release/public-acceptance/execute/action.yml",
|
||||
"e2e/lib/desktop",
|
||||
"e2e/lib/vitest",
|
||||
"e2e/scripts/release-smoke.ts",
|
||||
|
||||
@@ -24,6 +24,7 @@ function releaseChannelDisplayLabel(channel: string): string {
|
||||
}
|
||||
|
||||
export type ReleaseNotificationInput = {
|
||||
activationCompletedAt: string;
|
||||
actor: string;
|
||||
branch: string;
|
||||
channel: string;
|
||||
@@ -239,6 +240,29 @@ function actorMarkdown(actor: string): string {
|
||||
: "未知";
|
||||
}
|
||||
|
||||
function commitMarkdown(input: ReleaseNotificationInput): string {
|
||||
const shortCommit = input.commit.slice(0, 7);
|
||||
if (shortCommit.length === 0) return "";
|
||||
return input.repository.length > 0
|
||||
? `[${shortCommit}](https://github.com/${input.repository}/commit/${input.commit})`
|
||||
: shortCommit;
|
||||
}
|
||||
|
||||
function executionTimingMarkdown(input: ReleaseNotificationInput, execution: ReleaseRunContext | null): string {
|
||||
if (execution == null) return "";
|
||||
const activationMs = Date.parse(input.activationCompletedAt);
|
||||
const hasActivation = Number.isFinite(activationMs)
|
||||
&& activationMs >= execution.runStartedAtMs
|
||||
&& activationMs <= execution.observedAtMs;
|
||||
const releaseMs = hasActivation ? activationMs - execution.runStartedAtMs : execution.durationMs;
|
||||
const notificationMs = hasActivation ? execution.observedAtMs - activationMs : 0;
|
||||
return [
|
||||
`发布 ${duration(releaseMs)}`,
|
||||
hasActivation ? `通知 ${duration(notificationMs)}` : "",
|
||||
execution.queueDurationMs > 0 ? `排队 ${duration(execution.queueDurationMs)}` : "",
|
||||
].filter(Boolean).join(" · ");
|
||||
}
|
||||
|
||||
function triggerLabel(eventName: string): string {
|
||||
return {
|
||||
push: "Push",
|
||||
@@ -325,61 +349,43 @@ export function buildReleaseFeishuCard(
|
||||
published: warning ? "不可变发布完成(有告警)" : "不可变发布完成 · 未晋升",
|
||||
validation: "验证完成",
|
||||
}[state];
|
||||
const shortCommit = input.commit.slice(0, 7);
|
||||
const fields: FeishuElement[] = [];
|
||||
const rerunActor = input.triggeringActor.length > 0 && input.triggeringActor !== input.actor
|
||||
? ` · 重跑 ${actorMarkdown(input.triggeringActor)}`
|
||||
: "";
|
||||
const source = [escapeMarkdown(input.branch), commitMarkdown(input)].filter(Boolean).join(" · ");
|
||||
fields.push({
|
||||
is_short: true,
|
||||
text: { tag: "lark_md", content: `**触发者**\n${actorMarkdown(input.actor)}${rerunActor}` },
|
||||
is_short: false,
|
||||
text: {
|
||||
tag: "lark_md",
|
||||
content: `**触发** · ${actorMarkdown(input.actor)}${rerunActor} · ${escapeMarkdown(triggerLabel(input.eventName))}`
|
||||
+ (source.length > 0 ? ` · ${source}` : ""),
|
||||
},
|
||||
});
|
||||
fields.push({
|
||||
is_short: true,
|
||||
text: { tag: "lark_md", content: `**触发方式**\n${escapeMarkdown(triggerLabel(input.eventName))}` },
|
||||
});
|
||||
fields.push({
|
||||
is_short: true,
|
||||
text: { tag: "lark_md", content: `**发布模式**\n${releaseModeLabel(input.releaseMode)}` },
|
||||
is_short: false,
|
||||
text: { tag: "lark_md", content: `**模式** · ${releaseModeLabel(input.releaseMode)}` },
|
||||
});
|
||||
if (input.runNumber.length > 0) {
|
||||
const attempt = Number.parseInt(input.runAttempt, 10);
|
||||
const attemptLabel = Number.isSafeInteger(attempt) && attempt > 1 ? ` · 第 ${attempt} 次执行` : "";
|
||||
const runLabel = `${input.workflowName || "Workflow"} #${input.runNumber}${attemptLabel}`;
|
||||
fields.push({
|
||||
is_short: true,
|
||||
is_short: false,
|
||||
text: {
|
||||
tag: "lark_md",
|
||||
content: input.runUrl.length > 0
|
||||
? `**执行**\n[${escapeMarkdown(runLabel)}](${input.runUrl})`
|
||||
: `**执行**\n${escapeMarkdown(runLabel)}`,
|
||||
content: `**执行** · ${input.runUrl.length > 0
|
||||
? `[${escapeMarkdown(runLabel)}](${input.runUrl})`
|
||||
: escapeMarkdown(runLabel)}`
|
||||
+ (details.execution?.pullRequest != null
|
||||
? ` · [PR #${details.execution.pullRequest.number}](${details.execution.pullRequest.url})`
|
||||
: "")
|
||||
+ (details.execution != null
|
||||
? ` · ${executionTimingMarkdown(input, details.execution)}`
|
||||
: ""),
|
||||
},
|
||||
});
|
||||
}
|
||||
if (input.branch.length > 0) fields.push({
|
||||
is_short: true,
|
||||
text: { tag: "lark_md", content: `**分支**\n${escapeMarkdown(input.branch)}` },
|
||||
});
|
||||
if (shortCommit.length > 0) fields.push({
|
||||
is_short: true,
|
||||
text: {
|
||||
tag: "lark_md",
|
||||
content: input.repository.length > 0
|
||||
? `**提交**\n[${shortCommit}](https://github.com/${input.repository}/commit/${input.commit})`
|
||||
: `**提交**\n${shortCommit}`,
|
||||
},
|
||||
});
|
||||
if (details.execution != null && details.execution.durationMs > 0) fields.push({
|
||||
is_short: true,
|
||||
text: { tag: "lark_md", content: `**耗时**\n${duration(details.execution.durationMs)}` },
|
||||
});
|
||||
if (details.execution?.pullRequest != null) fields.push({
|
||||
is_short: true,
|
||||
text: {
|
||||
tag: "lark_md",
|
||||
content: `**关联 PR**\n[#${details.execution.pullRequest.number}](${details.execution.pullRequest.url})`,
|
||||
},
|
||||
});
|
||||
const elements: FeishuElement[] = fields.length > 0
|
||||
? [{ tag: "div", fields }, { tag: "hr" }]
|
||||
: [];
|
||||
|
||||
@@ -19,10 +19,13 @@ export type ReleaseRunFailure = {
|
||||
|
||||
export type ReleaseRunContext = {
|
||||
durationMs: number;
|
||||
observedAtMs: number;
|
||||
pullRequest: {
|
||||
number: number;
|
||||
url: string;
|
||||
} | null;
|
||||
queueDurationMs: number;
|
||||
runStartedAtMs: number;
|
||||
};
|
||||
|
||||
type GitHubCompareCommit = {
|
||||
@@ -110,10 +113,14 @@ export async function loadReleaseRunContext(input: {
|
||||
pull_requests?: unknown;
|
||||
run_started_at?: unknown;
|
||||
};
|
||||
const createdAtMs = Date.parse(text(payload.created_at));
|
||||
const startedAt = text(payload.run_started_at) || text(payload.created_at);
|
||||
const startedAtMs = Date.parse(startedAt);
|
||||
const now = input.now ?? Date.now();
|
||||
const durationMs = Number.isFinite(startedAtMs) ? Math.max(0, now - startedAtMs) : 0;
|
||||
const queueDurationMs = Number.isFinite(createdAtMs) && Number.isFinite(startedAtMs)
|
||||
? Math.max(0, startedAtMs - createdAtMs)
|
||||
: 0;
|
||||
const pullRequests = Array.isArray(payload.pull_requests)
|
||||
? payload.pull_requests.flatMap((entry) => {
|
||||
if (entry == null || typeof entry !== "object") return [];
|
||||
@@ -128,7 +135,13 @@ export async function loadReleaseRunContext(input: {
|
||||
url: `https://github.com/${input.repository}/pull/${uniquePullRequests[0]}`,
|
||||
}
|
||||
: null;
|
||||
return { durationMs, pullRequest };
|
||||
return {
|
||||
durationMs,
|
||||
observedAtMs: now,
|
||||
pullRequest,
|
||||
queueDurationMs,
|
||||
runStartedAtMs: Number.isFinite(startedAtMs) ? startedAtMs : 0,
|
||||
};
|
||||
}
|
||||
|
||||
function failedStep(value: unknown): string {
|
||||
|
||||
@@ -28,6 +28,7 @@ if (bot == null) {
|
||||
throw new Error(`unsupported release notification channel: ${channel}`);
|
||||
}
|
||||
const input: ReleaseNotificationInput = {
|
||||
activationCompletedAt: optionalEnv("RELEASE_ACTIVATION_COMPLETED_AT"),
|
||||
actor: optionalEnv("RELEASE_ACTOR"),
|
||||
branch: optionalEnv("RELEASE_BRANCH"),
|
||||
channel,
|
||||
|
||||
@@ -65,6 +65,9 @@ on:
|
||||
release_version:
|
||||
required: true
|
||||
type: string
|
||||
outputs:
|
||||
activation_completed_at:
|
||||
value: ${{ jobs.activate.outputs.activation_completed_at }}
|
||||
|
||||
permissions:
|
||||
actions: write
|
||||
@@ -75,109 +78,32 @@ jobs:
|
||||
name: Plan public content acceptance
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
acceptance_count: ${{ steps.selection.outputs.acceptance_count }}
|
||||
acceptance_matrix: ${{ steps.selection.outputs.acceptance_matrix }}
|
||||
mac_arm64_closure: ${{ steps.identities.outputs.mac_arm64_closure }}
|
||||
mac_arm64_run: ${{ steps.selection.outputs.mac_arm64_run }}
|
||||
mac_arm64_semantic: ${{ steps.mac_arm64.outputs.hash }}
|
||||
mac_arm64_shell: ${{ steps.identities.outputs.mac_arm64_shell }}
|
||||
mac_x64_closure: ${{ steps.identities.outputs.mac_x64_closure }}
|
||||
mac_x64_run: ${{ steps.selection.outputs.mac_x64_run }}
|
||||
mac_x64_semantic: ${{ steps.mac_x64.outputs.hash }}
|
||||
mac_x64_shell: ${{ steps.identities.outputs.mac_x64_shell }}
|
||||
reuse_json: ${{ steps.selection.outputs.reuse_json }}
|
||||
win_x64_closure: ${{ steps.identities.outputs.win_x64_closure }}
|
||||
win_x64_run: ${{ steps.selection.outputs.win_x64_run }}
|
||||
win_x64_semantic: ${{ steps.win_x64.outputs.hash }}
|
||||
win_x64_shell: ${{ steps.identities.outputs.win_x64_shell }}
|
||||
acceptance_count: ${{ steps.acceptance.outputs.acceptance_count }}
|
||||
acceptance_matrix: ${{ steps.acceptance.outputs.acceptance_matrix }}
|
||||
mac_arm64_closure: ${{ steps.acceptance.outputs.mac_arm64_closure }}
|
||||
mac_arm64_run: ${{ steps.acceptance.outputs.mac_arm64_run }}
|
||||
mac_arm64_semantic: ${{ steps.acceptance.outputs.mac_arm64_semantic }}
|
||||
mac_arm64_shell: ${{ steps.acceptance.outputs.mac_arm64_shell }}
|
||||
mac_x64_closure: ${{ steps.acceptance.outputs.mac_x64_closure }}
|
||||
mac_x64_run: ${{ steps.acceptance.outputs.mac_x64_run }}
|
||||
mac_x64_semantic: ${{ steps.acceptance.outputs.mac_x64_semantic }}
|
||||
mac_x64_shell: ${{ steps.acceptance.outputs.mac_x64_shell }}
|
||||
reuse_json: ${{ steps.acceptance.outputs.reuse_json }}
|
||||
win_x64_closure: ${{ steps.acceptance.outputs.win_x64_closure }}
|
||||
win_x64_run: ${{ steps.acceptance.outputs.win_x64_run }}
|
||||
win_x64_semantic: ${{ steps.acceptance.outputs.win_x64_semantic }}
|
||||
win_x64_shell: ${{ steps.acceptance.outputs.win_x64_shell }}
|
||||
steps:
|
||||
- name: Checkout accepted commit
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
ref: ${{ inputs.commit }}
|
||||
- name: Resolve acceptance content identities
|
||||
id: identities
|
||||
uses: actions/github-script@v8
|
||||
env:
|
||||
CONTENT_IDENTITIES: ${{ inputs.content_identities }}
|
||||
- name: Resolve public acceptance topology
|
||||
id: acceptance
|
||||
uses: ./.github/actions/release/public-acceptance/plan
|
||||
with:
|
||||
script: |
|
||||
const identities = JSON.parse(process.env.CONTENT_IDENTITIES || "{}");
|
||||
const targets = ["mac_arm64", "mac_x64", "win_x64"];
|
||||
const digest = /^sha256:[0-9a-f]{64}$/;
|
||||
const enabled = targets.every((target) => digest.test(identities[target]?.closure || "") && digest.test(identities[target]?.shell || ""));
|
||||
core.setOutput("enabled", String(enabled));
|
||||
for (const target of targets) {
|
||||
core.setOutput(`${target}_closure`, identities[target]?.closure || "");
|
||||
core.setOutput(`${target}_shell`, identities[target]?.shell || "");
|
||||
}
|
||||
|
||||
- name: Probe mac_arm64 public acceptance proof
|
||||
id: mac_arm64
|
||||
if: ${{ steps.identities.outputs.enabled == 'true' }}
|
||||
uses: ./.github/actions/hash-skip
|
||||
env:
|
||||
HASH_SKIP_EXTRA_CLOSURE: ${{ steps.identities.outputs.mac_arm64_closure }}
|
||||
HASH_SKIP_EXTRA_SHELL: ${{ steps.identities.outputs.mac_arm64_shell }}
|
||||
with:
|
||||
hash_skip: release.public-acceptance.mac
|
||||
|
||||
- name: Probe mac_x64 public acceptance proof
|
||||
id: mac_x64
|
||||
if: ${{ steps.identities.outputs.enabled == 'true' }}
|
||||
uses: ./.github/actions/hash-skip
|
||||
env:
|
||||
HASH_SKIP_EXTRA_CLOSURE: ${{ steps.identities.outputs.mac_x64_closure }}
|
||||
HASH_SKIP_EXTRA_SHELL: ${{ steps.identities.outputs.mac_x64_shell }}
|
||||
with:
|
||||
hash_skip: release.public-acceptance.mac
|
||||
|
||||
- name: Probe win_x64 public acceptance proof
|
||||
id: win_x64
|
||||
if: ${{ steps.identities.outputs.enabled == 'true' }}
|
||||
uses: ./.github/actions/hash-skip
|
||||
env:
|
||||
HASH_SKIP_EXTRA_CLOSURE: ${{ steps.identities.outputs.win_x64_closure }}
|
||||
HASH_SKIP_EXTRA_SHELL: ${{ steps.identities.outputs.win_x64_shell }}
|
||||
with:
|
||||
hash_skip: release.public-acceptance.win
|
||||
|
||||
- name: Select public acceptance topology
|
||||
id: selection
|
||||
uses: actions/github-script@v8
|
||||
env:
|
||||
ACCEPTANCE_MATRIX: ${{ inputs.acceptance_matrix }}
|
||||
CONTENT_IDENTITIES: ${{ inputs.content_identities }}
|
||||
CONTENT_IDENTITIES_ENABLED: ${{ steps.identities.outputs.enabled }}
|
||||
MAC_ARM64_HASH: ${{ steps.mac_arm64.outputs.hash }}
|
||||
MAC_ARM64_REUSE: ${{ steps.mac_arm64.outputs.skip }}
|
||||
MAC_X64_HASH: ${{ steps.mac_x64.outputs.hash }}
|
||||
MAC_X64_REUSE: ${{ steps.mac_x64.outputs.skip }}
|
||||
WIN_X64_HASH: ${{ steps.win_x64.outputs.hash }}
|
||||
WIN_X64_REUSE: ${{ steps.win_x64.outputs.skip }}
|
||||
with:
|
||||
script: |
|
||||
const matrix = JSON.parse(process.env.ACCEPTANCE_MATRIX);
|
||||
const identities = JSON.parse(process.env.CONTENT_IDENTITIES || "{}");
|
||||
const enabled = process.env.CONTENT_IDENTITIES_ENABLED === "true";
|
||||
const proof = {
|
||||
mac_arm64: { hash: process.env.MAC_ARM64_HASH, reuse: process.env.MAC_ARM64_REUSE === "true" },
|
||||
mac_x64: { hash: process.env.MAC_X64_HASH, reuse: process.env.MAC_X64_REUSE === "true" },
|
||||
win_x64: { hash: process.env.WIN_X64_HASH, reuse: process.env.WIN_X64_REUSE === "true" },
|
||||
};
|
||||
const include = matrix.include.filter(({ target }) => !enabled || !proof[target].reuse).map((entry) => ({
|
||||
...entry,
|
||||
closure_identity_digest: identities[entry.target]?.closure || "",
|
||||
semantic_digest: enabled ? proof[entry.target].hash : "",
|
||||
shell_identity_digest: identities[entry.target]?.shell || "",
|
||||
}));
|
||||
const reuse = Object.fromEntries(matrix.include.filter(({ target }) => enabled && proof[target].reuse).map(({ target }) => [target, proof[target].hash]));
|
||||
core.setOutput("acceptance_count", String(include.length));
|
||||
core.setOutput("acceptance_matrix", JSON.stringify({ include }));
|
||||
core.setOutput("reuse_json", JSON.stringify(reuse));
|
||||
for (const target of ["mac_arm64", "mac_x64", "win_x64"]) {
|
||||
core.setOutput(`${target}_run`, String(include.some((entry) => entry.target === target) && enabled));
|
||||
}
|
||||
acceptance-matrix: ${{ inputs.acceptance_matrix }}
|
||||
content-identities: ${{ inputs.content_identities }}
|
||||
|
||||
public_acceptance:
|
||||
name: Accept public ${{ matrix.target }} exact artifacts
|
||||
@@ -200,54 +126,19 @@ jobs:
|
||||
uses: actions/checkout@v6.0.2
|
||||
with:
|
||||
ref: ${{ inputs.commit }}
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v5
|
||||
- name: Execute immutable public ${{ matrix.target }} acceptance
|
||||
uses: ./.github/actions/release/public-acceptance/execute
|
||||
with:
|
||||
version: 10.33.2
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24.18.0
|
||||
cache: pnpm
|
||||
cache-dependency-path: pnpm-lock.yaml
|
||||
- name: Install dependencies
|
||||
run: pnpm install --frozen-lockfile
|
||||
- name: Re-download immutable public ${{ matrix.target }} artifacts
|
||||
env:
|
||||
RELEASE_METADATA_URL: ${{ inputs.metadata_url }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_BUILD_JSON_PATH: ${{ runner.temp }}/public-feedback/build.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_DOWNLOAD_DIR: ${{ runner.temp }}/public-feedback/tools-pack/out/${{ matrix.os }}/namespaces/${{ env.RELEASE_NAMESPACE }}/${{ matrix.artifact_dir }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_PLAN_PATH: ${{ runner.temp }}/public-feedback/plan.json
|
||||
run: pnpm exec tools-release prepare-public-acceptance
|
||||
- name: Smoke immutable public ${{ matrix.target }} install and online Closure cold start
|
||||
working-directory: e2e
|
||||
env:
|
||||
OD_PACKAGED_E2E_BUILD_JSON_PATH: ${{ runner.temp }}/public-feedback/build.json
|
||||
OD_PACKAGED_E2E_MAC: ${{ matrix.os == 'mac' && '1' || '' }}
|
||||
OD_PACKAGED_E2E_MAC_SMOKE_LANES: shell
|
||||
OD_PACKAGED_E2E_MAC_SMOKE_PROFILE: core
|
||||
OD_PACKAGED_E2E_NAMESPACE: ${{ env.RELEASE_NAMESPACE }}
|
||||
OD_PACKAGED_E2E_RELEASE_CHANNEL: ${{ inputs.exact_name }}
|
||||
OD_PACKAGED_E2E_RELEASE_VERSION: ${{ inputs.release_version }}
|
||||
OD_PACKAGED_E2E_REPORT_DIR: ${{ runner.temp }}/public-feedback/report
|
||||
OD_PACKAGED_E2E_SHELL_SMOKE_PROOF: public-immutable-artifacts
|
||||
OD_PACKAGED_E2E_TOOLS_PACK_DIR: ${{ runner.temp }}/public-feedback/tools-pack
|
||||
# Exercise the final reusable-Shell shape: an empty Store receives a
|
||||
# mutable latest discovery URL, then Standalone re-fetches the exact
|
||||
# immutable sibling before preparation. No releaseVersion is injected.
|
||||
OD_STANDALONE_METADATA_URL: ${{ inputs.mutable_metadata_url }}
|
||||
OD_PACKAGED_E2E_WIN: ${{ matrix.os == 'win' && '1' || '' }}
|
||||
OD_PACKAGED_E2E_WIN_SMOKE_LANES: shell
|
||||
OD_PACKAGED_E2E_WIN_SMOKE_PROFILE: core
|
||||
OD_TOOLS_PACK_EMBEDDED_CONFIG_ONLY: "1"
|
||||
run: pnpm exec tsx scripts/release-smoke.ts ${{ matrix.os }} specs/${{ matrix.os }}.spec.ts
|
||||
- name: Issue public ${{ matrix.target }} acceptance credential
|
||||
env:
|
||||
RELEASE_PUBLIC_ACCEPTANCE_CREDENTIAL_PATH: ${{ runner.temp }}/public-feedback/${{ matrix.target }}.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_PLAN_PATH: ${{ runner.temp }}/public-feedback/plan.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_SMOKE_SUMMARY_PATH: ${{ runner.temp }}/public-feedback/report/summary.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_SUITE_RESULT_PATH: ${{ runner.temp }}/public-feedback/report/suite-result.json
|
||||
run: pnpm exec tools-release issue-public-acceptance
|
||||
artifact-dir: ${{ matrix.artifact_dir }}
|
||||
channel: ${{ inputs.exact_name }}
|
||||
commit: ${{ inputs.commit }}
|
||||
metadata-url: ${{ inputs.metadata_url }}
|
||||
mutable-metadata-url: ${{ inputs.mutable_metadata_url }}
|
||||
namespace: ${{ env.RELEASE_NAMESPACE }}
|
||||
os: ${{ matrix.os }}
|
||||
public-origin: ${{ inputs.public_origin }}
|
||||
release-version: ${{ inputs.release_version }}
|
||||
target: ${{ matrix.target }}
|
||||
- name: Upload public ${{ matrix.target }} acceptance credential
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
@@ -270,6 +161,8 @@ jobs:
|
||||
needs: [plan, public_acceptance]
|
||||
if: ${{ !cancelled() && needs.plan.result == 'success' && (needs.public_acceptance.result == 'success' || needs.public_acceptance.result == 'skipped') }}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
activation_completed_at: ${{ steps.activation.outputs.activated_at }}
|
||||
env:
|
||||
OPEN_DESIGN_POSTINSTALL_LEVEL: release-prepare
|
||||
RELEASE_CHANNEL: ${{ inputs.exact_name }}
|
||||
@@ -359,20 +252,6 @@ jobs:
|
||||
with:
|
||||
hash_skip: release.public-acceptance.win
|
||||
mode: complete
|
||||
- name: Project reusable public acceptance credentials
|
||||
if: ${{ needs.plan.outputs.reuse_json != '{}' }}
|
||||
env:
|
||||
RELEASE_COMMIT: ${{ inputs.commit }}
|
||||
RELEASE_METADATA_URL: ${{ inputs.metadata_url }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_CREDENTIAL_DIR: ${{ runner.temp }}/public-acceptance
|
||||
RELEASE_PUBLIC_ACCEPTANCE_REUSE_JSON: ${{ needs.plan.outputs.reuse_json }}
|
||||
RELEASE_PUBLIC_ACCEPTANCE_WORK_DIR: ${{ runner.temp }}/public-acceptance-projection
|
||||
RELEASE_STORAGE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_RELEASES_AK }}
|
||||
RELEASE_STORAGE_BUCKET: ${{ secrets.CLOUDFLARE_R2_RELEASES_BUCKET }}
|
||||
RELEASE_STORAGE_ENDPOINT: ${{ secrets.CLOUDFLARE_R2_RELEASES_URL }}
|
||||
RELEASE_STORAGE_REGION: auto
|
||||
RELEASE_STORAGE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_RELEASES_SK }}
|
||||
run: pnpm exec tools-release project-public-acceptance
|
||||
- name: Issue stable qualification for accepted prerelease
|
||||
if: ${{ inputs.exact_name == 'prerelease' }}
|
||||
env:
|
||||
@@ -397,33 +276,22 @@ jobs:
|
||||
jq --arg target "$target" '.releaseTargets[$target]' "$RELEASE_METADATA_PATH" > "$RELEASE_MANIFEST_DIR/$target.json"
|
||||
done
|
||||
pnpm exec tools-release issue-stable-qualification
|
||||
- name: Activate accepted immutable exact metadata with CAS
|
||||
- name: Activate accepted public release
|
||||
id: activation
|
||||
uses: ./.github/actions/release/public-acceptance/activate
|
||||
with:
|
||||
channel: ${{ inputs.exact_name }}
|
||||
commit: ${{ inputs.commit }}
|
||||
metadata-url: ${{ inputs.metadata_url }}
|
||||
public-origin: ${{ inputs.public_origin }}
|
||||
release-version: ${{ inputs.release_version }}
|
||||
reuse-json: ${{ needs.plan.outputs.reuse_json }}
|
||||
env:
|
||||
RELEASE_ACTIVATION_WORK_DIR: ${{ runner.temp }}/release-activation
|
||||
RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-activation/outputs.json
|
||||
RELEASE_PUBLIC_ACCEPTANCE_CREDENTIAL_DIR: ${{ runner.temp }}/public-acceptance
|
||||
RELEASE_STORAGE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_RELEASES_AK }}
|
||||
RELEASE_STORAGE_BUCKET: ${{ secrets.CLOUDFLARE_R2_RELEASES_BUCKET }}
|
||||
RELEASE_STORAGE_ENDPOINT: ${{ secrets.CLOUDFLARE_R2_RELEASES_URL }}
|
||||
RELEASE_STORAGE_REGION: auto
|
||||
RELEASE_STORAGE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_RELEASES_SK }}
|
||||
run: pnpm exec tools-release activate-public-release
|
||||
- name: Read back activated exact public feed
|
||||
env:
|
||||
RELEASE_LATEST_METADATA_URL: ${{ inputs.public_origin }}/${{ inputs.exact_name }}/latest/metadata.json
|
||||
RELEASE_METADATA_URL: ${{ inputs.metadata_url }}
|
||||
RELEASE_PUBLIC_FEED_REPORT_PATH: ${{ runner.temp }}/release-activation/public-feed-observation.json
|
||||
run: pnpm exec tools-release observe-public-feed
|
||||
- name: Publish activation summary
|
||||
run: |
|
||||
{
|
||||
echo "## Accepted exact activation"
|
||||
echo ""
|
||||
echo "- version: \`${{ inputs.release_version }}\`"
|
||||
echo "- commit: \`${{ inputs.commit }}\`"
|
||||
echo "- mac_arm64/mac_x64/win_x64 public artifact smoke: \`success\`"
|
||||
echo "- latest CAS and public readback: \`success\`"
|
||||
} >> "$GITHUB_STEP_SUMMARY"
|
||||
- name: Cleanup workflow artifacts
|
||||
if: ${{ success() }}
|
||||
env:
|
||||
|
||||
@@ -150,6 +150,15 @@ jobs:
|
||||
version_lock_key: ${{ steps.reservation.outputs.version_lock_key }}
|
||||
build_matrix: ${{ steps.selection.outputs.build_matrix }}
|
||||
build_count: ${{ steps.selection.outputs.build_count }}
|
||||
hot_activated: ${{ steps.hot_activate.outcome == 'success' }}
|
||||
hot_activation_completed_at: ${{ steps.hot_activate.outputs.activated_at }}
|
||||
hot_staged: ${{ steps.hot_stage.outcome == 'success' }}
|
||||
hot_acceptance_latest_url: ${{ steps.hot_stage.outputs.acceptance_latest_url }}
|
||||
hot_release_state: ${{ steps.hot_stage.outputs.release_state }}
|
||||
hot_version_metadata_url: ${{ steps.hot_stage.outputs.version_metadata_url }}
|
||||
hot_mac_arm64_url: ${{ steps.hot_stage.outputs.mac_arm64_url }}
|
||||
hot_mac_x64_url: ${{ steps.hot_stage.outputs.mac_x64_url }}
|
||||
hot_win_x64_url: ${{ steps.hot_stage.outputs.win_x64_url }}
|
||||
steps:
|
||||
- name: Validate checkout ref shape
|
||||
env:
|
||||
@@ -294,6 +303,7 @@ jobs:
|
||||
|
||||
- name: Prepare immutable candidate identity
|
||||
id: candidate
|
||||
if: ${{ !inputs.promote }}
|
||||
env:
|
||||
RELEASE_CANDIDATE_SPEC_PATH: ${{ runner.temp }}/release-candidate/spec.json
|
||||
run: |
|
||||
@@ -320,6 +330,7 @@ jobs:
|
||||
pnpm exec tools-release prepare-candidate
|
||||
|
||||
- name: Upload immutable candidate spec
|
||||
if: ${{ !inputs.promote }}
|
||||
uses: actions/upload-artifact@v7
|
||||
with:
|
||||
name: open-design-${{ inputs.exact_name }}-candidate-spec
|
||||
@@ -471,6 +482,7 @@ jobs:
|
||||
RELEASE_VERSION_LOCK_REQUIRED: "true"
|
||||
with:
|
||||
channel: ${{ inputs.exact_name }}
|
||||
handoff-enabled: ${{ steps.selection.outputs.build_count != '0' || !inputs.publish || !inputs.promote }}
|
||||
identity-digest: ${{ steps.execution.outputs.shared_closure_digest }}
|
||||
min-shell-version: ${{ steps.exact.outputs.closure_min_shell_version }}
|
||||
publish-enabled: "true"
|
||||
@@ -492,6 +504,7 @@ jobs:
|
||||
with:
|
||||
artifact-id: mac-arm64
|
||||
channel: ${{ inputs.exact_name }}
|
||||
handoff-enabled: ${{ steps.selection.outputs.build_count != '0' || !inputs.publish || !inputs.promote }}
|
||||
closure-identity-digest: ${{ steps.execution.outputs.mac_arm64_closure_digest }}
|
||||
platform: darwin-arm64
|
||||
public-origin: ${{ env.RELEASE_PUBLIC_ORIGIN }}
|
||||
@@ -507,6 +520,7 @@ jobs:
|
||||
with:
|
||||
artifact-id: mac-x64
|
||||
channel: ${{ inputs.exact_name }}
|
||||
handoff-enabled: ${{ steps.selection.outputs.build_count != '0' || !inputs.publish || !inputs.promote }}
|
||||
closure-identity-digest: ${{ steps.execution.outputs.mac_x64_closure_digest }}
|
||||
platform: darwin-x64
|
||||
public-origin: ${{ env.RELEASE_PUBLIC_ORIGIN }}
|
||||
@@ -522,6 +536,7 @@ jobs:
|
||||
with:
|
||||
artifact-id: win-x64
|
||||
channel: ${{ inputs.exact_name }}
|
||||
handoff-enabled: ${{ steps.selection.outputs.build_count != '0' || !inputs.publish || !inputs.promote }}
|
||||
closure-identity-digest: ${{ steps.execution.outputs.win_x64_closure_digest }}
|
||||
platform: win32-x64
|
||||
public-origin: ${{ env.RELEASE_PUBLIC_ORIGIN }}
|
||||
@@ -530,6 +545,64 @@ jobs:
|
||||
shell-plan-path: ${{ runner.temp }}/release-identity-profiles/win-x64.json
|
||||
target: win_x64
|
||||
|
||||
- name: Stage fully reused exact content
|
||||
id: hot_stage
|
||||
if: ${{ steps.selection.outputs.build_count == '0' && inputs.publish && inputs.promote }}
|
||||
uses: ./.github/actions/release/exact/stage
|
||||
env:
|
||||
BASE_VERSION: ${{ steps.exact.outputs.base_version }}
|
||||
RELEASE_ACTIVATE_LATEST: "false"
|
||||
RELEASE_CHANNEL: ${{ inputs.exact_name }}
|
||||
RELEASE_CLOSURE_DISTRIBUTION_MANIFEST_PATH: ${{ runner.temp }}/release-closure/closure-distribution.json
|
||||
RELEASE_CLOSURE_DISTRIBUTION_REQUIRED: "true"
|
||||
RELEASE_INSTALLATION_VERSION_MIN_BETA: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_BETA }}
|
||||
RELEASE_INSTALLATION_VERSION_MIN_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_STABLE }}
|
||||
RELEASE_INSTALLATION_VERSION_MIN_URL_BETA: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_BETA }}
|
||||
RELEASE_INSTALLATION_VERSION_MIN_URL_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_STABLE }}
|
||||
RELEASE_LATEST_CAS_REQUIRED: "true"
|
||||
RELEASE_LEGACY_INSTALLATION_MIGRATION_REQUIRED: "true"
|
||||
RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests
|
||||
RELEASE_PUBLIC_ORIGIN: ${{ env.RELEASE_PUBLIC_ORIGIN }}
|
||||
RELEASE_SHELL_REQUIRED: "true"
|
||||
RELEASE_STORAGE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_RELEASES_AK }}
|
||||
RELEASE_STORAGE_BUCKET: ${{ secrets.CLOUDFLARE_R2_RELEASES_BUCKET }}
|
||||
RELEASE_STORAGE_ENDPOINT: ${{ secrets.CLOUDFLARE_R2_RELEASES_URL }}
|
||||
RELEASE_STORAGE_REGION: auto
|
||||
RELEASE_STORAGE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_RELEASES_SK }}
|
||||
RELEASE_VERSION: ${{ steps.reservation.outputs.release_version || steps.exact.outputs.release_version }}
|
||||
RELEASE_VERSION_LOCK_KEY: ${{ steps.reservation.outputs.version_lock_key }}
|
||||
RELEASE_VERSION_LOCK_REQUIRED: "true"
|
||||
STATE_SOURCE: ${{ steps.reservation.outputs.state_source || steps.exact.outputs.state_source }}
|
||||
with:
|
||||
exact-name: ${{ inputs.exact_name }}
|
||||
release-version: ${{ steps.reservation.outputs.release_version || steps.exact.outputs.release_version }}
|
||||
|
||||
- name: Plan fully reused public acceptance
|
||||
id: hot_acceptance
|
||||
if: ${{ steps.hot_stage.outcome == 'success' }}
|
||||
uses: ./.github/actions/release/public-acceptance/plan
|
||||
with:
|
||||
acceptance-matrix: '{"include":[{"artifact_dir":"dmg","os":"mac","runner":"macos-14","target":"mac_arm64"},{"artifact_dir":"dmg","os":"mac","runner":"macos-15-intel","target":"mac_x64"},{"artifact_dir":"builder","os":"win","runner":"windows-latest","target":"win_x64"}]}'
|
||||
content-identities: ${{ format('{{"mac_arm64":{{"closure":"{0}","shell":"{1}"}},"mac_x64":{{"closure":"{2}","shell":"{3}"}},"win_x64":{{"closure":"{4}","shell":"{5}"}}}}', steps.execution.outputs.mac_arm64_closure_digest, steps.execution.outputs.mac_arm64_shell_digest, steps.execution.outputs.mac_x64_closure_digest, steps.execution.outputs.mac_x64_shell_digest, steps.execution.outputs.win_x64_closure_digest, steps.execution.outputs.win_x64_shell_digest) }}
|
||||
|
||||
- name: Activate fully reused exact release
|
||||
id: hot_activate
|
||||
if: ${{ steps.hot_acceptance.outputs.acceptance_count == '0' }}
|
||||
uses: ./.github/actions/release/public-acceptance/activate
|
||||
env:
|
||||
RELEASE_STORAGE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_RELEASES_AK }}
|
||||
RELEASE_STORAGE_BUCKET: ${{ secrets.CLOUDFLARE_R2_RELEASES_BUCKET }}
|
||||
RELEASE_STORAGE_ENDPOINT: ${{ secrets.CLOUDFLARE_R2_RELEASES_URL }}
|
||||
RELEASE_STORAGE_REGION: auto
|
||||
RELEASE_STORAGE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_RELEASES_SK }}
|
||||
with:
|
||||
channel: ${{ inputs.exact_name }}
|
||||
commit: ${{ env.BUILT_SHA }}
|
||||
metadata-url: ${{ steps.hot_stage.outputs.version_metadata_url }}
|
||||
public-origin: ${{ env.RELEASE_PUBLIC_ORIGIN }}
|
||||
release-version: ${{ steps.reservation.outputs.release_version || steps.exact.outputs.release_version }}
|
||||
reuse-json: ${{ steps.hot_acceptance.outputs.reuse_json }}
|
||||
|
||||
build:
|
||||
name: Build exact ${{ matrix.target }}
|
||||
needs: metadata
|
||||
@@ -766,16 +839,17 @@ jobs:
|
||||
always() &&
|
||||
!cancelled() &&
|
||||
needs.metadata.result == 'success' &&
|
||||
needs.metadata.outputs.hot_staged != 'true' &&
|
||||
(needs.build.result == 'success' || needs.build.result == 'skipped')
|
||||
}}
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
acceptance_latest_url: ${{ steps.acceptance_feed.outputs.latest_url }}
|
||||
release_state: ${{ steps.distribute.outputs.release_state }}
|
||||
version_metadata_url: ${{ steps.distribute.outputs.version_metadata_url }}
|
||||
mac_arm64_url: ${{ steps.distribute.outputs.mac_arm64_url }}
|
||||
win_x64_url: ${{ steps.distribute.outputs.win_x64_url }}
|
||||
mac_x64_url: ${{ steps.distribute.outputs.mac_x64_url }}
|
||||
acceptance_latest_url: ${{ steps.staged.outputs.acceptance_latest_url }}
|
||||
release_state: ${{ steps.staged.outputs.release_state }}
|
||||
version_metadata_url: ${{ steps.staged.outputs.version_metadata_url }}
|
||||
mac_arm64_url: ${{ steps.staged.outputs.mac_arm64_url }}
|
||||
win_x64_url: ${{ steps.staged.outputs.win_x64_url }}
|
||||
mac_x64_url: ${{ steps.staged.outputs.mac_x64_url }}
|
||||
mac_arm64_smoke_result: ${{ steps.platform_results.outputs.mac_arm64_smoke_result }}
|
||||
mac_x64_smoke_result: ${{ steps.platform_results.outputs.mac_x64_smoke_result }}
|
||||
win_x64_smoke_result: ${{ steps.platform_results.outputs.win_x64_smoke_result }}
|
||||
@@ -868,38 +942,12 @@ jobs:
|
||||
core.setOutput(`${target}_smoke_result`, String(result.smokeResult || ""));
|
||||
}
|
||||
|
||||
- name: Merge the sole version-wide Standalone graph
|
||||
run: |
|
||||
set -euo pipefail
|
||||
mkdir -p "$RUNNER_TEMP/release-closure"
|
||||
pnpm exec tools-release merge-closure-distribution \
|
||||
"$RUNNER_TEMP/release-closure/shared/shared-contribution.json" \
|
||||
"$RUNNER_TEMP/release-closure/targets/darwin-arm64/target-contribution.json" \
|
||||
"$RUNNER_TEMP/release-closure/targets/darwin-x64/target-contribution.json" \
|
||||
"$RUNNER_TEMP/release-closure/targets/win32-x64/target-contribution.json" \
|
||||
--output "$RUNNER_TEMP/release-closure/closure-distribution.json"
|
||||
|
||||
- name: Accept the N-1 Shell preflight boundary
|
||||
run: |
|
||||
pnpm exec tools-release verify-closure-preflight \
|
||||
--channel "${{ inputs.exact_name }}" \
|
||||
--manifest "$RUNNER_TEMP/release-closure/closure-distribution.json" \
|
||||
--release-version "${{ needs.metadata.outputs.release_version }}"
|
||||
|
||||
- name: Distribute staged exact metadata
|
||||
id: distribute
|
||||
uses: ./.github/actions/release/publish-metadata
|
||||
- name: Stage exact release content
|
||||
id: staged
|
||||
uses: ./.github/actions/release/exact/stage
|
||||
with:
|
||||
enable_mac_arm64: true
|
||||
enable_mac_x64: true
|
||||
enable_win_x64: true
|
||||
# Replayed and runner-executed targets both reach this job only after
|
||||
# their manifests/contributions/results exist. An empty dynamic matrix
|
||||
# reports the build job as skipped, which is execution topology rather
|
||||
# than a platform outcome.
|
||||
mac_arm64_result: success
|
||||
mac_x64_result: success
|
||||
win_x64_result: success
|
||||
exact-name: ${{ inputs.exact_name }}
|
||||
release-version: ${{ needs.metadata.outputs.release_version }}
|
||||
env:
|
||||
BASE_VERSION: ${{ needs.metadata.outputs.base_version }}
|
||||
RELEASE_ACTIVATE_LATEST: "false"
|
||||
@@ -925,23 +973,6 @@ jobs:
|
||||
RELEASE_VERSION: ${{ needs.metadata.outputs.release_version }}
|
||||
STATE_SOURCE: ${{ needs.metadata.outputs.state_source }}
|
||||
|
||||
- name: Stage run-scoped mutable acceptance feed
|
||||
id: acceptance_feed
|
||||
env:
|
||||
RELEASE_ACCEPTANCE_FEED_PREFIX: ${{ inputs.exact_name }}/acceptance/runs/${{ github.run_id }}-${{ github.run_attempt }}
|
||||
RELEASE_METADATA_PATH: ${{ runner.temp }}/release-metadata/metadata.json
|
||||
RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }}
|
||||
RELEASE_STORAGE_ACCESS_KEY_ID: ${{ secrets.CLOUDFLARE_R2_RELEASES_AK }}
|
||||
RELEASE_STORAGE_BUCKET: ${{ secrets.CLOUDFLARE_R2_RELEASES_BUCKET }}
|
||||
RELEASE_STORAGE_ENDPOINT: ${{ secrets.CLOUDFLARE_R2_RELEASES_URL }}
|
||||
RELEASE_STORAGE_REGION: auto
|
||||
RELEASE_STORAGE_SECRET_ACCESS_KEY: ${{ secrets.CLOUDFLARE_R2_RELEASES_SK }}
|
||||
RELEASE_VERSION: ${{ needs.metadata.outputs.release_version }}
|
||||
run: |
|
||||
set -euo pipefail
|
||||
pnpm exec tools-release stage-acceptance-feed
|
||||
origin="${RELEASE_PUBLIC_ORIGIN%/}"
|
||||
echo "latest_url=$origin/$RELEASE_ACCEPTANCE_FEED_PREFIX/latest/metadata.json" >> "$GITHUB_OUTPUT"
|
||||
|
||||
accept:
|
||||
name: Accept and activate exact release
|
||||
@@ -954,8 +985,9 @@ jobs:
|
||||
inputs.publish &&
|
||||
inputs.promote &&
|
||||
needs.metadata.result == 'success' &&
|
||||
needs.stage.result == 'success' &&
|
||||
needs.stage.outputs.release_state == 'complete'
|
||||
needs.metadata.outputs.hot_activated != 'true' &&
|
||||
(needs.stage.result == 'success' || needs.metadata.outputs.hot_staged == 'true') &&
|
||||
(needs.stage.outputs.release_state == 'complete' || needs.metadata.outputs.hot_release_state == 'complete')
|
||||
}}
|
||||
uses: ./.github/workflows/distribution-exact-accept.yml
|
||||
secrets: inherit
|
||||
@@ -963,8 +995,8 @@ jobs:
|
||||
commit: ${{ needs.metadata.outputs.commit }}
|
||||
content_identities: ${{ format('{{"mac_arm64":{{"closure":"{0}","shell":"{1}"}},"mac_x64":{{"closure":"{2}","shell":"{3}"}},"win_x64":{{"closure":"{4}","shell":"{5}"}}}}', needs.metadata.outputs.mac_arm64_closure_identity_digest, needs.metadata.outputs.mac_arm64_shell_identity_digest, needs.metadata.outputs.mac_x64_closure_identity_digest, needs.metadata.outputs.mac_x64_shell_identity_digest, needs.metadata.outputs.win_x64_closure_identity_digest, needs.metadata.outputs.win_x64_shell_identity_digest) }}
|
||||
exact_name: ${{ inputs.exact_name }}
|
||||
metadata_url: ${{ needs.stage.outputs.version_metadata_url }}
|
||||
mutable_metadata_url: ${{ needs.stage.outputs.acceptance_latest_url }}
|
||||
metadata_url: ${{ needs.metadata.outputs.hot_version_metadata_url || needs.stage.outputs.version_metadata_url }}
|
||||
mutable_metadata_url: ${{ needs.metadata.outputs.hot_acceptance_latest_url || needs.stage.outputs.acceptance_latest_url }}
|
||||
public_origin: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }}
|
||||
release_version: ${{ needs.metadata.outputs.release_version }}
|
||||
|
||||
@@ -979,27 +1011,28 @@ jobs:
|
||||
if: ${{ always() && !cancelled() }}
|
||||
uses: ./.github/workflows/release-notify.yml
|
||||
with:
|
||||
activation_completed_at: ${{ needs.metadata.outputs.hot_activation_completed_at || needs.accept.outputs.activation_completed_at }}
|
||||
actor: ${{ github.actor }}
|
||||
branch: ${{ needs.metadata.outputs.branch }}
|
||||
channel: ${{ inputs.exact_name }}
|
||||
commit: ${{ needs.metadata.outputs.commit }}
|
||||
event_name: ${{ github.event_name }}
|
||||
mac_arm64_smoke: ${{ needs.stage.outputs.mac_arm64_smoke_result }}
|
||||
mac_arm64_url: ${{ !inputs.publish && needs.candidate.outputs.mac_arm64_url || needs.stage.outputs.mac_arm64_url }}
|
||||
mac_x64_smoke: ${{ needs.stage.outputs.mac_x64_smoke_result }}
|
||||
mac_x64_url: ${{ !inputs.publish && needs.candidate.outputs.mac_x64_url || needs.stage.outputs.mac_x64_url }}
|
||||
metadata_url: ${{ !inputs.publish && needs.candidate.outputs.manifest_url || needs.stage.outputs.version_metadata_url }}
|
||||
mac_arm64_smoke: ${{ needs.metadata.outputs.hot_staged == 'true' && 'success' || needs.stage.outputs.mac_arm64_smoke_result }}
|
||||
mac_arm64_url: ${{ !inputs.publish && needs.candidate.outputs.mac_arm64_url || needs.metadata.outputs.hot_mac_arm64_url || needs.stage.outputs.mac_arm64_url }}
|
||||
mac_x64_smoke: ${{ needs.metadata.outputs.hot_staged == 'true' && 'success' || needs.stage.outputs.mac_x64_smoke_result }}
|
||||
mac_x64_url: ${{ !inputs.publish && needs.candidate.outputs.mac_x64_url || needs.metadata.outputs.hot_mac_x64_url || needs.stage.outputs.mac_x64_url }}
|
||||
metadata_url: ${{ !inputs.publish && needs.candidate.outputs.manifest_url || needs.metadata.outputs.hot_version_metadata_url || needs.stage.outputs.version_metadata_url }}
|
||||
notification_stream: ${{ inputs.notification_stream || 'release' }}
|
||||
previous_commit: ${{ needs.metadata.outputs.previous_commit }}
|
||||
release_mode: ${{ inputs.publish && (inputs.promote && 'promote' || 'publish') || 'candidate' }}
|
||||
release_result: ${{ needs.accept.result != 'skipped' && needs.accept.result || needs.stage.result != 'skipped' && needs.stage.result || needs.build.result }}
|
||||
release_state: ${{ needs.accept.result == 'success' && 'complete' || needs.stage.outputs.release_state || (needs.build.result == 'success' && 'partial' || 'failed') }}
|
||||
release_result: ${{ needs.metadata.outputs.hot_activated == 'true' && 'success' || needs.accept.result != 'skipped' && needs.accept.result || needs.stage.result != 'skipped' && needs.stage.result || needs.build.result }}
|
||||
release_state: ${{ needs.metadata.outputs.hot_activated == 'true' && 'complete' || needs.accept.result == 'success' && 'complete' || needs.metadata.outputs.hot_release_state || needs.stage.outputs.release_state || (needs.build.result == 'success' && 'partial' || 'failed') }}
|
||||
run_attempt: ${{ github.run_attempt }}
|
||||
run_number: ${{ github.run_number }}
|
||||
triggering_actor: ${{ github.triggering_actor }}
|
||||
version: ${{ needs.metadata.outputs.release_version }}
|
||||
win_x64_smoke: ${{ needs.stage.outputs.win_x64_smoke_result }}
|
||||
win_x64_url: ${{ !inputs.publish && needs.candidate.outputs.win_x64_url || needs.stage.outputs.win_x64_url }}
|
||||
win_x64_smoke: ${{ needs.metadata.outputs.hot_staged == 'true' && 'success' || needs.stage.outputs.win_x64_smoke_result }}
|
||||
win_x64_url: ${{ !inputs.publish && needs.candidate.outputs.win_x64_url || needs.metadata.outputs.hot_win_x64_url || needs.stage.outputs.win_x64_url }}
|
||||
workflow_name: ${{ github.workflow }}
|
||||
secrets:
|
||||
bot: ${{ secrets.RELEASE_FEISHU_BETA }}
|
||||
|
||||
@@ -3,6 +3,10 @@ name: release-notify
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
activation_completed_at:
|
||||
required: false
|
||||
type: string
|
||||
default: ""
|
||||
actor:
|
||||
required: false
|
||||
type: string
|
||||
@@ -121,6 +125,7 @@ jobs:
|
||||
id: post
|
||||
continue-on-error: true
|
||||
env:
|
||||
RELEASE_ACTIVATION_COMPLETED_AT: ${{ inputs.activation_completed_at }}
|
||||
RELEASE_ACTOR: ${{ inputs.actor }}
|
||||
RELEASE_BRANCH: ${{ inputs.branch }}
|
||||
RELEASE_CHANNEL: ${{ inputs.channel }}
|
||||
|
||||
@@ -183,6 +183,10 @@ const runnersScriptPath = join(workspaceRoot, ".github", "scripts", "runners.py"
|
||||
const notifyDailyFeishuWorkflowPath = join(workspaceRoot, ".github", "workflows", "notify-daily-feishu.yml");
|
||||
const notifyReleaseFeishuWorkflowPath = join(workspaceRoot, ".github", "workflows", "notify-release-feishu.yml");
|
||||
const releaseNotifyWorkflowPath = join(workspaceRoot, ".github", "workflows", "release-notify.yml");
|
||||
const exactStageActionPath = join(workspaceRoot, ".github", "actions", "release", "exact", "stage", "action.yml");
|
||||
const publicAcceptancePlanActionPath = join(workspaceRoot, ".github", "actions", "release", "public-acceptance", "plan", "action.yml");
|
||||
const publicAcceptanceActivateActionPath = join(workspaceRoot, ".github", "actions", "release", "public-acceptance", "activate", "action.yml");
|
||||
const publicAcceptanceExecuteActionPath = join(workspaceRoot, ".github", "actions", "release", "public-acceptance", "execute", "action.yml");
|
||||
const cutReleaseWorkflowPath = join(workspaceRoot, ".github", "workflows", "cut-release.yml");
|
||||
const cutPatchReleaseWorkflowPath = join(workspaceRoot, ".github", "workflows", "cut-patch-release.yml");
|
||||
const feishuCardScriptPath = join(workspaceRoot, ".github", "scripts", "release_notification.ts");
|
||||
@@ -1939,6 +1943,7 @@ process.stdin.on("end", () => {
|
||||
winAction,
|
||||
betaMacAction,
|
||||
betaWinAction,
|
||||
publicAcceptanceExecution,
|
||||
] = await Promise.all([
|
||||
readReleaseWorkflow(releaseStableWorkflowPath, distributionStableWorkflowPath),
|
||||
readFile(releaseStableScriptPath, "utf8"),
|
||||
@@ -1948,6 +1953,7 @@ process.stdin.on("end", () => {
|
||||
readFile(winDistributionActionPath, "utf8"),
|
||||
readFile(betaMacDistributionActionPath, "utf8"),
|
||||
readFile(betaWinDistributionActionPath, "utf8"),
|
||||
readFile(publicAcceptanceExecuteActionPath, "utf8"),
|
||||
]);
|
||||
|
||||
expect(releaseStableScript).toContain('mac: releaseNamespace(channel, "mac"),');
|
||||
@@ -2020,7 +2026,7 @@ process.stdin.on("end", () => {
|
||||
expect(releaseBetaWorkflow).toContain("steps.mac_finish.outputs.smoke_result || steps.win_finish.outputs.smoke_result");
|
||||
expect(releaseBetaWorkflow).toContain("steps.mac_prepare.outputs.candidate_manifest_url || steps.win_prepare.outputs.candidate_manifest_url");
|
||||
|
||||
expectWindowsUpdaterSmokeContract(`${releaseBetaWorkflow}\n${betaWinAction}`, "beta");
|
||||
expectWindowsUpdaterSmokeContract(`${releaseBetaWorkflow}\n${betaWinAction}\n${publicAcceptanceExecution}`, "beta");
|
||||
expectWindowsUpdaterSmokeContract(`${releasePrereleaseWorkflow}\n${winAction}`, "prerelease");
|
||||
expectWindowsUpdaterSmokeContract(`${releaseStableWorkflow}\n${winAction}`, "stable");
|
||||
});
|
||||
@@ -2132,13 +2138,15 @@ process.stdin.on("end", () => {
|
||||
}
|
||||
});
|
||||
it("[P2] publishes release notes through one channel-neutral tools-release pipeline", async () => {
|
||||
const [betaWorkflow, prereleaseWorkflow, stableWorkflow, countedDistribution, metadataDistribution] = await Promise.all([
|
||||
const [betaWorkflowSource, prereleaseWorkflow, stableWorkflow, countedDistribution, metadataDistribution, exactStage] = await Promise.all([
|
||||
readReleaseWorkflow(releaseBetaWorkflowPath, distributionBetaWorkflowPath),
|
||||
readReleaseWorkflow(releasePrereleaseWorkflowPath, distributionPrereleaseWorkflowPath),
|
||||
readReleaseWorkflow(releaseStableWorkflowPath, distributionStableWorkflowPath),
|
||||
readFile(join(workspaceRoot, ".github", "actions", "release", "publish-counted", "action.yml"), "utf8"),
|
||||
readFile(join(workspaceRoot, ".github", "actions", "release", "publish-metadata", "action.yml"), "utf8"),
|
||||
readFile(exactStageActionPath, "utf8"),
|
||||
]);
|
||||
const betaWorkflow = `${betaWorkflowSource}\n${exactStage}`;
|
||||
|
||||
for (const workflow of [betaWorkflow, stableWorkflow, countedDistribution]) {
|
||||
expect(workflow).toContain("uses: ./.github/actions/release/publish-metadata");
|
||||
@@ -2422,11 +2430,15 @@ process.stdin.on("end", () => {
|
||||
});
|
||||
|
||||
it("[P1] keeps macOS and Windows public Closure binding and cold-start evidence symmetric", async () => {
|
||||
const [mac, win, distribution] = await Promise.all([
|
||||
const [mac, win, distributionWorkflow, acceptancePlan, acceptanceExecution, acceptanceActivation] = await Promise.all([
|
||||
readTypeScriptSourceGraph(packagedMacSpecRoot),
|
||||
readTypeScriptSourceGraph(packagedWinSpecRoot),
|
||||
readFile(join(workspaceRoot, ".github", "workflows", "distribution-exact-accept.yml"), "utf8"),
|
||||
readFile(publicAcceptancePlanActionPath, "utf8"),
|
||||
readFile(publicAcceptanceExecuteActionPath, "utf8"),
|
||||
readFile(publicAcceptanceActivateActionPath, "utf8"),
|
||||
]);
|
||||
const distribution = `${distributionWorkflow}\n${acceptancePlan}\n${acceptanceExecution}\n${acceptanceActivation}`;
|
||||
for (const [platform, spec] of [["mac", mac], ["win", win]] as const) {
|
||||
expect(spec, platform).toContain("readPackagedClosureBinding");
|
||||
expect(spec, platform).toContain("createPackagedColdStartObservation");
|
||||
@@ -2443,7 +2455,7 @@ process.stdin.on("end", () => {
|
||||
expect(distribution).toContain('"target":"mac_arm64"');
|
||||
expect(distribution).toContain('"target":"mac_x64"');
|
||||
expect(distribution).toContain('"target":"win_x64"');
|
||||
expect(distribution).toContain("Issue public ${{ matrix.target }} acceptance credential");
|
||||
expect(distribution).toContain("Issue public ${{ inputs.target }} acceptance credential");
|
||||
expect(distribution).not.toContain("lifecycle receipt");
|
||||
expect(distribution).not.toContain("workflow attest-public-target");
|
||||
});
|
||||
@@ -2950,14 +2962,16 @@ process.stdin.on("end", () => {
|
||||
});
|
||||
|
||||
it("keeps beta on the shared payload-aware metadata surface", async () => {
|
||||
const [releaseBetaWorkflow, platformPublishScript, publishMetadataScript, metadataDistribution, betaMacAction, betaWinAction] = await Promise.all([
|
||||
const [releaseBetaWorkflowSource, platformPublishScript, publishMetadataScript, metadataDistribution, betaMacAction, betaWinAction, exactStage] = await Promise.all([
|
||||
readReleaseWorkflow(releaseBetaWorkflowPath, distributionBetaWorkflowPath),
|
||||
readFile(releaseBetaPlatformPublishScriptPath, "utf8"),
|
||||
readFile(releasePublishMetadataScriptPath, "utf8"),
|
||||
readFile(join(workspaceRoot, ".github", "actions", "release", "publish-metadata", "action.yml"), "utf8"),
|
||||
readFile(betaMacDistributionActionPath, "utf8"),
|
||||
readFile(betaWinDistributionActionPath, "utf8"),
|
||||
readFile(exactStageActionPath, "utf8"),
|
||||
]);
|
||||
const releaseBetaWorkflow = `${releaseBetaWorkflowSource}\n${exactStage}`;
|
||||
|
||||
expect(betaMacAction).toContain("dmg-and-payload");
|
||||
expect(betaMacAction).toContain("tools-release publish-platform");
|
||||
@@ -2973,8 +2987,32 @@ process.stdin.on("end", () => {
|
||||
expect(publishMetadataScript).toContain("outputs[`${target}_${artifactName}_url`] = artifact.url");
|
||||
});
|
||||
|
||||
it("[P0] enters the single-runner exact transaction only when every reusable proof hits", async () => {
|
||||
const [workflow, acceptanceWorkflow, sharedClosure, targetProjection] = await Promise.all([
|
||||
readFile(releaseBetaWorkflowPath, "utf8"),
|
||||
readFile(join(workspaceRoot, ".github", "workflows", "distribution-exact-accept.yml"), "utf8"),
|
||||
readFile(join(workspaceRoot, ".github", "actions", "release", "closure", "shared", "action.yml"), "utf8"),
|
||||
readFile(join(workspaceRoot, ".github", "actions", "release", "platform", "project", "action.yml"), "utf8"),
|
||||
]);
|
||||
|
||||
expect(workflow).toContain("if: ${{ steps.selection.outputs.build_count == '0' && inputs.publish && inputs.promote }}");
|
||||
expect(workflow).toContain("if: ${{ steps.hot_acceptance.outputs.acceptance_count == '0' }}");
|
||||
expect(workflow).toContain("needs.metadata.outputs.hot_staged != 'true'");
|
||||
expect(workflow).toContain("needs.metadata.outputs.hot_activated != 'true'");
|
||||
expect(workflow.match(/uses: \.\/\.github\/actions\/release\/exact\/stage/gu)).toHaveLength(2);
|
||||
expect(workflow).toContain("uses: ./.github/actions/release/public-acceptance/plan");
|
||||
expect(workflow).toContain("uses: ./.github/actions/release/public-acceptance/activate");
|
||||
expect(acceptanceWorkflow).toContain("uses: ./.github/actions/release/public-acceptance/plan");
|
||||
expect(acceptanceWorkflow).toContain("uses: ./.github/actions/release/public-acceptance/activate");
|
||||
expect(workflow).toContain("handoff-enabled: ${{ steps.selection.outputs.build_count != '0' || !inputs.publish || !inputs.promote }}");
|
||||
expect(sharedClosure).toContain("if: ${{ inputs.handoff-enabled == 'true' }}");
|
||||
expect(targetProjection.match(/if: \$\{\{ inputs\.handoff-enabled == 'true' \}\}/gu)).toHaveLength(3);
|
||||
expect(workflow).toContain("Prepare immutable candidate identity\n id: candidate\n if: ${{ !inputs.promote }}");
|
||||
expect(workflow).toContain("Upload immutable candidate spec\n if: ${{ !inputs.promote }}");
|
||||
});
|
||||
|
||||
it("publishes one shared-plus-target Standalone graph in release-beta", async () => {
|
||||
const [workflow, betaMacAction, betaWinAction, sharedClosureAction, targetMacAction, targetWinAction, winSpec] = await Promise.all([
|
||||
const [workflow, betaMacAction, betaWinAction, sharedClosureAction, targetMacAction, targetWinAction, winSpec, exactStage, acceptanceExecution, acceptanceActivation] = await Promise.all([
|
||||
readReleaseWorkflow(releaseBetaWorkflowPath, distributionBetaWorkflowPath),
|
||||
readFile(betaMacDistributionActionPath, "utf8"),
|
||||
readFile(betaWinDistributionActionPath, "utf8"),
|
||||
@@ -2982,6 +3020,9 @@ process.stdin.on("end", () => {
|
||||
readFile(closureTargetMacActionPath, "utf8"),
|
||||
readFile(closureTargetWinActionPath, "utf8"),
|
||||
readTypeScriptSourceGraph(packagedWinSpecRoot),
|
||||
readFile(exactStageActionPath, "utf8"),
|
||||
readFile(publicAcceptanceExecuteActionPath, "utf8"),
|
||||
readFile(publicAcceptanceActivateActionPath, "utf8"),
|
||||
]);
|
||||
const sharedJob = sectionBetween(workflow, " metadata:", " build:");
|
||||
const buildJob = sectionBetween(workflow, " build:", " stage:");
|
||||
@@ -2991,7 +3032,10 @@ process.stdin.on("end", () => {
|
||||
" public_acceptance:",
|
||||
" activate:",
|
||||
);
|
||||
const publicAcceptanceSurface = `${publicAcceptanceJob}\n${acceptanceExecution}`;
|
||||
const activationJob = workflow.slice(workflow.indexOf("\n activate:"));
|
||||
const stageSurface = `${stageJob}\n${exactStage}`;
|
||||
const activationSurface = `${activationJob}\n${acceptanceActivation}`;
|
||||
|
||||
expect(workflow).not.toContain("CLOSURE_MIN_SHELL_VERSION: ${{ inputs.exact_name == 'beta'");
|
||||
expect(sharedJob).toContain("closure_min_shell_version: ${{ steps.exact.outputs.closure_min_shell_version }}");
|
||||
@@ -3088,13 +3132,13 @@ process.stdin.on("end", () => {
|
||||
expect(betaWinAction).toContain('RELEASE_CLOSURE_ENABLED: "false"');
|
||||
expect(betaWinAction).toContain('RELEASE_SHELL_ENABLED: "true"');
|
||||
expect(betaWinAction).toContain("RELEASE_SHELL_BUILD_JSON_PATH:");
|
||||
expect(stageJob).toContain("Merge the sole version-wide Standalone graph");
|
||||
expect(stageJob).toContain("tools-release merge-closure-distribution");
|
||||
expect(stageJob).toContain("RELEASE_CLOSURE_DISTRIBUTION_MANIFEST_PATH:");
|
||||
expect(stageJob).toContain('RELEASE_CLOSURE_DISTRIBUTION_REQUIRED: "true"');
|
||||
expect(stageJob).not.toContain("RELEASE_CLOSURE_REQUIRED:");
|
||||
expect(stageJob).toContain('RELEASE_SHELL_REQUIRED: "true"');
|
||||
expect(stageJob).toContain("mac_arm64_result: success");
|
||||
expect(stageSurface).toContain("Merge the sole version-wide Standalone graph");
|
||||
expect(stageSurface).toContain("tools-release merge-closure-distribution");
|
||||
expect(stageSurface).toContain("RELEASE_CLOSURE_DISTRIBUTION_MANIFEST_PATH:");
|
||||
expect(stageSurface).toContain('RELEASE_CLOSURE_DISTRIBUTION_REQUIRED: "true"');
|
||||
expect(stageSurface).not.toContain("RELEASE_CLOSURE_REQUIRED:");
|
||||
expect(stageSurface).toContain('RELEASE_SHELL_REQUIRED: "true"');
|
||||
expect(stageSurface).toContain("mac_arm64_result: success");
|
||||
expect(stageJob).toContain("needs.build.result == 'skipped'");
|
||||
expect(workflow).not.toContain("/beta/closure/");
|
||||
expect(workflow).not.toContain("OD_PACKAGED_E2E_CLOSURE_BUILD_JSON_PATH:");
|
||||
@@ -3107,22 +3151,22 @@ process.stdin.on("end", () => {
|
||||
expect(publicAcceptanceJob).toContain("runs-on: ${{ matrix.runner }}");
|
||||
expect(publicAcceptanceJob).toContain("matrix: ${{ fromJSON(needs.plan.outputs.acceptance_matrix) }}");
|
||||
expect(publicAcceptanceJob).toContain("OPEN_DESIGN_POSTINSTALL_LEVEL: release-smoke");
|
||||
expect(publicAcceptanceJob).toContain("tools-release prepare-public-acceptance");
|
||||
expect(publicAcceptanceJob).toContain("tools-release issue-public-acceptance");
|
||||
expect(publicAcceptanceJob).toContain("OD_PACKAGED_E2E_WIN_SMOKE_PROFILE: core");
|
||||
expect(publicAcceptanceJob).toContain("OD_PACKAGED_E2E_WIN_SMOKE_LANES: shell");
|
||||
expect(publicAcceptanceJob).toContain('OD_TOOLS_PACK_EMBEDDED_CONFIG_ONLY: "1"');
|
||||
expect(publicAcceptanceJob).toContain("OD_STANDALONE_METADATA_URL: ${{ inputs.mutable_metadata_url }}");
|
||||
expect(publicAcceptanceJob).not.toContain("OD_PACKAGED_CONFIG_PATH:");
|
||||
expect(publicAcceptanceJob).not.toContain("OD_PACKAGED_E2E_CLOSURE_BUILD_JSON_PATH");
|
||||
expect(publicAcceptanceSurface).toContain("tools-release prepare-public-acceptance");
|
||||
expect(publicAcceptanceSurface).toContain("tools-release issue-public-acceptance");
|
||||
expect(publicAcceptanceSurface).toContain("OD_PACKAGED_E2E_WIN_SMOKE_PROFILE: core");
|
||||
expect(publicAcceptanceSurface).toContain("OD_PACKAGED_E2E_WIN_SMOKE_LANES: shell");
|
||||
expect(publicAcceptanceSurface).toContain('OD_TOOLS_PACK_EMBEDDED_CONFIG_ONLY: "1"');
|
||||
expect(publicAcceptanceJob).toContain("mutable-metadata-url: ${{ inputs.mutable_metadata_url }}");
|
||||
expect(publicAcceptanceSurface).not.toContain("OD_PACKAGED_CONFIG_PATH:");
|
||||
expect(publicAcceptanceSurface).not.toContain("OD_PACKAGED_E2E_CLOSURE_BUILD_JSON_PATH");
|
||||
expect(publicAcceptanceJob).not.toContain("RELEASE_STORAGE_SECRET_ACCESS_KEY");
|
||||
expect(activationJob).toContain("needs.public_acceptance.result == 'success' || needs.public_acceptance.result == 'skipped'");
|
||||
expect(activationJob).not.toContain("tools-release workflow");
|
||||
expect(activationJob).toContain("tools-release activate-public-release");
|
||||
expect(activationJob).toContain("Activate accepted immutable exact metadata with CAS");
|
||||
expect(activationJob).toContain("Read back activated exact public feed");
|
||||
expect(activationJob).toContain("tools-release observe-public-feed");
|
||||
expect(activationJob).not.toContain("continue-on-error");
|
||||
expect(activationSurface).toContain("tools-release activate-public-release");
|
||||
expect(activationSurface).toContain("Activate accepted immutable exact metadata with CAS");
|
||||
expect(activationSurface).toContain("Read back activated exact public feed");
|
||||
expect(activationSurface).toContain("tools-release observe-public-feed");
|
||||
expect(activationSurface).not.toContain("continue-on-error");
|
||||
expect(winSpec).toContain("resolveNativeAcceptanceStandaloneMetadataUrl()");
|
||||
expect(winSpec).toContain("resolveNativeAcceptanceUpdateMetadataUrl()");
|
||||
expect(winSpec).toContain("${process.env.RELEASE_PUBLIC_ORIGIN}/${updateScenario.channel}/latest/metadata.json");
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
|
||||
function input(overrides: Partial<ReleaseNotificationInput> = {}): ReleaseNotificationInput {
|
||||
return {
|
||||
activationCompletedAt: "2026-08-17T03:47:30Z",
|
||||
actor: "alice",
|
||||
branch: "feat/standalone-closure",
|
||||
channel: "beta",
|
||||
@@ -138,10 +139,13 @@ describe("release Feishu notification", () => {
|
||||
coldStarts: [],
|
||||
execution: expect.objectContaining({
|
||||
durationMs: expect.any(Number),
|
||||
observedAtMs: expect.any(Number),
|
||||
pullRequest: {
|
||||
number: 6956,
|
||||
url: "https://github.com/nexu-io/open-design/pull/6956",
|
||||
},
|
||||
queueDurationMs: 0,
|
||||
runStartedAtMs: expect.any(Number),
|
||||
}),
|
||||
failures: [],
|
||||
warnings: [],
|
||||
@@ -150,14 +154,14 @@ describe("release Feishu notification", () => {
|
||||
expect(serialized).toContain("[0123456](https://github.com/nexu-io/open-design/commit/");
|
||||
expect(serialized).not.toContain("`0123456`");
|
||||
expect(serialized).not.toContain("渠道");
|
||||
expect(serialized).toContain("触发者");
|
||||
expect(serialized).toContain("触发");
|
||||
expect(serialized).toContain("[@alice](https://github.com/alice)");
|
||||
expect(serialized).toContain("手动");
|
||||
expect(serialized).toContain("publish=true · 晋升 latest");
|
||||
expect(serialized).toContain("release-beta #123");
|
||||
expect(serialized).toContain("关联 PR");
|
||||
expect(serialized).toContain("[#6956](https://github.com/nexu-io/open-design/pull/6956)");
|
||||
expect(serialized).toContain("耗时");
|
||||
expect(serialized).toContain("[PR #6956](https://github.com/nexu-io/open-design/pull/6956)");
|
||||
expect(serialized).toContain("发布");
|
||||
expect(serialized).toContain("通知");
|
||||
expect(serialized).not.toContain("Closure 冷启动");
|
||||
expect(serialized).not.toContain("hidden oldest change");
|
||||
expect(serialized).toContain("Mac Arm");
|
||||
|
||||
Reference in New Issue
Block a user