بنقرة واحدة
release-dmg
Full macOS DMG release - validate, build, sign, changelog, git tag, GitHub release
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Full macOS DMG release - validate, build, sign, changelog, git tag, GitHub release
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | release-dmg |
| description | Full macOS DMG release - validate, build, sign, changelog, git tag, GitHub release |
| argument-hint | <version> |
| disable-model-invocation | true |
Automate the full release pipeline for Blackbox. Execute each step sequentially. Stop immediately on any failure.
Target version: $ARGUMENTS
Run all checks in parallel where possible:
$ARGUMENTS is provided and matches semver format (X.Y.Z). If missing or invalid, ask the user and stop.git status --porcelain. Uncommitted changes are OK if they are part of this release (version was bumped ahead of time). Note them and continue.main. If not, warn and ask to confirm.Makefile (VERSION = ... line). If $ARGUMENTS equals the current version, skip the version bump step (already done). If greater, proceed normally. If less, stop.Makefile VERSION and Info.plist CFBundleShortVersionString match each other. If they don't, stop and report the mismatch.CHANGELOG.md and verify the [Unreleased] section has content (at least one list item under Added/Changed/Fixed/Removed). If empty, stop and tell the user to add changelog entries first.create-dmg is installed (command -v create-dmg).If any check fails, report all failures together and stop.
Skip this step if pre-flight detected version already matches $ARGUMENTS.
Makefile: change VERSION = X.Y.Z to the new version.Info.plist:
CFBundleShortVersionString to the new versionCFBundleVersion: read the current integer value and increment by 1CHANGELOG.md:
## [Unreleased] to ## [Unreleased] followed by a blank line and ## [X.Y.Z] - YYYY-MM-DD (today's date)[X.Y.Z]: https://github.com/tenequm/blackbox/compare/vPREVIOUS...vX.Y.Z[unreleased] link to compare from vX.Y.Z...HEADRun the full validation pipeline:
make check
This runs: make format (auto-fix) -> make build (Swift 6.2, warnings-as-errors) -> make test.
If any step fails, stop and report. Do NOT proceed to artifact creation with broken code.
Build the DMG, submit for notarization, and staple the ticket:
make release
This runs: make dmg -> xcrun notarytool submit --wait -> xcrun stapler staple.
If notarization fails with HTTP 403 "A required agreement is missing or has expired": the user must accept the updated Apple Developer agreement at developer.apple.com/account (sometimes App Store Connect). Acceptance takes a few minutes to propagate - retry xcrun notarytool submit build/Blackbox-X.Y.Z.dmg --keychain-profile blackbox --wait every ~60s until Accepted, then xcrun stapler staple manually.
Verify the DMG exists at build/Blackbox-X.Y.Z.dmg and report its file size. Then verify Gatekeeper end-to-end: xcrun stapler validate on the DMG, and mount it + spctl -a -t exec -v /Volumes/Blackbox/Blackbox.app -> must report Notarized Developer ID. (spctl -t open on the DMG itself reports "no usable signature" - expected; the DMG container is unsigned, the app inside is what matters.)
Generate the Sparkle EdDSA signature:
.build/artifacts/sparkle/Sparkle/bin/sign_update build/Blackbox-X.Y.Z.dmg
Parse the output to extract sparkle:edSignature="..." and length="..." values. These are needed for the appcast.
Create appcast.xml in the project root:
<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle">
<channel>
<title>Blackbox</title>
<item>
<title>Version X.Y.Z</title>
<pubDate>RFC 2822 DATE</pubDate>
<sparkle:version>BUILD_NUMBER</sparkle:version>
<sparkle:shortVersionString>X.Y.Z</sparkle:shortVersionString>
<enclosure
url="https://github.com/tenequm/blackbox/releases/download/vX.Y.Z/Blackbox-X.Y.Z.dmg"
type="application/octet-stream"
sparkle:edSignature="SIGNATURE"
length="FILE_SIZE_BYTES"
/>
</item>
</channel>
</rss>
Replace placeholders with actual values. sparkle:version is the CFBundleVersion integer. Use date -R format for pubDate. Get file size with stat -f%z.
git add Makefile Info.plist CHANGELOG.md Sources/ Tests/
git commit -m "chore: release vX.Y.Z"
git push
Use the exact version in the commit message. Only stage known files - never git add -A.
Extract the changelog section for version X.Y.Z from CHANGELOG.md (everything between ## [X.Y.Z] and the next ## [ heading). Use this as the release body.
gh release create vX.Y.Z build/Blackbox-X.Y.Z.dmg appcast.xml \
--title "Blackbox X.Y.Z" \
--notes "CHANGELOG_CONTENT"
Use a heredoc for the notes to preserve formatting.
A GitHub release does NOT update Homebrew - the cask is pinned in tenequm/homebrew-tap.
cd ~/Projects/homebrew-tap && git pull
curl -sL https://github.com/tenequm/blackbox/releases/download/vX.Y.Z/Blackbox-X.Y.Z.dmg | shasum -a 256
Update Casks/blackbox.rb: version "X.Y.Z" and the new sha256. Always hash the published GitHub asset (curl above), not the local file, so the cask matches what brew downloads. Then:
git add Casks/blackbox.rb && git commit -m "chore(blackbox): bump to X.Y.Z" && git push
Keep auto_updates true in the cask: Sparkle self-updates the app, so plain brew upgrade intentionally skips it (users can force with --greedy). Removing it would let a lagging cask downgrade a Sparkle-updated install.
rm -f appcast.xml
Report:
gh release view vX.Y.Z --json url -q .url)curl -sL https://github.com/tenequm/blackbox/releases/latest/download/appcast.xml