name: release-beta on: workflow_dispatch: inputs: enable_mac_arm64: description: "Build and publish macOS arm64 beta artifacts." required: true type: boolean default: true enable_win_x64: description: "Build and publish Windows x64 beta artifacts." required: true type: boolean default: true enable_mac_x64: description: "Build and publish macOS x64 beta artifacts." required: true type: boolean default: false enable_linux_x64: description: "Build and publish Linux x64 AppImage beta artifacts." required: true type: boolean default: false publish: description: "Publish beta assets and metadata." required: true type: boolean default: true force: description: "Allow a beta build whose base version is not greater than the current stable/beta feed." required: true type: boolean default: false release_version: description: "Optional beta version override. Empty resolves the next beta version from metadata." required: false type: string default: "" release_origin: description: "Release storage origin." required: true type: choice options: - cloudflare-r2 default: cloudflare-r2 release_public_origin: description: "Optional public release origin override." required: false type: string default: "" ref: description: "Optional git ref to build. Empty builds the dispatched ref." required: false type: string default: "" amr_profile: description: "Optional AMR profile baked into the build (e.g. feature-test to point the packaged app at that profile's AMR backend and enable the workspace-team transport). Empty leaves the default (prod)." required: false type: string default: "" mac_arm64_sign_mode: description: "macOS arm64 signing mode." required: true type: choice options: - "no" - "sign-only" - "notarize" default: "notarize" mac_arm64_smoke_mode: description: "macOS arm64 smoke coverage." required: true type: choice options: - skip - core - full default: core mac_arm64_target: description: "macOS arm64 build target." required: true type: choice options: - dmg - all default: dmg mac_arm64_update_metadata_url: description: "Optional external updater metadata URL for full macOS arm64 payload smoke." required: false type: string default: "" mac_arm64_update_target_version: description: "Optional external updater target version expected by full macOS arm64 payload smoke." required: false type: string default: "" mac_x64_sign_mode: description: "macOS x64 signing mode." required: true type: choice options: - "no" - "sign-only" - "notarize" default: "no" mac_x64_smoke_mode: description: "macOS x64 smoke coverage." required: true type: choice options: - skip - core - full default: skip mac_x64_target: description: "macOS x64 build target." required: true type: choice options: - dmg - all default: all win_x64_sign_mode: description: "Windows x64 signing mode." required: true type: choice options: - "off" - "on" default: "off" win_x64_smoke_mode: description: "Windows x64 smoke coverage." required: true type: choice options: - skip - core - full default: core win_x64_target: description: "Windows x64 build target." required: true type: choice options: - nsis - all - zip - dir default: all win_x64_update_metadata_url: description: "Optional external updater metadata URL for full Windows payload smoke." required: false type: string default: "" win_x64_update_target_version: description: "Optional external updater target version expected by full Windows payload smoke." required: false type: string default: "" linux_x64_smoke_mode: description: "Linux x64 smoke coverage." required: true type: choice options: - skip - core - full default: core workflow_call: inputs: enable_mac_arm64: required: false type: boolean default: true enable_win_x64: required: false type: boolean default: true enable_mac_x64: required: false type: boolean default: false enable_linux_x64: required: false type: boolean default: false publish: required: false type: boolean default: true force: required: false type: boolean default: false promote: description: "Promote this build to beta/latest after publishing versioned platform artifacts." required: false type: boolean default: true release_version: required: false type: string default: "" release_origin: required: false type: string default: cloudflare-r2 release_public_origin: required: false type: string default: "" ref: required: false type: string default: "" amr_profile: required: false type: string default: "" mac_arm64_sign_mode: required: false type: string default: notarize mac_arm64_smoke_mode: required: false type: string default: core mac_arm64_target: required: false type: string default: dmg mac_arm64_update_metadata_url: required: false type: string default: "" mac_arm64_update_target_version: required: false type: string default: "" mac_x64_sign_mode: required: false type: string default: "no" mac_x64_smoke_mode: required: false type: string default: skip mac_x64_target: required: false type: string default: all win_x64_sign_mode: required: false type: string default: "off" win_x64_smoke_mode: required: false type: string default: core win_x64_target: required: false type: string default: all win_x64_update_metadata_url: required: false type: string default: "" win_x64_update_target_version: required: false type: string default: "" linux_x64_smoke_mode: required: false type: string default: core outputs: beta_version: description: "The beta version that was built." value: ${{ jobs.metadata.outputs.beta_version }} branch: description: "The branch that was built." value: ${{ jobs.metadata.outputs.branch }} commit: description: "The commit SHA that was built." value: ${{ jobs.metadata.outputs.commit }} previous_commit: description: "Commit SHA of the previously published beta." value: ${{ jobs.metadata.outputs.previous_commit }} release_state: description: "complete | partial | failed." value: ${{ jobs.publish.outputs.release_state || (jobs.metadata.outputs.promote == 'false' && 'partial') }} version_metadata_url: description: "Public URL of this build's version metadata.json." value: ${{ jobs.publish.outputs.version_metadata_url }} mac_arm64_url: description: "macOS arm64 dmg download URL." value: ${{ jobs.publish.outputs.mac_arm64_url || jobs.build_mac_arm64.outputs.mac_arm64_url }} win_x64_url: description: "Windows x64 installer download URL." value: ${{ jobs.publish.outputs.win_x64_url || jobs.build_win_x64.outputs.win_x64_url }} mac_arm64_smoke_result: description: "macOS arm64 packaged smoke outcome; advisory to publication." value: ${{ jobs.build_mac_arm64.outputs.smoke_result }} win_x64_smoke_result: description: "Windows x64 packaged smoke outcome; advisory to publication." value: ${{ jobs.build_win_x64.outputs.smoke_result }} mac_x64_url: description: "macOS x64 dmg download URL." value: ${{ jobs.publish.outputs.mac_x64_url }} linux_x64_url: description: "Linux x64 AppImage download URL." value: ${{ jobs.publish.outputs.linux_x64_url }} permissions: actions: write contents: read concurrency: group: open-design-release-beta cancel-in-progress: false env: OPEN_DESIGN_TELEMETRY_RELAY_URL: ${{ vars.OPEN_DESIGN_TELEMETRY_RELAY_URL }} POSTHOG_KEY: ${{ inputs.publish && secrets.POSTHOG_KEY || '' }} POSTHOG_HOST: ${{ inputs.publish && vars.POSTHOG_HOST || '' }} POSTHOG_CLI_API_KEY: ${{ inputs.publish && secrets.POSTHOG_CLI_API_KEY || '' }} POSTHOG_CLI_PROJECT_ID: ${{ inputs.publish && vars.POSTHOG_CLI_PROJECT_ID || '' }} # Vela web console origin for the AMR profile this build targets. Held in a # per-profile repository secret instead of the source tree: the non-prod AMR # environments are internal deployments and this repository is public, so # neither the workflow nor the product code may name their hostnames. # # tools-pack bakes it into open-design-config.json and the packaged runtime # forwards it to the daemon as OD_VELA_WEB_URL, which is the second half of the # workspace-team gate (the first being the AMR profile allowlist). A profile # whose selected secret is not configured therefore ships with workspace-team # dormant rather than pointed at an unknown backend. An empty profile defaults # to prod and receives the prod origin, matching resolveAmrProfile. # # OD_VELA_WEB_URL preserves the build's startup profile. The three explicit # values are also baked into the package as a profile map, so the hidden # runtime environment switcher can move data AND console links together. # Secrets read here: VELA_WEB_URL_FEATURE_TEST, VELA_WEB_URL_TEST, # VELA_WEB_URL_PROD. OD_VELA_WEB_URL: ${{ inputs.amr_profile == 'feature-test' && secrets.VELA_WEB_URL_FEATURE_TEST || inputs.amr_profile == 'test' && secrets.VELA_WEB_URL_TEST || (inputs.amr_profile == 'prod' || inputs.amr_profile == '') && secrets.VELA_WEB_URL_PROD || '' }} OD_VELA_WEB_URL_FEATURE_TEST: ${{ secrets.VELA_WEB_URL_FEATURE_TEST }} OD_VELA_WEB_URL_TEST: ${{ secrets.VELA_WEB_URL_TEST }} OD_VELA_WEB_URL_PROD: ${{ secrets.VELA_WEB_URL_PROD }} RELEASE_BRANCH: ${{ inputs.ref != '' && inputs.ref || github.ref_name }} RELEASE_REPOSITORY: ${{ github.repository }} RELEASE_RUN_ATTEMPT: ${{ github.run_attempt }} RELEASE_RUN_ID: ${{ github.run_id }} RELEASE_WORKFLOW: ${{ github.workflow }} jobs: metadata: name: Prepare beta metadata if: github.repository == 'nexu-io/open-design' runs-on: ubuntu-latest env: RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} OPEN_DESIGN_BETA_METADATA_URL: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }}/beta/latest/metadata.json outputs: asset_version_suffix: ${{ steps.beta.outputs.asset_version_suffix }} base_version: ${{ steps.beta.outputs.base_version }} beta_version: ${{ inputs.release_version != '' && inputs.release_version || steps.beta.outputs.beta_version }} branch: ${{ steps.identity.outputs.branch }} commit: ${{ steps.identity.outputs.commit }} previous_commit: ${{ steps.prev.outputs.previous_commit }} promote: ${{ inputs.promote }} release_name: ${{ steps.beta.outputs.release_name }} state_source: ${{ steps.beta.outputs.state_source }} steps: - name: Checkout uses: actions/checkout@v6.0.2 with: ref: ${{ inputs.ref != '' && inputs.ref || github.ref }} fetch-depth: 0 - 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 - name: Install dependencies run: pnpm install --frozen-lockfile - name: Resolve built identity id: identity env: BUILD_REF: ${{ inputs.ref != '' && inputs.ref || github.ref_name }} run: | set -euo pipefail built_sha="$(git rev-parse HEAD)" echo "BUILT_SHA=$built_sha" >> "$GITHUB_ENV" { echo "branch=$BUILD_REF" echo "commit=$built_sha" } >> "$GITHUB_OUTPUT" - name: Validate shared beta publisher if: ${{ inputs.publish }} run: | set -euo pipefail built_sha="$(git rev-parse HEAD)" main_sha="$(git ls-remote origin refs/heads/main | awk '{print $1}')" if [ -z "$main_sha" ]; then echo "Could not resolve the current main commit; refusing shared beta publication." >&2 exit 1 fi if [ "$built_sha" != "$main_sha" ]; then echo "Shared beta publication is restricted to the current main commit ($main_sha); got $built_sha. Re-run this ref with publish=false for dogfood artifacts." >&2 exit 1 fi - name: Capture previous beta commit id: prev run: | set -euo pipefail prev="$(curl -fsSL "$OPEN_DESIGN_BETA_METADATA_URL" | jq -r '.github.commit // ""' 2>/dev/null || true)" echo "previous beta commit: ${prev:-}" echo "previous_commit=$prev" >> "$GITHUB_OUTPUT" - name: Validate beta inputs run: | set -euo pipefail if [ "${{ inputs.release_origin }}" != "cloudflare-r2" ]; then echo "release-beta supports release_origin=cloudflare-r2 only" >&2 exit 1 fi if [ "${{ inputs.enable_mac_arm64 }}" != "true" ] && [ "${{ inputs.enable_win_x64 }}" != "true" ] && [ "${{ inputs.enable_mac_x64 }}" != "true" ] && [ "${{ inputs.enable_linux_x64 }}" != "true" ]; then echo "release-beta requires at least one target to be enabled" >&2 exit 1 fi if [ "${{ inputs.publish }}" = "true" ] && [ "${{ inputs.enable_win_x64 }}" = "true" ] && [ "${{ inputs.win_x64_target }}" != "nsis" ] && [ "${{ inputs.win_x64_target }}" != "all" ]; then echo "release-beta publish requires win_x64_target=nsis or all so the installer and updater feed are produced" >&2 exit 1 fi - name: Validate R2 release access if: ${{ inputs.publish }} env: GITHUB_SHA: ${{ env.BUILT_SHA }} R2_ACCESS_PROBE_NAME: release-beta RELEASE_CHANNEL: beta RELEASE_PUBLIC_ORIGIN: ${{ env.RELEASE_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 }} run: pnpm exec tools-release check-storage - name: Prepare beta release metadata id: beta env: GITHUB_SHA: ${{ env.BUILT_SHA }} GITHUB_REF_NAME: ${{ inputs.ref != '' && inputs.ref || github.ref_name }} OPEN_DESIGN_RELEASE_FORCE: ${{ inputs.force && '1' || '' }} run: pnpm exec tools-release prepare beta typecheck: name: Validate web types independently needs: metadata runs-on: ubuntu-latest timeout-minutes: 20 steps: - name: Checkout build commit uses: actions/checkout@v6.0.2 with: ref: ${{ needs.metadata.outputs.commit }} fetch-depth: 1 - 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 - name: Install dependencies run: pnpm install --frozen-lockfile - name: Check web source, tests and generated route types env: NODE_OPTIONS: --max-old-space-size=4096 run: pnpm --filter @open-design/web typecheck build_mac_arm64: name: Build beta mac_arm64 needs: metadata if: ${{ inputs.enable_mac_arm64 }} runs-on: macos-14 outputs: mac_arm64_url: ${{ steps.mac_arm64_platform_outputs.outputs.dmg_url }} smoke_result: ${{ steps.mac_arm64_smoke.outcome }} env: RELEASE_COMMIT: ${{ needs.metadata.outputs.commit }} steps: - name: Checkout uses: actions/checkout@v6.0.2 with: ref: ${{ needs.metadata.outputs.commit }} - 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 - name: Compute mac_arm64 tools-pack cache key id: mac_arm64_tools_pack_cache_key env: MAC_TOOLS_PACK_ORIGIN_KEY: ${{ hashFiles('package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'apps/daemon/**', 'apps/web/**', 'apps/desktop/**', 'apps/packaged/**', 'packages/agui-adapter/**', 'packages/contracts/**', 'packages/plugin-runtime/**', 'packages/sidecar-proto/**', 'packages/sidecar/**', 'packages/platform/**', 'tools/pack/bin/**', 'tools/pack/package.json', 'tools/pack/resources/**', 'tools/pack/src/**', 'tools/pack/tsconfig.json', 'assets/community-pets/**', 'assets/frames/**', 'craft/**', 'design-systems/**', 'design-templates/**', 'plugins/_official/**', 'plugins/registry/**', 'prompt-templates/**', 'skills/**', '.github/workflows/release-beta.yml', '.github/scripts/release/cache/mac.sh') }} run: | set -euo pipefail if [ -z "$MAC_TOOLS_PACK_ORIGIN_KEY" ]; then echo "mac_arm64 tools-pack cache origin key is empty" >&2 exit 1 fi prefix="tools-pack-mac-v1-beta-${RUNNER_OS}-arm64-" { echo "origin=$MAC_TOOLS_PACK_ORIGIN_KEY" echo "prefix=$prefix" echo "key=$prefix$MAC_TOOLS_PACK_ORIGIN_KEY" } >> "$GITHUB_OUTPUT" - name: Restore mac_arm64 tools-pack cache id: mac_arm64_tools_pack_cache_restore uses: actions/cache/restore@v5 continue-on-error: true with: path: ${{ runner.temp }}/tools-pack-cache key: ${{ steps.mac_arm64_tools_pack_cache_key.outputs.key }} restore-keys: | ${{ steps.mac_arm64_tools_pack_cache_key.outputs.prefix }} - name: Install dependencies run: pnpm install --frozen-lockfile - name: Prepare mac_arm64 signing certificate if: ${{ inputs.mac_arm64_sign_mode != 'no' }} env: APPLE_SIGNING_CERTIFICATE_BASE64: ${{ secrets.APPLE_SIGNING_CERTIFICATE_BASE64 }} APPLE_SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_SIGNING_CERTIFICATE_PASSWORD }} run: | set -euo pipefail cert_path="$RUNNER_TEMP/open-design-signing.p12" if ! printf '%s' "$APPLE_SIGNING_CERTIFICATE_BASE64" | base64 --decode > "$cert_path" 2>/dev/null; then printf '%s' "$APPLE_SIGNING_CERTIFICATE_BASE64" | base64 -D > "$cert_path" fi { echo "CSC_LINK=$cert_path" echo "CSC_KEY_PASSWORD=$APPLE_SIGNING_CERTIFICATE_PASSWORD" } >> "$GITHUB_ENV" - name: Build beta mac_arm64 id: mac_arm64_tools_pack_build continue-on-error: true env: APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} # Bake the AMR profile (tools-pack reads OPEN_DESIGN_AMR_PROFILE) so a # feature-test dispatch produces a packaged app that targets that # profile's AMR backend and enables the workspace-team transport. The # matching console origin arrives via the workflow-level # OD_VELA_WEB_URL. Empty = default (prod) — the normal beta pipeline is # unaffected. OPEN_DESIGN_AMR_PROFILE: ${{ inputs.amr_profile }} run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/release-build/mac_arm64" rm -rf "$RUNNER_TEMP/tools-pack" : > "$RUNNER_TEMP/release-build/mac_arm64/build.log" build_args=( exec tools-pack mac build --dir "$RUNNER_TEMP/tools-pack" --cache-dir "$RUNNER_TEMP/tools-pack-cache" --namespace release-beta --portable --app-version "${{ needs.metadata.outputs.beta_version }}" --mac-compression normal --to "${{ inputs.mac_arm64_target }}" --json --require-vela-cli ) case "${{ inputs.mac_arm64_sign_mode }}" in no) ;; sign-only) build_args+=(--signed) ;; notarize) build_args+=(--signed --notarize) ;; *) echo "unsupported mac_arm64_sign_mode: ${{ inputs.mac_arm64_sign_mode }}" >&2; exit 1 ;; esac if build_output="$(pnpm "${build_args[@]}" 2> >(tee -a "$RUNNER_TEMP/release-build/mac_arm64/build.log" >&2))"; then printf '%s\n' "$build_output" | tee "$RUNNER_TEMP/release-build/mac_arm64/build.json" else build_status=$? printf '%s\n' "$build_output" exit "$build_status" fi - name: Retry beta mac_arm64 without restored cache if: ${{ steps.mac_arm64_tools_pack_build.outcome == 'failure' }} env: APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} OPEN_DESIGN_AMR_PROFILE: ${{ inputs.amr_profile }} run: | set -euo pipefail rm -rf "$RUNNER_TEMP/tools-pack-cache" mkdir -p "$RUNNER_TEMP/release-build/mac_arm64" pnpm exec tools-pack mac cleanup --dir "$RUNNER_TEMP/tools-pack" --namespace release-beta --json : > "$RUNNER_TEMP/release-build/mac_arm64/build.log" build_args=( exec tools-pack mac build --dir "$RUNNER_TEMP/tools-pack" --cache-dir "$RUNNER_TEMP/tools-pack-cache" --namespace release-beta --portable --app-version "${{ needs.metadata.outputs.beta_version }}" --mac-compression normal --to "${{ inputs.mac_arm64_target }}" --json --require-vela-cli ) case "${{ inputs.mac_arm64_sign_mode }}" in no) ;; sign-only) build_args+=(--signed) ;; notarize) build_args+=(--signed --notarize) ;; *) echo "unsupported mac_arm64_sign_mode: ${{ inputs.mac_arm64_sign_mode }}" >&2; exit 1 ;; esac if build_output="$(pnpm "${build_args[@]}" 2> >(tee -a "$RUNNER_TEMP/release-build/mac_arm64/build.log" >&2))"; then printf '%s\n' "$build_output" | tee "$RUNNER_TEMP/release-build/mac_arm64/build.json" else build_status=$? printf '%s\n' "$build_output" exit "$build_status" fi - name: Upload mac_arm64 DMG for manual distribution # Only when NOT publishing to the release feed: this is the downloadable # artifact for a manual dispatch (e.g. a signed feature-test build handed # to teammates). The normal publish=true release pipeline is unchanged. if: ${{ !cancelled() && !inputs.publish }} uses: actions/upload-artifact@v7 with: name: open-design-beta-mac-arm64-dmg path: ${{ runner.temp }}/tools-pack/out/mac/namespaces/release-beta/**/*.dmg if-no-files-found: warn retention-days: 14 - name: Upload mac_arm64 dogfood build to release storage # Companion to the artifact step above, for publish=false only. A GitHub # artifact needs a logged-in teammate and a zip round-trip; this puts the # same DMG in R2 under dogfood/// so the link can be # handed over directly. It writes no channel metadata and no latest # pointer (enforced by the guard in tools/release/src/storage/dogfood.ts), # so it cannot change what an installed client sees as an available # update. The publish=true pipeline is untouched. if: ${{ !cancelled() && !inputs.publish }} continue-on-error: true env: DOGFOOD_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }} DOGFOOD_BUILD_JSON_KEYS: dmgPath DOGFOOD_BUILD_JSON_PATH: ${{ runner.temp }}/release-build/mac_arm64/build.json DOGFOOD_LABEL: macOS arm64 beta ${{ needs.metadata.outputs.beta_version }} DOGFOOD_VERSION: ${{ needs.metadata.outputs.beta_version }} 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 }} run: pnpm exec tools-release publish-dogfood - name: Delete failed mac_arm64 tools-pack cache if: ${{ steps.mac_arm64_tools_pack_build.outcome == 'failure' && steps.mac_arm64_tools_pack_cache_restore.outputs.cache-matched-key != '' }} continue-on-error: true env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail matched_key="${{ steps.mac_arm64_tools_pack_cache_restore.outputs.cache-matched-key }}" cache_ids="$(gh cache list --key "$matched_key" --limit 100 --json id,key,ref --jq ".[] | select(.key == \"$matched_key\") | .id")" count=0 while IFS= read -r cache_id; do if [ -n "$cache_id" ]; then gh cache delete "$cache_id" count=$((count + 1)) fi done <<< "$cache_ids" echo "deletedFailedCacheKey=$matched_key count=$count" - name: Build beta mac_arm64 update fixture id: mac_arm64_update_fixture if: ${{ inputs.mac_arm64_smoke_mode == 'full' && inputs.mac_arm64_update_metadata_url == '' && inputs.mac_arm64_update_target_version == '' }} run: | set -euo pipefail version="${{ needs.metadata.outputs.beta_version }}" if [[ "$version" =~ ^([0-9]+\.[0-9]+\.[0-9]+)-beta\.([0-9]+)$ ]]; then update_version="${BASH_REMATCH[1]}-beta.$((BASH_REMATCH[2] + 1))" else echo "full mac_arm64 smoke requires counted beta version x.y.z-beta.N; got $version" >&2 exit 1 fi update_build_json_path="$RUNNER_TEMP/release-work/mac_arm64/mac-tools-pack-update-build.json" mkdir -p "$(dirname "$update_build_json_path")" update_output="$(pnpm exec tools-pack mac build \ --dir "$RUNNER_TEMP/release-work/mac_arm64/tools-pack-update-fixture" \ --cache-dir "$RUNNER_TEMP/tools-pack-cache" \ --namespace release-beta \ --portable \ --app-version "$update_version" \ --mac-compression normal \ --to dmg \ --require-vela-cli \ --json)" printf '%s\n' "$update_output" > "$update_build_json_path" { echo "update_build_json_path=$update_build_json_path" echo "update_version=$update_version" } >> "$GITHUB_OUTPUT" - name: Smoke beta mac_arm64 packaged runtime id: mac_arm64_smoke if: ${{ inputs.mac_arm64_smoke_mode != 'skip' }} continue-on-error: true working-directory: e2e env: OD_PACKAGED_E2E_BUILD_JSON_PATH: ${{ runner.temp }}/release-build/mac_arm64/build.json OD_PACKAGED_E2E_BUILD_LOG_PATH: ${{ runner.temp }}/release-build/mac_arm64/build.log OD_PACKAGED_E2E_MAC: "1" OD_PACKAGED_E2E_MAC_UPDATE_BUILD_JSON_PATH: ${{ steps.mac_arm64_update_fixture.outputs.update_build_json_path }} OD_PACKAGED_E2E_MAC_UPDATE_FIXTURE: ${{ inputs.mac_arm64_smoke_mode == 'full' && inputs.mac_arm64_update_metadata_url == '' && inputs.mac_arm64_update_target_version == '' && 'tools-serve' || '' }} OD_PACKAGED_E2E_MAC_UPDATE_METADATA_URL: ${{ inputs.mac_arm64_update_metadata_url }} OD_PACKAGED_E2E_MAC_UPDATE_VERSION: ${{ inputs.mac_arm64_update_target_version != '' && inputs.mac_arm64_update_target_version || steps.mac_arm64_update_fixture.outputs.update_version }} OD_PACKAGED_E2E_MAC_SMOKE_PROFILE: ${{ inputs.mac_arm64_smoke_mode }} OD_PACKAGED_E2E_NAMESPACE: release-beta OD_PACKAGED_E2E_RELEASE_CHANNEL: beta OD_PACKAGED_E2E_RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} OD_PACKAGED_E2E_REPORT_DIR: ${{ runner.temp }}/release-report/mac_arm64 OD_PACKAGED_E2E_TOOLS_PACK_DIR: ${{ runner.temp }}/tools-pack run: pnpm exec tsx scripts/release-smoke.ts mac specs/mac.spec.ts - name: Write mac_arm64 release report if: ${{ always() }} env: BUILD_JSON_PATH: ${{ runner.temp }}/release-build/mac_arm64/build.json BUILD_LOG_PATH: ${{ runner.temp }}/release-build/mac_arm64/build.log RELEASE_BUILD_TARGET: ${{ inputs.mac_arm64_target }} RELEASE_CHANNEL: beta RELEASE_NAMESPACE: release-beta RELEASE_REPORT_DIR: ${{ runner.temp }}/release-report/mac_arm64 RELEASE_REPORT_JSON_PATH: ${{ runner.temp }}/release-report/mac_arm64/report.json RELEASE_REPORT_SUMMARY_PATH: ${{ runner.temp }}/release-report/mac_arm64/summary.md # The smoke step is continue-on-error, so this job reports success even # when the packaged gate is red. Feed the outcome to the report writer # so the failure gets a run annotation and a summary banner instead of # disappearing behind a green check. RELEASE_SMOKE_EXEMPT: "true" RELEASE_SMOKE_MODE: ${{ inputs.mac_arm64_smoke_mode }} RELEASE_SMOKE_OUTCOME: ${{ steps.mac_arm64_smoke.outcome }} RELEASE_TARGET: mac_arm64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} REPORT_TITLE: mac_arm64 beta build run: pnpm exec tools-release write-report - name: Publish mac_arm64 report summary if: ${{ always() }} run: cat "${{ runner.temp }}/release-report/mac_arm64/summary.md" >> "$GITHUB_STEP_SUMMARY" - name: Prune mac_arm64 tools-pack cache continue-on-error: true run: bash .github/scripts/release/cache/mac.sh - name: Save mac_arm64 tools-pack cache if: ${{ success() && (steps.mac_arm64_tools_pack_cache_restore.outputs.cache-hit != 'true' || steps.mac_arm64_tools_pack_build.outcome == 'failure') }} uses: actions/cache/save@v5 continue-on-error: true with: path: ${{ runner.temp }}/tools-pack-cache key: ${{ steps.mac_arm64_tools_pack_cache_key.outputs.key }} - name: Retain recent mac_arm64 tools-pack caches if: ${{ success() }} continue-on-error: true env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail prefix="${{ steps.mac_arm64_tools_pack_cache_key.outputs.prefix }}" keep=1 cache_ids="$(gh cache list --key "$prefix" --sort created_at --order desc --limit 100 --json id,key,createdAt --jq ".[$keep:] | .[].id")" count=0 while IFS= read -r cache_id; do if [ -n "$cache_id" ]; then gh cache delete "$cache_id" count=$((count + 1)) fi done <<< "$cache_ids" echo "actionsCachePrefix=$prefix deleted=$count" - name: Prepare mac_arm64 assets if: ${{ inputs.publish }} env: RELEASE_ARTIFACT_MODE: dmg-and-payload RELEASE_ASSET_SUFFIX: .signed RELEASE_ASSETS_DIR: ${{ runner.temp }}/release-assets/mac_arm64 RELEASE_CHANNEL: beta RELEASE_NAMESPACE: release-beta RELEASE_NOTES: OpenDesign beta ${{ needs.metadata.outputs.beta_version }}.signed RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_TARGET: mac_arm64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} TOOLS_PACK_DIR: ${{ runner.temp }}/tools-pack run: bash tools/release/scripts/prepare-platform-assets.sh - name: Publish mac_arm64 platform if: ${{ inputs.publish }} env: RELEASE_ASSET_SUFFIX: .signed RELEASE_ASSETS_DIR: ${{ runner.temp }}/release-assets/mac_arm64 RELEASE_ARTIFACT_MODE: dmg-and-payload RELEASE_CHANNEL: beta RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-platform-outputs/mac_arm64.json RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_REPORT_DIR: ${{ runner.temp }}/release-report/mac_arm64 RELEASE_REPORT_ZIP_PATH: ${{ runner.temp }}/release-report/mac_arm64-report.zip RELEASE_SIGNED: "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_SUMMARY_PATH: ${{ runner.temp }}/release-platform-outputs/mac_arm64.md RELEASE_TARGET: mac_arm64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} run: pnpm exec tools-release publish-platform - name: Read mac_arm64 platform outputs id: mac_arm64_platform_outputs if: ${{ inputs.publish }} uses: actions/github-script@v8 with: script: | const fs = require("fs"); const outputs = JSON.parse(fs.readFileSync(`${process.env.RUNNER_TEMP}/release-platform-outputs/mac_arm64.json`, "utf8")); for (const [key, value] of Object.entries(outputs)) core.setOutput(key, String(value)); - name: Upload mac_arm64 publish manifest if: ${{ inputs.publish }} uses: actions/upload-artifact@v7 with: name: open-design-beta-mac-arm64-publish-manifest path: ${{ runner.temp }}/release-platform-manifests/mac_arm64.json if-no-files-found: error build_mac_x64: name: Build beta mac_x64 needs: metadata if: ${{ inputs.enable_mac_x64 }} runs-on: macos-15-intel env: RELEASE_COMMIT: ${{ needs.metadata.outputs.commit }} steps: - name: Checkout uses: actions/checkout@v6.0.2 with: ref: ${{ needs.metadata.outputs.commit }} - 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 - name: Compute mac_x64 tools-pack cache key id: mac_x64_tools_pack_cache_key env: MAC_TOOLS_PACK_ORIGIN_KEY: ${{ hashFiles('package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'apps/daemon/**', 'apps/web/**', 'apps/desktop/**', 'apps/packaged/**', 'packages/agui-adapter/**', 'packages/contracts/**', 'packages/plugin-runtime/**', 'packages/sidecar-proto/**', 'packages/sidecar/**', 'packages/platform/**', 'tools/pack/bin/**', 'tools/pack/package.json', 'tools/pack/resources/**', 'tools/pack/src/**', 'tools/pack/tsconfig.json', 'assets/community-pets/**', 'assets/frames/**', 'craft/**', 'design-systems/**', 'design-templates/**', 'plugins/_official/**', 'plugins/registry/**', 'prompt-templates/**', 'skills/**', '.github/workflows/release-beta.yml', '.github/scripts/release/cache/mac.sh') }} run: | set -euo pipefail if [ -z "$MAC_TOOLS_PACK_ORIGIN_KEY" ]; then echo "mac_x64 tools-pack cache origin key is empty" >&2 exit 1 fi prefix="tools-pack-mac-v1-beta-${RUNNER_OS}-x64-" { echo "origin=$MAC_TOOLS_PACK_ORIGIN_KEY" echo "prefix=$prefix" echo "key=$prefix$MAC_TOOLS_PACK_ORIGIN_KEY" } >> "$GITHUB_OUTPUT" - name: Restore mac_x64 tools-pack cache id: mac_x64_tools_pack_cache_restore uses: actions/cache/restore@v5 continue-on-error: true with: path: ${{ runner.temp }}/tools-pack-cache key: ${{ steps.mac_x64_tools_pack_cache_key.outputs.key }} restore-keys: | ${{ steps.mac_x64_tools_pack_cache_key.outputs.prefix }} - name: Install dependencies run: pnpm install --frozen-lockfile - name: Prepare mac_x64 signing certificate if: ${{ inputs.mac_x64_sign_mode != 'no' }} env: APPLE_SIGNING_CERTIFICATE_BASE64: ${{ secrets.APPLE_SIGNING_CERTIFICATE_BASE64 }} APPLE_SIGNING_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_SIGNING_CERTIFICATE_PASSWORD }} run: | set -euo pipefail cert_path="$RUNNER_TEMP/open-design-signing.p12" if ! printf '%s' "$APPLE_SIGNING_CERTIFICATE_BASE64" | base64 --decode > "$cert_path" 2>/dev/null; then printf '%s' "$APPLE_SIGNING_CERTIFICATE_BASE64" | base64 -D > "$cert_path" fi { echo "CSC_LINK=$cert_path" echo "CSC_KEY_PASSWORD=$APPLE_SIGNING_CERTIFICATE_PASSWORD" } >> "$GITHUB_ENV" - name: Build beta mac_x64 id: mac_x64_tools_pack_build continue-on-error: true env: APPLE_ID: ${{ secrets.APPLE_ID }} APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} run: | set -euo pipefail mkdir -p "$RUNNER_TEMP/release-build/mac_x64" rm -rf "$RUNNER_TEMP/tools-pack" : > "$RUNNER_TEMP/release-build/mac_x64/build.log" build_args=( exec tools-pack mac build --dir "$RUNNER_TEMP/tools-pack" --cache-dir "$RUNNER_TEMP/tools-pack-cache" --namespace release-beta-x64 --portable --app-version "${{ needs.metadata.outputs.beta_version }}" --mac-compression normal --to "${{ inputs.mac_x64_target }}" --json --require-vela-cli ) case "${{ inputs.mac_x64_sign_mode }}" in no) ;; sign-only) build_args+=(--signed) ;; notarize) build_args+=(--signed --notarize) ;; *) echo "unsupported mac_x64_sign_mode: ${{ inputs.mac_x64_sign_mode }}" >&2; exit 1 ;; esac if build_output="$(pnpm "${build_args[@]}" 2> >(tee -a "$RUNNER_TEMP/release-build/mac_x64/build.log" >&2))"; then printf '%s\n' "$build_output" | tee "$RUNNER_TEMP/release-build/mac_x64/build.json" else build_status=$? printf '%s\n' "$build_output" exit "$build_status" fi - name: Retry beta mac_x64 without restored cache if: ${{ steps.mac_x64_tools_pack_build.outcome == 'failure' }} run: | set -euo pipefail rm -rf "$RUNNER_TEMP/tools-pack-cache" mkdir -p "$RUNNER_TEMP/release-build/mac_x64" pnpm exec tools-pack mac cleanup --dir "$RUNNER_TEMP/tools-pack" --namespace release-beta-x64 --json : > "$RUNNER_TEMP/release-build/mac_x64/build.log" build_args=( exec tools-pack mac build --dir "$RUNNER_TEMP/tools-pack" --cache-dir "$RUNNER_TEMP/tools-pack-cache" --namespace release-beta-x64 --portable --app-version "${{ needs.metadata.outputs.beta_version }}" --mac-compression normal --to "${{ inputs.mac_x64_target }}" --json --require-vela-cli ) case "${{ inputs.mac_x64_sign_mode }}" in no) ;; sign-only) build_args+=(--signed) ;; notarize) build_args+=(--signed --notarize) ;; *) echo "unsupported mac_x64_sign_mode: ${{ inputs.mac_x64_sign_mode }}" >&2; exit 1 ;; esac if build_output="$(pnpm "${build_args[@]}" 2> >(tee -a "$RUNNER_TEMP/release-build/mac_x64/build.log" >&2))"; then printf '%s\n' "$build_output" | tee "$RUNNER_TEMP/release-build/mac_x64/build.json" else build_status=$? printf '%s\n' "$build_output" exit "$build_status" fi - name: Delete failed mac_x64 tools-pack cache if: ${{ steps.mac_x64_tools_pack_build.outcome == 'failure' && steps.mac_x64_tools_pack_cache_restore.outputs.cache-matched-key != '' }} continue-on-error: true env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail matched_key="${{ steps.mac_x64_tools_pack_cache_restore.outputs.cache-matched-key }}" cache_ids="$(gh cache list --key "$matched_key" --limit 100 --json id,key,ref --jq ".[] | select(.key == \"$matched_key\") | .id")" count=0 while IFS= read -r cache_id; do if [ -n "$cache_id" ]; then gh cache delete "$cache_id" count=$((count + 1)) fi done <<< "$cache_ids" echo "deletedFailedCacheKey=$matched_key count=$count" - name: Smoke beta mac_x64 packaged runtime if: ${{ inputs.mac_x64_smoke_mode != 'skip' }} working-directory: e2e env: OD_PACKAGED_E2E_BUILD_JSON_PATH: ${{ runner.temp }}/release-build/mac_x64/build.json OD_PACKAGED_E2E_BUILD_LOG_PATH: ${{ runner.temp }}/release-build/mac_x64/build.log OD_PACKAGED_E2E_MAC: "1" OD_PACKAGED_E2E_MAC_SMOKE_PROFILE: ${{ inputs.mac_x64_smoke_mode }} OD_PACKAGED_E2E_NAMESPACE: release-beta-x64 OD_PACKAGED_E2E_RELEASE_CHANNEL: beta OD_PACKAGED_E2E_RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} OD_PACKAGED_E2E_REPORT_DIR: ${{ runner.temp }}/release-report/mac_x64 OD_PACKAGED_E2E_TOOLS_PACK_DIR: ${{ runner.temp }}/tools-pack run: pnpm exec tsx scripts/release-smoke.ts mac specs/mac.spec.ts - name: Write mac_x64 release report if: ${{ always() }} env: BUILD_JSON_PATH: ${{ runner.temp }}/release-build/mac_x64/build.json BUILD_LOG_PATH: ${{ runner.temp }}/release-build/mac_x64/build.log RELEASE_BUILD_TARGET: ${{ inputs.mac_x64_target }} RELEASE_CHANNEL: beta RELEASE_NAMESPACE: release-beta-x64 RELEASE_REPORT_DIR: ${{ runner.temp }}/release-report/mac_x64 RELEASE_REPORT_JSON_PATH: ${{ runner.temp }}/release-report/mac_x64/report.json RELEASE_REPORT_SUMMARY_PATH: ${{ runner.temp }}/release-report/mac_x64/summary.md RELEASE_SMOKE_MODE: ${{ inputs.mac_x64_smoke_mode }} RELEASE_TARGET: mac_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} REPORT_TITLE: mac_x64 beta build run: pnpm exec tools-release write-report - name: Publish mac_x64 report summary if: ${{ always() }} run: cat "${{ runner.temp }}/release-report/mac_x64/summary.md" >> "$GITHUB_STEP_SUMMARY" - name: Prune mac_x64 tools-pack cache continue-on-error: true run: bash .github/scripts/release/cache/mac.sh - name: Save mac_x64 tools-pack cache if: ${{ success() && (steps.mac_x64_tools_pack_cache_restore.outputs.cache-hit != 'true' || steps.mac_x64_tools_pack_build.outcome == 'failure') }} uses: actions/cache/save@v5 continue-on-error: true with: path: ${{ runner.temp }}/tools-pack-cache key: ${{ steps.mac_x64_tools_pack_cache_key.outputs.key }} - name: Retain recent mac_x64 tools-pack caches if: ${{ success() }} continue-on-error: true env: GH_TOKEN: ${{ github.token }} run: | set -euo pipefail prefix="${{ steps.mac_x64_tools_pack_cache_key.outputs.prefix }}" keep=1 cache_ids="$(gh cache list --key "$prefix" --sort created_at --order desc --limit 100 --json id,key,createdAt --jq ".[$keep:] | .[].id")" count=0 while IFS= read -r cache_id; do if [ -n "$cache_id" ]; then gh cache delete "$cache_id" count=$((count + 1)) fi done <<< "$cache_ids" echo "actionsCachePrefix=$prefix deleted=$count" - name: Prepare mac_x64 assets if: ${{ inputs.publish }} env: RELEASE_ARTIFACT_MODE: ${{ inputs.mac_x64_target == 'all' && 'all' || 'dmg-and-payload' }} RELEASE_ASSET_SUFFIX: ${{ inputs.mac_x64_sign_mode != 'no' && '.signed' || '.unsigned' }} RELEASE_ASSETS_DIR: ${{ runner.temp }}/release-assets/mac_x64 RELEASE_CHANNEL: beta RELEASE_NAMESPACE: release-beta-x64 RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_TARGET: mac_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} TOOLS_PACK_DIR: ${{ runner.temp }}/tools-pack run: bash tools/release/scripts/prepare-platform-assets.sh - name: Publish mac_x64 platform if: ${{ inputs.publish }} env: RELEASE_ASSET_SUFFIX: ${{ inputs.mac_x64_sign_mode != 'no' && '.signed' || '.unsigned' }} RELEASE_ASSETS_DIR: ${{ runner.temp }}/release-assets/mac_x64 RELEASE_ARTIFACT_MODE: ${{ inputs.mac_x64_target == 'all' && 'all' || 'dmg-and-payload' }} RELEASE_CHANNEL: beta RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-platform-outputs/mac_x64.json RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_SIGNED: ${{ inputs.mac_x64_sign_mode != 'no' && 'true' || 'false' }} 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_TARGET: mac_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} run: pnpm exec tools-release publish-platform - name: Upload mac_x64 publish manifest if: ${{ inputs.publish }} uses: actions/upload-artifact@v7 with: name: open-design-beta-mac-x64-publish-manifest path: ${{ runner.temp }}/release-platform-manifests/mac_x64.json if-no-files-found: error build_win_x64: name: Build beta win_x64 needs: metadata if: ${{ inputs.enable_win_x64 }} runs-on: windows-latest outputs: smoke_result: ${{ steps.win_x64_smoke.outcome }} win_x64_url: ${{ steps.win_x64_platform_outputs.outputs.installer_url }} env: RELEASE_COMMIT: ${{ needs.metadata.outputs.commit }} steps: - name: Checkout uses: actions/checkout@v6.0.2 with: ref: ${{ needs.metadata.outputs.commit }} - 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 cache: pnpm cache-dependency-path: pnpm-lock.yaml - name: Compute Windows tools-pack cache key id: win_tools_pack_cache_key shell: pwsh env: WIN_TOOLS_PACK_ORIGIN_KEY: ${{ hashFiles('package.json', 'pnpm-lock.yaml', 'pnpm-workspace.yaml', 'apps/daemon/**', 'apps/web/**', 'apps/desktop/**', 'apps/packaged/**', 'packages/agui-adapter/**', 'packages/contracts/**', 'packages/plugin-runtime/**', 'packages/sidecar-proto/**', 'packages/sidecar/**', 'packages/platform/**', 'tools/pack/bin/**', 'tools/pack/package.json', 'tools/pack/resources/**', 'tools/pack/src/**', 'tools/pack/tsconfig.json', 'assets/community-pets/**', 'assets/frames/**', 'craft/**', 'design-systems/**', 'design-templates/**', 'plugins/_official/**', 'plugins/registry/**', 'prompt-templates/**', 'skills/**', '.github/workflows/release-beta.yml', '.github/scripts/release/cache/win.ps1', '.github/scripts/release/cache/windows.ts', '.github/actions/defer-pack-cache/action.yml') }} run: | if ([string]::IsNullOrWhiteSpace($env:WIN_TOOLS_PACK_ORIGIN_KEY)) { throw "Windows tools-pack cache origin key is empty" } $prefix = "tools-pack-win-v2-slim-beta-$env:RUNNER_OS-" "origin=$env:WIN_TOOLS_PACK_ORIGIN_KEY" | Out-File -FilePath $env:GITHUB_OUTPUT -Append "prefix=$prefix" | Out-File -FilePath $env:GITHUB_OUTPUT -Append "key=$prefix$env:WIN_TOOLS_PACK_ORIGIN_KEY" | Out-File -FilePath $env:GITHUB_OUTPUT -Append - name: Restore Windows tools-pack cache id: win_tools_pack_cache_restore uses: actions/cache/restore@v5 continue-on-error: true with: path: ${{ runner.temp }}/tools-pack-cache key: ${{ steps.win_tools_pack_cache_key.outputs.key }} restore-keys: | ${{ steps.win_tools_pack_cache_key.outputs.prefix }} - name: Install dependencies run: pnpm install --frozen-lockfile - name: Setup NSIS shell: pwsh run: | if ((Get-Command makensis.exe -ErrorAction SilentlyContinue) -or (Test-Path "C:\Program Files (x86)\NSIS\makensis.exe")) { exit 0 } choco install nsis -y --no-progress - name: Probe Windows signing capability id: sign_probe shell: pwsh run: .\.github\scripts\release\probe-win-signing.ps1 -SignMode "${{ inputs.win_x64_sign_mode }}" - name: Build beta win_x64 id: win_tools_pack_build continue-on-error: true shell: pwsh env: OD_BETA_WINDOWS_SIGNING_CERTIFICATE_FOUND: ${{ steps.sign_probe.outputs.certificate_found }} OD_BETA_WINDOWS_SIGNING_ENABLED: ${{ steps.sign_probe.outputs.enabled }} OD_BETA_WINDOWS_SIGNING_MODE: ${{ steps.sign_probe.outputs.mode }} OD_BETA_WINDOWS_SIGNING_PROBED: ${{ steps.sign_probe.outputs.probed }} OD_BETA_WINDOWS_SIGNING_REASON: ${{ steps.sign_probe.outputs.reason }} OD_BETA_WINDOWS_SIGNING_REQUESTED: ${{ steps.sign_probe.outputs.requested }} OD_BETA_WINDOWS_SIGNING_SIGNTOOL_FOUND: ${{ steps.sign_probe.outputs.signtool_found }} OD_BETA_WINDOWS_SIGNTOOL_PATH: ${{ steps.sign_probe.outputs.signtool_path }} OD_BETA_WINDOWS_SIGN_CERT_SHA1: ${{ steps.sign_probe.outputs.thumbprint }} OD_PACKAGED_E2E_WIN_UPDATE_METADATA_URL: ${{ inputs.win_x64_update_metadata_url }} OD_PACKAGED_E2E_WIN_UPDATE_VERSION: ${{ inputs.win_x64_update_target_version }} # Bake the AMR profile (tools-pack reads OPEN_DESIGN_AMR_PROFILE) so a # feature-test dispatch produces a packaged app that targets that # profile's AMR backend and enables the workspace-team transport. Empty # = default (prod) — the normal beta pipeline is unaffected. Mirrors the # mac_arm64 build step above; this was missing here, so every win_x64 # dogfood build silently fell back to prod and could not sign in to a # feature-test AMR environment. OPEN_DESIGN_AMR_PROFILE: ${{ inputs.amr_profile }} run: | $ErrorActionPreference = "Stop" New-Item -ItemType Directory -Force -Path "${{ runner.temp }}\release-build\win_x64" | Out-Null pnpm.cmd exec tools-pack win cleanup --dir "${{ runner.temp }}\tools-pack" --namespace release-beta-win --json $buildArgs = @("exec", "tools-pack", "win", "build", "--dir", "${{ runner.temp }}\tools-pack", "--cache-dir", "${{ runner.temp }}\tools-pack-cache", "--namespace", "release-beta-win", "--portable", "--app-version", "${{ needs.metadata.outputs.beta_version }}", "--to", "${{ inputs.win_x64_target }}", "--require-vela-cli", "--json") if ("${{ inputs.win_x64_sign_mode }}" -eq "on") { $buildArgs += "--signed" } $buildOutput = pnpm.cmd @buildArgs if ($LASTEXITCODE -ne 0) { throw "tools-pack win build failed with exit code $LASTEXITCODE" } $buildOutput | Set-Content -Path "${{ runner.temp }}\release-build\win_x64\build.json" -Encoding utf8 $build = $buildOutput | ConvertFrom-Json pnpm.cmd exec tools-pack win validate-payload --namespace release-beta-win --payload-path $build.payloadPath --expected-version "${{ needs.metadata.outputs.beta_version }}" --json - name: Retry beta win_x64 without restored cache id: win_tools_pack_build_retry if: ${{ steps.win_tools_pack_build.outcome == 'failure' }} shell: pwsh env: OPEN_DESIGN_AMR_PROFILE: ${{ inputs.amr_profile }} run: | $ErrorActionPreference = "Stop" Remove-Item -Recurse -Force -ErrorAction SilentlyContinue "${{ runner.temp }}\tools-pack-cache" New-Item -ItemType Directory -Force -Path "${{ runner.temp }}\release-build\win_x64" | Out-Null pnpm.cmd exec tools-pack win cleanup --dir "${{ runner.temp }}\tools-pack" --namespace release-beta-win --json $buildArgs = @("exec", "tools-pack", "win", "build", "--dir", "${{ runner.temp }}\tools-pack", "--cache-dir", "${{ runner.temp }}\tools-pack-cache", "--namespace", "release-beta-win", "--portable", "--app-version", "${{ needs.metadata.outputs.beta_version }}", "--to", "${{ inputs.win_x64_target }}", "--require-vela-cli", "--json") if ("${{ inputs.win_x64_sign_mode }}" -eq "on") { $buildArgs += "--signed" } $buildOutput = pnpm.cmd @buildArgs if ($LASTEXITCODE -ne 0) { throw "tools-pack win fallback build failed with exit code $LASTEXITCODE" } $buildOutput | Set-Content -Path "${{ runner.temp }}\release-build\win_x64\build.json" -Encoding utf8 $build = $buildOutput | ConvertFrom-Json pnpm.cmd exec tools-pack win validate-payload --namespace release-beta-win --payload-path $build.payloadPath --expected-version "${{ needs.metadata.outputs.beta_version }}" --json - name: Upload win_x64 installer for manual distribution # Only when NOT publishing to the release feed, mirroring the mac DMG # step. Before this existed a publish=false dispatch left the Windows job # with nothing retrievable at all, so a QA/dogfood build could not be # handed to a teammate without also publishing to the public feed. The # glob covers every win_x64_target: nsis produces the setup exe, zip the # portable zip, all both. The normal publish=true pipeline is unchanged. if: ${{ !cancelled() && !inputs.publish }} uses: actions/upload-artifact@v7 with: name: open-design-beta-win-x64-installer path: | ${{ runner.temp }}\tools-pack\out\win\namespaces\release-beta-win\builder\*-setup.exe ${{ runner.temp }}\tools-pack\out\win\namespaces\release-beta-win\builder\*-portable.zip if-no-files-found: warn retention-days: 14 - name: Upload win_x64 dogfood build to release storage # publish=false only. Artifact paths come from the build's own --json # output rather than a hardcoded layout, so whichever of installerPath / # portableZipPath the selected win_x64_target actually produced is what # gets uploaded. Writes under dogfood/// and nowhere # else; see the guard in tools/release/src/storage/dogfood.ts. if: ${{ !cancelled() && !inputs.publish }} continue-on-error: true env: DOGFOOD_BUILD_ID: ${{ github.run_id }}-${{ github.run_attempt }} DOGFOOD_BUILD_JSON_KEYS: installerPath,portableZipPath DOGFOOD_BUILD_JSON_PATH: ${{ runner.temp }}\release-build\win_x64\build.json DOGFOOD_LABEL: Windows x64 beta ${{ needs.metadata.outputs.beta_version }} DOGFOOD_VERSION: ${{ needs.metadata.outputs.beta_version }} 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 }} run: pnpm exec tools-release publish-dogfood - name: Delete failed Windows tools-pack cache if: ${{ steps.win_tools_pack_build.outcome == 'failure' && steps.win_tools_pack_cache_restore.outputs.cache-matched-key != '' }} shell: pwsh continue-on-error: true env: GH_TOKEN: ${{ github.token }} run: | $matchedKey = "${{ steps.win_tools_pack_cache_restore.outputs.cache-matched-key }}" $caches = @(gh cache list --key $matchedKey --limit 100 --json id,key,ref | ConvertFrom-Json | Where-Object { $_.key -eq $matchedKey }) foreach ($cache in $caches) { gh cache delete $cache.id } "deletedFailedCacheKey=$matchedKey count=$($caches.Count)" - name: Build beta win_x64 update fixture if: ${{ inputs.win_x64_smoke_mode == 'full' && inputs.win_x64_update_metadata_url == '' && inputs.win_x64_update_target_version == '' }} shell: pwsh run: | $ErrorActionPreference = "Stop" $match = [regex]::Match("${{ needs.metadata.outputs.beta_version }}", "^(?\d+\.\d+\.\d+)-beta\.(?\d+)$") if (-not $match.Success) { throw "full Windows smoke requires a counted beta version; got ${{ needs.metadata.outputs.beta_version }}" } $updateVersion = "{0}-beta.{1}" -f $match.Groups["base"].Value, ([int]$match.Groups["number"].Value + 1) $buildArgs = @("exec", "tools-pack", "win", "build", "--dir", "${{ runner.temp }}\release-work\win_x64\tools-pack-update-fixture", "--cache-dir", "${{ runner.temp }}\tools-pack-cache", "--namespace", "release-beta-win", "--app-version", $updateVersion, "--to", "nsis", "--require-vela-cli", "--json") if ("${{ inputs.win_x64_sign_mode }}" -eq "on") { $buildArgs += "--signed" } $updateOutput = pnpm.cmd @buildArgs if ($LASTEXITCODE -ne 0) { throw "tools-pack win update fixture failed with exit code $LASTEXITCODE" } $updateOutput | Set-Content -Path "${{ runner.temp }}\release-build\win_x64\windows-tools-pack-update-build.json" -Encoding utf8 $updateBuild = $updateOutput | ConvertFrom-Json pnpm.cmd exec tools-pack win validate-payload --namespace release-beta-win --payload-path $updateBuild.payloadPath --expected-version $updateVersion --json - name: Smoke beta win_x64 packaged runtime id: win_x64_smoke if: ${{ inputs.win_x64_smoke_mode != 'skip' }} continue-on-error: true working-directory: e2e env: OD_PACKAGED_E2E_BUILD_JSON_PATH: ${{ runner.temp }}\release-build\win_x64\build.json OD_PACKAGED_E2E_NAMESPACE: release-beta-win OD_PACKAGED_E2E_RELEASE_CHANNEL: beta OD_PACKAGED_E2E_RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} OD_PACKAGED_E2E_REPORT_DIR: ${{ runner.temp }}\release-report\win_x64 OD_PACKAGED_E2E_TOOLS_PACK_DIR: ${{ runner.temp }}\tools-pack OD_PACKAGED_E2E_WIN: "1" OD_PACKAGED_E2E_WIN_SMOKE_PROFILE: ${{ inputs.win_x64_smoke_mode }} OD_PACKAGED_E2E_WIN_UPDATE_FIXTURE: ${{ inputs.win_x64_smoke_mode == 'full' && inputs.win_x64_update_metadata_url == '' && inputs.win_x64_update_target_version == '' && 'tools-serve' || '' }} OD_PACKAGED_E2E_WIN_UPDATE_METADATA_URL: ${{ inputs.win_x64_update_metadata_url }} OD_PACKAGED_E2E_WIN_UPDATE_VERSION: ${{ inputs.win_x64_update_target_version }} run: pnpm exec tsx scripts/release-smoke.ts win specs/win.spec.ts - name: Write win_x64 release report if: ${{ always() }} env: BUILD_JSON_PATH: ${{ runner.temp }}\release-build\win_x64\build.json RELEASE_BUILD_TARGET: ${{ inputs.win_x64_target }} RELEASE_CHANNEL: beta RELEASE_NAMESPACE: release-beta-win RELEASE_REPORT_DIR: ${{ runner.temp }}\release-report\win_x64 RELEASE_REPORT_JSON_PATH: ${{ runner.temp }}\release-report\win_x64\report.json RELEASE_REPORT_SUMMARY_PATH: ${{ runner.temp }}\release-report\win_x64\summary.md # Same exemption as mac_arm64: keep the job green, but never let the # red be silent. RELEASE_SMOKE_EXEMPT: "true" RELEASE_SMOKE_MODE: ${{ inputs.win_x64_smoke_mode }} RELEASE_SMOKE_OUTCOME: ${{ steps.win_x64_smoke.outcome }} RELEASE_TARGET: win_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} REPORT_TITLE: win_x64 beta build run: pnpm exec tools-release write-report - name: Publish win_x64 report summary if: ${{ always() }} shell: pwsh run: Get-Content "${{ runner.temp }}\release-report\win_x64\summary.md" | Add-Content $env:GITHUB_STEP_SUMMARY - name: Prepare win_x64 assets if: ${{ inputs.publish }} shell: pwsh run: | tools\release\scripts\prepare-platform-assets.ps1 ` -ReleaseTarget win_x64 ` -ReleaseAssetsDir "${{ runner.temp }}\release-assets\win_x64" ` -BuildJsonPath "${{ runner.temp }}\release-build\win_x64\build.json" ` -ReleaseNamespace release-beta-win ` -ReleaseVersion "${{ needs.metadata.outputs.beta_version }}" ` -ReleaseAssetSuffix ".unsigned" ` -ReleaseChannel beta ` -ReleasePublicOrigin "${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }}" ` -IncludeZip $${{ inputs.win_x64_target == 'all' || inputs.win_x64_target == 'zip' }} - name: Publish win_x64 platform if: ${{ inputs.publish }} env: RELEASE_ASSET_SUFFIX: .unsigned RELEASE_ASSETS_DIR: ${{ runner.temp }}\release-assets\win_x64 RELEASE_CHANNEL: beta RELEASE_MANIFEST_DIR: ${{ runner.temp }}\release-platform-manifests RELEASE_OUTPUTS_PATH: ${{ runner.temp }}\release-platform-outputs\win_x64.json RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_REPORT_DIR: ${{ runner.temp }}\release-report\win_x64 WIN_INCLUDE_ZIP: ${{ inputs.win_x64_target == 'all' || inputs.win_x64_target == 'zip' }} RELEASE_SIGNED: "false" 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_TARGET: win_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} run: pnpm exec tools-release publish-platform - name: Read win_x64 platform outputs id: win_x64_platform_outputs if: ${{ inputs.publish }} uses: actions/github-script@v8 with: script: | const fs = require("fs"); const outputs = JSON.parse(fs.readFileSync(`${process.env.RUNNER_TEMP}/release-platform-outputs/win_x64.json`, "utf8")); for (const [key, value] of Object.entries(outputs)) core.setOutput(key, String(value)); - name: Upload win_x64 publish manifest if: ${{ inputs.publish }} uses: actions/upload-artifact@v7 with: name: open-design-beta-win-x64-publish-manifest path: ${{ runner.temp }}\release-platform-manifests\win_x64.json if-no-files-found: error # Cache persistence is optional and runs outside this release workflow. - name: Defer Windows tools-pack cache save if: ${{ success() && (steps.win_tools_pack_cache_restore.outputs.cache-hit != 'true' || steps.win_tools_pack_build.outcome == 'failure') }} continue-on-error: true uses: ./.github/actions/defer-pack-cache with: key: ${{ steps.win_tools_pack_cache_key.outputs.key }} prefix: ${{ steps.win_tools_pack_cache_key.outputs.prefix }} build_linux_x64: name: Build beta linux_x64 needs: metadata if: ${{ inputs.enable_linux_x64 }} runs-on: ubuntu-latest env: RELEASE_COMMIT: ${{ needs.metadata.outputs.commit }} steps: - name: Checkout uses: actions/checkout@v6.0.2 with: ref: ${{ needs.metadata.outputs.commit }} - 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 cache: pnpm cache-dependency-path: pnpm-lock.yaml - name: Install dependencies run: pnpm install --frozen-lockfile - name: Install Linux smoke dependencies if: ${{ inputs.linux_x64_smoke_mode != 'skip' }} run: | sudo apt-get update sudo apt-get install -y xvfb - name: Build beta linux_x64 env: BUILD_JSON_PATH: ${{ runner.temp }}/release-build/linux_x64/build.json BUILD_LOG_PATH: ${{ runner.temp }}/release-build/linux_x64/build.log RELEASE_BUILD_TARGET: appimage RELEASE_NAMESPACE: release-beta-linux RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-build/linux_x64/outputs.json RELEASE_REPORT_DIR: ${{ runner.temp }}/release-report/linux_x64 RELEASE_SMOKE_MODE: ${{ inputs.linux_x64_smoke_mode }} RELEASE_TARGET: linux_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} RELEASE_WORK_DIR: ${{ runner.temp }}/release-work/linux_x64 TOOLS_PACK_CACHE_DIR: ${{ runner.temp }}/tools-pack-cache TOOLS_PACK_DIR: ${{ runner.temp }}/tools-pack run: bash tools/release/scripts/build-platform.sh - name: Write linux_x64 release report if: ${{ always() }} env: BUILD_JSON_PATH: ${{ runner.temp }}/release-build/linux_x64/build.json BUILD_LOG_PATH: ${{ runner.temp }}/release-build/linux_x64/build.log RELEASE_BUILD_TARGET: appimage RELEASE_CHANNEL: beta RELEASE_NAMESPACE: release-beta-linux RELEASE_REPORT_DIR: ${{ runner.temp }}/release-report/linux_x64 RELEASE_REPORT_JSON_PATH: ${{ runner.temp }}/release-report/linux_x64/report.json RELEASE_REPORT_SUMMARY_PATH: ${{ runner.temp }}/release-report/linux_x64/summary.md RELEASE_SMOKE_MODE: ${{ inputs.linux_x64_smoke_mode }} RELEASE_TARGET: linux_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} REPORT_TITLE: linux_x64 beta build run: pnpm exec tools-release write-report - name: Publish linux_x64 report summary if: ${{ always() }} run: cat "${{ runner.temp }}/release-report/linux_x64/summary.md" >> "$GITHUB_STEP_SUMMARY" - name: Prepare linux_x64 assets if: ${{ inputs.publish }} env: RELEASE_ASSET_SUFFIX: .unsigned RELEASE_ASSETS_DIR: ${{ runner.temp }}/release-assets/linux_x64 RELEASE_CHANNEL: beta RELEASE_NAMESPACE: release-beta-linux RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_TARGET: linux_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} TOOLS_PACK_DIR: ${{ runner.temp }}/tools-pack run: bash tools/release/scripts/prepare-platform-assets.sh - name: Publish linux_x64 platform if: ${{ inputs.publish }} env: RELEASE_ASSET_SUFFIX: .unsigned RELEASE_ASSETS_DIR: ${{ runner.temp }}/release-assets/linux_x64 RELEASE_CHANNEL: beta RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-platform-outputs/linux_x64.json RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_REPORT_DIR: ${{ runner.temp }}/release-report/linux_x64 RELEASE_REPORT_ZIP_PATH: ${{ runner.temp }}/release-report/linux_x64-report.zip RELEASE_SIGNED: "false" 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_TARGET: linux_x64 RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} run: pnpm exec tools-release publish-platform - name: Upload linux_x64 publish manifest if: ${{ inputs.publish }} uses: actions/upload-artifact@v7 with: name: open-design-beta-linux-x64-publish-manifest path: ${{ runner.temp }}/release-platform-manifests/linux_x64.json if-no-files-found: error publish: name: Publish beta metadata needs: - metadata - build_mac_arm64 - build_mac_x64 - build_win_x64 - build_linux_x64 if: >- ${{ always() && !cancelled() && inputs.publish && inputs.promote && needs.metadata.result == 'success' && (inputs.enable_mac_arm64 || inputs.enable_win_x64 || inputs.enable_mac_x64 || inputs.enable_linux_x64) && (!inputs.enable_mac_arm64 || needs.build_mac_arm64.result == 'success') && (!inputs.enable_win_x64 || needs.build_win_x64.result == 'success') && (!inputs.enable_mac_x64 || needs.build_mac_x64.result == 'success') && (!inputs.enable_linux_x64 || needs.build_linux_x64.result == 'success') }} runs-on: ubuntu-latest outputs: release_state: ${{ steps.outputs.outputs.release_state }} version_metadata_url: ${{ steps.outputs.outputs.version_metadata_url }} mac_arm64_url: ${{ steps.outputs.outputs.mac_arm64_dmg_url }} win_x64_url: ${{ steps.outputs.outputs.win_x64_installer_url }} mac_x64_url: ${{ steps.outputs.outputs.mac_x64_dmg_url }} linux_x64_url: ${{ steps.outputs.outputs.linux_x64_appImage_url }} env: GITHUB_SHA: ${{ needs.metadata.outputs.commit }} RELEASE_COMMIT: ${{ needs.metadata.outputs.commit }} steps: - name: Checkout uses: actions/checkout@v6.0.2 with: ref: ${{ needs.metadata.outputs.commit }} - name: Download mac_arm64 publish manifest if: ${{ inputs.enable_mac_arm64 && needs.build_mac_arm64.result == 'success' }} uses: actions/download-artifact@v8 with: name: open-design-beta-mac-arm64-publish-manifest path: ${{ runner.temp }}/release-platform-manifests - name: Download mac_x64 publish manifest if: ${{ inputs.enable_mac_x64 && needs.build_mac_x64.result == 'success' }} uses: actions/download-artifact@v8 with: name: open-design-beta-mac-x64-publish-manifest path: ${{ runner.temp }}/release-platform-manifests - name: Download win_x64 publish manifest if: ${{ inputs.enable_win_x64 && needs.build_win_x64.result == 'success' }} uses: actions/download-artifact@v8 with: name: open-design-beta-win-x64-publish-manifest path: ${{ runner.temp }}/release-platform-manifests - name: Download linux_x64 publish manifest if: ${{ inputs.enable_linux_x64 && needs.build_linux_x64.result == 'success' }} uses: actions/download-artifact@v8 with: name: open-design-beta-linux-x64-publish-manifest path: ${{ runner.temp }}/release-platform-manifests - 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 - name: Install dependencies run: pnpm install --frozen-lockfile - name: Prepare and publish beta release notes env: RELEASE_CHANNEL: beta RELEASE_NOTE_MANIFEST_PATH: ${{ runner.temp }}/release-metadata/release-note-publication.json RELEASE_NOTE_PLAN_PATH: ${{ runner.temp }}/release-metadata/release-note-plan.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.beta_version }} run: | pnpm exec tools-release prepare-release-note pnpm exec tools-release publish-release-note pnpm exec tools-release verify-release-note - name: Publish beta metadata env: BASE_VERSION: ${{ needs.metadata.outputs.base_version }} ENABLE_LINUX_X64: ${{ inputs.enable_linux_x64 }} ENABLE_MAC_ARM64: ${{ inputs.enable_mac_arm64 }} ENABLE_MAC_X64: ${{ inputs.enable_mac_x64 }} ENABLE_WIN_X64: ${{ inputs.enable_win_x64 }} LINUX_X64_RESULT: ${{ needs.build_linux_x64.result }} MAC_ARM64_RESULT: ${{ needs.build_mac_arm64.result }} MAC_X64_RESULT: ${{ needs.build_mac_x64.result }} RELEASE_ASSET_SUFFIX: ${{ needs.metadata.outputs.asset_version_suffix }} RELEASE_CHANNEL: beta RELEASE_LAUNCHER_VERSION_MIN_BETA: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_BETA }} RELEASE_LAUNCHER_VERSION_MIN_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_STABLE }} RELEASE_LAUNCHER_VERSION_MIN_URL_BETA: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_BETA }} RELEASE_LAUNCHER_VERSION_MIN_URL_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_STABLE }} RELEASE_MANIFEST_DIR: ${{ runner.temp }}/release-platform-manifests RELEASE_METADATA_DIR: ${{ runner.temp }}/release-metadata RELEASE_NOTE_MANIFEST_PATH: ${{ runner.temp }}/release-metadata/release-note-publication.json RELEASE_OUTPUTS_PATH: ${{ runner.temp }}/release-metadata/outputs.json RELEASE_PUBLIC_ORIGIN: ${{ inputs.release_public_origin != '' && inputs.release_public_origin || vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }} RELEASE_SIGNED: "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: ${{ needs.metadata.outputs.beta_version }} STATE_SOURCE: ${{ needs.metadata.outputs.state_source }} WIN_X64_RESULT: ${{ needs.build_win_x64.result }} run: pnpm exec tools-release publish-metadata - name: Read metadata outputs id: outputs uses: actions/github-script@v8 with: script: | const fs = require("fs"); const outputs = JSON.parse(fs.readFileSync(`${process.env.RUNNER_TEMP}/release-metadata/outputs.json`, "utf8")); for (const [key, value] of Object.entries(outputs)) core.setOutput(key, String(value)); - name: Verify beta metadata env: ENABLE_LINUX_X64: ${{ inputs.enable_linux_x64 }} ENABLE_MAC_ARM64: ${{ inputs.enable_mac_arm64 }} ENABLE_MAC_X64: ${{ inputs.enable_mac_x64 }} ENABLE_WIN_X64: ${{ inputs.enable_win_x64 }} LINUX_X64_RESULT: ${{ needs.build_linux_x64.result }} MAC_ARM64_RESULT: ${{ needs.build_mac_arm64.result }} MAC_X64_RESULT: ${{ needs.build_mac_x64.result }} RELEASE_CHANNEL: beta RELEASE_LAUNCHER_VERSION_MIN_BETA: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_BETA }} RELEASE_LAUNCHER_VERSION_MIN_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_STABLE }} RELEASE_LAUNCHER_VERSION_MIN_URL_BETA: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_BETA }} RELEASE_LAUNCHER_VERSION_MIN_URL_STABLE: ${{ vars.RELEASE_LAUNCHER_VERSION_MIN_URL_STABLE }} RELEASE_METADATA_URL: ${{ steps.outputs.outputs.version_metadata_url }} RELEASE_NOTE_MANIFEST_PATH: ${{ runner.temp }}/release-metadata/release-note-publication.json RELEASE_VERSION: ${{ needs.metadata.outputs.beta_version }} WIN_X64_RESULT: ${{ needs.build_win_x64.result }} run: pnpm exec tools-release verify-metadata - name: Write beta metadata summary env: RELEASE_CHANNEL: beta RELEASE_METADATA_URL: ${{ steps.outputs.outputs.version_metadata_url }} RELEASE_SUMMARY_PATH: ${{ runner.temp }}/release-metadata/summary.md run: pnpm exec tools-release summary-metadata - name: Publish summary run: cat "${{ runner.temp }}/release-metadata/summary.md" >> "$GITHUB_STEP_SUMMARY" - name: Cleanup workflow artifacts if: ${{ success() && steps.outputs.outputs.release_state == 'complete' }} env: GH_TOKEN: ${{ github.token }} run: bash .github/scripts/release/github/cleanup-artifacts.sh