@@ -36,6 +36,7 @@ const releaseBetaSelfHostedWorkflowPath = join(workspaceRoot, ".github", "workfl
3636const releasePreviewWorkflowPath = join ( workspaceRoot , ".github" , "workflows" , "release-preview.yml" ) ;
3737const releasePrereleaseWorkflowPath = join ( workspaceRoot , ".github" , "workflows" , "release-prerelease.yml" ) ;
3838const releaseStableWorkflowPath = join ( workspaceRoot , ".github" , "workflows" , "release-stable.yml" ) ;
39+ const releaseStableNotesScriptPath = join ( workspaceRoot , ".github" , "scripts" , "release" , "github" , "stable-notes.sh" ) ;
3940const releasePreviewScriptPath = join ( workspaceRoot , "tools" , "release" , "src" , "metadata" , "prepare-preview.ts" ) ;
4041const releaseStableScriptPath = join ( workspaceRoot , "tools" , "release" , "src" , "metadata" , "prepare-stable.ts" ) ;
4142const releaseBetaScriptPath = join ( workspaceRoot , "tools" , "release" , "src" , "metadata" , "prepare-beta.ts" ) ;
@@ -1407,6 +1408,8 @@ process.stdin.on("end", () => {
14071408 expect ( workflow ) . toContain ( "default: metadata" ) ;
14081409 expect ( workflow ) . not . toContain ( "inputs.channel" ) ;
14091410 expect ( workflow ) . toContain ( "OPEN_DESIGN_RELEASE_DRY_RUN: ${{ inputs.dry_run == 'publish' && 'false' || inputs.dry_run }}" ) ;
1411+ expect ( workflow ) . toContain ( "RELEASE_PUBLIC_ORIGIN: ${{ vars.CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN }}" ) ;
1412+ expect ( workflow ) . toContain ( "run: bash .github/scripts/release/github/stable-notes.sh" ) ;
14101413 expect ( workflow ) . toContain ( "dry_run: ${{ steps.stable.outputs.dry_run }}" ) ;
14111414 expect ( workflow ) . toContain ( "dry_run_mode: ${{ steps.stable.outputs.dry_run_mode }}" ) ;
14121415 expect ( workflow ) . toContain ( "if: ${{ needs.metadata.outputs.run_prepublish_jobs == 'true' }}" ) ;
@@ -1420,6 +1423,43 @@ process.stdin.on("end", () => {
14201423 expect ( script ) . toContain ( 'setOutput("publish_side_effects_enabled", publishSideEffectsEnabled ? "true" : "false");' ) ;
14211424 } ) ;
14221425
1426+ it ( "[P2] writes stable release notes from the release public origin variable" , async ( ) => {
1427+ for ( const [ envName , origin ] of [
1428+ [ "RELEASE_PUBLIC_ORIGIN" , "https://releases.open-design.ai/current/" ] ,
1429+ [ "CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN" , "https://releases.open-design.ai/legacy/" ] ,
1430+ ] as const ) {
1431+ const runnerTemp = await mkdtemp ( join ( tmpdir ( ) , "od-stable-notes-" ) ) ;
1432+ const outputPath = join ( runnerTemp , "github-output.txt" ) ;
1433+
1434+ try {
1435+ await execFileAsync ( "bash" , [ releaseStableNotesScriptPath ] , {
1436+ cwd : workspaceRoot ,
1437+ env : {
1438+ ...process . env ,
1439+ BRANCH_NAME : "release/v0.13.0" ,
1440+ CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN : envName === "CLOUDFLARE_R2_RELEASES_PUBLIC_ORIGIN" ? origin : "" ,
1441+ GITHUB_OUTPUT : outputPath ,
1442+ GITHUB_REPOSITORY : "nexu-io/open-design" ,
1443+ GITHUB_SHA : "0123456789abcdef0123456789abcdef01234567" ,
1444+ RELEASE_CHANNEL : "stable" ,
1445+ RELEASE_PUBLIC_ORIGIN : envName === "RELEASE_PUBLIC_ORIGIN" ? origin : "" ,
1446+ RELEASE_SIGNED : "true" ,
1447+ RELEASE_VERSION : "0.13.0" ,
1448+ RUNNER_TEMP : runnerTemp ,
1449+ VERSION_TAG : "open-design-v0.13.0" ,
1450+ } ,
1451+ } ) ;
1452+
1453+ const outputs = parseGithubOutput ( await readFile ( outputPath , "utf8" ) ) ;
1454+ const notes = await readFile ( outputs . notes_file ?? "" , "utf8" ) ;
1455+ expect ( notes ) . toContain ( `R2 metadata: ${ origin . replace ( / \/ + $ / , "" ) } /stable/latest/metadata.json` ) ;
1456+ expect ( notes ) . toContain ( `E2E report: ${ origin . replace ( / \/ + $ / , "" ) } /stable/versions/0.13.0/report.zip` ) ;
1457+ } finally {
1458+ await rm ( runnerTemp , { force : true , recursive : true } ) ;
1459+ }
1460+ }
1461+ } ) ;
1462+
14231463 it ( "[P2] validates stable dry-run prerelease metadata from a release branch" , async ( ) => {
14241464 const baseVersion = await readPackagedVersion ( ) ;
14251465 const prereleaseVersion = `${ baseVersion } -prerelease.12` ;
0 commit comments