Repository navigation
feat(core): an on switch wears the theme's accent (#138) (#139) #66
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
| # EVERY MERGE TO MAIN IS A RELEASE, when it carries a new version (#23). | |
| # | |
| # The app already checks GitHub Releases for a newer `v<version>` and shows an | |
| # update chip in its title bar (src/main/update.ts). Until now nothing PUBLISHED | |
| # a release: the chip had never had anything to find. Owner, 2026-09-19: "users | |
| # of the app can get an update available banner in their app title bar." | |
| # | |
| # Same gates as ci.yml, then the installer, then `v<version>` as the latest | |
| # release. A push whose version is ALREADY released publishes nothing and says | |
| # so, without failing: a docs-only or CI-only merge is not an error. Bump | |
| # package.json in the PR when a release is meant (patch for fixes, minor for | |
| # features). | |
| # | |
| # The app's tags are `v*`. The shared terminal core's are `core-v*`, plain git | |
| # tags with no GitHub Release behind them (core-release.yml), so "latest | |
| # release" is always an app release. | |
| # | |
| # SIGNED ONCE SIGNPATH IS SET UP (docs/code-signing.md). Until the secret | |
| # SIGNPATH_API_TOKEN exists the two signing steps are skipped and the release is | |
| # unsigned, exactly as before; with it, the installer is sent to SignPath | |
| # (SignPath Foundation's free certificate for open source), approved there, and | |
| # the SIGNED file is what gets published. Nothing else changes. | |
| name: release | |
| on: | |
| push: | |
| branches: [main] | |
| concurrency: | |
| group: release-main | |
| cancel-in-progress: false | |
| jobs: | |
| release: | |
| runs-on: windows-latest | |
| timeout-minutes: 40 | |
| permissions: | |
| contents: write | |
| # Job level, so a step's `if` can see whether signing is set up at all. | |
| env: | |
| SIGNPATH_API_TOKEN: ${{ secrets.SIGNPATH_API_TOKEN }} | |
| steps: | |
| - uses: actions/checkout@v4 | |
| - name: Is this version already released? | |
| id: ver | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| $v = (Get-Content package.json -Raw | ConvertFrom-Json).version | |
| "version=$v" >> $env:GITHUB_OUTPUT | |
| gh release view "v$v" *> $null | |
| if ($LASTEXITCODE -eq 0) { | |
| "fresh=false" >> $env:GITHUB_OUTPUT | |
| Write-Host "::notice::v$v is already released. Nothing to publish (bump package.json in a PR to release)." | |
| } else { | |
| "fresh=true" >> $env:GITHUB_OUTPUT | |
| } | |
| $global:LASTEXITCODE = 0 | |
| - uses: actions/setup-node@v4 | |
| if: steps.ver.outputs.fresh == 'true' | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - run: npm ci | |
| if: steps.ver.outputs.fresh == 'true' | |
| - run: npm run typecheck | |
| if: steps.ver.outputs.fresh == 'true' | |
| - run: npm run lint | |
| if: steps.ver.outputs.fresh == 'true' | |
| - run: npm test | |
| if: steps.ver.outputs.fresh == 'true' | |
| # The speech engine for dictation, pinned by SHA-256. `--if-present`: the | |
| # script arrives with the dictation PR, and this file may land before it. | |
| - run: npm run fetch:bin --if-present | |
| if: steps.ver.outputs.fresh == 'true' | |
| - run: npx electron-vite build | |
| if: steps.ver.outputs.fresh == 'true' | |
| - run: npx electron-builder --win --publish never | |
| if: steps.ver.outputs.fresh == 'true' | |
| # Code signing (docs/code-signing.md). Skipped while the secret is absent. | |
| - name: Upload the unsigned installer for signing | |
| id: unsigned | |
| if: steps.ver.outputs.fresh == 'true' && env.SIGNPATH_API_TOKEN != '' | |
| uses: actions/upload-artifact@v4 | |
| with: | |
| name: unsigned-installer | |
| path: dist/PrismTerminal-Setup-x64-${{ steps.ver.outputs.version }}.exe | |
| if-no-files-found: error | |
| - name: Sign the installer through SignPath | |
| if: steps.ver.outputs.fresh == 'true' && env.SIGNPATH_API_TOKEN != '' | |
| uses: signpath/github-action-submit-signing-request@v3 | |
| with: | |
| api-token: ${{ secrets.SIGNPATH_API_TOKEN }} | |
| organization-id: ${{ vars.SIGNPATH_ORGANIZATION_ID }} | |
| project-slug: ${{ vars.SIGNPATH_PROJECT_SLUG }} | |
| signing-policy-slug: ${{ vars.SIGNPATH_SIGNING_POLICY_SLUG }} | |
| github-artifact-id: ${{ steps.unsigned.outputs.artifact-id }} | |
| wait-for-completion: true | |
| # Written over the unsigned file, so Publish below sends the signed one. | |
| output-artifact-directory: dist | |
| - name: Publish | |
| if: steps.ver.outputs.fresh == 'true' | |
| shell: pwsh | |
| env: | |
| GH_TOKEN: ${{ github.token }} | |
| run: | | |
| $v = "${{ steps.ver.outputs.version }}" | |
| $exe = "dist/PrismTerminal-Setup-x64-$v.exe" | |
| if (-not (Test-Path $exe)) { throw "installer not found: $exe" } | |
| # --target pins the tag to the commit this run BUILT (code review | |
| # 2026-09-24, #11). Without it GitHub tags main's head at publish | |
| # time, which is a later merge whenever one landed during the build: | |
| # the installer from one commit, the tag, source and notes of another. | |
| # | |
| # BUT NOT OVER A NEWER WORKFLOW (2026-09-28, MEASURED on v0.18.5): a | |
| # merge that changed .github/workflows landed 49 s before this step, | |
| # and GitHub refuses the workflow token a tag on a commit whose | |
| # workflows differ from main's ("HTTP 403: Resource not accessible by | |
| # integration"; that needs a permission the token cannot hold). The | |
| # next run on main builds a commit that contains this one, starts | |
| # only after this run (the concurrency group), finds the version | |
| # unreleased and publishes it; so this run says so and stands down. | |
| git fetch -q --depth=1 origin main | |
| git diff --quiet "${{ github.sha }}" FETCH_HEAD -- .github/workflows | |
| if ($LASTEXITCODE -ne 0) { | |
| "::notice::main has moved past ${{ github.sha }} with changed workflows; the next release run publishes v$v." | |
| exit 0 | |
| } | |
| gh release create "v$v" $exe --target "${{ github.sha }}" --title "Prism Terminal $v" --generate-notes --latest | |
| if ($LASTEXITCODE -ne 0) { throw "Release publication failed" } |