Skip to content
Latchkey

Electron Builder CI workflow (jgraph/drawio-desktop)

The Electron Builder CI workflow from jgraph/drawio-desktop, explained and optimized by Latchkey.

D

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 →
Source: jgraph/drawio-desktop.github/workflows/electron-builder.ymlLicense Apache-2.0View source

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

workflow (.yml)
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-*.snap

The 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

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:

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.

Actions used in this workflow