Skip to content

Marketplace release #70

Marketplace release

Marketplace release #70

name: Marketplace release
on:
workflow_run:
workflows: ["Production Desktop App Release"]
types:
- completed
branches:
- main
workflow_dispatch:
env:
VITE_API_URL: ${{vars.VITE_API_URL}}
VITE_MIX_PANEL_TOKEN: ${{vars.VITE_MIX_PANEL_TOKEN}}
VITE_ENABLE_MIX_PANEL: ${{vars.VITE_ENABLE_MIX_PANEL}}
VITE_API_TIMEOUT: ${{vars.VITE_API_TIMEOUT}}
VITE_SPARROW_SUPPORT_EMAIL: ${{ vars.VITE_SPARROW_SUPPORT_EMAIL }}
VITE_AUTH_URL: ${{ vars.VITE_AUTH_URL }}
VITE_SPARROW_GITHUB: ${{ vars.VITE_SPARROW_GITHUB }}
VITE_SPARROW_DOWNLOAD_LINK: ${{ vars.VITE_SPARROW_DOWNLOAD_LINK }}
VITE_RELEASE_NOTES_PAT_TOKEN: ${{ secrets.VITE_RELEASE_NOTES_PAT_TOKEN }}
VITE_RELEASE_NOTES_API: ${{ vars.VITE_RELEASE_NOTES_API }}
VITE_AZURE_CDN_URL: ${{ vars.VITE_AZURE_CDN_URL }}
VITE_AZURE_INSIGHTS_CONNECTION_STRING: ${{ vars.VITE_AZURE_INSIGHTS_CONNECTION_STRING }}
VITE_OPENFEEDBACK_API: ${{ vars.VITE_OPENFEEDBACK_API }}
VITE_OPENFEEDBACK_URL: ${{ vars.VITE_OPENFEEDBACK_URL }}
VITE_OPENFEEDBACK_BOARD_ID: ${{ vars.VITE_OPENFEEDBACK_BOARD_ID }}
VITE_BASE_URL: ${{ vars.VITE_BASE_URL }}
VITE_SPARROW_LINKEDIN: ${{ vars.VITE_SPARROW_LINKEDIN }}
VITE_WEB_SOCKET_IO_API_URL: ${{ vars.VITE_WEB_SOCKET_IO_API_URL }}
VITE_SPARROW_DOCS: ${{ vars.VITE_SPARROW_DOCS }}
VITE_SPARROW_AI_WEBSOCKET: ${{ vars.VITE_SPARROW_AI_WEBSOCKET }}
VITE_APP_ENVIRONMENT_PATH: ${{ vars.VITE_APP_ENVIRONMENT_PATH }}
VITE_OPENFEEDBACK_FEEDBACK_URL: ${{ vars.VITE_OPENFEEDBACK_FEEDBACK_URL }}
VITE_SPARROW_WEB_APP_URL: ${{ vars.VITE_SPARROW_WEB_APP_URL }}
VITE_MARKETING_URL: ${{ vars.VITE_MARKETING_URL }}
VITE_SENTRY_DSN: ${{ vars.VITE_SENTRY_DSN }}
VITE_APP_ENVIRONMENT: ${{ vars.VITE_APP_ENVIRONMENT }}
VITE_POSTHOG_CONNECTION_API_KEY: ${{ vars.VITE_POSTHOG_CONNECTION_API_KEY }}
VITE_POSTHOG_API_URL: ${{ vars.VITE_POSTHOG_API_URL }}
VITE_SPARROW_ADMIN_URL: ${{ vars.VITE_SPARROW_ADMIN_URL }}
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
CI: false
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
jobs:
build-snap:
runs-on: ubuntu-latest
environment: production
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
env:
SNAP_CHANNEL: ${{ vars.SNAP_RELEASE_CHANNEL || 'edge' }}
steps:
- name: Checkout Repo
uses: actions/checkout@v3
- name: Install Snapcraft
run: |
sudo snap install snapcraft --classic
- name: Check Snapcraft Credentials
run: |
snapcraft whoami
- name: Set up Sparrow APT Repo
run: |
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://sparrow-release-assests-prod.s3.us-west-1.amazonaws.com/linux/sparrow-repo-key.gpg | sudo tee /etc/apt/keyrings/sparrow.asc > /dev/null
echo "deb [signed-by=/etc/apt/keyrings/sparrow.asc] https://sparrow-release-assests-prod.s3.us-west-1.amazonaws.com/linux stable main" | sudo tee /etc/apt/sources.list.d/sparrow.list
sudo apt-get update
- name: Download Latest Sparrow DEB
run: |
apt download sparrow
deb_file=$(ls sparrow_*.deb | head -n 1)
mv "$deb_file" sparrow.deb
- name: Set Version and Generate snapcraft.yaml
run: |
export SPARROW_VERSION=$(dpkg-deb -f sparrow.deb Version)
echo "Using Sparrow version: $SPARROW_VERSION"
envsubst < snapcraft.yaml.in > snapcraft.yaml
- name: Build Snap from DEB
run: |
sudo snapcraft --destructive-mode
- name: Prepare Snapcraft credentials
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
run: |
# 1. Override XDG_CONFIG_HOME to a .config folder in the workspace
export XDG_CONFIG_HOME="$PWD/.config"
# 2. Create the snapcraft subfolder under that config
mkdir -p "$XDG_CONFIG_HOME/snapcraft"
# 3. Write the exported credentials JSON (your long token) to the file
echo "$SNAPCRAFT_STORE_CREDENTIALS" > "$XDG_CONFIG_HOME/snapcraft/credentials.json"
chmod 600 "$XDG_CONFIG_HOME/snapcraft/credentials.json"
echo "Stored Snapcraft creds in $XDG_CONFIG_HOME/snapcraft/credentials.json"
- name: Upload Snap to Snap Store
env:
SNAP_CHANNEL: ${{ vars.SNAP_RELEASE_CHANNEL || 'edge' }}
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
XDG_CONFIG_HOME: "$PWD/.config"
run: |
SNAP_FILE=$(ls *.snap | head -n1)
echo "Uploading $SNAP_FILE to $SNAP_CHANNEL"
snapcraft upload "$SNAP_FILE" --release "$SNAP_CHANNEL"
- name: Post Linux Snap Store Link to Teams
env:
TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_INCOMING_WEBHOOK_URL }}
SNAP_STORE_URL: ${{ secrets.SNAP_STORE_URL }}
run: |
curl -H "Content-Type: application/json" -d "{
\"type\": \"message\",
\"attachments\": [
{
\"contentType\": \"application/vnd.microsoft.card.adaptive\",
\"content\": {
\"type\": \"AdaptiveCard\",
\"body\": [
{
\"type\": \"TextBlock\",
\"text\": \"📦 New Linux Snap Store Build Available\",
\"weight\": \"bolder\",
\"size\": \"large\",
\"color\": \"good\"
},
{
\"type\": \"TextBlock\",
\"text\": \"A new Linux snap package has been uploaded to the Snap Store:\",
\"wrap\": true
},
{
\"type\": \"TextBlock\",
\"text\": \"Channel: $SNAP_CHANNEL\",
\"wrap\": true
},
{
\"type\": \"TextBlock\",
\"text\": \"Snap Store URL:\",
\"wrap\": true
},
{
\"type\": \"TextBlock\",
\"text\": \"$SNAP_STORE_URL\",
\"color\": \"accent\",
\"wrap\": true
}
],
\"\$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\",
\"version\": \"1.2\",
\"msteams\": {
\"width\": \"Full\"
}
}
}
]
}" "$TEAMS_WEBHOOK_URL"
shell: bash
release_mac_app_store:
runs-on: macos-latest
environment: production
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
steps:
- name: Checkout Repository
uses: actions/checkout@v2
- name: Install Rust 1.82.0
run: |
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
rustup install 1.82.0
rustup default 1.82.0
rustup target add x86_64-apple-darwin
- name: Sync node version and setup cache
uses: actions/setup-node@v3
with:
node-version: "20.8"
- name: Install project dependencies
run: yarn
- name: Increase Yarn network timeout
run: yarn config set network-timeout 600000
- name: Import Apple Certificates
env:
MAC_INSTALLER_CERT: ${{ secrets.MAC_INSTALLER_CERT }}
MAC_INSTALLER_CERT_PASSWORD: ${{ secrets.MAC_INSTALLER_CERT_PASSWORD }}
KEYCHAIN_PASSWORD: ${{ secrets.KEYCHAIN_PASSWORD }}
run: |
# Create and unlock keychain
security create-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security default-keychain -s build.keychain
security unlock-keychain -p "$KEYCHAIN_PASSWORD" build.keychain
security set-keychain-settings -t 3600 -u build.keychain
# Import certificates
echo "$MAC_INSTALLER_CERT" | base64 --decode > InstallerCert.p12
security import InstallerCert.p12 \
-k build.keychain \
-P "$MAC_INSTALLER_CERT_PASSWORD" \
-T /usr/bin/codesign \
-T /usr/bin/productbuild
# Configure keychain permissions
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k "$KEYCHAIN_PASSWORD" build.keychain
# Verify installation
security find-identity -v -p codesigning build.keychain
- name: Extract Certificate IDs
id: extract-cert-ids
run: |
# Extract Apple Distribution (codesigning) ID
CODESIGN_ID=$(security find-identity -v -p codesigning build.keychain | grep "Apple Distribution" | awk -F'"' '{print $2}')
if [ -z "$CODESIGN_ID" ]; then
echo "::error::Apple Distribution certificate not found in keychain"
exit 1
fi
echo "CODESIGN_ID=$CODESIGN_ID" >> $GITHUB_ENV
# Extract 3rd Party Installer ID (must search all identities)
INSTALLER_ID=$(security find-identity -v build.keychain | grep "3rd Party Mac Developer Installer" | awk -F'"' '{print $2}')
if [ -z "$INSTALLER_ID" ]; then
echo "::error::Installer certificate not found in keychain"
exit 1
fi
echo "INSTALLER_ID=$INSTALLER_ID" >> $GITHUB_ENV
echo "Using codesign identity: $CODESIGN_ID"
echo "Using installer identity: $INSTALLER_ID"
- name: Build Tauri App
run: |
yarn cache clean
yarn install
yarn workspace @sparrow/desktop tauri build --debug --verbose
env:
APPLE_SIGNING_IDENTITY: "${{ env.CODESIGN_ID }}"
TAURI_SIGNING_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
TAURI_SIGNING_PRIVATE_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
GITHUB_TOKEN: ${{ secrets.PR_GITHUB_TOKEN }}
- name: Create signed .pkg for App Store
run: |
APP_NAME="Sparrow"
BUNDLE_PATH="apps/@sparrow-desktop/src-tauri/target/debug/bundle/macos/${APP_NAME}.app"
PKG_PATH="apps/@sparrow-desktop/src-tauri/target/debug/bundle/${APP_NAME}.pkg"
if [ ! -d "$BUNDLE_PATH" ]; then
echo "::error::App bundle not found at $BUNDLE_PATH"
exit 1
fi
# Sign with INSTALLER_ID (3rd Party Mac Developer Installer)
productbuild \
--component "$BUNDLE_PATH" /Applications \
--sign "$INSTALLER_ID" \
"$PKG_PATH"
if [ ! -f "$PKG_PATH" ]; then
echo "::error::Failed to create package at $PKG_PATH"
exit 1
fi
env:
INSTALLER_ID: ${{ env.INSTALLER_ID }}
- name: Upload to App Store Connect
env:
PKG_PATH: "apps/@sparrow-desktop/src-tauri/target/debug/bundle/Sparrow.pkg"
APP_STORE_CONNECT_API_KEY: ${{ secrets.APP_STORE_CONNECT_API_KEY }}
APP_STORE_CONNECT_API_KEY_ID: ${{ secrets.APP_STORE_CONNECT_API_KEY_ID }}
APP_STORE_CONNECT_API_ISSUER: ${{ secrets.APP_STORE_CONNECT_API_ISSUER }}
run: |
mkdir -p ~/.appstoreconnect/private_keys
echo "$APP_STORE_CONNECT_API_KEY" | base64 --decode > ~/.appstoreconnect/private_keys/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8
chmod 600 ~/.appstoreconnect/private_keys/AuthKey_${APP_STORE_CONNECT_API_KEY_ID}.p8
xcrun altool --upload-app -f "$PKG_PATH" -t macos \
--apiKey "$APP_STORE_CONNECT_API_KEY_ID" \
--apiIssuer "$APP_STORE_CONNECT_API_ISSUER" \
--verbose
- name: Post Mac App Store TestFlight Link to Teams
env:
TEAMS_WEBHOOK_URL: ${{ secrets.TEAMS_INCOMING_WEBHOOK_URL }}
TESTFLIGHT_URL: ${{ secrets.TESTFLIGHT_URL }}
run: |
curl -H "Content-Type: application/json" -d "{
\"type\": \"message\",
\"attachments\": [
{
\"contentType\": \"application/vnd.microsoft.card.adaptive\",
\"content\": {
\"type\": \"AdaptiveCard\",
\"body\": [
{
\"type\": \"TextBlock\",
\"text\": \"📲 New Mac App Store TestFlight Build Available\",
\"weight\": \"bolder\",
\"size\": \"large\",
\"color\": \"good\"
},
{
\"type\": \"TextBlock\",
\"text\": \"A new macOS app store build is available for testing in TestFlight:\",
\"wrap\": true
},
{
\"type\": \"TextBlock\",
\"text\": \"TestFlight URL:\",
\"wrap\": true
},
{
\"type\": \"TextBlock\",
\"text\": \"$TESTFLIGHT_URL\",
\"color\": \"accent\",
\"wrap\": true
}
],
\"\$schema\": \"http://adaptivecards.io/schemas/adaptive-card.json\",
\"version\": \"1.2\",
\"msteams\": {
\"width\": \"Full\"
}
}
}
]
}" "$TEAMS_WEBHOOK_URL"
shell: bash