chore: bump to v0.1.2 #17
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*' | |
| concurrency: | |
| group: release | |
| cancel-in-progress: false | |
| permissions: | |
| contents: write | |
| env: | |
| SCHEME: buddi | |
| TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| SIGNING_IDENTITY: "Developer ID Application" | |
| DEVELOPER_DIR: /Applications/Xcode_26.4.app/Contents/Developer | |
| jobs: | |
| release: | |
| runs-on: macos-26 | |
| timeout-minutes: 45 | |
| steps: | |
| - name: Generate App token | |
| id: app-token | |
| uses: actions/create-github-app-token@v2 | |
| with: | |
| app-id: ${{ vars.RELEASE_BOT_APP_ID }} | |
| private-key: ${{ secrets.RELEASE_BOT_PRIVATE_KEY }} | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| token: ${{ steps.app-token.outputs.token }} | |
| - name: Show Xcode version | |
| run: | | |
| echo "DEVELOPER_DIR=$DEVELOPER_DIR" | |
| xcodebuild -version | |
| xcrun swift --version | |
| - name: Extract and validate version | |
| id: version | |
| run: | | |
| VERSION=${GITHUB_REF_NAME#v} | |
| echo "VERSION=$VERSION" >> $GITHUB_OUTPUT | |
| BUILD_SETTINGS=$(xcodebuild -showBuildSettings \ | |
| -scheme $SCHEME 2>/dev/null) | |
| MARKETING_VERSION=$(printf '%s\n' "$BUILD_SETTINGS" | awk -F' = ' '/MARKETING_VERSION/ { print $2; exit }') | |
| BUILD_NUMBER=$(printf '%s\n' "$BUILD_SETTINGS" | awk -F' = ' '/CURRENT_PROJECT_VERSION/ { print $2; exit }') | |
| if [ "$MARKETING_VERSION" != "$VERSION" ]; then | |
| echo "::error::Tag v$VERSION does not match MARKETING_VERSION $MARKETING_VERSION" | |
| exit 1 | |
| fi | |
| LAST_BUILD=$(grep -oE '<sparkle:version>[0-9]+' Updates/appcast.xml 2>/dev/null | sed 's#<sparkle:version>##' | head -1 || true) | |
| if [ -n "$LAST_BUILD" ] && [ "$BUILD_NUMBER" -le "$LAST_BUILD" ]; then | |
| echo "::error::BUILD $BUILD_NUMBER must be > last published $LAST_BUILD" | |
| exit 1 | |
| fi | |
| echo "BUILD_NUMBER=$BUILD_NUMBER" >> $GITHUB_OUTPUT | |
| echo "Validated: v$VERSION (build $BUILD_NUMBER)" | |
| - name: Import code signing certificate | |
| env: | |
| CERTIFICATE_P12_BASE64: ${{ secrets.CERTIFICATE_P12_BASE64 }} | |
| CERTIFICATE_PASSWORD: ${{ secrets.CERTIFICATE_PASSWORD }} | |
| run: | | |
| KEYCHAIN=$RUNNER_TEMP/signing.keychain-db | |
| KEYCHAIN_PW=$(openssl rand -base64 32) | |
| security create-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN" | |
| security set-keychain-settings -lut 21600 "$KEYCHAIN" | |
| security unlock-keychain -p "$KEYCHAIN_PW" "$KEYCHAIN" | |
| echo "$CERTIFICATE_P12_BASE64" | base64 --decode > $RUNNER_TEMP/cert.p12 | |
| security import $RUNNER_TEMP/cert.p12 \ | |
| -P "$CERTIFICATE_PASSWORD" \ | |
| -A -t cert -f pkcs12 \ | |
| -k "$KEYCHAIN" | |
| rm -f $RUNNER_TEMP/cert.p12 | |
| security set-key-partition-list \ | |
| -S apple-tool:,apple:,codesign: \ | |
| -s -k "$KEYCHAIN_PW" "$KEYCHAIN" | |
| security list-keychain -d user -s "$KEYCHAIN" | |
| - name: Resolve SPM dependencies | |
| run: xcodebuild -resolvePackageDependencies -scheme $SCHEME | |
| - name: Locate Sparkle tools | |
| id: sparkle | |
| run: | | |
| SPARKLE_BIN=$(find ~/Library/Developer/Xcode/DerivedData \ | |
| -path "*/Sparkle/bin" -type d 2>/dev/null | head -1) | |
| if [ -z "$SPARKLE_BIN" ]; then | |
| echo "::error::Sparkle bin not found" | |
| exit 1 | |
| fi | |
| echo "SPARKLE_BIN=$SPARKLE_BIN" >> $GITHUB_OUTPUT | |
| - name: Archive | |
| run: | | |
| rm -f mediaremote-adapter/MediaRemoteAdapterTestClient | |
| xcodebuild archive \ | |
| -scheme $SCHEME \ | |
| -configuration Release \ | |
| -archivePath $RUNNER_TEMP/buddi.xcarchive \ | |
| DEVELOPMENT_TEAM=$TEAM_ID \ | |
| CODE_SIGN_STYLE=Manual \ | |
| CODE_SIGN_IDENTITY="$SIGNING_IDENTITY" | |
| - name: Export app | |
| run: | | |
| /usr/libexec/PlistBuddy -c "Add :method string developer-id" $RUNNER_TEMP/export.plist | |
| /usr/libexec/PlistBuddy -c "Add :teamID string $TEAM_ID" $RUNNER_TEMP/export.plist | |
| xcodebuild -exportArchive \ | |
| -archivePath $RUNNER_TEMP/buddi.xcarchive \ | |
| -exportOptionsPlist $RUNNER_TEMP/export.plist \ | |
| -exportPath $RUNNER_TEMP/export | |
| - name: Notarize and staple app | |
| env: | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APP_SPECIFIC_PASSWORD: ${{ secrets.APP_SPECIFIC_PASSWORD }} | |
| run: | | |
| ditto -c -k --keepParent \ | |
| "$RUNNER_TEMP/export/buddi.app" \ | |
| "$RUNNER_TEMP/buddi-submit.zip" | |
| xcrun notarytool submit "$RUNNER_TEMP/buddi-submit.zip" \ | |
| --apple-id "$APPLE_ID" \ | |
| --password "$APP_SPECIFIC_PASSWORD" \ | |
| --team-id "$TEAM_ID" \ | |
| --wait --timeout 15m | |
| xcrun stapler staple "$RUNNER_TEMP/export/buddi.app" | |
| - name: Create DMG | |
| env: | |
| VERSION: ${{ steps.version.outputs.VERSION }} | |
| run: | | |
| STAGING=$RUNNER_TEMP/dmg-staging | |
| DMG_PATH=$RUNNER_TEMP/buddi-${VERSION}.dmg | |
| mkdir -p "$STAGING" | |
| cp -R "$RUNNER_TEMP/export/buddi.app" "$STAGING/" | |
| ln -s /Applications "$STAGING/Applications" | |
| hdiutil create \ | |
| -volname "Buddi $VERSION" \ | |
| -srcfolder "$STAGING" \ | |
| -ov -format UDZO \ | |
| "$DMG_PATH" | |
| echo "DMG_PATH=$DMG_PATH" >> $GITHUB_ENV | |
| - name: Write checksum | |
| env: | |
| VERSION: ${{ steps.version.outputs.VERSION }} | |
| run: | | |
| SHASUM=$(shasum -a 256 "$DMG_PATH" | awk '{print $1}') | |
| printf '%s\n' "$SHASUM" > "$RUNNER_TEMP/buddi-${VERSION}.sha256" | |
| { | |
| echo "## Release checksum" | |
| echo | |
| echo "\`buddi-${VERSION}.dmg\` SHA-256:" | |
| echo "\`$SHASUM\`" | |
| } >> "$GITHUB_STEP_SUMMARY" | |
| - name: Write Sparkle key | |
| env: | |
| SPARKLE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }} | |
| run: | | |
| echo "$SPARKLE_KEY" > "$RUNNER_TEMP/sparkle_key" | |
| chmod 600 "$RUNNER_TEMP/sparkle_key" | |
| - name: Sign DMG for Sparkle | |
| env: | |
| VERSION: ${{ steps.version.outputs.VERSION }} | |
| SPARKLE_BIN: ${{ steps.sparkle.outputs.SPARKLE_BIN }} | |
| run: | | |
| "$SPARKLE_BIN/sign_update" --ed-key-file "$RUNNER_TEMP/sparkle_key" "$DMG_PATH" | |
| - name: Update appcast.xml | |
| env: | |
| VERSION: ${{ steps.version.outputs.VERSION }} | |
| SPARKLE_BIN: ${{ steps.sparkle.outputs.SPARKLE_BIN }} | |
| run: | | |
| mkdir -p $RUNNER_TEMP/appcast-staging | |
| cp "$DMG_PATH" $RUNNER_TEMP/appcast-staging/ | |
| cp Updates/appcast.xml $RUNNER_TEMP/appcast-staging/ 2>/dev/null || true | |
| "$SPARKLE_BIN/generate_appcast" \ | |
| --ed-key-file "$RUNNER_TEMP/sparkle_key" \ | |
| --download-url-prefix "https://github.com/talkvalue/Buddi/releases/download/v$VERSION/" \ | |
| -o Updates/appcast.xml \ | |
| $RUNNER_TEMP/appcast-staging | |
| - name: Create GitHub Release | |
| uses: softprops/action-gh-release@v2 | |
| with: | |
| files: | | |
| ${{ env.DMG_PATH }} | |
| ${{ runner.temp }}/buddi-${{ steps.version.outputs.VERSION }}.sha256 | |
| - name: Commit updated appcast | |
| env: | |
| VERSION: ${{ steps.version.outputs.VERSION }} | |
| run: | | |
| cp Updates/appcast.xml /tmp/appcast.xml | |
| git restore Updates/appcast.xml | |
| git config user.name "buddi-release-bot[bot]" | |
| git config user.email "buddi-release-bot[bot]@users.noreply.github.com" | |
| git fetch origin main | |
| git checkout main | |
| git pull origin main | |
| cp /tmp/appcast.xml Updates/appcast.xml | |
| git add Updates/appcast.xml | |
| git diff --cached --quiet && echo "No appcast changes" || \ | |
| git commit -m "chore: update appcast for v$VERSION" | |
| git push origin main | |
| - name: Deploy appcast to GitHub Pages | |
| run: | | |
| cp Updates/appcast.xml /tmp/appcast.xml | |
| git checkout --orphan gh-pages-tmp | |
| git rm -rf . --quiet | |
| cp /tmp/appcast.xml appcast.xml | |
| git add appcast.xml | |
| git commit -m "Update appcast for v${{ steps.version.outputs.VERSION }}" | |
| git push origin gh-pages-tmp:gh-pages --force | |
| git checkout main | |
| git branch -D gh-pages-tmp | |
| - name: Update Homebrew cask | |
| env: | |
| VERSION: ${{ steps.version.outputs.VERSION }} | |
| HOMEBREW_TAP_TOKEN: ${{ secrets.HOMEBREW_TAP_TOKEN }} | |
| run: | | |
| DMG_URL="https://github.com/talkvalue/Buddi/releases/download/v${VERSION}/buddi-${VERSION}.dmg" | |
| for attempt in 1 2 3; do | |
| if SHA256=$(curl -sL --fail "$DMG_URL" | shasum -a 256 | cut -d' ' -f1); then break; fi | |
| echo "Attempt $attempt failed, retrying in 10s..."; sleep 10 | |
| done | |
| [[ -n "${SHA256:-}" ]] || { echo "::error::Failed to download DMG for SHA256"; exit 1; } | |
| git clone https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/talkvalue/homebrew-buddi.git $RUNNER_TEMP/tap | |
| mkdir -p $RUNNER_TEMP/tap/Casks | |
| cat > $RUNNER_TEMP/tap/Casks/buddi.rb << CASK | |
| cask "buddi" do | |
| version "${VERSION}" | |
| sha256 "${SHA256}" | |
| url "https://github.com/talkvalue/Buddi/releases/download/v#{version}/buddi-#{version}.dmg" | |
| name "Buddi" | |
| desc "Claude Code companion for the macOS notch" | |
| homepage "https://github.com/talkvalue/Buddi" | |
| livecheck do | |
| url :url | |
| strategy :github_latest | |
| end | |
| auto_updates true | |
| depends_on macos: ">= :sequoia" | |
| app "buddi.app" | |
| uninstall quit: "com.talkvalue.buddi" | |
| zap trash: [ | |
| "~/Library/Preferences/com.talkvalue.buddi.plist", | |
| "~/Library/Application Support/Buddi", | |
| ] | |
| end | |
| CASK | |
| cd $RUNNER_TEMP/tap | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| git add Casks/buddi.rb | |
| git diff --cached --quiet && echo "No cask changes" || \ | |
| git commit -m "Update Buddi to v${VERSION}" && \ | |
| git push "https://x-access-token:${HOMEBREW_TAP_TOKEN}@github.com/talkvalue/homebrew-buddi.git" HEAD:main | |
| - name: Cleanup secrets | |
| if: always() | |
| run: | | |
| rm -f "$RUNNER_TEMP/sparkle_key" | |
| security delete-keychain $RUNNER_TEMP/signing.keychain-db 2>/dev/null || true |