From 58fbe56298177208131a38a65e18f24e7a78244e Mon Sep 17 00:00:00 2001 From: SuperDooper86 Date: Thu, 10 Sep 2026 00:08:31 +0200 Subject: [PATCH] ci: retire the superseded GitHub release workflows --- .github/workflows/build.yml | 63 --------- .github/workflows/finalize-release.yml | 92 ------------- .github/workflows/release.yml | 88 ------------- scripts/configure_github_release_secrets.sh | 34 ----- scripts/finalize_release.sh | 139 -------------------- 5 files changed, 416 deletions(-) delete mode 100644 .github/workflows/build.yml delete mode 100644 .github/workflows/finalize-release.yml delete mode 100644 .github/workflows/release.yml delete mode 100755 scripts/configure_github_release_secrets.sh delete mode 100755 scripts/finalize_release.sh diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml deleted file mode 100644 index 2127681..0000000 --- a/.github/workflows/build.yml +++ /dev/null @@ -1,63 +0,0 @@ -name: Build - -on: - pull_request: - branches: [main] - push: - branches: [main] - workflow_dispatch: - -jobs: - macos: - runs-on: macos-15 - steps: - - uses: actions/checkout@v4 - - name: Build Meetingnotes - run: >- - xcodebuild - -project Meetingnotes.xcodeproj - -scheme meetingnotes - -configuration Release - -destination 'generic/platform=macOS' - -derivedDataPath "$RUNNER_TEMP/DerivedData" - ARCHS="arm64 x86_64" - ONLY_ACTIVE_ARCH=NO - CODE_SIGNING_ALLOWED=NO - build - - name: Sign test build - run: | - app_path="$RUNNER_TEMP/DerivedData/Build/Products/Release/Meetingnotes.app" - codesign --force --deep --sign - \ - --entitlements meetingnotes/meetingnotes.entitlements \ - "$app_path" - codesign --verify --deep --strict "$app_path" - codesign -d --entitlements :- "$app_path" 2>&1 \ - | grep -q 'com.apple.security.network.server' - - name: Smoke test local API - run: | - defaults write net.jamesbone.meetingnotes muteDeckAPIEnabled -bool true - defaults write net.jamesbone.meetingnotes muteDeckAPIPort -int 19880 - "$RUNNER_TEMP/DerivedData/Build/Products/Release/Meetingnotes.app/Contents/MacOS/Meetingnotes" >"$RUNNER_TEMP/meetingnotes.log" 2>&1 & - app_pid=$! - trap 'kill "$app_pid" 2>/dev/null || true' EXIT - - for _ in {1..20}; do - if curl -fsS http://127.0.0.1:19880/api/info >"$RUNNER_TEMP/api-info.json"; then - break - fi - sleep 1 - done - - grep -q '"name":"MeetingDebrief"' "$RUNNER_TEMP/api-info.json" - test "$(curl -sS -o /dev/null -w '%{http_code}' http://127.0.0.1:19880/api/recording/status)" = "401" - - name: Package test build - run: | - app_path="$RUNNER_TEMP/DerivedData/Build/Products/Release/Meetingnotes.app" - ditto -c -k --sequesterRsrc --keepParent \ - "$app_path" "$RUNNER_TEMP/Meetingnotes-macOS.zip" - - name: Upload test build - uses: actions/upload-artifact@v4 - with: - name: Meetingnotes-macOS-${{ github.sha }} - path: ${{ runner.temp }}/Meetingnotes-macOS.zip - retention-days: 30 diff --git a/.github/workflows/finalize-release.yml b/.github/workflows/finalize-release.yml deleted file mode 100644 index 21ff57a..0000000 --- a/.github/workflows/finalize-release.yml +++ /dev/null @@ -1,92 +0,0 @@ -name: Finalize Notarization (manual) - -on: - workflow_dispatch: - inputs: - release_run_id: - description: Release workflow run ID; leave blank to use the latest pending run - required: false - type: string - -permissions: - actions: read - contents: write - -concurrency: - group: meetingnotes-finalize-release - cancel-in-progress: false - -jobs: - finalize: - if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success' - runs-on: macos-15 - env: - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} - SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }} - GH_TOKEN: ${{ github.token }} - steps: - - uses: actions/checkout@v7 - - - name: Validate release secrets - run: | - for variable in APPLE_ID APPLE_TEAM_ID APPLE_APP_PASSWORD SPARKLE_PRIVATE_KEY; do - if [[ -z "${!variable:-}" ]]; then - echo "Missing GitHub Actions secret: $variable" >&2 - exit 1 - fi - done - - - name: Download pending signed build - id: submission - env: - MANUAL_RUN_ID: ${{ inputs.release_run_id }} - COMPLETED_RUN_ID: ${{ github.event.workflow_run.id }} - run: | - PENDING_DIR="$RUNNER_TEMP/meetingnotes-pending" - candidate_ids=() - if [[ -n "${MANUAL_RUN_ID:-}" ]]; then - candidate_ids+=("$MANUAL_RUN_ID") - elif [[ -n "${COMPLETED_RUN_ID:-}" ]]; then - candidate_ids+=("$COMPLETED_RUN_ID") - else - while IFS= read -r run_id; do - candidate_ids+=("$run_id") - done < <(gh run list --repo "$GITHUB_REPOSITORY" --workflow Release --status success --limit 20 --json databaseId --jq '.[].databaseId') - fi - - for run_id in "${candidate_ids[@]}"; do - if [[ ! "$run_id" =~ ^[0-9]+$ ]]; then - echo "Invalid release run ID: $run_id" >&2 - exit 1 - fi - - artifact_name="meetingnotes-notarization-$run_id" - artifact_count=$(gh api "repos/$GITHUB_REPOSITORY/actions/runs/$run_id/artifacts" \ - --jq "[.artifacts[] | select(.name == \"$artifact_name\" and .expired == false)] | length") - if [[ "$artifact_count" == 0 ]]; then - continue - fi - - rm -rf "$PENDING_DIR" - mkdir -p "$PENDING_DIR" - gh run download "$run_id" --repo "$GITHUB_REPOSITORY" --name "$artifact_name" --dir "$PENDING_DIR" - - version=$(<"$PENDING_DIR/version") - if gh release view "v$version" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then - continue - fi - - echo "found=true" >> "$GITHUB_OUTPUT" - echo "run_id=$run_id" >> "$GITHUB_OUTPUT" - echo "Using release submission from workflow run $run_id" - exit 0 - done - - echo "found=false" >> "$GITHUB_OUTPUT" - echo "No pending release submission was found" - - - name: Check notarization and publish when accepted - if: steps.submission.outputs.found == 'true' - run: scripts/finalize_release.sh diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 1d67cd9..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: Release - -on: - workflow_dispatch: - inputs: - version: - description: Version from MARKETING_VERSION, without the v prefix - required: true - type: string - -permissions: - contents: write - -concurrency: - group: meetingnotes-release - cancel-in-progress: false - -jobs: - release: - runs-on: macos-15 - env: - VERSION: ${{ inputs.version }} - APPLE_ID: ${{ secrets.APPLE_ID }} - APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} - APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }} - SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }} - steps: - - uses: actions/checkout@v7 - with: - fetch-depth: 0 - - - name: Validate release secrets - env: - APPLE_CERTIFICATE_P12: ${{ secrets.APPLE_CERTIFICATE_P12 }} - APPLE_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - run: | - for variable in APPLE_CERTIFICATE_P12 APPLE_CERTIFICATE_PASSWORD APPLE_ID APPLE_TEAM_ID APPLE_APP_PASSWORD SPARKLE_PRIVATE_KEY; do - if [[ -z "${!variable:-}" ]]; then - echo "Missing GitHub Actions secret: $variable" >&2 - exit 1 - fi - done - - - name: Import Developer ID certificate - uses: apple-actions/import-codesign-certs@v7 - with: - p12-file-base64: ${{ secrets.APPLE_CERTIFICATE_P12 }} - p12-password: ${{ secrets.APPLE_CERTIFICATE_PASSWORD }} - - - name: Locate Developer ID identity - run: | - signing_identity=$(security find-identity -v -p codesigning | awk -F '"' '/Developer ID Application/{print $2; exit}') - if [[ -z "$signing_identity" ]]; then - echo "The .p12 does not contain a Developer ID Application identity" >&2 - exit 1 - fi - echo "SIGNING_IDENTITY=$signing_identity" >> "$GITHUB_ENV" - - - name: Build, sign, and notarize release - timeout-minutes: 30 - run: scripts/package_release.sh - - - name: Preserve signed release artifacts - uses: actions/upload-artifact@v4 - with: - name: meetingnotes-signed-release-${{ github.run_id }} - path: ${{ runner.temp }}/meetingnotes-release/release - if-no-files-found: error - retention-days: 30 - - - name: Publish signed GitHub release - env: - GH_TOKEN: ${{ github.token }} - run: | - tag="v$VERSION" - if gh release view "$tag" >/dev/null 2>&1; then - gh release upload "$tag" \ - "$RUNNER_TEMP/meetingnotes-release/release/Meetingnotes-$VERSION.zip" \ - "$RUNNER_TEMP/meetingnotes-release/release/appcast.xml" \ - --clobber - else - gh release create "$tag" \ - "$RUNNER_TEMP/meetingnotes-release/release/Meetingnotes-$VERSION.zip" \ - "$RUNNER_TEMP/meetingnotes-release/release/appcast.xml" \ - --target "$GITHUB_SHA" \ - --title "Meetingnotes $VERSION" \ - --generate-notes - fi diff --git a/scripts/configure_github_release_secrets.sh b/scripts/configure_github_release_secrets.sh deleted file mode 100755 index ea9baee..0000000 --- a/scripts/configure_github_release_secrets.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -REPOSITORY="${REPOSITORY:-superdooper86/meetingnotes}" - -if ! command -v gh >/dev/null 2>&1; then - echo "Install GitHub CLI first: brew install gh" >&2 - exit 1 -fi - -gh auth status >/dev/null - -read -r -p "Developer ID certificate (.p12) path: " certificate_path -if [[ ! -f "$certificate_path" ]]; then - echo "Certificate not found: $certificate_path" >&2 - exit 1 -fi - -read -r -s -p "Certificate export password: " certificate_password -printf '\n' -read -r -p "Apple ID email: " apple_id -read -r -p "Apple Developer Team ID: " team_id -read -r -s -p "Apple app-specific password: " app_password -printf '\n' - -base64 < "$certificate_path" | gh secret set APPLE_CERTIFICATE_P12 -R "$REPOSITORY" -printf '%s' "$certificate_password" | gh secret set APPLE_CERTIFICATE_PASSWORD -R "$REPOSITORY" -printf '%s' "$apple_id" | gh secret set APPLE_ID -R "$REPOSITORY" -printf '%s' "$team_id" | gh secret set APPLE_TEAM_ID -R "$REPOSITORY" -printf '%s' "$app_password" | gh secret set APPLE_APP_PASSWORD -R "$REPOSITORY" - -unset certificate_password app_password -echo "Apple release secrets configured for $REPOSITORY." diff --git a/scripts/finalize_release.sh b/scripts/finalize_release.sh deleted file mode 100755 index 42dabdf..0000000 --- a/scripts/finalize_release.sh +++ /dev/null @@ -1,139 +0,0 @@ -#!/usr/bin/env bash - -set -euo pipefail - -APP_NAME="Meetingnotes" -RUNNER_TEMP="${RUNNER_TEMP:-/tmp}" -PENDING_DIR="${PENDING_DIR:-$RUNNER_TEMP/meetingnotes-pending}" -WORK_ROOT="${WORK_ROOT:-$RUNNER_TEMP/meetingnotes-finalize}" -APP_PATH="$WORK_ROOT/$APP_NAME.app" -RELEASE_DIR="$WORK_ROOT/release" -VERSION_PATH="$PENDING_DIR/version" -COMMIT_SHA_PATH="$PENDING_DIR/commit-sha" -SUBMISSION_PATH="$PENDING_DIR/notary-submission.json" -PRE_NOTARY_ZIP="$PENDING_DIR/$APP_NAME-pre-notary.zip" - -required_variables=( - APPLE_ID - APPLE_TEAM_ID - APPLE_APP_PASSWORD - SPARKLE_PRIVATE_KEY - GH_TOKEN - GITHUB_REPOSITORY -) - -for variable in "${required_variables[@]}"; do - if [[ -z "${!variable:-}" ]]; then - echo "Missing required environment variable: $variable" >&2 - exit 1 - fi -done - -for path in "$VERSION_PATH" "$COMMIT_SHA_PATH" "$SUBMISSION_PATH" "$PRE_NOTARY_ZIP" "$PENDING_DIR/generate_appcast"; do - if [[ ! -e "$path" ]]; then - echo "Missing release submission artifact: $path" >&2 - exit 1 - fi -done - -VERSION=$(<"$VERSION_PATH") -COMMIT_SHA=$(<"$COMMIT_SHA_PATH") -SUBMISSION_ID=$(plutil -extract id raw -o - "$SUBMISSION_PATH") -TAG="v$VERSION" - -if gh release view "$TAG" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then - echo "Release already exists: $TAG" - exit 0 -fi - -STATUS_PATH="$WORK_ROOT/notary-status.json" -rm -rf "$WORK_ROOT" -mkdir -p "$RELEASE_DIR" - -notary_info_succeeded=false -for attempt in 1 2 3; do - if xcrun notarytool info "$SUBMISSION_ID" \ - --apple-id "$APPLE_ID" \ - --team-id "$APPLE_TEAM_ID" \ - --password "$APPLE_APP_PASSWORD" \ - --output-format json > "$STATUS_PATH"; then - notary_info_succeeded=true - break - fi - echo "Notary status check failed ($attempt/3); retrying" - sleep 15 -done - -if [[ "$notary_info_succeeded" != true ]]; then - echo "Unable to query Apple notarization status after three attempts" >&2 - exit 1 -fi - -NOTARY_STATUS=$(plutil -extract status raw -o - "$STATUS_PATH") -echo "Notarization status for $SUBMISSION_ID: $NOTARY_STATUS" - -case "$NOTARY_STATUS" in - "In Progress") - if [[ -n "${GITHUB_STEP_SUMMARY:-}" ]]; then - printf 'Apple is still processing Meetingnotes %s. Submission: `%s`. The scheduled workflow will check again.\n' \ - "$VERSION" "$SUBMISSION_ID" >> "$GITHUB_STEP_SUMMARY" - fi - exit 0 - ;; - Accepted) - ;; - Invalid|Rejected) - xcrun notarytool log "$SUBMISSION_ID" \ - --apple-id "$APPLE_ID" \ - --team-id "$APPLE_TEAM_ID" \ - --password "$APPLE_APP_PASSWORD" || true - exit 1 - ;; - *) - echo "Unexpected notarization status: $NOTARY_STATUS" >&2 - exit 1 - ;; -esac - -ditto -x -k "$PRE_NOTARY_ZIP" "$WORK_ROOT" -if [[ ! -d "$APP_PATH" ]]; then - echo "Signed app was not found after extracting $PRE_NOTARY_ZIP" >&2 - exit 1 -fi - -APP_VERSION=$(plutil -extract CFBundleShortVersionString raw -o - "$APP_PATH/Contents/Info.plist") -if [[ "$APP_VERSION" != "$VERSION" ]]; then - echo "Signed app version $APP_VERSION does not match release version $VERSION" >&2 - exit 1 -fi - -xcrun stapler staple "$APP_PATH" -xcrun stapler validate "$APP_PATH" -spctl --assess --type execute --verbose=2 "$APP_PATH" - -ARCHIVE_NAME="$APP_NAME-$VERSION.zip" -ARCHIVE_PATH="$RELEASE_DIR/$ARCHIVE_NAME" -ditto -c -k --sequesterRsrc --keepParent "$APP_PATH" "$ARCHIVE_PATH" - -GENERATE_APPCAST="$PENDING_DIR/generate_appcast" -chmod +x "$GENERATE_APPCAST" -DOWNLOAD_URL="https://github.com/$GITHUB_REPOSITORY/releases/download/$TAG/" -printf '%s' "$SPARKLE_PRIVATE_KEY" | "$GENERATE_APPCAST" "$RELEASE_DIR" \ - --ed-key-file - \ - --download-url-prefix "$DOWNLOAD_URL" \ - --maximum-deltas 0 \ - -o "$RELEASE_DIR/appcast.xml" - -grep -q "$DOWNLOAD_URL$ARCHIVE_NAME" "$RELEASE_DIR/appcast.xml" -grep -q 'sparkle:edSignature=' "$RELEASE_DIR/appcast.xml" - -gh release \ - create "$TAG" \ - "$ARCHIVE_PATH" \ - "$RELEASE_DIR/appcast.xml" \ - --repo "$GITHUB_REPOSITORY" \ - --target "$COMMIT_SHA" \ - --title "Meetingnotes $VERSION" \ - --generate-notes - -echo "Published Meetingnotes $VERSION"