Skip to content

v2.1.0: core 0.6.0 with QoderWork and TRAE SOLO support #11

v2.1.0: core 0.6.0 with QoderWork and TRAE SOLO support

v2.1.0: core 0.6.0 with QoderWork and TRAE SOLO support #11

Workflow file for this run

name: Release CodeDrobe Desktop
on:
push:
tags:
- 'v*.*.*'
# Manual runs build and sign macOS artifacts without publishing a release,
# so code signing can be tested without cutting a version.
workflow_dispatch:
permissions:
contents: write
concurrency:
group: desktop-release-${{ github.ref }}
cancel-in-progress: false
env:
NODE_VERSION: '22'
jobs:
validate:
name: Validate release source
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: package-lock.json
- name: Validate semantic version tag
if: startsWith(github.ref, 'refs/tags/')
shell: bash
run: |
set -euo pipefail
VERSION="${GITHUB_REF_NAME#v}"
[[ "$VERSION" =~ ^[0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?$ ]]
echo "Building CodeDrobe Desktop $VERSION"
- name: Install dependencies
run: npm ci
- name: Type-check and test desktop and core
run: npm run check
build-macos:
name: Build macOS arm64
needs: validate
runs-on: macos-14
timeout-minutes: 45
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Set application version from tag
if: startsWith(github.ref, 'refs/tags/')
shell: bash
run: npm version "${GITHUB_REF_NAME#v}" --no-git-tag-version --allow-same-version
# Imports the Developer ID Application certificate into a throwaway
# keychain and stages the App Store Connect API key for notarization.
# When the signing secrets are absent (e.g. forks) the build proceeds
# unsigned, matching the previous behaviour.
- name: Import code signing credentials
env:
MACOS_CERT_P12_BASE64: ${{ secrets.MACOS_CERT_P12_BASE64 }}
MACOS_CERT_PASSWORD: ${{ secrets.MACOS_CERT_PASSWORD }}
APPLE_API_KEY_BASE64: ${{ secrets.APPLE_API_KEY_BASE64 }}
shell: bash
run: |
set -euo pipefail
if [[ -z "${MACOS_CERT_P12_BASE64}" ]]; then
echo "MACOS_CERT_P12_BASE64 secret not configured; building unsigned."
exit 0
fi
KEYCHAIN_PATH="$RUNNER_TEMP/codedrobe-signing.keychain-db"
KEYCHAIN_PASSWORD="$(openssl rand -base64 24)"
echo "::add-mask::$KEYCHAIN_PASSWORD"
security create-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
security set-keychain-settings -lut 21600 "$KEYCHAIN_PATH"
security unlock-keychain -p "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH"
printf '%s' "$MACOS_CERT_P12_BASE64" | base64 --decode > "$RUNNER_TEMP/certificate.p12"
security import "$RUNNER_TEMP/certificate.p12" -k "$KEYCHAIN_PATH" \
-P "${MACOS_CERT_PASSWORD}" -T /usr/bin/codesign -T /usr/bin/security
rm -f "$RUNNER_TEMP/certificate.p12"
# The Developer ID G2 intermediate is required to build the trust
# chain; import it in case the runner image lacks it.
if curl -fsSL --retry 3 https://www.apple.com/certificateauthority/DeveloperIDG2CA.cer \
-o "$RUNNER_TEMP/DeveloperIDG2CA.cer"; then
security import "$RUNNER_TEMP/DeveloperIDG2CA.cer" -k "$KEYCHAIN_PATH" || true
else
echo "::warning::Could not download the Developer ID G2 intermediate certificate."
fi
security set-key-partition-list -S 'apple-tool:,apple:' -s \
-k "$KEYCHAIN_PASSWORD" "$KEYCHAIN_PATH" > /dev/null
security list-keychains -d user -s "$KEYCHAIN_PATH" login.keychain-db
security find-identity -v -p codesigning "$KEYCHAIN_PATH"
echo "MACOS_SIGN=1" >> "$GITHUB_ENV"
if [[ -n "${APPLE_API_KEY_BASE64}" ]]; then
API_KEY_PATH="$RUNNER_TEMP/apple-api-key.p8"
printf '%s' "$APPLE_API_KEY_BASE64" | base64 --decode > "$API_KEY_PATH"
echo "APPLE_API_KEY=$API_KEY_PATH" >> "$GITHUB_ENV"
else
echo "::warning::APPLE_API_KEY_BASE64 secret not configured; skipping notarization."
fi
- name: Build DMG and ZIP
env:
APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }}
APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }}
run: npm run make -- --arch=arm64
- name: Verify code signature and notarization
if: env.MACOS_SIGN == '1'
shell: bash
run: |
set -euo pipefail
APP_PATH="out/CodeDrobe-darwin-arm64/CodeDrobe.app"
codesign --verify --deep --strict --verbose=2 "$APP_PATH"
if [[ -n "${APPLE_API_KEY:-}" ]]; then
xcrun stapler validate "$APP_PATH"
spctl --assess --type execute --verbose=2 "$APP_PATH"
fi
- name: Verify macOS artifacts and bundled runtime
shell: bash
run: |
set -euo pipefail
test -f out/make/CodeDrobe.dmg
find out/make -type f -name '*.zip' -print -quit | grep -q .
test -f out/CodeDrobe-darwin-arm64/CodeDrobe.app/Contents/Resources/runtime/icon.png
test -f out/CodeDrobe-darwin-arm64/CodeDrobe.app/Contents/Resources/runtime/trayTemplate.png
test -f out/CodeDrobe-darwin-arm64/CodeDrobe.app/Contents/Resources/runtime/tray-icon.png
test -f out/CodeDrobe-darwin-arm64/CodeDrobe.app/Contents/Resources/LICENSE
test -f out/CodeDrobe-darwin-arm64/CodeDrobe.app/Contents/Resources/SOURCE_CODE.md
test -f out/CodeDrobe-darwin-arm64/CodeDrobe.app/Contents/Resources/THIRD_PARTY_NOTICES.md
test -f out/CodeDrobe-darwin-arm64/CodeDrobe.app/Contents/Resources/licenses/Apache-2.0.txt
- name: Upload macOS release assets
uses: actions/upload-artifact@v4
with:
name: CodeDrobe-macOS-arm64-${{ github.ref_name }}
path: |
out/make/**/*.dmg
out/make/**/*.zip
if-no-files-found: error
retention-days: 14
- name: Clean up signing keychain
if: always()
shell: bash
run: security delete-keychain "$RUNNER_TEMP/codedrobe-signing.keychain-db" 2>/dev/null || true
build-windows:
name: Build Windows x64 installers
# Signing test runs (workflow_dispatch) only need the macOS build.
if: startsWith(github.ref, 'refs/tags/')
needs: validate
runs-on: windows-latest
timeout-minutes: 45
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Set up Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: npm
cache-dependency-path: package-lock.json
- name: Install dependencies
run: npm ci
- name: Install WiX Toolset
shell: pwsh
# WiX 3.14.0 was unlisted from Chocolatey (burn CVE); install the
# latest listed 3.x package instead of pinning a dead version.
run: choco install wixtoolset --yes --no-progress
- name: Set application version from tag
shell: bash
run: npm version "${GITHUB_REF_NAME#v}" --no-git-tag-version --allow-same-version
- name: Build WiX MSI and packaged application
run: npm run make -- --arch=x64
- name: Build NSIS and Portable executables
run: npm run make:windows:installers
- name: Verify Windows artifacts and bundled runtime
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
if (-not (Get-ChildItem out/make -Recurse -Filter '*.msi')) {
throw 'The WiX MSI installer was not generated.'
}
if (-not (Get-ChildItem out/make -Recurse -Filter '*-Setup.exe')) {
throw 'The NSIS Setup executable was not generated.'
}
if (-not (Get-ChildItem out/make -Recurse -Filter '*-Portable.exe')) {
throw 'The Portable executable was not generated.'
}
$resources = 'out/CodeDrobe-win32-x64/resources'
foreach ($file in @('runtime/icon.png', 'runtime/trayTemplate.png', 'runtime/tray-icon.png')) {
if (-not (Test-Path (Join-Path $resources $file))) {
throw "Bundled runtime asset is missing: $file"
}
}
foreach ($file in @('LICENSE', 'SOURCE_CODE.md', 'THIRD_PARTY_NOTICES.md', 'licenses/Apache-2.0.txt')) {
if (-not (Test-Path (Join-Path $resources $file))) {
throw "Bundled license or source notice is missing: $file"
}
}
- name: Upload Windows release assets
uses: actions/upload-artifact@v4
with:
name: CodeDrobe-Windows-x64-${{ github.ref_name }}
path: |
out/make/**/*.exe
out/make/**/*.msi
if-no-files-found: error
retention-days: 14
release:
name: Publish GitHub Release
if: startsWith(github.ref, 'refs/tags/')
needs:
- build-macos
- build-windows
runs-on: ubuntu-latest
timeout-minutes: 10
steps:
- name: Download release assets
uses: actions/download-artifact@v4
with:
path: release-assets
merge-multiple: true
- name: List release assets
run: find release-assets -maxdepth 8 -type f -print
- name: Generate SHA-256 checksums
shell: bash
run: |
set -euo pipefail
find release-assets -type f -print0 | sort -z | xargs -0 sha256sum > /tmp/SHA256SUMS.txt
mv /tmp/SHA256SUMS.txt release-assets/SHA256SUMS.txt
- name: Create release and upload assets
env:
GH_TOKEN: ${{ github.token }}
shell: bash
run: |
set -euo pipefail
mapfile -d '' ASSETS < <(find release-assets -type f -print0)
test "${#ASSETS[@]}" -gt 0
gh release create "$GITHUB_REF_NAME" "${ASSETS[@]}" \
--repo "$GITHUB_REPOSITORY" \
--title "CodeDrobe Desktop $GITHUB_REF_NAME" \
--generate-notes \
--verify-tag