Merge pull request #7 from off-grid-ai/release-core #34
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: Build and Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| permissions: | |
| contents: write | |
| concurrency: | |
| group: release | |
| cancel-in-progress: false | |
| # macOS-only for now. ONE signed + notarized DMG: the build bundles the private pro | |
| # source (cloned from off-grid-ai/desktop-pro) and is license-gated at runtime — | |
| # free = unlicensed (pro tabs locked), a valid Keygen key unlocks in place (no | |
| # re-download). The ASAR integrity fuse (electron-builder.yml) makes a tampered | |
| # app.asar refuse to load — our local-first anti-tamper lever (we don't phone home). | |
| # Actions are pinned to commit SHAs. Windows is parked. | |
| jobs: | |
| # Bump the version once and push it so the build job builds that exact commit. | |
| version: | |
| if: "!contains(github.event.head_commit.message, '[skip ci]')" | |
| runs-on: ubuntu-latest | |
| outputs: | |
| version: ${{ steps.bump.outputs.version }} | |
| sha: ${{ steps.bump.outputs.sha }} | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| fetch-depth: 0 | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 | |
| with: | |
| node-version: '20' | |
| - name: Bump patch version | |
| id: bump | |
| run: | | |
| git config user.name "github-actions[bot]" | |
| git config user.email "github-actions[bot]@users.noreply.github.com" | |
| npm version patch --no-git-tag-version | |
| VERSION=$(node -p "require('./package.json').version") | |
| echo "version=$VERSION" >> "$GITHUB_OUTPUT" | |
| git add package.json package-lock.json | |
| git commit -m "chore: bump version to $VERSION [skip ci]" | |
| git push | |
| # Pin the build to THIS exact commit, not floating main (avoids the | |
| # concurrent-bump version race). | |
| echo "sha=$(git rev-parse HEAD)" >> "$GITHUB_OUTPUT" | |
| # Single build: pro code bundled, license-gated. Publishes to the default update | |
| # channel (latest-mac.yml). | |
| build-mac: | |
| needs: version | |
| runs-on: macos-latest | |
| steps: | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| ref: ${{ needs.version.outputs.sha }} # the exact bumped commit | |
| fetch-depth: 0 | |
| lfs: true # resources/bin/* (llama-server, sd-cli, whisper, ffmpeg, dylibs) | |
| # are Git LFS — without this CI bundles pointer stubs and every | |
| # runtime spawn fails with ENOEXEC. | |
| - name: Pull LFS binaries | |
| run: git lfs pull | |
| # Private pro source into pro/ → __OFFGRID_PRO__ true. The checkout action | |
| # injects the token as an http.extraheader (never in a clone URL) and scrubs | |
| # it afterwards — safer than embedding ${TOKEN} in a git URL. | |
| - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 | |
| with: | |
| repository: off-grid-ai/desktop-pro | |
| token: ${{ secrets.PRO_REPO_TOKEN }} | |
| path: pro | |
| fetch-depth: 1 | |
| - name: Drop nested .git from pro/ | |
| run: rm -rf pro/.git # don't nest a repo inside the build tree | |
| - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 | |
| with: | |
| node-version: '20' | |
| cache: 'npm' | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build (typecheck + bundle) | |
| run: npm run build | |
| - name: Package, sign, notarize & publish (DMG + auto-update metadata) | |
| env: | |
| CSC_LINK: ${{ secrets.CSC_LINK }} | |
| CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} | |
| APPLE_API_KEY_CONTENT: ${{ secrets.APPLE_API_KEY }} | |
| APPLE_API_KEY_ID: ${{ secrets.APPLE_API_KEY_ID }} | |
| APPLE_API_ISSUER: ${{ secrets.APPLE_API_ISSUER }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| # notarytool needs the API key as a file; write it from the secret. | |
| printf '%s' "$APPLE_API_KEY_CONTENT" > "$RUNNER_TEMP/AuthKey.p8" | |
| export APPLE_API_KEY="$RUNNER_TEMP/AuthKey.p8" | |
| # ONE signed + notarized build, published to the default update channel | |
| # (the flow that shipped 0.0.22–0.0.24). electron-builder uploads the DMG | |
| # (human download) plus the zip + latest-mac.yml + blockmap that | |
| # electron-updater needs, so existing users keep auto-updating. | |
| npx electron-builder --mac \ | |
| -c.dmg.artifactName='OffGrid-${version}.${ext}' \ | |
| --publish always | |
| - name: Migrate legacy Pro update channel (publish pro-mac.yml) | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| VERSION: ${{ needs.version.outputs.version }} | |
| run: | | |
| # Older Pro builds poll a SEPARATE channel (pro-mac.yml); the single build | |
| # now publishes only the default latest-mac.yml. Upload a copy as | |
| # pro-mac.yml (identical - same signed zip + version) so those installs see | |
| # this release, auto-update, and land on the default channel. After that | |
| # they follow latest-mac.yml. One-time bridge so no Pro user is orphaned. | |
| cp dist/latest-mac.yml dist/pro-mac.yml | |
| gh release upload "v$VERSION" dist/pro-mac.yml --clobber |