fix: make language switching reliable during refresh #6
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 | |
| on: | |
| push: | |
| tags: | |
| - "v*" | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: Existing semantic version tag to publish | |
| required: true | |
| type: string | |
| permissions: | |
| contents: write | |
| id-token: write | |
| attestations: write | |
| jobs: | |
| release: | |
| runs-on: macos-26 | |
| timeout-minutes: 30 | |
| env: | |
| APPLE_DEVELOPER_ID_CERTIFICATE_BASE64: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE_BASE64 }} | |
| APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD: ${{ secrets.APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| APPLE_NOTARY_KEY_BASE64: ${{ secrets.APPLE_NOTARY_KEY_BASE64 }} | |
| APPLE_NOTARY_KEY_ID: ${{ secrets.APPLE_NOTARY_KEY_ID }} | |
| APPLE_NOTARY_ISSUER_ID: ${{ secrets.APPLE_NOTARY_ISSUER_ID }} | |
| SPARKLE_EDDSA_PRIVATE_KEY: ${{ secrets.SPARKLE_EDDSA_PRIVATE_KEY }} | |
| GH_TOKEN: ${{ github.token }} | |
| steps: | |
| - name: Resolve release tag | |
| id: release | |
| env: | |
| INPUT_TAG: ${{ inputs.tag }} | |
| run: | | |
| if [[ "${GITHUB_REF_TYPE:-}" == "tag" ]]; then | |
| TAG="$GITHUB_REF_NAME" | |
| else | |
| TAG="$INPUT_TAG" | |
| fi | |
| if [[ ! "$TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+$ ]]; then | |
| echo "Expected a semantic version tag such as v0.2.0" >&2 | |
| exit 1 | |
| fi | |
| echo "tag=$TAG" >>"$GITHUB_OUTPUT" | |
| echo "version=${TAG#v}" >>"$GITHUB_OUTPUT" | |
| - name: Check out release tag | |
| uses: actions/checkout@v6 | |
| with: | |
| ref: ${{ steps.release.outputs.tag }} | |
| - name: Resolve signing mode | |
| id: signing | |
| run: | | |
| required=( | |
| APPLE_DEVELOPER_ID_CERTIFICATE_BASE64 | |
| APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD | |
| APPLE_TEAM_ID | |
| APPLE_NOTARY_KEY_BASE64 | |
| APPLE_NOTARY_KEY_ID | |
| APPLE_NOTARY_ISSUER_ID | |
| ) | |
| configured=0 | |
| for name in "${required[@]}"; do | |
| if [[ -n "${!name:-}" ]]; then | |
| configured=$((configured + 1)) | |
| fi | |
| done | |
| if [[ "$configured" -eq 0 ]]; then | |
| echo "mode=adhoc" >>"$GITHUB_OUTPUT" | |
| echo "SIGNING_MODE=adhoc" >>"$GITHUB_ENV" | |
| echo "CODE_SIGN_IDENTITY=-" >>"$GITHUB_ENV" | |
| echo "Publishing an ad-hoc signed release." | |
| elif [[ "$configured" -eq "${#required[@]}" ]]; then | |
| echo "mode=developer-id" >>"$GITHUB_OUTPUT" | |
| echo "SIGNING_MODE=developer-id" >>"$GITHUB_ENV" | |
| echo "Publishing a Developer ID signed and notarized release." | |
| else | |
| echo "Apple release credentials are only partially configured." >&2 | |
| echo "Configure all six Apple secrets, or remove all of them for an ad-hoc release." >&2 | |
| for name in "${required[@]}"; do | |
| if [[ -z "${!name:-}" ]]; then | |
| echo "Missing GitHub Actions secret: $name" >&2 | |
| fi | |
| done | |
| exit 1 | |
| fi | |
| - name: Install XcodeGen | |
| run: brew install xcodegen | |
| - name: Import Developer ID certificate | |
| if: steps.signing.outputs.mode == 'developer-id' | |
| run: | | |
| KEYCHAIN_PATH="$RUNNER_TEMP/codex-usage-signing.keychain-db" | |
| CERTIFICATE_PATH="$RUNNER_TEMP/developer-id.p12" | |
| KEYCHAIN_PASSWORD="$(openssl rand -hex 24)" | |
| printf '%s' "$APPLE_DEVELOPER_ID_CERTIFICATE_BASE64" \ | |
| | base64 --decode >"$CERTIFICATE_PATH" | |
| 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 "$CERTIFICATE_PATH" \ | |
| -k "$KEYCHAIN_PATH" \ | |
| -P "$APPLE_DEVELOPER_ID_CERTIFICATE_PASSWORD" \ | |
| -T /usr/bin/codesign | |
| security set-key-partition-list \ | |
| -S apple-tool:,apple:,codesign: \ | |
| -s \ | |
| -k "$KEYCHAIN_PASSWORD" \ | |
| "$KEYCHAIN_PATH" | |
| security list-keychains -d user -s "$KEYCHAIN_PATH" | |
| IDENTITY="$( | |
| security find-identity -v -p codesigning "$KEYCHAIN_PATH" \ | |
| | awk '/Developer ID Application/{print $2; exit}' | |
| )" | |
| if [[ -z "$IDENTITY" ]]; then | |
| echo "Developer ID Application identity was not imported" >&2 | |
| exit 1 | |
| fi | |
| echo "CODE_SIGN_IDENTITY=$IDENTITY" >>"$GITHUB_ENV" | |
| echo "APP_GROUP_IDENTIFIER=$APPLE_TEAM_ID.io.cmmuu.codex-usage-bar" \ | |
| >>"$GITHUB_ENV" | |
| - name: Build and package DMG | |
| env: | |
| VERSION: ${{ steps.release.outputs.version }} | |
| BUILD_NUMBER: ${{ github.run_number }} | |
| run: make release-package | |
| - name: Verify release artifacts | |
| env: | |
| VERSION: ${{ steps.release.outputs.version }} | |
| run: | | |
| APP="dist/Codex Usage Bar.app" | |
| WIDGET="$APP/Contents/PlugIns/CodexUsageWidget.appex" | |
| ICON="$APP/Contents/Resources/AppIcon.icns" | |
| SPARKLE="$APP/Contents/Frameworks/Sparkle.framework" | |
| DMG="dist/Codex-Usage-Bar-v$VERSION-universal.dmg" | |
| WIDGET_ENTITLEMENTS="$RUNNER_TEMP/widget-entitlements.plist" | |
| codesign --verify --deep --strict --verbose=2 "$APP" | |
| ( | |
| cd dist | |
| shasum -a 256 -c "$(basename "$DMG").sha256" | |
| ) | |
| test -d "$WIDGET" | |
| test -f "$ICON" | |
| test -d "$SPARKLE" | |
| codesign --verify --deep --strict --verbose=2 "$SPARKLE" | |
| codesign -d --entitlements :- "$WIDGET" \ | |
| >"$WIDGET_ENTITLEMENTS" | |
| test "$( | |
| plutil -extract 'com\.apple\.security\.network\.client' raw \ | |
| "$WIDGET_ENTITLEMENTS" | |
| )" = "true" | |
| test "$( | |
| plutil -extract CFBundleIconFile raw "$APP/Contents/Info.plist" | |
| )" = "AppIcon.icns" | |
| test "$( | |
| plutil -extract SUFeedURL raw "$APP/Contents/Info.plist" | |
| )" = "https://github.com/CMMUU/codex-usage-bar/releases/latest/download/appcast.xml" | |
| test "$( | |
| plutil -extract SUVerifyUpdateBeforeExtraction raw \ | |
| "$APP/Contents/Info.plist" | |
| )" = "true" | |
| if [[ "$SIGNING_MODE" == "developer-id" ]]; then | |
| codesign --verify --verbose=2 "$DMG" | |
| xcrun stapler validate "$DMG" | |
| spctl --assess --type execute --verbose=2 "$APP" | |
| else | |
| codesign -dvv "$APP" 2>&1 | grep -q "Signature=adhoc" | |
| fi | |
| - name: Generate signed Sparkle appcast | |
| env: | |
| TAG: ${{ steps.release.outputs.tag }} | |
| VERSION: ${{ steps.release.outputs.version }} | |
| run: | | |
| test -n "$SPARKLE_EDDSA_PRIVATE_KEY" | |
| ./Scripts/generate_appcast.sh | |
| - name: Generate build provenance | |
| uses: actions/attest@v4 | |
| with: | |
| subject-path: | | |
| dist/Codex-Usage-Bar-v${{ steps.release.outputs.version }}-universal.dmg | |
| dist/Codex-Usage-Bar-v${{ steps.release.outputs.version }}-universal.dmg.sha256 | |
| dist/appcast.xml | |
| - name: Publish GitHub Release | |
| env: | |
| TAG: ${{ steps.release.outputs.tag }} | |
| VERSION: ${{ steps.release.outputs.version }} | |
| run: | | |
| DMG="dist/Codex-Usage-Bar-v$VERSION-universal.dmg" | |
| CHECKSUM="$DMG.sha256" | |
| APPCAST="dist/appcast.xml" | |
| NOTES="docs/release-notes/$TAG.md" | |
| if gh release view "$TAG" >/dev/null 2>&1; then | |
| gh release upload \ | |
| "$TAG" "$DMG" "$CHECKSUM" "$APPCAST" \ | |
| --clobber | |
| gh release edit "$TAG" \ | |
| --title "Codex Usage Bar $TAG" \ | |
| --notes-file "$NOTES" \ | |
| --latest | |
| else | |
| gh release create "$TAG" "$DMG" "$CHECKSUM" "$APPCAST" \ | |
| --title "Codex Usage Bar $TAG" \ | |
| --notes-file "$NOTES" \ | |
| --latest | |
| fi |