From 529b6383e848a3690f70d6bd418241d7e6678827 Mon Sep 17 00:00:00 2001 From: FernandoM33 Date: Tue, 25 Aug 2026 00:12:56 -0700 Subject: [PATCH] release: make future notes creator-first --- scripts/prepare-public-release.js | 46 +++++++++++++++++-------------- scripts/smoke-release-notes.js | 36 +++++++++++++++++++++++- 2 files changed, 60 insertions(+), 22 deletions(-) diff --git a/scripts/prepare-public-release.js b/scripts/prepare-public-release.js index 9587cf8..1b8363c 100644 --- a/scripts/prepare-public-release.js +++ b/scripts/prepare-public-release.js @@ -147,6 +147,7 @@ function publicManifest({ pkg, tag, commit, artifact, candidate, dmgAttestation function publicNotes(manifest, { changelogPath, publicationNotesRequired = false } = {}) { const artifact = manifest.artifact.filename; + const downloadUrl = `https://github.com/FernandoAbishai/ScriptCut/releases/download/${manifest.releaseTag}/${artifact}`; const curated = selectReleaseNotes({ releaseTag: manifest.releaseTag, changelogPath, @@ -155,15 +156,29 @@ function publicNotes(manifest, { changelogPath, publicationNotesRequired = false const dryRunLabel = curated.source === 'Unreleased' ? `> Dry-run / planned release-note content from \`CHANGELOG.md\` → \`Unreleased\`; it is not part of a published release history.\n\n` : ''; - return `# ScriptCut ${manifest.releaseTag} alpha + return `# ScriptCut ${manifest.releaseTag} -## What's changed +## Download + +[Download ScriptCut for macOS — Apple Silicon](${downloadUrl}) + +macOS Apple Silicon / arm64 · Public prerelease alpha · ad-hoc signed · not notarized + +## Install + +1. Download the DMG above. +2. Open it and move ScriptCut to Applications. +3. Launch ScriptCut. + +If macOS blocks the first launch of the official ScriptCut GitHub download, open **System Settings → Privacy & Security → Open Anyway**, confirm the macOS prompt, and launch ScriptCut normally. Do not use this approval path for random applications or downloads. + +## What's new ${dryRunLabel}${curated.markdown} ## ScriptCut alpha status -This is a public prerelease alpha for creator validation. It is provided from the official ScriptCut GitHub repository and uses an ad-hoc code signature for package integrity. +This is a public prerelease alpha for creator validation. It is provided from the official ScriptCut GitHub repository and uses an ad-hoc code signature for package integrity. It is not signed with Apple Developer ID and is not notarized by Apple. ## Supported platform @@ -174,18 +189,7 @@ macOS Apple Silicon (arm64) only. Intel, Windows, Linux, and browser builds are - A self-contained Electron application with portable Python ${manifest.runtime.pythonVersion} and the pinned core runtime. - Bundled FFmpeg and FFprobe for local export. - Baseline Whisper transcription code and a trusted model manifest. -- Optional capabilities may not be included in this build. - -## Install - -1. Open the official [ScriptCut Releases page](https://github.com/FernandoAbishai/ScriptCut/releases). -2. Download the Apple Silicon DMG for **${manifest.releaseTag}**. -3. Open the DMG and move or open ScriptCut as appropriate for the DMG layout. -4. Attempt to launch ScriptCut and select a video. - -## macOS first-launch notice - -This macOS build uses an ad-hoc code signature for package integrity, but it is not signed with Apple Developer ID and is not notarized by Apple. macOS may block the first launch because the app is not from an identified developer. If you obtained this DMG from the official ScriptCut GitHub release, open **System Settings → Privacy & Security → Open Anyway**, confirm the macOS prompt, and then open ScriptCut normally. Do not use this approval path for random applications or downloads. +- Optional capabilities may be absent from this build. ## Baseline transcription model behavior @@ -195,6 +199,12 @@ If the verified baseline model is not present, ScriptCut downloads and verifies WhisperX, NeMo/Parakeet, pyannote, DeepFilterNet, MediaPipe, OpenCV, MoviePy, and other optional stacks may not be bundled. The packaged baseline path remains the supported transcription path for this alpha. +## Known alpha limitations + +- The app uses an ad-hoc code signature but is not signed with Apple Developer ID or notarized, so the first launch requires the macOS approval path above. +- This release is a prerelease alpha; keep original media and project backups. +- Optional capabilities and some caption/export behavior depend on the packaged resources and current baseline support. + ## Verify download From the directory containing the downloaded files: @@ -222,12 +232,6 @@ gh attestation verify release-manifest.json \\ \`\`\` Attestation establishes build provenance; it does not prove that the software is free of bugs or vulnerabilities. Checksums establish integrity and do not make macOS treat this app as notarized. - -## Known alpha limitations - -- The app uses an ad-hoc code signature but is not signed with Apple Developer ID or notarized, so the first launch requires the macOS approval path above. -- This release is a prerelease alpha; keep original media and project backups. -- Optional capabilities and some caption/export behavior depend on the packaged resources and current baseline support. `; } diff --git a/scripts/smoke-release-notes.js b/scripts/smoke-release-notes.js index be9baa1..dcb1448 100644 --- a/scripts/smoke-release-notes.js +++ b/scripts/smoke-release-notes.js @@ -118,9 +118,43 @@ async function main() { changelogPath: plannedFixture, }); const notes = fs.readFileSync(path.join(result.outputDir, 'RELEASE_NOTES.md'), 'utf8'); - assert(notes.includes("## What's changed"), 'generated notes lack curated section'); + const downloadIndex = notes.indexOf('## Download'); + const installIndex = notes.indexOf('## Install'); + const whatsNewIndex = notes.indexOf("## What's new"); + const verifyIndex = notes.indexOf('## Verify download'); + const provenanceIndex = notes.indexOf('## Build provenance'); + const expectedDownloadUrl = `https://github.com/FernandoAbishai/ScriptCut/releases/download/${result.manifest.releaseTag}/${result.manifest.artifact.filename}`; + assert(notes.startsWith(`# ScriptCut ${result.manifest.releaseTag}\n\n## Download`), 'generated notes do not begin with creator download path'); + assert(downloadIndex >= 0, 'generated notes lack Download section'); + assert(installIndex >= 0, 'generated notes lack Install section'); + assert(whatsNewIndex >= 0, 'generated notes lack What\'s new section'); + assert(verifyIndex >= 0, 'generated notes lack verification section'); + assert(provenanceIndex >= 0, 'generated notes lack provenance section'); + assert(notes.includes(expectedDownloadUrl), 'generated notes lack exact direct DMG URL'); + assert(downloadIndex < installIndex, 'Download must precede Install'); + assert(installIndex < whatsNewIndex, 'Install must precede What\'s new'); + assert(whatsNewIndex < verifyIndex, 'What\'s new must precede verification'); + assert(whatsNewIndex < provenanceIndex, 'What\'s new must precede provenance'); + assert(notes.includes("## What's new"), 'generated notes lack curated section'); assert(notes.includes('Dry-run / planned release-note content'), 'Unreleased dry-run content is not labeled'); assert(notes.includes('Planned.'), 'generated notes omit Unreleased content'); + assert(!notes.includes('/releases/latest'), 'generated notes use a moving latest-release URL'); + assert(notes.includes('Privacy & Security → Open Anyway'), 'generated notes omit Open Anyway guidance'); + assert(notes.includes('shasum -a 256 -c SHA256SUMS.txt'), 'generated notes omit checksum verification command'); + assert(notes.includes('gh attestation verify'), 'generated notes omit attestation verification command'); + const exactChangelog = writeChangelog(fixtureRoot, '# Changelog\n\n## Unreleased\n\n- Planned.\n\n## v0.1.0-alpha.4\n\n- Exact selected.\n'); + const publicationResult = await preparePublicRelease({ + tag: 'v0.1.0-alpha.4', + existingTags: ['v0.1.0-alpha.1', 'v0.1.0-alpha.2', 'v0.1.0-alpha.3'], + candidateDir, + outputDir: path.join(fixtureRoot, 'publication-with-exact-notes'), + commit: 'a'.repeat(40), + changelogPath: exactChangelog, + publicationNotesRequired: true, + }); + const publicationNotes = fs.readFileSync(path.join(publicationResult.outputDir, 'RELEASE_NOTES.md'), 'utf8'); + assert(publicationNotes.includes('Exact selected.'), 'generated publication notes omit the exact CHANGELOG section'); + assert(!publicationNotes.includes('Planned.'), 'generated publication notes used Unreleased despite an exact section'); await expectFailureAsync(() => preparePublicRelease({ tag: 'v0.1.0-alpha.5', existingTags: ['v0.1.0-alpha.1', 'v0.1.0-alpha.2', 'v0.1.0-alpha.3'],