Electron Builder CI workflow (jgraph/drawio-desktop)
The Electron Builder CI workflow from jgraph/drawio-desktop, explained and optimized by Latchkey.
CI health: D - needs work
Run this on Latchkey for self-healing, caching, and up to 58% lower cost.
Grade your own workflow free or run it on Latchkey →What it does
This is the Electron Builder CI workflow from the jgraph/drawio-desktop repository, a real project running GitHub Actions. It is shown here with attribution under its Apache-2.0 license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: Electron Builder CI
on:
push:
tags:
- 'v*'
jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
env:
CC: clang
CXX: clang++
npm_config_clang: 1
APPLEID: ${{ secrets.APPLEID }}
APPLEIDPASS: ${{ secrets.APPLEIDPASS }}
APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }}
CSC_LINK: ${{ secrets.CSC_LINK }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }}
OS_NAME: ${{ matrix.os }}
steps:
- name: Checkout reposistory
uses: actions/checkout@v6
with:
submodules: true
- name: Checkout drawio-dev
uses: actions/checkout@v6
with:
repository: jgraph/drawio-dev
token: ${{ secrets.GH_TOKEN }}
ref: release
path: drawio-dev
submodules: false
- name: Stage drawio-dev release into public submodule
run: |
# Build from the current HEAD of drawio-dev's release branch (checked out
# above). We no longer require a matching diagramly-X_Y_Z tag, and the
# public drawio submodule can lag its own VERSION/tag behind this.
if [ ! -f drawio-dev/VERSION ]; then
echo "::error::drawio-dev/VERSION not found on the release branch"
exit 1
fi
if ! grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$' drawio-dev/VERSION; then
echo "::error::drawio-dev/VERSION has unexpected format: $(cat drawio-dev/VERSION)"
exit 1
fi
echo "Internal drawio-dev VERSION: $(cat drawio-dev/VERSION)"
echo "Public drawio submodule VERSION: $(cat drawio/VERSION)"
# Copy the built minified JS and the authoritative VERSION into the
# public submodule tree. `npm run sync` will then stamp the internal
# version into package.json without any changes to sync.cjs - keeping
# the public-facing build (which has no drawio-dev) working as-is.
cp drawio-dev/src/main/webapp/js/*.min.js drawio/src/main/webapp/js/
cp drawio-dev/VERSION drawio/VERSION
rm -rf drawio-dev
cd drawio
rm -rf docs etc src/main/java src/main/webapp/connect src/main/webapp/service-worker* src/main/webapp/workbox-*
cd src/main/webapp/js
# Save viewer-static.min.js for macOS Quick Look extension before cleanup
if [ "$OS_NAME" = "macos-latest" ]; then cp viewer-static.min.js ../../../../../build/viewer-static.min.js; fi
# js/mermaid must survive: bootstrap.js eager-loads elk > mermaid > plantuml
# in a chain, so deleting it also kills PlantUML and PostConfig at runtime
rm -rf atlas-viewer.min.js atlas.min.js cryptojs deflate dropbox embed* freehand integrate.min.js jquery jszip onedrive orgchart reader.min.js rough sanitizer simplepeer spin viewer-static.min.js viewer.min.js
- name: Installing Node
uses: actions/setup-node@v6
with:
node-version: 24
- name: Build for ${{ matrix.os}}
run: |
if [ "$OS_NAME" = "ubuntu-latest" ]; then sudo apt-get update && sudo apt-get install -y icnsutils graphicsmagick xz-utils rpm; fi
git config --global url."https://github.com/".insteadOf "git@github.com:"
npm ci
if [ "$OS_NAME" = "ubuntu-latest" ]; then sed -ie 's/"asar": true,/"asar": true,\n"productName": "drawio",/' electron-builder-linux-mac.json; fi
npm run sync
npm run release-linux
- name: Build for Snap
if: ${{ matrix.os == 'ubuntu-latest' }}
run: |
#To generate SNAP_TOKEN run `snapcraft export-login [FILE]` and login with your snapcraft credentials. It is used now without login
sudo snap install snapcraft --classic
npm run release-snap
# Cannot configure electron-builder to publish to stable channel, so do it explicitly
snapcraft upload --release edge dist/draw.io-amd64-*.snapThe same workflow, on Latchkey
Estimated ~20% faster on cache hits, plus fewer wasted runs and a safer supply chain. Added and changed lines are highlighted.
name: Electron Builder CI on: push: tags: - 'v*' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: timeout-minutes: 30 runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest] env: CC: clang CXX: clang++ npm_config_clang: 1 APPLEID: ${{ secrets.APPLEID }} APPLEIDPASS: ${{ secrets.APPLEIDPASS }} APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }} CSC_KEY_PASSWORD: ${{ secrets.CSC_KEY_PASSWORD }} CSC_LINK: ${{ secrets.CSC_LINK }} GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAP_TOKEN }} OS_NAME: ${{ matrix.os }} steps: - name: Checkout reposistory uses: actions/checkout@v6 with: submodules: true - name: Checkout drawio-dev uses: actions/checkout@v6 with: repository: jgraph/drawio-dev token: ${{ secrets.GH_TOKEN }} ref: release path: drawio-dev submodules: false - name: Stage drawio-dev release into public submodule run: | # Build from the current HEAD of drawio-dev's release branch (checked out # above). We no longer require a matching diagramly-X_Y_Z tag, and the # public drawio submodule can lag its own VERSION/tag behind this. if [ ! -f drawio-dev/VERSION ]; then echo "::error::drawio-dev/VERSION not found on the release branch" exit 1 fi if ! grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$' drawio-dev/VERSION; then echo "::error::drawio-dev/VERSION has unexpected format: $(cat drawio-dev/VERSION)" exit 1 fi echo "Internal drawio-dev VERSION: $(cat drawio-dev/VERSION)" echo "Public drawio submodule VERSION: $(cat drawio/VERSION)" # Copy the built minified JS and the authoritative VERSION into the # public submodule tree. `npm run sync` will then stamp the internal # version into package.json without any changes to sync.cjs - keeping # the public-facing build (which has no drawio-dev) working as-is. cp drawio-dev/src/main/webapp/js/*.min.js drawio/src/main/webapp/js/ cp drawio-dev/VERSION drawio/VERSION rm -rf drawio-dev cd drawio rm -rf docs etc src/main/java src/main/webapp/connect src/main/webapp/service-worker* src/main/webapp/workbox-* cd src/main/webapp/js # Save viewer-static.min.js for macOS Quick Look extension before cleanup if [ "$OS_NAME" = "macos-latest" ]; then cp viewer-static.min.js ../../../../../build/viewer-static.min.js; fi # js/mermaid must survive: bootstrap.js eager-loads elk > mermaid > plantuml # in a chain, so deleting it also kills PlantUML and PostConfig at runtime rm -rf atlas-viewer.min.js atlas.min.js cryptojs deflate dropbox embed* freehand integrate.min.js jquery jszip onedrive orgchart reader.min.js rough sanitizer simplepeer spin viewer-static.min.js viewer.min.js - name: Installing Node uses: actions/setup-node@v6 with: cache: 'npm' node-version: 24 - name: Build for ${{ matrix.os}} run: | if [ "$OS_NAME" = "ubuntu-latest" ]; then sudo apt-get update && sudo apt-get install -y icnsutils graphicsmagick xz-utils rpm; fi git config --global url."https://github.com/".insteadOf "git@github.com:" npm ci if [ "$OS_NAME" = "ubuntu-latest" ]; then sed -ie 's/"asar": true,/"asar": true,\n"productName": "drawio",/' electron-builder-linux-mac.json; fi npm run sync npm run release-linux - name: Build for Snap if: ${{ matrix.os == 'ubuntu-latest' }} run: | #To generate SNAP_TOKEN run `snapcraft export-login [FILE]` and login with your snapcraft credentials. It is used now without login sudo snap install snapcraft --classic npm run release-snap # Cannot configure electron-builder to publish to stable channel, so do it explicitly snapcraft upload --release edge dist/draw.io-amd64-*.snap
What changed
- Cancel superseded runs when a branch or PR gets a newer push.
- Cache dependency installs on the setup step so they are served from cache.
- Add a job timeout so a hung step cannot burn hours of runner time.
What Latchkey heals here
This workflow has steps that commonly fail on transient issues (network, registries, flaky browsers). On Latchkey managed runners they are detected, retried, and self-healed instead of failing your build:
- Dependency installs
This workflow runs 1 job (2 with the matrix expanded) per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.