updated release script with zsh guard and ony dmg in dist directory
This commit is contained in:
@@ -105,7 +105,7 @@ Data stays under `~/Library/Application Support/KJamsClone/` for continuity. Bac
|
||||
./scripts/release.sh
|
||||
```
|
||||
|
||||
Release output: a branded DMG and app ZIP. Normal `./scripts/release.sh` requires Developer ID signing and a saved notarization profile, notarizes/staples both app and DMG, and requires Gatekeeper checks before publishing the final files. Run `./scripts/setup-notarization.sh` once in Terminal to save the default `KJMixPro` profile. For a deliberately unnotarized local build use `./scripts/release.sh --signed-only`; `--unsigned` creates an unsigned preview and the legacy `dist/KJMixPro-unsigned-macOS.zip`. See [release setup](docs/RELEASING.md). The approved icon, complete AppIcon set, high-resolution master and original generation prompt are included under Brand/assets. Bundle/module identifiers remain compatible internally; displayed branding is KJMix Pro.
|
||||
Release output: only the current branded DMG in dist. Verification reports and the checksum are stored under build-release/release-verification. Normal `./scripts/release.sh` requires Developer ID signing and a saved notarization profile, notarizes/staples both app and DMG, and requires Gatekeeper checks before publishing the final files. Run `./scripts/setup-notarization.sh` once in Terminal to save the default `KJMixPro` profile. For a deliberately unnotarized local build use `./scripts/release.sh --signed-only`; `--unsigned` creates an unsigned preview DMG. See [release setup](docs/RELEASING.md). The approved icon, complete AppIcon set, high-resolution master and original generation prompt are included under Brand/assets. Bundle/module identifiers remain compatible internally; displayed branding is KJMix Pro.
|
||||
|
||||
**73 XCTest cases passed**, including real loopback HTTP, access isolation/revocation, rotation, independent singer settings, fades, timed slides, batch atomicity, search, MP3/MP4 tag backup/media preservation and all earlier library/playback/waveform/venue/drop regressions. Release builds arm64 and x86_64, tested on Apple Silicon macOS 27.2 with Xcode 27.2/Swift 6.4.2. Deployment target macOS 13; this Xcode's XCTest runtime may require macOS 14+. Intel/older macOS execution is untested. See docs/VERIFICATION.md.
|
||||
|
||||
|
||||
+5
-7
@@ -28,13 +28,9 @@ If you already have a profile with a different name, use that name through `KJMI
|
||||
|
||||
The script builds Release, stages a copy, signs the app with Developer ID and hardened runtime, submits it to Apple, checks Accepted status, staples/validates its ticket, and checks app Gatekeeper assessment. It then creates the compressed DMG with the colourful app/volume/file icon and Applications shortcut, signs and notarizes the DMG, staples/validates its ticket, checks its Gatekeeper assessment and mounts the finished image to recheck the enclosed app. A fresh-Mac launch/install check is still recommended before public distribution.
|
||||
|
||||
Outputs are versioned, for example:
|
||||
The only file in dist is the current versioned DMG, for example `dist/KJMixPro-0.6.4-macOS.dmg`. After all checks pass, old DMGs, ZIPs, checksum sidecars and other output entries are removed. Reports and SHA-256 are kept outside dist under `build-release/release-verification/KJMixPro-0.6.4-macOS/`. The temporary ZIP required for app notarization stays in the private staging folder and is removed automatically.
|
||||
|
||||
- `dist/KJMixPro-0.6.4-macOS.dmg`
|
||||
- `dist/KJMixPro-0.6.4-macOS.zip` (stapled app)
|
||||
- SHA-256 sidecars and `dist/KJMixPro-0.6.4-macOS-verification/` reports
|
||||
|
||||
The script publishes these files only after the checks succeed. A failed run returns nonzero and never labels that attempt Gatekeeper verified. Existing files from earlier builds can remain in dist; check the current report and successful script completion.
|
||||
The script publishes the DMG and cleans old output only after the checks succeed. A failed run retains the existing distribution, returns nonzero and never labels that attempt Gatekeeper verified.
|
||||
|
||||
You can configure another saved profile or signing identity without editing the script:
|
||||
|
||||
@@ -52,6 +48,8 @@ The script auto-selects a Developer ID identity if all available matching certif
|
||||
./scripts/release.sh --unsigned
|
||||
```
|
||||
|
||||
These modes have clearly marked filenames and status reports. **They are not notarized or Gatekeeper verified.** Signed-only does not need notarization credentials. Unsigned creates the compatibility ZIP as well. Neither mode changes Gatekeeper settings or bypasses macOS security.
|
||||
These modes have clearly marked filenames and status reports. **They are not notarized or Gatekeeper verified.** Signed-only does not need notarization credentials. Both modes also keep only their current DMG in dist. Neither mode changes Gatekeeper settings or bypasses macOS security.
|
||||
|
||||
References: [Apple notarization](https://developer.apple.com/documentation/security/notarizing-macos-software-before-distribution), [packaging for distribution](https://developer.apple.com/documentation/xcode/packaging-mac-software-for-distribution).
|
||||
|
||||
Run `./scripts/release.sh` or `bash ./scripts/release.sh`; do not source it into your interactive shell. Notarization uses `notary_status`, avoiding zsh’s read-only `status` variable.
|
||||
|
||||
@@ -8,7 +8,7 @@ Verified on 3 November 2026.
|
||||
- Release builds both arm64 and x86_64. Source ZIP includes canonical KJMix Pro.xcodeproj/project.pbxproj and shared scheme, source, tests, executable scripts, icon assets and original test media only.
|
||||
- ZIP CRC checks, extracted file hashes and extracted Xcode project listing are checked during packaging. Personal media, library databases, invitations, bookmarks and user settings are excluded.
|
||||
|
||||
The production DMG and app ZIP are Developer ID signed, notarized and stapled; explicit local preview modes remain unnotarized. Intel/older macOS runtime, broad commercial media, hardware/display latency, large-library show stress and every native drag/keyboard interaction are not exhaustively validated. Music-store profiles/catalogue imports are not provider purchase or subscription integrations. See README.md for feature limits.
|
||||
The production DMG and its enclosed app are Developer ID signed, notarized and stapled; explicit local preview modes remain unnotarized. Intel/older macOS runtime, broad commercial media, hardware/display latency, large-library show stress and every native drag/keyboard interaction are not exhaustively validated. Music-store profiles/catalogue imports are not provider purchase or subscription integrations. See README.md for feature limits.
|
||||
|
||||
The complete operating-system drag gesture is not automated end to end. Drop payload delivery and ordering are tested with real NSItemProviders, and visible reorder arrows provide an independently mouse-tested alternative.
|
||||
|
||||
@@ -25,3 +25,5 @@ Batch waveform checks verify cache reuse versus forced regeneration, deduplicati
|
||||
The release script now creates a compressed DMG with the approved app icon as both its volume icon and Finder file icon, plus an Applications shortcut. A real `--signed-only` run succeeded with the installed Developer ID Application identity and hardened runtime. DMG checksum, mounted contents, custom icon flag, app/volume artwork matching, app signature and disk-image signature were verified. Gatekeeper assessments of both app and DMG explicitly returned `Unnotarized Developer ID`; this output is **not** a Gatekeeper-verified release.
|
||||
|
||||
The normal release mode is fail-closed: it requires a valid notarytool Keychain profile, notarizes/staples the app and DMG, and requires Gatekeeper success for both the image and mounted app before publishing verified filenames. The missing-profile failure was verified before credential setup. After the `KJMixPro` profile was configured, Apple accepted both the app and DMG, both tickets were stapled and validated, and Gatekeeper accepted the final DMG and mounted app as `Notarized Developer ID`. The app also passed `syspolicy_check distribution`. An independent final check confirmed the downloadable DMG/app tickets, extracted ZIP app signature, ZIP integrity and download SHA-256 hashes. See RELEASING.md.
|
||||
|
||||
The release script now keeps only the current DMG in dist. Reports/checksums are written under build-release/release-verification, and old outputs are removed only after the new image passes its checks. The notarization result variable is notary_status; Bash/zsh function regressions verified Accepted and Invalid responses without the zsh read-only status error.
|
||||
|
||||
+21
-16
@@ -1,4 +1,11 @@
|
||||
#!/bin/bash
|
||||
# Also honor the Bash requirement if launched explicitly as `zsh scripts/release.sh`.
|
||||
if [ -z "${BASH_VERSION:-}" ]; then
|
||||
case "${ZSH_EVAL_CONTEXT:-}" in
|
||||
*:file) printf 'Run this script with: bash ./scripts/release.sh\n' >&2;return 1 ;;
|
||||
*) exec /bin/bash "$0" "$@" ;;
|
||||
esac
|
||||
fi
|
||||
set -euo pipefail
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
@@ -7,9 +14,10 @@ usage() {
|
||||
Usage: ./scripts/release.sh [--signed-only | --unsigned] [--] [xcodebuild arguments]
|
||||
|
||||
Default: Developer ID sign, notarize and staple the app and branded DMG, then
|
||||
require successful Gatekeeper checks before publishing the files.
|
||||
require successful Gatekeeper checks before publishing the DMG.
|
||||
--signed-only: Build a Developer ID signed DMG without notarization.
|
||||
--unsigned: Build an unsigned preview DMG and the legacy unsigned ZIP.
|
||||
--unsigned: Build an unsigned preview DMG.
|
||||
Only the current DMG is kept in dist; reports stay under build-release/release-verification.
|
||||
|
||||
KJMIX_SIGNING_IDENTITY: Developer ID Application certificate name or SHA-1.
|
||||
Auto-selects when all matching certificates have one name.
|
||||
@@ -61,6 +69,7 @@ release_built="$PWD/build-release/Build/Products/Release/KJMix Pro.app"
|
||||
release_version="$(/usr/libexec/PlistBuddy -c 'Print :CFBundleShortVersionString' "$release_built/Contents/Info.plist")"
|
||||
[[ "$release_version" =~ ^[A-Za-z0-9._-]+$ ]] || fail 'Invalid release version.'
|
||||
release_payload="$release_work/payload"
|
||||
[[ ! -L "$PWD/dist" ]] || fail 'dist must be a real directory, not a symbolic link.'
|
||||
/bin/mkdir -p "$release_payload" dist
|
||||
release_app="$release_payload/KJMix Pro.app"
|
||||
/usr/bin/ditto --noextattr --norsrc "$release_built" "$release_app"
|
||||
@@ -73,21 +82,21 @@ release_suffix=macOS
|
||||
if [[ "$release_mode" == unsigned ]]; then release_suffix=unsigned-macOS;fi
|
||||
if [[ "$release_mode" == signed ]]; then release_suffix=signed-unnotarized-macOS;fi
|
||||
release_name="KJMixPro-$release_version-$release_suffix"
|
||||
release_reports="$PWD/dist/$release_name-verification"
|
||||
release_reports="$PWD/build-release/release-verification/$release_name"
|
||||
/bin/mkdir -p "$release_reports"
|
||||
printf 'Preparing release. NOT yet verified.\n' > "$release_reports/STATUS.txt"
|
||||
notarize() {
|
||||
local artifact="$1" label="$2" report="$release_reports/$2-notary.json" submission status
|
||||
local artifact="$1" label="$2" report="$release_reports/$2-notary.json" submission notary_status
|
||||
printf 'Submitting %s to Apple notarization…\n' "$label"
|
||||
if ! xcrun notarytool submit "$artifact" --keychain-profile "$release_profile" --wait --timeout 30m --output-format json > "$report"; then
|
||||
printf 'Notarization did not complete. Inspect %s; Apple may still be processing the submission.\n' "$report" >&2
|
||||
return 1
|
||||
fi
|
||||
status="$(/usr/bin/plutil -extract status raw -o - "$report")"
|
||||
notary_status="$(/usr/bin/plutil -extract status raw -o - "$report")"
|
||||
submission="$(/usr/bin/plutil -extract id raw -o - "$report")"
|
||||
if [[ "$status" != Accepted ]]; then
|
||||
if [[ "$notary_status" != Accepted ]]; then
|
||||
xcrun notarytool log "$submission" --keychain-profile "$release_profile" "$release_reports/$label-notary-log.json" || true
|
||||
fail "Apple did not accept $label (status: $status). See $release_reports."
|
||||
fail "Apple did not accept $label (status: $notary_status). See $release_reports."
|
||||
fi
|
||||
}
|
||||
if [[ "$release_mode" != unsigned ]]; then
|
||||
@@ -140,19 +149,15 @@ if [[ "$release_mode" == notarized ]]; then
|
||||
fi
|
||||
/usr/bin/hdiutil detach -quiet "$release_mount"
|
||||
release_mounted=false
|
||||
/usr/bin/ditto -c -k --sequesterRsrc --keepParent "$release_app" "$release_work/$release_name.zip"
|
||||
/bin/mv -f "$release_dmg" "dist/$release_name.dmg"
|
||||
/bin/mv -f "$release_work/$release_name.zip" "dist/$release_name.zip"
|
||||
if [[ "$release_mode" == unsigned ]]; then /bin/cp "dist/$release_name.zip" dist/KJMixPro-unsigned-macOS.zip;fi
|
||||
(
|
||||
cd dist
|
||||
/usr/bin/shasum -a 256 "$release_name.dmg" > "$release_name.dmg.sha256"
|
||||
/usr/bin/shasum -a 256 "$release_name.zip" > "$release_name.zip.sha256"
|
||||
)
|
||||
# Preserve the previous distribution until the new image has passed every check.
|
||||
# Nothing other than the current DMG belongs in this generated output directory.
|
||||
/usr/bin/find "$PWD/dist" -mindepth 1 -maxdepth 1 ! -name "$release_name.dmg" -exec /bin/rm -rf -- {} +
|
||||
/usr/bin/shasum -a 256 "dist/$release_name.dmg" > "$release_reports/SHA256.txt"
|
||||
if [[ "$release_mode" == notarized ]]; then
|
||||
printf 'Developer ID signed; Apple notarization accepted; app and DMG tickets stapled; Gatekeeper checks passed.\n' | /usr/bin/tee "$release_reports/STATUS.txt"
|
||||
else
|
||||
printf '%s build only. NOT notarized or Gatekeeper verified.\n' "$release_mode" | /usr/bin/tee "$release_reports/STATUS.txt"
|
||||
fi
|
||||
release_completed=true
|
||||
printf 'Created dist/%s.dmg and dist/%s.zip\n' "$release_name" "$release_name"
|
||||
printf 'Created dist/%s.dmg\nVerification reports: %s\n' "$release_name" "$release_reports"
|
||||
|
||||
Reference in New Issue
Block a user