Skip to content

Document oc-chatgpt-multi-auth authentication support #583

Document oc-chatgpt-multi-auth authentication support

Document oc-chatgpt-multi-auth authentication support #583

Workflow file for this run

name: Build and Release
on:
push:
pull_request:
workflow_dispatch:
inputs:
version:
description: 'Release version (e.g., v2.0.3). Leave empty for unsigned build.'
required: false
type: string
jobs:
build:
runs-on: macos-14
env:
IS_RELEASE: ${{ startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.version != '') }}
VERSION_INPUT: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs.version || github.ref_name }}
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Xcode
uses: maxim-lobanov/setup-xcode@v1
with:
xcode-version: '15.4'
- name: Import Developer ID Certificate
if: env.IS_RELEASE == 'true'
env:
BUILD_CERTIFICATE_BASE64: ${{ secrets.BUILD_CERTIFICATE_BASE64 }}
P12_PASSWORD: ${{ secrets.P12_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
CERTIFICATE_PATH="$RUNNER_TEMP/build_certificate.p12"
KEYCHAIN_PATH="$RUNNER_TEMP/app-signing.keychain-db"
echo -n "$BUILD_CERTIFICATE_BASE64" | base64 --decode -o "$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" -P "$P12_PASSWORD" -A -t cert -f pkcs12 -k "$KEYCHAIN_PATH"
security set-key-partition-list -S apple-tool:,apple: -k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security list-keychain -d user -s "$KEYCHAIN_PATH"
- name: Build App (Unsigned - for branch push)
if: ${{ env.IS_RELEASE != 'true' }}
run: |
cd CopilotMonitor
xcodebuild -project CopilotMonitor.xcodeproj \
-scheme CopilotMonitor \
-configuration Release \
-destination "generic/platform=macOS" \
-archivePath build/CopilotMonitor.xcarchive \
archive \
ARCHS="arm64 x86_64" \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGN_IDENTITY="-" \
CODE_SIGNING_REQUIRED=NO \
CODE_SIGNING_ALLOWED=NO
- name: Build App (Signed - for tag or manual release)
if: env.IS_RELEASE == 'true'
env:
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
cd CopilotMonitor
xcodebuild archive \
-project CopilotMonitor.xcodeproj \
-scheme CopilotMonitor \
-configuration Release \
-destination "generic/platform=macOS" \
-archivePath "$RUNNER_TEMP/CopilotMonitor.xcarchive" \
ARCHS="arm64 x86_64" \
ONLY_ACTIVE_ARCH=NO \
CODE_SIGN_IDENTITY="Developer ID Application" \
DEVELOPMENT_TEAM="$APPLE_TEAM_ID" \
CODE_SIGN_STYLE=Manual
- name: Export App (Unsigned)
if: ${{ env.IS_RELEASE != 'true' }}
run: |
mkdir -p CopilotMonitor/build/export
cp -R "CopilotMonitor/build/CopilotMonitor.xcarchive/Products/Applications/OpenCode Bar.app" CopilotMonitor/build/export/
- name: Verify Universal Binary (Unsigned)
if: ${{ env.IS_RELEASE != 'true' }}
run: |
APP_PATH="CopilotMonitor/build/export/OpenCode Bar.app"
MAIN_BIN="$APP_PATH/Contents/MacOS/OpenCode Bar"
MAIN_ARCHS=$(lipo -archs "$MAIN_BIN")
echo "Main binary architectures: $MAIN_ARCHS"
if ! lipo -archs "$MAIN_BIN" | grep -q "x86_64"; then
echo "Missing x86_64 slice in main binary"
exit 1
fi
if ! lipo -archs "$MAIN_BIN" | grep -q "arm64"; then
echo "Missing arm64 slice in main binary"
exit 1
fi
CLI_BIN="$APP_PATH/Contents/MacOS/opencodebar-cli"
if [ -f "$CLI_BIN" ]; then
CLI_ARCHS=$(lipo -archs "$CLI_BIN")
echo "CLI binary architectures: $CLI_ARCHS"
if ! lipo -archs "$CLI_BIN" | grep -q "x86_64"; then
echo "Missing x86_64 slice in CLI binary"
exit 1
fi
if ! lipo -archs "$CLI_BIN" | grep -q "arm64"; then
echo "Missing arm64 slice in CLI binary"
exit 1
fi
else
echo "CLI binary not found at $CLI_BIN"
exit 1
fi
- name: Export App (Signed)
if: env.IS_RELEASE == 'true'
run: |
xcodebuild -exportArchive \
-archivePath "$RUNNER_TEMP/CopilotMonitor.xcarchive" \
-exportPath "$RUNNER_TEMP/export" \
-exportOptionsPlist ExportOptions.plist
- name: Verify Universal Binary (Signed)
if: env.IS_RELEASE == 'true'
run: |
APP_PATH="$RUNNER_TEMP/export/OpenCode Bar.app"
MAIN_BIN="$APP_PATH/Contents/MacOS/OpenCode Bar"
MAIN_ARCHS=$(lipo -archs "$MAIN_BIN")
echo "Main binary architectures: $MAIN_ARCHS"
if ! lipo -archs "$MAIN_BIN" | grep -q "x86_64"; then
echo "Missing x86_64 slice in main binary"
exit 1
fi
if ! lipo -archs "$MAIN_BIN" | grep -q "arm64"; then
echo "Missing arm64 slice in main binary"
exit 1
fi
CLI_BIN="$APP_PATH/Contents/MacOS/opencodebar-cli"
if [ -f "$CLI_BIN" ]; then
CLI_ARCHS=$(lipo -archs "$CLI_BIN")
echo "CLI binary architectures: $CLI_ARCHS"
if ! lipo -archs "$CLI_BIN" | grep -q "x86_64"; then
echo "Missing x86_64 slice in CLI binary"
exit 1
fi
if ! lipo -archs "$CLI_BIN" | grep -q "arm64"; then
echo "Missing arm64 slice in CLI binary"
exit 1
fi
else
echo "CLI binary not found at $CLI_BIN"
fi
- name: Verify Code Signing
if: env.IS_RELEASE == 'true'
run: |
codesign --verify --deep --strict --verbose=2 "$RUNNER_TEMP/export/OpenCode Bar.app"
codesign -dv --verbose=4 "$RUNNER_TEMP/export/OpenCode Bar.app" 2>&1 | grep "Authority"
- name: Notarize App
if: env.IS_RELEASE == 'true'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
cd "$RUNNER_TEMP/export"
ditto -c -k --keepParent "OpenCode Bar.app" "OpenCode Bar.zip"
xcrun notarytool submit "OpenCode Bar.zip" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait \
--timeout 30m
xcrun stapler staple "OpenCode Bar.app"
- name: Install create-dmg
if: env.IS_RELEASE == 'true'
run: brew install create-dmg
- name: Create DMG (Unsigned)
if: ${{ env.IS_RELEASE != 'true' }}
run: |
mkdir -p dmg_temp
cp -R "CopilotMonitor/build/export/OpenCode Bar.app" dmg_temp/
ln -s /Applications dmg_temp/Applications
hdiutil create -volname "OpenCode Bar" \
-srcfolder dmg_temp \
-ov -format UDZO \
OpenCode-Bar.dmg
rm -rf dmg_temp
- name: Create and Sign DMG
if: env.IS_RELEASE == 'true'
run: |
VERSION="${{ env.VERSION_INPUT }}"
DMG_NAME="OpenCode-Bar-${VERSION}.dmg"
# Create clean staging directory with ONLY the app and Applications symlink
# This prevents extra files (Packaging.log, DistributionSummary.plist, etc.) from being included
DMG_STAGING="$RUNNER_TEMP/dmg_staging"
mkdir -p "$DMG_STAGING"
cp -R "$RUNNER_TEMP/export/OpenCode Bar.app" "$DMG_STAGING/"
ln -s /Applications "$DMG_STAGING/Applications"
create-dmg \
--volname "OpenCode Bar" \
--window-pos 200 120 \
--window-size 600 400 \
--icon-size 100 \
--icon "OpenCode Bar.app" 150 200 \
--app-drop-link 450 200 \
--hide-extension "OpenCode Bar.app" \
"$DMG_NAME" \
"$DMG_STAGING" || true
if [ ! -f "$DMG_NAME" ]; then
hdiutil create -volname "OpenCode Bar ${VERSION}" \
-srcfolder "$DMG_STAGING" -ov -format UDZO "$DMG_NAME"
fi
codesign --force --sign "Developer ID Application" "$DMG_NAME"
# Cleanup staging directory
rm -rf "$DMG_STAGING"
- name: Notarize DMG
if: env.IS_RELEASE == 'true'
env:
APPLE_ID: ${{ secrets.APPLE_ID }}
APPLE_APP_PASSWORD: ${{ secrets.APPLE_APP_PASSWORD }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
run: |
VERSION="${{ env.VERSION_INPUT }}"
DMG_NAME="OpenCode-Bar-${VERSION}.dmg"
xcrun notarytool submit "$DMG_NAME" \
--apple-id "$APPLE_ID" \
--password "$APPLE_APP_PASSWORD" \
--team-id "$APPLE_TEAM_ID" \
--wait \
--timeout 30m
xcrun stapler staple "$DMG_NAME"
- name: Download Sparkle Tools
if: env.IS_RELEASE == 'true'
run: |
curl -L -o sparkle.tar.xz https://github.com/sparkle-project/Sparkle/releases/download/2.8.1/Sparkle-2.8.1.tar.xz
mkdir -p sparkle
tar -xf sparkle.tar.xz -C sparkle
chmod +x sparkle/bin/*
- name: Generate Sparkle Signature and Appcast
if: env.IS_RELEASE == 'true'
env:
SPARKLE_PRIVATE_KEY: ${{ secrets.SPARKLE_PRIVATE_KEY }}
run: |
VERSION="${{ env.VERSION_INPUT }}"
DMG_NAME="OpenCode-Bar-${VERSION}.dmg"
DOWNLOAD_URL="https://github.com/opgginc/opencode-bar/releases/download/${VERSION}/${DMG_NAME}"
echo "$SPARKLE_PRIVATE_KEY" > "$RUNNER_TEMP/sparkle_key"
# Extract just the signature string from the output
# Output format: sparkle:edSignature="<SIG>" length="<LEN>"
FULL_OUTPUT=$(./sparkle/bin/sign_update "$DMG_NAME" --ed-key-file "$RUNNER_TEMP/sparkle_key")
SIGNATURE=$(echo "$FULL_OUTPUT" | awk -F '"' '{print $2}')
DMG_SIZE=$(stat -f%z "$DMG_NAME")
printf '%s\n' '<?xml version="1.0" encoding="utf-8"?>' \
'<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle" xmlns:dc="http://purl.org/dc/elements/1.1/">' \
' <channel>' \
' <title>OpenCode Bar Updates</title>' \
' <link>https://github.com/opgginc/opencode-bar/releases/latest/download/appcast.xml</link>' \
' <description>Most recent changes with links to updates.</description>' \
' <language>en</language>' \
' <item>' \
" <title>Version ${VERSION#v}</title>" \
" <pubDate>$(date -R)</pubDate>" \
" <sparkle:version>${VERSION#v}</sparkle:version>" \
" <sparkle:shortVersionString>${VERSION#v}</sparkle:shortVersionString>" \
' <sparkle:minimumSystemVersion>13.0</sparkle:minimumSystemVersion>' \
" <enclosure url=\"${DOWNLOAD_URL}\"" \
" sparkle:edSignature=\"${SIGNATURE}\"" \
" length=\"${DMG_SIZE}\"" \
' type="application/octet-stream"/>' \
' </item>' \
' </channel>' \
'</rss>' > appcast.xml
rm -f "$RUNNER_TEMP/sparkle_key"
- name: Cleanup Keychain
if: always() && (env.IS_RELEASE == 'true')
run: |
security delete-keychain "$RUNNER_TEMP/app-signing.keychain-db" 2>/dev/null || true
- name: Upload Artifact (Branch Build)
if: ${{ env.IS_RELEASE != 'true' }}
uses: actions/upload-artifact@v4
with:
name: OpenCode-Bar
path: OpenCode-Bar.dmg
- name: Upload Artifact (Release Build)
if: env.IS_RELEASE == 'true'
uses: actions/upload-artifact@v4
with:
name: OpenCode-Bar-Release
path: |
OpenCode-Bar-*.dmg
appcast.xml
release:
needs: build
runs-on: ubuntu-latest
if: startsWith(github.ref, 'refs/tags/v') || (github.event_name == 'workflow_dispatch' && github.event.inputs.version != '')
permissions:
contents: write
steps:
- name: Download Artifact
uses: actions/download-artifact@v4
with:
name: OpenCode-Bar-Release
- name: Get Version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.version }}" ]; then
echo "version=${{ github.event.inputs.version }}" >> "$GITHUB_OUTPUT"
else
echo "version=${GITHUB_REF#refs/tags/}" >> "$GITHUB_OUTPUT"
fi
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: ${{ steps.version.outputs.version }}
name: OpenCode Bar ${{ steps.version.outputs.version }}
draft: false
prerelease: false
files: |
OpenCode-Bar-${{ steps.version.outputs.version }}.dmg
appcast.xml
generate_release_notes: true
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}