Build Binaries workflow (gnmyt/MySpeed)
The Build Binaries workflow from gnmyt/MySpeed, explained and optimized by Latchkey.
CI health: B - good
Point runs-on at Latchkey and get job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Build Binaries workflow from the gnmyt/MySpeed repository, a real project running GitHub Actions. It is shown here with attribution under its MIT license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Build Binaries
on:
workflow_call:
inputs:
version:
required: true
type: string
release_id:
required: true
type: string
jobs:
build-windows:
name: "Windows (x64)"
runs-on: windows-latest
steps:
- name: Checkout project
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install client dependencies
working-directory: client
run: bun install
- name: Build client
working-directory: client
run: bun run build
- name: Move build folder
run: Move-Item -Path client/build -Destination .
- name: Install server dependencies
run: bun install
- name: Generate migrations
run: bun run generate-migrations
- name: Generate integrations
run: bun run generate-integrations
- name: Generate client embed
run: bun run generate-client-embed
- name: Compile binary
run: bun build --compile --compile-autoload-package-json --external pg-hstore --external pg --target=bun-windows-x64 server/index.js --outfile MySpeed.exe
- name: Upload to Release
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: ${{ inputs.release_id }},
name: 'MySpeed-windows-x64.exe',
data: fs.readFileSync('MySpeed.exe')
});
- name: Upload artifact for MSI
uses: actions/upload-artifact@v4
with:
name: MySpeed-windows-x64.exe
path: MySpeed.exe
- name: Upload build folder for MSI
uses: actions/upload-artifact@v4
with:
name: build-folder
path: build
build-linux:
name: "Linux (${{ matrix.arch }})"
runs-on: ${{ matrix.runner }}
strategy:
fail-fast: false
matrix:
include:
- arch: x64
target: bun-linux-x64
runner: ubuntu-latest
artifact_name: MySpeed-linux-x64
- arch: arm64
target: bun-linux-arm64
runner: ubuntu-24.04-arm
artifact_name: MySpeed-linux-arm64
steps:
- name: Checkout project
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install client dependencies
working-directory: client
run: bun install
- name: Build client
working-directory: client
run: bun run build
- name: Move build folder
run: mv client/build .
- name: Install server dependencies
run: bun install
- name: Generate migrations
run: bun run generate-migrations
- name: Generate integrations
run: bun run generate-integrations
- name: Generate client embed
run: bun run generate-client-embed
- name: Compile binary
run: bun build --compile --compile-autoload-package-json --external pg-hstore --external pg --target=${{ matrix.target }} server/index.js --outfile MySpeed
- name: Rename binary
run: mv MySpeed ${{ matrix.artifact_name }}
- name: Upload to Release
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: ${{ inputs.release_id }},
name: '${{ matrix.artifact_name }}',
data: fs.readFileSync('${{ matrix.artifact_name }}')
});
build-macos:
name: "macOS (${{ matrix.arch }})"
runs-on: macos-latest
strategy:
fail-fast: false
matrix:
include:
- arch: x64
target: bun-darwin-x64
artifact_name: MySpeed-macos-x64
- arch: arm64
target: bun-darwin-arm64
artifact_name: MySpeed-macos-arm64
steps:
- name: Checkout project
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install client dependencies
working-directory: client
run: bun install
- name: Build client
working-directory: client
run: bun run build
- name: Move build folder
run: mv client/build .
- name: Install server dependencies
run: bun install
- name: Generate migrations
run: bun run generate-migrations
- name: Generate integrations
run: bun run generate-integrations
- name: Generate client embed
run: bun run generate-client-embed
- name: Compile binary
run: bun build --compile --compile-autoload-package-json --external pg-hstore --external pg --target=${{ matrix.target }} server/index.js --outfile MySpeed
- name: Rename binary
run: mv MySpeed ${{ matrix.artifact_name }}
- name: Upload to Release
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: ${{ inputs.release_id }},
name: '${{ matrix.artifact_name }}',
data: fs.readFileSync('${{ matrix.artifact_name }}')
});
build-zip:
name: "Source ZIP"
runs-on: ubuntu-latest
steps:
- name: Checkout project
uses: actions/checkout@v4
- name: Setup Bun
uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Install client dependencies
working-directory: client
run: bun install
- name: Build client
working-directory: client
run: bun run build
- name: Move build folder
run: mv client/build .
- name: Install server dependencies
run: bun install
- name: Generate migrations
run: bun run generate-migrations
- name: Generate integrations
run: bun run generate-integrations
- name: Create zip archive
run: zip -r MySpeed.zip build server package.json
- name: Upload to Release
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
await github.rest.repos.uploadReleaseAsset({
owner: context.repo.owner,
repo: context.repo.repo,
release_id: ${{ inputs.release_id }},
name: 'MySpeed.zip',
data: fs.readFileSync('MySpeed.zip')
});
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Build Binaries on: workflow_call: inputs: version: required: true type: string release_id: required: true type: string jobs: build-windows: timeout-minutes: 30 name: "Windows (x64)" runs-on: windows-latest steps: - name: Checkout project uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install client dependencies working-directory: client run: bun install - name: Build client working-directory: client run: bun run build - name: Move build folder run: Move-Item -Path client/build -Destination . - name: Install server dependencies run: bun install - name: Generate migrations run: bun run generate-migrations - name: Generate integrations run: bun run generate-integrations - name: Generate client embed run: bun run generate-client-embed - name: Compile binary run: bun build --compile --compile-autoload-package-json --external pg-hstore --external pg --target=bun-windows-x64 server/index.js --outfile MySpeed.exe - name: Upload to Release uses: actions/github-script@v7 with: script: | const fs = require('fs'); await github.rest.repos.uploadReleaseAsset({ owner: context.repo.owner, repo: context.repo.repo, release_id: ${{ inputs.release_id }}, name: 'MySpeed-windows-x64.exe', data: fs.readFileSync('MySpeed.exe') }); - name: Upload artifact for MSI uses: actions/upload-artifact@v4 with: name: MySpeed-windows-x64.exe path: MySpeed.exe - name: Upload build folder for MSI uses: actions/upload-artifact@v4 with: name: build-folder path: build build-linux: timeout-minutes: 30 name: "Linux (${{ matrix.arch }})" runs-on: ${{ matrix.runner }} strategy: fail-fast: false matrix: include: - arch: x64 target: bun-linux-x64 runner: ubuntu-latest artifact_name: MySpeed-linux-x64 - arch: arm64 target: bun-linux-arm64 runner: ubuntu-24.04-arm artifact_name: MySpeed-linux-arm64 steps: - name: Checkout project uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install client dependencies working-directory: client run: bun install - name: Build client working-directory: client run: bun run build - name: Move build folder run: mv client/build . - name: Install server dependencies run: bun install - name: Generate migrations run: bun run generate-migrations - name: Generate integrations run: bun run generate-integrations - name: Generate client embed run: bun run generate-client-embed - name: Compile binary run: bun build --compile --compile-autoload-package-json --external pg-hstore --external pg --target=${{ matrix.target }} server/index.js --outfile MySpeed - name: Rename binary run: mv MySpeed ${{ matrix.artifact_name }} - name: Upload to Release uses: actions/github-script@v7 with: script: | const fs = require('fs'); await github.rest.repos.uploadReleaseAsset({ owner: context.repo.owner, repo: context.repo.repo, release_id: ${{ inputs.release_id }}, name: '${{ matrix.artifact_name }}', data: fs.readFileSync('${{ matrix.artifact_name }}') }); build-macos: timeout-minutes: 30 name: "macOS (${{ matrix.arch }})" runs-on: macos-latest strategy: fail-fast: false matrix: include: - arch: x64 target: bun-darwin-x64 artifact_name: MySpeed-macos-x64 - arch: arm64 target: bun-darwin-arm64 artifact_name: MySpeed-macos-arm64 steps: - name: Checkout project uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install client dependencies working-directory: client run: bun install - name: Build client working-directory: client run: bun run build - name: Move build folder run: mv client/build . - name: Install server dependencies run: bun install - name: Generate migrations run: bun run generate-migrations - name: Generate integrations run: bun run generate-integrations - name: Generate client embed run: bun run generate-client-embed - name: Compile binary run: bun build --compile --compile-autoload-package-json --external pg-hstore --external pg --target=${{ matrix.target }} server/index.js --outfile MySpeed - name: Rename binary run: mv MySpeed ${{ matrix.artifact_name }} - name: Upload to Release uses: actions/github-script@v7 with: script: | const fs = require('fs'); await github.rest.repos.uploadReleaseAsset({ owner: context.repo.owner, repo: context.repo.repo, release_id: ${{ inputs.release_id }}, name: '${{ matrix.artifact_name }}', data: fs.readFileSync('${{ matrix.artifact_name }}') }); build-zip: timeout-minutes: 30 name: "Source ZIP" runs-on: latchkey-small steps: - name: Checkout project uses: actions/checkout@v4 - name: Setup Bun uses: oven-sh/setup-bun@v2 with: bun-version: latest - name: Install client dependencies working-directory: client run: bun install - name: Build client working-directory: client run: bun run build - name: Move build folder run: mv client/build . - name: Install server dependencies run: bun install - name: Generate migrations run: bun run generate-migrations - name: Generate integrations run: bun run generate-integrations - name: Create zip archive run: zip -r MySpeed.zip build server package.json - name: Upload to Release uses: actions/github-script@v7 with: script: | const fs = require('fs'); await github.rest.repos.uploadReleaseAsset({ owner: context.repo.owner, repo: context.repo.repo, release_id: ${{ inputs.release_id }}, name: 'MySpeed.zip', data: fs.readFileSync('MySpeed.zip') });
What changed
- Run on Latchkey managed runners with one line (
runs-on), which apply the fixes below automatically and self-heal transient failures. This example useslatchkey-small; pick the runner size that fits the job. - Add a job timeout so a hung step cannot burn hours of runner time.
1 third-party action is referenced by a movable tag. Pin it to the commit SHA (Latchkey resolves and applies this automatically) so a repointed tag cannot change what runs.
This workflow runs 4 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.