Fix slogan localization and reorganize update menu #65
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Release macOS | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| permissions: | |
| contents: write | |
| jobs: | |
| build-macos: | |
| runs-on: macos-latest | |
| env: | |
| IOGRAPH_VERSION: ${{ github.ref_name }} | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.11" | |
| cache: "pip" | |
| - name: Install dependencies | |
| run: | | |
| python -m pip install --upgrade pip | |
| pip install -r requirements.txt | |
| pip install pyinstaller | |
| CREATE_DMG_TAG="v1.2.2" | |
| CREATE_DMG_DIR="${RUNNER_TEMP}/create-dmg" | |
| git clone --depth 1 --branch "${CREATE_DMG_TAG}" https://github.com/create-dmg/create-dmg.git "${CREATE_DMG_DIR}" | |
| echo "CREATE_DMG_BIN=${CREATE_DMG_DIR}/create-dmg" >> "${GITHUB_ENV}" | |
| - name: Build app bundle | |
| run: | | |
| pyinstaller \ | |
| --noconfirm \ | |
| --windowed \ | |
| --name IOGraph \ | |
| --icon packaging/assets/dmg/IOGraphVolume.icns \ | |
| --add-data "iograph/resources:iograph/resources" \ | |
| --collect-all PyQt6 \ | |
| run_iograph.py | |
| - name: Set app bundle version metadata | |
| run: | | |
| APP_PLIST="dist/IOGraph.app/Contents/Info.plist" | |
| /usr/libexec/PlistBuddy -c "Set :CFBundleShortVersionString ${IOGRAPH_VERSION}" "$APP_PLIST" || /usr/libexec/PlistBuddy -c "Add :CFBundleShortVersionString string ${IOGRAPH_VERSION}" "$APP_PLIST" | |
| /usr/libexec/PlistBuddy -c "Set :CFBundleVersion ${GITHUB_RUN_NUMBER}" "$APP_PLIST" || /usr/libexec/PlistBuddy -c "Add :CFBundleVersion string ${GITHUB_RUN_NUMBER}" "$APP_PLIST" | |
| /usr/libexec/PlistBuddy -c "Set :LSUIElement true" "$APP_PLIST" || /usr/libexec/PlistBuddy -c "Add :LSUIElement bool true" "$APP_PLIST" | |
| - name: Validate signing and notarization secrets | |
| env: | |
| APPLE_CERT_P12_BASE64: ${{ secrets.APPLE_CERT_P12_BASE64 }} | |
| APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }} | |
| APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }} | |
| run: | | |
| set -euo pipefail | |
| for key in APPLE_CERT_P12_BASE64 APPLE_CERT_PASSWORD APPLE_TEAM_ID APPLE_API_KEY_ID APPLE_API_ISSUER_ID APPLE_API_KEY_P8; do | |
| if [[ -z "${!key:-}" ]]; then | |
| echo "::error::Missing required secret: ${key}" | |
| exit 1 | |
| fi | |
| done | |
| - name: Import Developer ID certificate | |
| env: | |
| APPLE_CERT_P12_BASE64: ${{ secrets.APPLE_CERT_P12_BASE64 }} | |
| APPLE_CERT_PASSWORD: ${{ secrets.APPLE_CERT_PASSWORD }} | |
| run: | | |
| set -euo pipefail | |
| CERT_PATH="${RUNNER_TEMP}/developer_id_application.p12" | |
| KEYCHAIN_PATH="${RUNNER_TEMP}/build-signing.keychain-db" | |
| KEYCHAIN_PASSWORD="$(openssl rand -hex 16)" | |
| if ! echo -n "${APPLE_CERT_P12_BASE64}" | base64 --decode > "${CERT_PATH}" 2>/dev/null; then | |
| echo -n "${APPLE_CERT_P12_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 "${APPLE_CERT_PASSWORD}" -T /usr/bin/codesign -T /usr/bin/security | |
| security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "${KEYCHAIN_PASSWORD}" "${KEYCHAIN_PATH}" | |
| security default-keychain -d user -s "${KEYCHAIN_PATH}" | |
| SIGN_IDENTITY="$(security find-identity -v -p codesigning "${KEYCHAIN_PATH}" | awk -F '\"' '/Developer ID Application/ {print $2; exit}')" | |
| if [[ -z "${SIGN_IDENTITY}" || "${SIGN_IDENTITY}" == "\\1" ]]; then | |
| echo "::error::Developer ID Application identity not found in imported certificate" | |
| exit 1 | |
| fi | |
| echo "MACOS_SIGN_IDENTITY=${SIGN_IDENTITY}" >> "${GITHUB_ENV}" | |
| - name: Sign app bundle (Developer ID) | |
| run: | | |
| codesign --force --deep --options runtime --timestamp --sign "${MACOS_SIGN_IDENTITY}" dist/IOGraph.app | |
| codesign --verify --deep --strict --verbose=2 dist/IOGraph.app | |
| - name: Prepare artifact | |
| run: | | |
| mkdir -p release | |
| rm -rf build/dmg-root | |
| mkdir -p build/dmg-root | |
| cp -R "dist/IOGraph.app" "build/dmg-root/IOGraph.app" | |
| ditto -c -k --sequesterRsrc --keepParent dist/IOGraph.app "release/IOGraph-macos-${IOGRAPH_VERSION}.zip" | |
| "${CREATE_DMG_BIN}" \ | |
| --volname "IOGraph" \ | |
| --volicon "packaging/assets/dmg/IOGraphVolume.icns" \ | |
| --window-pos 120 120 \ | |
| --window-size 446 216 \ | |
| --icon-size 128 \ | |
| --icon "IOGraph.app" 50 24 \ | |
| --app-drop-link 260 24 \ | |
| --format UDBZ \ | |
| "release/IOGraph-macos-${IOGRAPH_VERSION}.dmg" \ | |
| "build/dmg-root" | |
| - name: Notarize and staple DMG | |
| env: | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_ISSUER_ID: ${{ secrets.APPLE_API_ISSUER_ID }} | |
| APPLE_API_KEY_P8: ${{ secrets.APPLE_API_KEY_P8 }} | |
| run: | | |
| set -euo pipefail | |
| DMG_FILE="release/IOGraph-macos-${IOGRAPH_VERSION}.dmg" | |
| API_KEY_PATH="${RUNNER_TEMP}/AuthKey_${APPLE_API_KEY_ID}.p8" | |
| printf '%s' "${APPLE_API_KEY_P8}" > "${API_KEY_PATH}" | |
| chmod 600 "${API_KEY_PATH}" | |
| xcrun notarytool submit "${DMG_FILE}" \ | |
| --key "${API_KEY_PATH}" \ | |
| --key-id "${APPLE_API_KEY_ID}" \ | |
| --issuer "${APPLE_API_ISSUER_ID}" \ | |
| --wait | |
| xcrun stapler staple "${DMG_FILE}" | |
| xcrun stapler validate "${DMG_FILE}" | |
| # On CI runners, Gatekeeper context for DMG "open" checks can be unavailable | |
| # even for accepted + stapled artifacts ("source=Insufficient Context"). | |
| if ! spctl -a -vvv -t open "${DMG_FILE}"; then | |
| echo "::warning::spctl open check reported insufficient CI context; notarization/staple already succeeded." | |
| fi | |
| - name: Upload artifact | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: IOGraph-macos | |
| path: | | |
| release/IOGraph-macos-*.zip | |
| release/IOGraph-macos-*.dmg | |
| - name: Publish GitHub Release asset | |
| if: startsWith(github.ref, 'refs/tags/') | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| set -euo pipefail | |
| retry() { | |
| local attempt=1 | |
| local max_attempts=4 | |
| local delay_seconds=10 | |
| until "$@"; do | |
| if (( attempt >= max_attempts )); then | |
| return 1 | |
| fi | |
| echo "Command failed. Retrying in ${delay_seconds}s (attempt ${attempt}/${max_attempts})..." | |
| sleep "${delay_seconds}" | |
| attempt=$((attempt + 1)) | |
| delay_seconds=$((delay_seconds * 2)) | |
| done | |
| } | |
| TAG="${GITHUB_REF_NAME}" | |
| ZIP_FILE="release/IOGraph-macos-${IOGRAPH_VERSION}.zip" | |
| DMG_FILE="release/IOGraph-macos-${IOGRAPH_VERSION}.dmg" | |
| if ! gh release view "${TAG}" >/dev/null 2>&1; then | |
| CREATE_ARGS=(gh release create "${TAG}" --title "${TAG}" --notes "Automated release for ${TAG}") | |
| if [[ "${TAG}" == *-* ]]; then | |
| CREATE_ARGS+=(--prerelease) | |
| fi | |
| retry "${CREATE_ARGS[@]}" | |
| fi | |
| retry gh release upload "${TAG}" "${ZIP_FILE}" "${DMG_FILE}" --clobber |