From 36c0a651eb58e3b8bd19bbe9e62b00cd2773427e Mon Sep 17 00:00:00 2001 From: ryanleecode <> Date: Wed, 7 Oct 2026 00:59:42 -0400 Subject: [PATCH 1/2] ci/release: remove macOS entirely (tests, release, notarization, dmg, Homebrew cask) Removes all macOS from CI, release, and distribution: - cross-platform-tests: drop macos-tests job (macos-15/26/intel legs) - benchmark-targets: drop macos/apple-silicon matrix entry - build-release-artifacts: drop build_macos job, MACOS_SIGNING_*/MACOS_NOTARY_* secrets, macOS artifact download/assembly, dmg args in cask generation - release path: Homebrew cask is now Linux-only (AppImage); deploy-homebrew-tap keeps publishing the Linux cask - deployment-ci: drop macos-packaging-smoke job; drop deleted macOS scripts from path triggers and bash -n; cask gate asserts Linux-only (no macos/.dmg/.app) - delete scripts/package-macos.sh, scripts/notarize-macos.sh, scripts/macos-cargo-config.sh - rewrite scripts/generate-homebrew-cask.sh to a Linux-only cask - delete docs/macos-release-signing.md; drop macOS from README/CONTRIBUTING install+packaging docs Windows and Linux distribution unchanged. App source cfg(target_os=macos) untouched (out of scope). Repo secrets not deleted; now-unused macOS secrets listed in PR body. --- .github/workflows/benchmark-targets.yml | 2 - .github/workflows/build-release-artifacts.yml | 221 +----------- .github/workflows/cross-platform-tests.yml | 56 --- .github/workflows/deployment-ci.yml | 89 +---- CONTRIBUTING.md | 12 +- README.md | 4 +- docs/macos-release-signing.md | 158 -------- scripts/generate-homebrew-cask.sh | 46 +-- scripts/macos-cargo-config.sh | 70 ---- scripts/notarize-macos.sh | 243 ------------- scripts/package-macos.sh | 337 ------------------ 11 files changed, 14 insertions(+), 1224 deletions(-) delete mode 100644 docs/macos-release-signing.md delete mode 100755 scripts/macos-cargo-config.sh delete mode 100755 scripts/notarize-macos.sh delete mode 100755 scripts/package-macos.sh diff --git a/.github/workflows/benchmark-targets.yml b/.github/workflows/benchmark-targets.yml index 9434e4d39..390537937 100644 --- a/.github/workflows/benchmark-targets.yml +++ b/.github/workflows/benchmark-targets.yml @@ -28,8 +28,6 @@ jobs: include: - name: linux / ubuntu-22.04 runs_on: ubuntu-22.04 - - name: macos / apple-silicon - runs_on: macos-latest - name: windows / x86_64 runs_on: windows-latest - name: windows / arm64 diff --git a/.github/workflows/build-release-artifacts.yml b/.github/workflows/build-release-artifacts.yml index 3fe8507c6..e012aebf5 100644 --- a/.github/workflows/build-release-artifacts.yml +++ b/.github/workflows/build-release-artifacts.yml @@ -19,18 +19,6 @@ on: secrets: AZURE_CREDENTIALS: required: false - MACOS_SIGNING_IDENTITY: - required: false - MACOS_SIGNING_CERT_BASE64: - required: false - MACOS_SIGNING_CERT_PASSWORD: - required: false - MACOS_NOTARY_KEY_ID: - required: false - MACOS_NOTARY_ISSUER_ID: - required: false - MACOS_NOTARY_API_KEY_P8: - required: false workflow_dispatch: inputs: tag: @@ -534,201 +522,11 @@ jobs: if-no-files-found: error retention-days: 7 - build_macos: - name: Build macOS artifacts (${{ matrix.target_platform }}) - runs-on: ${{ matrix.runs_on }} - timeout-minutes: 120 - needs: prepare - strategy: - fail-fast: false - matrix: - include: - - target_platform: aarch64-darwin - arch: arm64 - runs_on: macos-latest - - target_platform: x86_64-darwin - arch: x86_64 - runs_on: macos-15-intel - env: - TAG: ${{ needs.prepare.outputs.tag }} - VERSION: ${{ needs.prepare.outputs.version }} - ARCH: ${{ matrix.arch }} - MACOS_SIGNING_IDENTITY: ${{ secrets.MACOS_SIGNING_IDENTITY }} - MACOS_SIGNING_CERT_BASE64: ${{ secrets.MACOS_SIGNING_CERT_BASE64 }} - MACOS_SIGNING_CERT_PASSWORD: ${{ secrets.MACOS_SIGNING_CERT_PASSWORD }} - MACOS_NOTARY_KEY_ID: ${{ secrets.MACOS_NOTARY_KEY_ID }} - MACOS_NOTARY_ISSUER_ID: ${{ secrets.MACOS_NOTARY_ISSUER_ID }} - MACOS_NOTARY_API_KEY_P8: ${{ secrets.MACOS_NOTARY_API_KEY_P8 }} - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - with: - ref: ${{ needs.prepare.outputs.tag }} - fetch-depth: 0 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable - - - name: Cache Rust artifacts - uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 - with: - cache-targets: false - - - name: Determine macOS signing mode - id: macos_signing_mode - run: | - set -euo pipefail - - required=( - MACOS_SIGNING_IDENTITY - MACOS_SIGNING_CERT_BASE64 - MACOS_SIGNING_CERT_PASSWORD - MACOS_NOTARY_KEY_ID - MACOS_NOTARY_ISSUER_ID - MACOS_NOTARY_API_KEY_P8 - ) - present=() - missing=() - - for name in "${required[@]}"; do - if [ -n "${!name:-}" ]; then - present+=("$name") - else - missing+=("$name") - fi - done - - if [ "${#present[@]}" -eq 0 ]; then - echo "enabled=false" >> "$GITHUB_OUTPUT" - echo "macOS signing is not configured; building unsigned macOS artifacts." - exit 0 - fi - - if [ "${#missing[@]}" -gt 0 ]; then - echo "::error title=Incomplete macOS signing configuration::Missing required secret(s): ${missing[*]}" - echo "::error title=Partial macOS signing configuration::Either provide all macOS signing and notarization secrets or leave them all unset to build unsigned artifacts." - exit 1 - fi - - echo "enabled=true" >> "$GITHUB_OUTPUT" - - - name: Prepare macOS signing and notarization credentials - if: ${{ steps.macos_signing_mode.outputs.enabled == 'true' }} - id: macos_signing - run: | - set -euo pipefail - - keychain_path="${RUNNER_TEMP}/gitcomet-signing.keychain-db" - keychain_password="$(openssl rand -hex 24)" - cert_path="${RUNNER_TEMP}/gitcomet-signing-cert.p12" - api_key_path="${RUNNER_TEMP}/AuthKey_${MACOS_NOTARY_KEY_ID}.p8" - default_keychain="$(security default-keychain -d user | tr -d '"' | xargs)" - - if base64 --help 2>&1 | grep -q -- '--decode'; then - printf '%s' "$MACOS_SIGNING_CERT_BASE64" | base64 --decode > "$cert_path" - else - printf '%s' "$MACOS_SIGNING_CERT_BASE64" | base64 -D > "$cert_path" - fi - - security create-keychain -p "$keychain_password" "$keychain_path" - security set-keychain-settings -lut 21600 "$keychain_path" - security unlock-keychain -p "$keychain_password" "$keychain_path" - security import "$cert_path" \ - -k "$keychain_path" \ - -P "$MACOS_SIGNING_CERT_PASSWORD" \ - -T /usr/bin/codesign \ - -T /usr/bin/security - security set-key-partition-list -S apple-tool:,apple: -s -k "$keychain_password" "$keychain_path" - security default-keychain -d user -s "$keychain_path" - - security find-identity -v -p codesigning "$keychain_path" - - printf '%s' "$MACOS_NOTARY_API_KEY_P8" > "$api_key_path" - chmod 600 "$api_key_path" - - echo "keychain_path=$keychain_path" >> "$GITHUB_OUTPUT" - echo "api_key_path=$api_key_path" >> "$GITHUB_OUTPUT" - echo "default_keychain=$default_keychain" >> "$GITHUB_OUTPUT" - - - name: Show macOS disk usage before packaging - run: | - set -euo pipefail - df -h || true - for path in target "$HOME/.cargo/registry" "$HOME/.cargo/git" dist "$RUNNER_TEMP"; do - if [ -e "$path" ]; then - du -sh "$path" || true - else - echo "missing: $path" - fi - done - - - name: Package macOS release assets - env: - GITCOMET_MACOS_PACKAGE_CLEAN_TARGET: "1" - run: | - set -euo pipefail - package_args=( - --version "${VERSION}" - --arch "${ARCH}" - --release - --out-dir dist - ) - - if [ "${{ steps.macos_signing_mode.outputs.enabled }}" = "true" ]; then - package_args+=( - --codesign-identity "${MACOS_SIGNING_IDENTITY}" - --codesign-keychain "${{ steps.macos_signing.outputs.keychain_path }}" - ) - else - echo "Building unsigned macOS artifacts because signing is not configured." - fi - - scripts/package-macos.sh "${package_args[@]}" - - - name: Notarize and verify macOS artifacts - if: ${{ steps.macos_signing_mode.outputs.enabled == 'true' }} - run: | - set -euo pipefail - scripts/notarize-macos.sh \ - --version "${VERSION}" \ - --arch "${ARCH}" \ - --out-dir dist \ - --api-key "${{ steps.macos_signing.outputs.api_key_path }}" \ - --key-id "${MACOS_NOTARY_KEY_ID}" \ - --issuer "${MACOS_NOTARY_ISSUER_ID}" - - - name: Cleanup macOS signing keychain - if: ${{ always() && steps.macos_signing_mode.outputs.enabled == 'true' }} - env: - KEYCHAIN_PATH: ${{ steps.macos_signing.outputs.keychain_path }} - DEFAULT_KEYCHAIN_PATH: ${{ steps.macos_signing.outputs.default_keychain }} - API_KEY_PATH: ${{ steps.macos_signing.outputs.api_key_path }} - run: | - set -euo pipefail - if [ -n "${DEFAULT_KEYCHAIN_PATH:-}" ]; then - security default-keychain -d user -s "$DEFAULT_KEYCHAIN_PATH" || true - fi - if [ -n "${KEYCHAIN_PATH:-}" ] && [ -f "$KEYCHAIN_PATH" ]; then - security delete-keychain "$KEYCHAIN_PATH" || true - fi - if [ -n "${API_KEY_PATH:-}" ] && [ -f "$API_KEY_PATH" ]; then - rm -f "$API_KEY_PATH" - fi - - - name: Upload macOS artifacts - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7 - with: - name: macos-release-artifacts-${{ matrix.target_platform }} - path: | - dist/*.tar.gz - dist/*.dmg - if-no-files-found: error - retention-days: 7 - publish_release_assets: name: Attach assets and checksums to GitHub release runs-on: ubuntu-22.04 timeout-minutes: 30 - needs: [prepare, build_windows, build_linux, build_macos] + needs: [prepare, build_windows, build_linux] env: TAG: ${{ needs.prepare.outputs.tag }} VERSION: ${{ needs.prepare.outputs.version }} @@ -752,19 +550,12 @@ jobs: path: dist/linux merge-multiple: true - - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 - with: - pattern: macos-release-artifacts-* - path: dist/macos - merge-multiple: true - - name: Assemble release payload run: | set -euo pipefail mkdir -p dist/release find dist/windows -maxdepth 1 -type f -exec cp -f {} dist/release/ \; find dist/linux -maxdepth 1 -type f -exec cp -f {} dist/release/ \; - find dist/macos -maxdepth 1 -type f -exec cp -f {} dist/release/ \; file_count="$(find dist/release -maxdepth 1 -type f | wc -l | tr -d '[:space:]')" if [ "${file_count}" = "0" ]; then echo "::error title=No release artifacts::No files were assembled into dist/release." @@ -777,23 +568,17 @@ jobs: set -euo pipefail linux_arm_appimage="gitcomet-v${VERSION}-linux-arm64.AppImage" linux_intel_appimage="gitcomet-v${VERSION}-linux-x86_64.AppImage" - arm_dmg="gitcomet-v${VERSION}-macos-arm64.dmg" - intel_dmg="gitcomet-v${VERSION}-macos-x86_64.dmg" linux_arm_appimage_path="dist/release/${linux_arm_appimage}" linux_intel_appimage_path="dist/release/${linux_intel_appimage}" - arm_dmg_path="dist/release/${arm_dmg}" - intel_dmg_path="dist/release/${intel_dmg}" - if [ ! -f "${linux_arm_appimage_path}" ] || [ ! -f "${linux_intel_appimage_path}" ] || [ ! -f "${arm_dmg_path}" ] || [ ! -f "${intel_dmg_path}" ]; then - echo "::error title=Missing release assets::Expected ${linux_arm_appimage}, ${linux_intel_appimage}, ${arm_dmg}, and ${intel_dmg} in dist/release." + if [ ! -f "${linux_arm_appimage_path}" ] || [ ! -f "${linux_intel_appimage_path}" ]; then + echo "::error title=Missing release assets::Expected ${linux_arm_appimage} and ${linux_intel_appimage} in dist/release." exit 1 fi scripts/generate-homebrew-cask.sh \ --version "${VERSION}" \ --github-repo "${GITHUB_REPOSITORY}" \ - --arm-dmg "${arm_dmg_path}" \ - --intel-dmg "${intel_dmg_path}" \ --linux-arm-appimage "${linux_arm_appimage_path}" \ --linux-intel-appimage "${linux_intel_appimage_path}" \ --output "dist/release/gitcomet.rb" diff --git a/.github/workflows/cross-platform-tests.yml b/.github/workflows/cross-platform-tests.yml index 09621e8ef..4436732d6 100644 --- a/.github/workflows/cross-platform-tests.yml +++ b/.github/workflows/cross-platform-tests.yml @@ -172,62 +172,6 @@ jobs: - name: Run UI smoke test under selected profile run: cargo test -p gitcomet-ui-gpui smoke_tests::smoke_view_renders_without_panicking -- --exact - macos-tests: - name: macOS Tests (${{ matrix.name }}) - runs-on: ${{ matrix.runs_on }} - timeout-minutes: 60 - strategy: - fail-fast: false - matrix: - include: - - target_platform: aarch64-darwin - name: macbook-m1 / macos-15 - runs_on: macos-15 - - target_platform: aarch64-darwin - name: latest-macos / macos-26 - runs_on: macos-26 - - target_platform: x86_64-darwin - name: intel (macos-15-intel) - runs_on: macos-15-intel - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - name: Show Git version - run: git --version - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable - - name: Cache Rust artifacts - uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 - - name: Show host target - run: rustc -vV - - name: Assert Apple Silicon runner - if: matrix.target_platform == 'aarch64-darwin' - run: | - set -euo pipefail - test "$(uname -m)" = "arm64" - rust_host="$(rustc -vV | sed -n 's/^host: //p')" - test "$rust_host" = "aarch64-apple-darwin" - - name: Run headless test suite - run: | - cargo test --workspace \ - --exclude gitcomet-ui-gpui \ - $APP_FEATURES \ - --locked \ - --verbose - - name: Gatekeeper and code-signing check (informational) - run: | - set -euo pipefail - cargo_config_output="$(scripts/macos-cargo-config.sh "$(uname -m)" release)" - set -- - if [[ -n "$cargo_config_output" ]]; then - while IFS= read -r arg; do - set -- "$@" "$arg" - done <<<"$cargo_config_output" - fi - set -- "$@" -p gitcomet $APP_FEATURES --release --locked - cargo build "$@" - codesign --verify --verbose target/release/gitcomet || true - spctl --assess --type execute --verbose target/release/gitcomet || true - windows-tests: name: Windows Tests (${{ matrix.target_platform }}) runs-on: ${{ matrix.runs_on }} diff --git a/.github/workflows/deployment-ci.yml b/.github/workflows/deployment-ci.yml index a62162f71..566f0e57d 100644 --- a/.github/workflows/deployment-ci.yml +++ b/.github/workflows/deployment-ci.yml @@ -13,8 +13,6 @@ on: - ".github/workflows/release-manual-main.yml" - "scripts/update-aur.sh" - "scripts/cargo-flatten-dupes.sh" - - "scripts/package-macos.sh" - - "scripts/macos-cargo-config.sh" - "scripts/generate-homebrew-cask.sh" - "scripts/build-apt-repo.sh" - "scripts/windows/verify-signed-artifact.ps1" @@ -30,8 +28,6 @@ on: - ".github/workflows/release-manual-main.yml" - "scripts/update-aur.sh" - "scripts/cargo-flatten-dupes.sh" - - "scripts/package-macos.sh" - - "scripts/macos-cargo-config.sh" - "scripts/generate-homebrew-cask.sh" - "scripts/build-apt-repo.sh" - "scripts/windows/verify-signed-artifact.ps1" @@ -55,9 +51,6 @@ jobs: run: | bash -n scripts/cargo-flatten-dupes.sh bash -n scripts/update-aur.sh - bash -n scripts/package-macos.sh - bash -n scripts/notarize-macos.sh - bash -n scripts/macos-cargo-config.sh bash -n scripts/generate-homebrew-cask.sh bash -n scripts/build-apt-repo.sh @@ -158,29 +151,25 @@ jobs: mkdir -p dist/deployment-ci printf 'linux-arm-appimage-test' > dist/deployment-ci/gitcomet-v0.0.0-ci-linux-arm64.AppImage printf 'linux-appimage-test' > dist/deployment-ci/gitcomet-v0.0.0-ci-linux-x86_64.AppImage - printf 'arm64-dmg-test' > dist/deployment-ci/gitcomet-v0.0.0-ci-macos-arm64.dmg - printf 'intel-dmg-test' > dist/deployment-ci/gitcomet-v0.0.0-ci-macos-x86_64.dmg scripts/generate-homebrew-cask.sh \ --version "0.0.0-ci" \ --github-repo "Auto-Explore/GitComet" \ - --arm-dmg "dist/deployment-ci/gitcomet-v0.0.0-ci-macos-arm64.dmg" \ - --intel-dmg "dist/deployment-ci/gitcomet-v0.0.0-ci-macos-x86_64.dmg" \ --linux-arm-appimage "dist/deployment-ci/gitcomet-v0.0.0-ci-linux-arm64.AppImage" \ --linux-intel-appimage "dist/deployment-ci/gitcomet-v0.0.0-ci-linux-x86_64.AppImage" \ --output "dist/deployment-ci/gitcomet.rb" ruby -c dist/deployment-ci/gitcomet.rb grep -q 'cask "gitcomet" do' dist/deployment-ci/gitcomet.rb - grep -q 'os macos: "macos", linux: "linux"' dist/deployment-ci/gitcomet.rb + grep -q 'os linux: "linux"' dist/deployment-ci/gitcomet.rb grep -q 'on_linux do' dist/deployment-ci/gitcomet.rb - grep -q 'on_macos do' dist/deployment-ci/gitcomet.rb - grep -q 'app "GitComet.app"' dist/deployment-ci/gitcomet.rb - grep -q 'binary "#{appdir}/GitComet.app/Contents/MacOS/gitcomet", target: "gitcomet"' dist/deployment-ci/gitcomet.rb grep -q 'container type: :naked' dist/deployment-ci/gitcomet.rb grep -q 'binary "gitcomet-v#{version}-linux-#{arch}.AppImage", target: "gitcomet"' dist/deployment-ci/gitcomet.rb grep -q 'gitcomet-v#{version}-linux-#{arch}.AppImage' dist/deployment-ci/gitcomet.rb - grep -q 'depends_on macos:' dist/deployment-ci/gitcomet.rb + if grep -qi 'macos\|\.dmg\|GitComet.app' dist/deployment-ci/gitcomet.rb; then + echo "::error title=Unexpected macOS cask content::The Homebrew cask must be Linux-only." + exit 1 + fi - name: Validate Homebrew tap publish detection run: | @@ -441,71 +430,3 @@ jobs: -o Dir::Etc::sourceparts="${source_dir}" \ -o Dir::State::lists="${lists_dir}" \ | grep -q '0.0.0~ci1' - - macos-packaging-smoke: - name: macOS packaging smoke (${{ matrix.target_platform }}) - runs-on: ${{ matrix.runs_on }} - timeout-minutes: 90 - strategy: - fail-fast: false - matrix: - include: - - target_platform: aarch64-darwin - arch: arm64 - runs_on: macos-latest - - target_platform: x86_64-darwin - arch: x86_64 - runs_on: macos-15-intel - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 - - - name: Install Rust toolchain - uses: dtolnay/rust-toolchain@4360b52568e2003a75bf9bc1d59f33a8e3fc893c # stable - - - name: Cache Rust artifacts - uses: Swatinem/rust-cache@49a0bdc70d2e1b713ca9e2869b211fcce03d3c1c # v2 - - - name: Build release binary - run: | - set -euo pipefail - cargo_config_output="$(scripts/macos-cargo-config.sh "${{ matrix.arch }}" release)" - set -- - if [[ -n "$cargo_config_output" ]]; then - while IFS= read -r arg; do - set -- "$@" "$arg" - done <<<"$cargo_config_output" - fi - set -- "$@" -p gitcomet --release --locked --features ui-gpui,gix --bins - cargo build "$@" - - - name: Package macOS artifacts - run: | - set -euo pipefail - scripts/package-macos.sh \ - --version 0.0.0-ci \ - --arch "${{ matrix.arch }}" \ - --release \ - --no-build \ - --out-dir dist - - - name: Verify tarball contents - run: | - set -euo pipefail - tarball="dist/gitcomet-v0.0.0-ci-macos-${{ matrix.arch }}.tar.gz" - test -f "$tarball" - tar -tzf "$tarball" | grep -q "GitComet.app/Contents/MacOS/gitcomet$" - - - name: Verify DMG launches binary - run: | - set -euo pipefail - dmg="dist/gitcomet-v0.0.0-ci-macos-${{ matrix.arch }}.dmg" - test -f "$dmg" - - mount_point="$(hdiutil attach "$dmg" | awk '/\/Volumes\// {print $3; exit}')" - if [ -z "$mount_point" ]; then - echo "Failed to determine DMG mount point." >&2 - exit 1 - fi - - "${mount_point}/GitComet.app/Contents/MacOS/gitcomet" --help >/dev/null - hdiutil detach "$mount_point" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 9dd755cce..47776ff2b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -71,21 +71,11 @@ This writes: ### Release packaging -macOS packaging is handled by: - -```bash -scripts/package-macos.sh --version 0.2.0 --arch arm64 --release -scripts/package-macos.sh --version 0.2.0 --arch x86_64 --release -``` - -Use `--skip-dmg` when running in restricted/sandboxed environments where `hdiutil create` is unavailable. - The release workflow `.github/workflows/build-release-artifacts.yml` builds and publishes: - Windows: portable ZIP + MSI - Linux: tar.gz + AppImage + .deb -- macOS: DMG + tar.gz for `arm64` and `x86_64` -- Homebrew cask asset: `gitcomet.rb` (generated from macOS DMG artifacts and Linux AppImages plus their SHA256 values) +- Homebrew cask asset: `gitcomet.rb` (Linux-only, generated from the Linux AppImages plus their SHA256 values) ### Homebrew deployment diff --git a/README.md b/README.md index 9bbb1971a..21323a413 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ GitComet is built for teams that want fast Git operations with local-first privacy, familiar workflows, and open source freedom. -Available for Linux, Windows, and macOS. +Available for Linux and Windows. GitComet demo @@ -34,7 +34,7 @@ Install from the Microsoft Store:
-Homebrew (macOS / Linux) +Homebrew (Linux) App and `gitcomet` command from tap: diff --git a/docs/macos-release-signing.md b/docs/macos-release-signing.md deleted file mode 100644 index 9406392ee..000000000 --- a/docs/macos-release-signing.md +++ /dev/null @@ -1,158 +0,0 @@ -# macOS Release Signing - -This repository already contains the basic macOS release flow: - -- [`scripts/package-macos.sh`](../scripts/package-macos.sh) builds the macOS app bundle, signs the bundled executable and app when a signing identity is provided, and emits the macOS `.tar.gz` and `.dmg` artifacts. -- [`scripts/notarize-macos.sh`](../scripts/notarize-macos.sh) submits the packaged DMG to Apple's notary service, staples the resulting ticket to the staged `.app` bundle and DMG, validates the stapled artifacts, and rebuilds the tarball so the archived `.app` bundle is current. -- [`.github/workflows/build-release-artifacts.yml`](../.github/workflows/build-release-artifacts.yml) wires the same process into release CI. - -## What You Need - -For outside-the-App-Store distribution you need: - -1. An Apple Developer Program team. -2. A `Developer ID Application` certificate with the private key available to `codesign`. -3. A notarization credential for `notarytool`. - Recommended in this repo: an App Store Connect API key. - Local alternative: a stored `notarytool` keychain profile. - -Check whether the current shell can see a usable signing identity: - -```bash -security find-identity -v -p codesigning -``` - -For release signing, this must show a valid `Developer ID Application: ...` identity. If it shows `0 valid identities found`, fix the certificate/private-key installation in Keychain Access before trying to sign. - -## Local Release Flow - -First, verify that macOS can see the correct signing identity: - -```bash -security find-identity -v -p codesigning -``` - -You should see a valid `Developer ID Application: ...` entry. - -Build and sign on each native architecture you ship: - -```bash -scripts/package-macos.sh \ - --version 0.2.0 \ - --arch arm64 \ - --release \ - --codesign-identity "Developer ID Application: Example, Inc. (TEAMID)" -``` - -Then notarize and staple the generated artifacts: - -```bash -scripts/notarize-macos.sh \ - --version 0.2.0 \ - --arch arm64 \ - --keychain-profile gitcomet-notary -``` - -If you prefer direct API-key authentication instead of a stored profile: - -```bash -scripts/notarize-macos.sh \ - --version 0.2.0 \ - --arch arm64 \ - --api-key /path/to/AuthKey_ABC1234567.p8 \ - --key-id ABC1234567 \ - --issuer 00000000-0000-0000-0000-000000000000 -``` - -To create a local keychain profile up front: - -```bash -xcrun notarytool store-credentials gitcomet-notary \ - --key /path/to/AuthKey_ABC1234567.p8 \ - --key-id ABC1234567 \ - --issuer 00000000-0000-0000-0000-000000000000 -``` - -Repeat the same packaging and notarization flow on Intel macOS for `--arch x86_64`. - -## Local Verification Checklist - -The packaging and notarization scripts already run the important checks for you: - -- [`scripts/package-macos.sh`](../scripts/package-macos.sh) signs with Hardened Runtime and runs `codesign --verify` on the app and standalone binary. -- [`scripts/notarize-macos.sh`](../scripts/notarize-macos.sh) submits the DMG with `notarytool`, staples the `.app` and `.dmg`, validates stapling, then runs `codesign --verify` and `spctl --assess`. - -After a successful local run, you can manually spot-check the finished artifacts: - -```bash -codesign --verify --deep --strict --verbose=2 dist/stage/gitcomet-v0.2.0-macos-arm64/GitComet.app -spctl --assess --type open --context context:primary-signature --verbose=4 dist/stage/gitcomet-v0.2.0-macos-arm64/GitComet.app -spctl --assess --type open --context context:primary-signature --verbose=4 dist/gitcomet-v0.2.0-macos-arm64.dmg -xcrun stapler validate dist/stage/gitcomet-v0.2.0-macos-arm64/GitComet.app -xcrun stapler validate dist/gitcomet-v0.2.0-macos-arm64.dmg -``` - -If all of those commands return success, the signed macOS app bundle and DMG are in good shape. - -## GitHub Setup - -Use repository-level or organization-level GitHub Actions secrets for the macOS signing values used by the reusable release workflow. - -1. Export the `Developer ID Application` identity from Keychain Access as a `.p12`. -2. Choose an export password for that `.p12`. -3. Base64-encode the `.p12` as a single line: - -```bash -base64 -i gitcomet-signing.p12 | tr -d '\n' -``` - -4. In GitHub, add these Actions secrets: - -- `MACOS_SIGNING_IDENTITY` - The exact identity string, for example `Developer ID Application: Example, Inc. (TEAMID)`. -- `MACOS_SIGNING_CERT_BASE64` - The single-line base64 output of the exported `.p12`. -- `MACOS_SIGNING_CERT_PASSWORD` - The password you set when exporting the `.p12`. -- `MACOS_NOTARY_KEY_ID` - The App Store Connect API key ID. -- `MACOS_NOTARY_ISSUER_ID` - The App Store Connect issuer UUID. -- `MACOS_NOTARY_API_KEY_P8` - The full contents of the downloaded `AuthKey_.p8` file. - -5. Trigger the release workflow from [`release-manual-main.yml`](../.github/workflows/release-manual-main.yml) on `main`. - -## App Store Connect Notary Key - -This repository's CI uses an App Store Connect API key for notarization. - -Create a Team API key, download the `.p8` file once, and store the key material securely. The key ID and issuer ID become GitHub secrets, and the `.p8` contents become `MACOS_NOTARY_API_KEY_P8`. - -For local testing you can either: - -- use the same `.p8` file directly with [`scripts/notarize-macos.sh`](../scripts/notarize-macos.sh), or -- save the credentials into your macOS keychain with `xcrun notarytool store-credentials`. - -## CI Secrets - -Release CI enables macOS signing only when all of these secrets are present: - -- `MACOS_SIGNING_IDENTITY` -- `MACOS_SIGNING_CERT_BASE64` -- `MACOS_SIGNING_CERT_PASSWORD` -- `MACOS_NOTARY_KEY_ID` -- `MACOS_NOTARY_ISSUER_ID` -- `MACOS_NOTARY_API_KEY_P8` - -The workflow imports the `.p12` certificate into a temporary keychain, signs the macOS artifacts, notarizes the DMG, staples the `.app` and `.dmg`, and uploads the resulting release assets. - -## Artifact Expectations - -Treat the DMG as the canonical trusted macOS download. - -- The DMG is the notarized and stapled end-user artifact. -- The tarball is rebuilt after stapling so the bundled `GitComet.app` is current. -- The standalone `gitcomet` binary at the tarball root is only code-signed. Apple's notary service does not accept `.tar.gz` uploads directly, and that file is not inside the submitted DMG. - -If you want a separately trusted CLI-only macOS artifact, publish it in a notary-supported container such as a ZIP, DMG, or signed flat PKG and update downstream packaging accordingly. diff --git a/scripts/generate-homebrew-cask.sh b/scripts/generate-homebrew-cask.sh index 54c0261b5..c922a5b5c 100755 --- a/scripts/generate-homebrew-cask.sh +++ b/scripts/generate-homebrew-cask.sh @@ -6,20 +6,16 @@ usage() { Usage: scripts/generate-homebrew-cask.sh \ --version VERSION \ --github-repo OWNER/REPO \ - --arm-dmg PATH \ - --intel-dmg PATH \ --linux-arm-appimage PATH \ --linux-intel-appimage PATH \ --output PATH -Generates a Homebrew cask for GitComet from macOS DMG and Linux AppImage artifacts. +Generates a Linux-only Homebrew cask for GitComet from the Linux AppImage artifacts. USAGE } version="" github_repo="" -arm_dmg="" -intel_dmg="" linux_arm_appimage="" linux_intel_appimage="" out_path="" @@ -34,14 +30,6 @@ while [[ $# -gt 0 ]]; do github_repo="${2:-}" shift 2 ;; - --arm-dmg) - arm_dmg="${2:-}" - shift 2 - ;; - --intel-dmg) - intel_dmg="${2:-}" - shift 2 - ;; --linux-arm-appimage) linux_arm_appimage="${2:-}" shift 2 @@ -66,7 +54,7 @@ while [[ $# -gt 0 ]]; do esac done -if [[ -z "$version" || -z "$github_repo" || -z "$arm_dmg" || -z "$intel_dmg" || -z "$linux_arm_appimage" || -z "$linux_intel_appimage" || -z "$out_path" ]]; then +if [[ -z "$version" || -z "$github_repo" || -z "$linux_arm_appimage" || -z "$linux_intel_appimage" || -z "$out_path" ]]; then echo "All arguments are required." >&2 usage exit 2 @@ -77,16 +65,6 @@ if ! [[ "$github_repo" =~ ^[^/]+/[^/]+$ ]]; then exit 2 fi -if [[ ! -f "$arm_dmg" ]]; then - echo "arm DMG not found: $arm_dmg" >&2 - exit 1 -fi - -if [[ ! -f "$intel_dmg" ]]; then - echo "intel DMG not found: $intel_dmg" >&2 - exit 1 -fi - if [[ ! -f "$linux_arm_appimage" ]]; then echo "linux arm AppImage not found: $linux_arm_appimage" >&2 exit 1 @@ -111,8 +89,6 @@ sha256_file() { exit 1 } -arm_sha="$(sha256_file "$arm_dmg")" -intel_sha="$(sha256_file "$intel_dmg")" linux_arm_sha="$(sha256_file "$linux_arm_appimage")" linux_intel_sha="$(sha256_file "$linux_intel_appimage")" @@ -122,23 +98,7 @@ cat > "$out_path" < [release|debug] - -Prints extra Cargo CLI args for GitComet macOS builds, one argument per line. - -Environment: - GITCOMET_MACOS_X86_RELEASE_LTO - Release LTO override for Intel macOS builds. - Supported: thin, fat, false, off, inherit - Default: thin -EOF -} - -if [[ $# -lt 1 || $# -gt 2 ]]; then - usage >&2 - exit 2 -fi - -arch="$1" -mode="${2:-release}" - -case "$arch" in - arm64|aarch64) - arch="arm64" - ;; - x86_64|amd64) - arch="x86_64" - ;; - -h|--help) - usage - exit 0 - ;; - *) - echo "Unsupported macOS arch: $arch" >&2 - exit 2 - ;; -esac - -case "$mode" in - release|debug) ;; - *) - echo "Unsupported build mode: $mode" >&2 - exit 2 - ;; -esac - -if [[ "$mode" != "release" || "$arch" != "x86_64" ]]; then - exit 0 -fi - -lto_mode="${GITCOMET_MACOS_X86_RELEASE_LTO:-thin}" - -case "$lto_mode" in - ""|inherit) - ;; - thin|fat) - printf '%s\n' --config "profile.release.lto=\"${lto_mode}\"" - ;; - false|off) - printf '%s\n' --config "profile.release.lto=false" - ;; - *) - echo "Unsupported GITCOMET_MACOS_X86_RELEASE_LTO value: $lto_mode" >&2 - exit 2 - ;; -esac diff --git a/scripts/notarize-macos.sh b/scripts/notarize-macos.sh deleted file mode 100755 index 2a30b243f..000000000 --- a/scripts/notarize-macos.sh +++ /dev/null @@ -1,243 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -usage() { - cat <<'USAGE' -Usage: scripts/notarize-macos.sh --version VERSION [--arch arm64|x86_64] [--out-dir PATH] [--timeout DURATION] [--keychain PATH] (--keychain-profile PROFILE | --api-key PATH --key-id ID [--issuer UUID]) - -Submits an already-packaged macOS DMG to Apple's notary service, staples the -resulting ticket to the staged .app bundle and DMG, and refreshes the macOS -tarball so the archived app bundle also carries the stapled ticket. - -Expected inputs: - - /gitcomet-v-macos-.dmg - - /stage/gitcomet-v-macos-/GitComet.app - -Authentication: - --keychain-profile PROFILE - Use credentials previously saved with: - xcrun notarytool store-credentials PROFILE ... - - --api-key PATH --key-id ID [--issuer UUID] - Use an App Store Connect API key directly. This matches the CI workflow. - -Notes: - - The macOS tarball is rebuilt after stapling so the bundled .app is up to date. - - The standalone gitcomet binary at the tarball root is only code-signed. - Apple's notary service does not accept .tar.gz uploads directly. - -Defaults: - --arch matches the host architecture - --out-dir ./dist - --timeout 2h -USAGE -} - -version="" -arch="" -out_dir="dist" -wait_timeout="2h" -keychain_profile="" -keychain_path="" -api_key_path="" -api_key_id="" -api_issuer="" - -while [[ $# -gt 0 ]]; do - case "$1" in - --version) - version="${2:-}" - shift 2 - ;; - --arch) - arch="${2:-}" - shift 2 - ;; - --out-dir) - out_dir="${2:-}" - shift 2 - ;; - --timeout) - wait_timeout="${2:-}" - shift 2 - ;; - --keychain-profile) - keychain_profile="${2:-}" - shift 2 - ;; - --keychain) - keychain_path="${2:-}" - shift 2 - ;; - --api-key) - api_key_path="${2:-}" - shift 2 - ;; - --key-id) - api_key_id="${2:-}" - shift 2 - ;; - --issuer) - api_issuer="${2:-}" - shift 2 - ;; - -h|--help) - usage - exit 0 - ;; - *) - echo "Unknown arg: $1" >&2 - usage - exit 2 - ;; - esac -done - -if [[ -z "$version" ]]; then - echo "--version is required (e.g. --version 0.2.0)." >&2 - exit 2 -fi - -host_arch_raw="$(uname -m)" -case "$host_arch_raw" in - arm64|aarch64) host_arch="arm64" ;; - x86_64|amd64) host_arch="x86_64" ;; - *) - echo "Unsupported machine architecture: $host_arch_raw" >&2 - exit 1 - ;; -esac - -if [[ -z "$arch" ]]; then - arch="$host_arch" -fi - -if [[ "$arch" != "arm64" && "$arch" != "x86_64" ]]; then - echo "Unsupported --arch '$arch'. Expected arm64 or x86_64." >&2 - exit 2 -fi - -if [[ -n "$keychain_profile" ]]; then - if [[ -n "$api_key_path" || -n "$api_key_id" || -n "$api_issuer" ]]; then - echo "Use either --keychain-profile or --api-key/--key-id/--issuer, not both." >&2 - exit 2 - fi -else - if [[ -z "$api_key_path" || -z "$api_key_id" ]]; then - echo "Provide either --keychain-profile or --api-key PATH --key-id ID." >&2 - exit 2 - fi - if [[ -n "$keychain_path" ]]; then - echo "--keychain only applies with --keychain-profile." >&2 - exit 2 - fi -fi - -if [[ "$out_dir" = /* ]]; then - mkdir -p "$out_dir" - out_abs="$(cd "$out_dir" && pwd)" -else - repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" - mkdir -p "${repo_root}/${out_dir}" - out_abs="$(cd "${repo_root}/${out_dir}" && pwd)" -fi - -release_root="gitcomet-v${version}-macos-${arch}" -stage_root="${out_abs}/stage" -release_dir="${stage_root}/${release_root}" -app_path="${release_dir}/GitComet.app" -app_binary="${app_path}/Contents/MacOS/gitcomet" -tarball_path="${out_abs}/${release_root}.tar.gz" -dmg_path="${out_abs}/${release_root}.dmg" -standalone_binary="${release_dir}/gitcomet" - -for tool in xcrun codesign spctl tar; do - if ! command -v "$tool" >/dev/null 2>&1; then - echo "Required tool not found: $tool" >&2 - exit 1 - fi -done - -if [[ ! -f "$dmg_path" ]]; then - echo "DMG not found: $dmg_path" >&2 - exit 1 -fi - -if [[ ! -d "$app_path" ]]; then - echo "App bundle not found: $app_path" >&2 - exit 1 -fi - -if [[ ! -x "$app_binary" ]]; then - echo "App binary not found or not executable: $app_binary" >&2 - exit 1 -fi - -notary_args=() -if [[ -n "$keychain_profile" ]]; then - notary_args+=(--keychain-profile "$keychain_profile") - if [[ -n "$keychain_path" ]]; then - notary_args+=(--keychain "$keychain_path") - fi -else - if [[ ! -f "$api_key_path" ]]; then - echo "API key file not found: $api_key_path" >&2 - exit 1 - fi - notary_args+=( - --key "$api_key_path" - --key-id "$api_key_id" - ) - if [[ -n "$api_issuer" ]]; then - notary_args+=(--issuer "$api_issuer") - fi -fi - -echo "Submitting $dmg_path for notarization" -submit_log="$(mktemp -t gitcomet-notary-submit.XXXXXX)" -set +e -xcrun notarytool submit "$dmg_path" "${notary_args[@]}" --wait --timeout "$wait_timeout" 2>&1 | tee "$submit_log" -submit_status=${PIPESTATUS[0]} -set -e - -if [[ $submit_status -ne 0 ]]; then - submission_id="$(sed -n 's/^ id: //p' "$submit_log" | tail -n1)" - if [[ -n "$submission_id" ]]; then - echo "Submission did not complete successfully; current status for $submission_id:" - xcrun notarytool info "$submission_id" "${notary_args[@]}" || true - else - echo "Submission did not complete successfully and no submission id could be parsed from notarytool output." >&2 - fi - echo "Apple's notary service can hold uploads for additional analysis. If this stays in progress for many hours, treat it as an Apple-side queue or account issue rather than a local packaging failure." >&2 - rm -f "$submit_log" - exit "$submit_status" -fi -rm -f "$submit_log" - -echo "Stapling notarization tickets" -xcrun stapler staple "$app_path" -xcrun stapler staple "$dmg_path" -xcrun stapler validate "$app_path" -xcrun stapler validate "$dmg_path" - -if [[ -f "$tarball_path" ]]; then - echo "Refreshing $tarball_path with stapled app bundle" - rm -f "$tarball_path" - tar -C "$stage_root" -czf "$tarball_path" "$release_root" -fi - -echo "Verifying signed macOS artifacts" -codesign --verify --deep --strict --verbose=2 "$app_path" -if [[ -f "$standalone_binary" ]]; then - codesign --verify --strict --verbose=2 "$standalone_binary" -fi -spctl --assess --type open --context context:primary-signature --verbose=4 "$app_path" -spctl --assess --type execute --verbose=4 "$app_binary" -spctl --assess --type open --context context:primary-signature --verbose=4 "$dmg_path" - -echo "Notarized macOS artifacts:" -echo " $app_path" -echo " $dmg_path" -if [[ -f "$tarball_path" ]]; then - echo " $tarball_path" -fi diff --git a/scripts/package-macos.sh b/scripts/package-macos.sh deleted file mode 100755 index 14730738d..000000000 --- a/scripts/package-macos.sh +++ /dev/null @@ -1,337 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -usage() { - cat <<'USAGE' -Usage: scripts/package-macos.sh --version VERSION [--arch arm64|x86_64] [--release|--debug] [--no-build] [--skip-dmg] [--out-dir PATH] [--codesign-identity NAME] [--codesign-keychain PATH] - -Builds a macOS app bundle and release artifacts: - - gitcomet-v-macos-.tar.gz - - gitcomet-v-macos-.dmg - -Defaults: - --release, build if needed, output to ./dist - -Environment: - GITCOMET_MACOS_X86_RELEASE_LTO=thin|fat|false|off|inherit - Overrides release LTO for Intel macOS builds. Default: thin. - GITCOMET_MACOS_PACKAGE_CLEAN_TARGET=1 - Deletes Cargo release build intermediates after staging artifacts. Intended - for disk-constrained CI runners. -USAGE -} - -version="" -arch="" -mode="release" -build=1 -create_dmg=1 -out_dir="dist" -codesign_identity="" -codesign_keychain="" - -while [[ $# -gt 0 ]]; do - case "$1" in - --version) - version="${2:-}" - shift 2 - ;; - --arch) - arch="${2:-}" - shift 2 - ;; - --release) - mode="release" - shift - ;; - --debug) - mode="debug" - shift - ;; - --no-build) - build=0 - shift - ;; - --skip-dmg) - create_dmg=0 - shift - ;; - --out-dir) - out_dir="${2:-}" - shift 2 - ;; - --codesign-identity) - codesign_identity="${2:-}" - shift 2 - ;; - --codesign-keychain) - codesign_keychain="${2:-}" - shift 2 - ;; - -h|--help) - usage - exit 0 - ;; - *) - echo "Unknown arg: $1" >&2 - usage - exit 2 - ;; - esac -done - -if [[ -z "$version" ]]; then - echo "--version is required (e.g. --version 0.2.0)." >&2 - exit 2 -fi - -host_arch_raw="$(uname -m)" -case "$host_arch_raw" in - arm64|aarch64) host_arch="arm64" ;; - x86_64|amd64) host_arch="x86_64" ;; - *) - echo "Unsupported machine architecture: $host_arch_raw" >&2 - exit 1 - ;; -esac - -if [[ -z "$arch" ]]; then - arch="$host_arch" -fi - -if [[ "$arch" != "arm64" && "$arch" != "x86_64" ]]; then - echo "Unsupported --arch '$arch'. Expected arm64 or x86_64." >&2 - exit 2 -fi - -if [[ "$arch" != "$host_arch" ]]; then - echo "Requested --arch '$arch' does not match host architecture '$host_arch'." >&2 - echo "Use a native runner for each architecture." >&2 - exit 1 -fi - -repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" -bin_src="${repo_root}/target/${mode}/gitcomet" - -if [[ $build -eq 1 && ! -x "$bin_src" ]]; then - cargo_config_output="" - cargo_config_output="$("${repo_root}/scripts/macos-cargo-config.sh" "$arch" "$mode")" - ( - cd "$repo_root" - set -- - if [[ -n "$cargo_config_output" ]]; then - while IFS= read -r arg; do - set -- "$@" "$arg" - done <<<"$cargo_config_output" - fi - if [[ "$mode" == "release" ]]; then - set -- "$@" --release - fi - set -- "$@" -p gitcomet --locked --features ui-gpui,gix --bin gitcomet - cargo build "$@" - ) -fi - -if [[ ! -x "$bin_src" ]]; then - echo "Binary not found or not executable: $bin_src" >&2 - echo "Build first or omit --no-build." >&2 - exit 1 -fi - -if [[ "$out_dir" = /* ]]; then - mkdir -p "$out_dir" - out_abs="$(cd "$out_dir" && pwd)" -else - mkdir -p "${repo_root}/${out_dir}" - out_abs="$(cd "${repo_root}/${out_dir}" && pwd)" -fi - -show_disk_usage() { - local label="$1" - local cargo_home="${CARGO_HOME:-${HOME:-}/.cargo}" - - echo "macOS packaging disk usage ($label):" - df -h || true - for path in \ - "${repo_root}/target" \ - "${cargo_home}/registry" \ - "${cargo_home}/git" \ - "$out_abs" \ - "${RUNNER_TEMP:-}" - do - if [[ -z "$path" ]]; then - continue - fi - if [[ -e "$path" ]]; then - du -sh "$path" || true - else - echo "missing: $path" - fi - done -} - -dmg_size_for_source() { - local source_dir="$1" - local source_kib - source_kib="$(du -sk "$source_dir" | awk '{print $1}')" - - # hdiutil's inferred size for -srcfolder can be too small for signed app - # bundles. Add 30% plus 64 MiB for filesystem metadata and small-file slack. - echo $(( (source_kib * 13 / 10 + 65536 + 1023) / 1024 )) -} - -clean_target_intermediates_for_ci() { - if [[ "${GITCOMET_MACOS_PACKAGE_CLEAN_TARGET:-0}" != "1" ]]; then - return - fi - - local target_dir="${repo_root}/target/${mode}" - if [[ ! -d "$target_dir" ]]; then - return - fi - - echo "Cleaning Cargo ${mode} build intermediates before creating macOS archives." - for path in \ - "${target_dir}/.fingerprint" \ - "${target_dir}/build" \ - "${target_dir}/deps" \ - "${target_dir}/examples" \ - "${target_dir}/incremental" - do - if [[ -e "$path" ]]; then - rm -rf "$path" - fi - done -} - -stage_root="${out_abs}/stage" -release_root="gitcomet-v${version}-macos-${arch}" -release_dir="${stage_root}/${release_root}" -app_bundle="${release_dir}/GitComet.app" -contents_dir="${app_bundle}/Contents" -macos_dir="${contents_dir}/MacOS" -resources_dir="${contents_dir}/Resources" - -rm -rf "$release_dir" -mkdir -p "$macos_dir" "$resources_dir" - -install -m755 "$bin_src" "${macos_dir}/gitcomet" -install -m755 "$bin_src" "${release_dir}/gitcomet" -install -m644 "${repo_root}/README.md" "${release_dir}/README.md" -install -m644 "${repo_root}/LICENSE-AGPL-3.0" "${release_dir}/LICENSE-AGPL-3.0" -install -m644 "${repo_root}/NOTICE" "${release_dir}/NOTICE" - -icon_png="${repo_root}/assets/gitcomet-512.png" -icon_icns="${resources_dir}/GitComet.icns" - -if [[ ! -f "$icon_png" ]]; then - echo "Missing macOS icon source: $icon_png" >&2 - exit 1 -fi -if ! command -v sips >/dev/null 2>&1; then - echo "sips is required to build the macOS app icon." >&2 - exit 1 -fi -sips -s format icns "$icon_png" --out "$icon_icns" >/dev/null - -cat > "${contents_dir}/Info.plist" < - - - - CFBundleDevelopmentRegion - en - CFBundleDisplayName - GitComet - CFBundleExecutable - gitcomet - CFBundleIdentifier - ai.autoexplore.gitcomet - CFBundleIconFile - GitComet.icns - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - GitComet - CFBundlePackageType - APPL - CFBundleShortVersionString - ${version} - CFBundleVersion - ${version} - LSMinimumSystemVersion - 13.0 - NSHighResolutionCapable - - - -PLIST - -if [[ -n "$codesign_identity" ]]; then - if ! command -v codesign >/dev/null 2>&1; then - echo "codesign is required when --codesign-identity is set." >&2 - exit 1 - fi - - sign_args=(--force --timestamp --options runtime --sign "$codesign_identity") - if [[ -n "$codesign_keychain" ]]; then - sign_args+=(--keychain "$codesign_keychain") - fi - - echo "Signing macOS artifacts with identity: $codesign_identity" - codesign "${sign_args[@]}" "${macos_dir}/gitcomet" - codesign "${sign_args[@]}" "${release_dir}/gitcomet" - codesign "${sign_args[@]}" "$app_bundle" - - codesign --verify --strict --verbose=2 "${release_dir}/gitcomet" - codesign --verify --strict --verbose=2 "$app_bundle" -fi - -if [[ "${GITCOMET_MACOS_PACKAGE_CLEAN_TARGET:-0}" == "1" ]]; then - show_disk_usage "before target cleanup" - clean_target_intermediates_for_ci - show_disk_usage "after target cleanup" -fi - -# Create a deterministic tarball root directory per version/arch. -tarball_path="${out_abs}/${release_root}.tar.gz" -rm -f "$tarball_path" -tar -C "$stage_root" -czf "$tarball_path" "$release_root" - -dmg_path="${out_abs}/${release_root}.dmg" -if [[ $create_dmg -eq 1 ]]; then - # Build a drag-and-drop DMG with an /Applications shortcut. - dmg_stage="${out_abs}/dmg-stage-${arch}" - rm -rf "$dmg_stage" - mkdir -p "$dmg_stage" - cp -R "$app_bundle" "${dmg_stage}/GitComet.app" - ln -s /Applications "${dmg_stage}/Applications" - dmg_size_mib="$(dmg_size_for_source "$dmg_stage")" - echo "Creating macOS DMG with ${dmg_size_mib} MiB filesystem." - - # Preserve compatibility with older macOS tooling. - rm -f "$dmg_path" - hdiutil create \ - -volname "GitComet" \ - -srcfolder "$dmg_stage" \ - -fs HFS+ \ - -size "${dmg_size_mib}m" \ - -ov \ - -format UDZO \ - "$dmg_path" >/dev/null - - rm -rf "$dmg_stage" - - if [[ -n "$codesign_identity" ]]; then - codesign "${sign_args[@]}" "$dmg_path" - codesign --verify --strict --verbose=2 "$dmg_path" - fi -fi - -echo "Packaged macOS artifacts:" -echo " $tarball_path" -if [[ $create_dmg -eq 1 ]]; then - echo " $dmg_path" -else - echo " (skipped DMG creation via --skip-dmg)" -fi From 6770e9c51c9da398c06f0803b20eb30485915480 Mon Sep 17 00:00:00 2001 From: ryanleecode <> Date: Wed, 7 Oct 2026 01:34:30 -0400 Subject: [PATCH 2/2] ci: fix deployment-ci apppublisher gate grep for SHA-pinned action The 'Validate deployment workflow config keys' step asserted the literal microsoft/microsoft-store-apppublisher@v1.4, but deploy-microsoft-store.yml pins that action by commit SHA (@cc9910a8... # v1.4). Match the action reference plus its '# v1.4' version comment so the gate stays green. This step first runs on this PR because it is the first change to touch the deployment-ci trigger paths. --- .github/workflows/deployment-ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/deployment-ci.yml b/.github/workflows/deployment-ci.yml index 566f0e57d..ff49816d2 100644 --- a/.github/workflows/deployment-ci.yml +++ b/.github/workflows/deployment-ci.yml @@ -113,7 +113,8 @@ jobs: grep -Fq 'dbus-launch --sh-syntax' .github/workflows/deploy-microsoft-store.yml grep -Fq 'gnome-keyring-daemon --start --components=secrets' .github/workflows/deploy-microsoft-store.yml grep -Fq 'libsecret-1-0' .github/workflows/deploy-microsoft-store.yml - grep -Fq 'microsoft/microsoft-store-apppublisher@v1.4' .github/workflows/deploy-microsoft-store.yml + grep -Fq 'microsoft/microsoft-store-apppublisher@' .github/workflows/deploy-microsoft-store.yml + grep -Fq '# v1.4' .github/workflows/deploy-microsoft-store.yml grep -Fq 'gh release view' .github/workflows/deploy-microsoft-store.yml grep -Fq 'msstore submission update' .github/workflows/deploy-microsoft-store.yml grep -Fq 'msstore submission updateMetadata' .github/workflows/deploy-microsoft-store.yml