Nightly #74
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: Nightly | |
| on: | |
| schedule: | |
| - cron: '0 3 * * *' # 03:00 UTC daily | |
| workflow_dispatch: {} # manual trigger (always builds) | |
| permissions: | |
| contents: write | |
| jobs: | |
| check: | |
| # Cheap gate so scheduled runs don't cut an empty nightly when nothing | |
| # has landed. Manual dispatches always build. | |
| runs-on: ubuntu-latest | |
| outputs: | |
| should_build: ${{ steps.decide.outputs.should_build }} | |
| steps: | |
| - name: Checkout git repo | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Decide whether to build | |
| id: decide | |
| run: | | |
| if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then | |
| echo "should_build=true" >> "$GITHUB_OUTPUT" | |
| elif [ -n "$(git log --since='24 hours ago' --oneline)" ]; then | |
| echo "should_build=true" >> "$GITHUB_OUTPUT" | |
| else | |
| echo "should_build=false" >> "$GITHUB_OUTPUT" | |
| echo "No commits in the last 24h — skipping nightly." | |
| fi | |
| build: | |
| needs: check | |
| if: needs.check.outputs.should_build == 'true' | |
| runs-on: macos-latest | |
| steps: | |
| - name: Checkout git repo | |
| uses: actions/checkout@v4 | |
| - name: Install Node and NPM | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: 22 | |
| cache: npm | |
| - name: Install dependencies | |
| run: npm install | |
| - name: Set nightly version | |
| # Build-time only — not committed. electron-builder packages from | |
| # directories.app (release/app), so the app version it bakes in (and | |
| # what app.getVersion() returns) comes from release/app/package.json — | |
| # NOT apps/desktop/package.json. Bump that one. Each nightly takes the | |
| # next patch above the highest version ever published (release tags + | |
| # the local base), so versions increment cleanly (0.1.2, 0.1.3, …) | |
| # instead of carrying a timestamp suffix. | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| cd apps/desktop/release/app | |
| gh api "repos/${{ github.repository }}/releases" --paginate --jq '.[].tag_name' > /tmp/release-tags.txt || true | |
| node -e " | |
| const fs = require('fs'); | |
| const p = require('./package.json'); | |
| const parse = (s) => { | |
| const m = String(s).trim().match(/^v?(\d+)\.(\d+)\.(\d+)/); | |
| return m ? [+m[1], +m[2], +m[3]] : null; | |
| }; | |
| const tags = fs.existsSync('/tmp/release-tags.txt') | |
| ? fs.readFileSync('/tmp/release-tags.txt', 'utf8').split('\n') | |
| : []; | |
| const cmp = (a, b) => a[0] - b[0] || a[1] - b[1] || a[2] - b[2]; | |
| const max = [...tags, p.version].map(parse).filter(Boolean).sort(cmp).pop(); | |
| p.version = [max[0], max[1], max[2] + 1].join('.'); | |
| fs.writeFileSync('./package.json', JSON.stringify(p, null, 2) + '\n'); | |
| console.log('Building nightly', p.version); | |
| " | |
| - name: Build shared package | |
| run: npm run build -w @talyn/shared | |
| - name: Build desktop app | |
| # These are baked into the renderer bundle at build time by webpack's | |
| # EnvironmentPlugin — they must be set on THIS step, not the publish | |
| # step. Without them the app defaults to http://localhost:4747 with no | |
| # auth config. The Supabase anon key is publishable (client-embedded | |
| # by design), so it lives in repo variables, not secrets. | |
| env: | |
| TALYN_API_URL: https://prod.talyn.dev | |
| TALYN_SUPABASE_URL: ${{ vars.TALYN_SUPABASE_URL }} | |
| TALYN_SUPABASE_ANON_KEY: ${{ vars.TALYN_SUPABASE_ANON_KEY }} | |
| TALYN_POSTHOG_KEY: ${{ vars.TALYN_POSTHOG_KEY }} | |
| TALYN_POSTHOG_HOST: https://us.i.posthog.com | |
| run: npm run build -w @talyn/desktop | |
| - name: Upload renderer source maps to PostHog | |
| # Symbolicates renderer exceptions in PostHog. `inject` stamps chunk IDs | |
| # into the built JS + maps so PostHog can match a minified frame back to | |
| # its source; `upload --delete-after` ships the maps to PostHog then | |
| # deletes them from disk so they aren't packed into the shipped app. | |
| # Runs after the build and before packaging so electron-builder bundles | |
| # the injected JS. No-op until POSTHOG_CLI_API_KEY is configured, and | |
| # never blocks a release — symbolication is auxiliary. (The skip is | |
| # guarded inside the script, not via `if:` — the `secrets` context is | |
| # not allowed in `if` conditions.) | |
| continue-on-error: true | |
| env: | |
| POSTHOG_CLI_HOST: https://us.posthog.com | |
| POSTHOG_CLI_PROJECT_ID: ${{ vars.POSTHOG_CLI_PROJECT_ID }} | |
| POSTHOG_CLI_API_KEY: ${{ secrets.POSTHOG_CLI_API_KEY }} | |
| run: | | |
| if [ -z "$POSTHOG_CLI_API_KEY" ]; then | |
| echo "POSTHOG_CLI_API_KEY not set — skipping source map upload." | |
| exit 0 | |
| fi | |
| npx --yes @posthog/cli@latest sourcemap inject \ | |
| --directory apps/desktop/release/app/dist/renderer | |
| npx --yes @posthog/cli@latest sourcemap upload \ | |
| --directory apps/desktop/release/app/dist/renderer --delete-after | |
| - name: Publish nightly pre-release | |
| env: | |
| # Code-signing + notarization — required or Squirrel.Mac refuses | |
| # to apply the update on the client. | |
| APPLE_ID: ${{ secrets.APPLE_ID }} | |
| APPLE_APP_SPECIFIC_PASSWORD: ${{ secrets.APPLE_APP_SPECIFIC_PASSWORD }} | |
| APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} | |
| CSC_LINK: ${{ secrets.CSC_LINK }} | |
| CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| cd apps/desktop | |
| # electron is hoisted to the monorepo root node_modules, so | |
| # electron-builder can't infer the version from this workspace — | |
| # resolve it explicitly and pass it in. | |
| ELECTRON_VERSION=$(node -p "require('electron/package.json').version") | |
| # arm64-only: every Mac from 2020+ is Apple Silicon, and a single | |
| # notarization submission roughly halves the nightly wait. Intel | |
| # (x64) coverage stays on the stable publish.yml release path. | |
| npm exec electron-builder -- --publish always --arm64 \ | |
| -c.electronVersion="$ELECTRON_VERSION" \ | |
| -c.publish.releaseType=prerelease |