Emscripten workflow (libass/JavascriptSubtitlesOctopus)
The Emscripten workflow from libass/JavascriptSubtitlesOctopus, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, SHA-pinned actions, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the Emscripten workflow from the libass/JavascriptSubtitlesOctopus 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: Emscripten
on:
push:
branches: [master, ci]
pull_request:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Cancel previous runs
uses: styfle/cancel-workflow-action@0.12.1
with:
access_token: ${{ github.token }}
all_but_latest: true
- name: Checkout Base Repo
uses: actions/checkout@v4
- name: Prepare Submodules
run: |
git submodule sync
git submodule update --init --recursive --force
mv lib lib_
- name: Calculate Hash Key
id: cache_config
run: |
# Invalidate cache if submodules, patches or emscripten version changed
key="$(find build/patches/ -type f | sort | xargs cat .gitmodules Dockerfile \
Makefile Makefile_licence | shasum -a 256 | cut -d' ' -f1)"
echo "key=0-${key}" >> $GITHUB_OUTPUT
- name: Ensure Cache will be newer than Checkout
run: |
find . -exec touch -d 1971-01-01T00:00:00 '{}' +
- name: Retrieve Cached Built Dependencies
uses: actions/cache@v4
id: cache
with:
key: ${{ steps.cache_config.outputs.key }}
path: |
lib
build/lib
dist/libraries
dist/license/*
!dist/license/subtitlesoctopus
!dist/license/all*
/tmp/emcc_lto
- name: Checkout Submodules
if: steps.cache.outputs.cache-hit != 'true'
run: |
mv lib_ lib
- name: Build Docker Image
run: |
docker build -t libass/jso .
- name: Build Binaries
run: |
mkdir -p /tmp/emcc_lto
docker run --rm --env LC_ALL=C.UTF-8 -v "${PWD}":/code -v "/tmp/emcc_lto:/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/lto" libass/jso:latest
- name: Upload Nightly Build
uses: actions/upload-artifact@v4
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master'
with:
name: js
path: dist/js
update_gh-pages:
if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master'
needs: build
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
ref: gh-pages
- name: Remove old assets
run: rm -fr assets/js
- name: Download nightly build
uses: actions/download-artifact@v4
with:
name: js
path: assets/js
- name: Push new version
run: |
git config --global user.email "actions@noreply.github.com"
git config --global user.name "GitHub Action"
git add assets/js
(git commit -m "$(printf \
"Update binaries to latest nightly\n\nFrom %s" "${{ github.sha }}")" \
&& git push origin gh-pages) \
|| : # Ignore if nothing changed
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Emscripten on: push: branches: [master, ci] pull_request: workflow_dispatch: concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: timeout-minutes: 30 runs-on: latchkey-small steps: - name: Cancel previous runs uses: styfle/cancel-workflow-action@0.12.1 with: access_token: ${{ github.token }} all_but_latest: true - name: Checkout Base Repo uses: actions/checkout@v4 - name: Prepare Submodules run: | git submodule sync git submodule update --init --recursive --force mv lib lib_ - name: Calculate Hash Key id: cache_config run: | # Invalidate cache if submodules, patches or emscripten version changed key="$(find build/patches/ -type f | sort | xargs cat .gitmodules Dockerfile \ Makefile Makefile_licence | shasum -a 256 | cut -d' ' -f1)" echo "key=0-${key}" >> $GITHUB_OUTPUT - name: Ensure Cache will be newer than Checkout run: | find . -exec touch -d 1971-01-01T00:00:00 '{}' + - name: Retrieve Cached Built Dependencies uses: actions/cache@v4 id: cache with: key: ${{ steps.cache_config.outputs.key }} path: | lib build/lib dist/libraries dist/license/* !dist/license/subtitlesoctopus !dist/license/all* /tmp/emcc_lto - name: Checkout Submodules if: steps.cache.outputs.cache-hit != 'true' run: | mv lib_ lib - name: Build Docker Image run: | docker build -t libass/jso . - name: Build Binaries run: | mkdir -p /tmp/emcc_lto docker run --rm --env LC_ALL=C.UTF-8 -v "${PWD}":/code -v "/tmp/emcc_lto:/emsdk/upstream/emscripten/cache/sysroot/lib/wasm32-emscripten/lto" libass/jso:latest - name: Upload Nightly Build uses: actions/upload-artifact@v4 if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master' with: name: js path: dist/js update_gh-pages: timeout-minutes: 30 if: (github.event_name == 'push' || github.event_name == 'workflow_dispatch') && github.ref == 'refs/heads/master' needs: build runs-on: latchkey-small steps: - name: Checkout uses: actions/checkout@v4 with: ref: gh-pages - name: Remove old assets run: rm -fr assets/js - name: Download nightly build uses: actions/download-artifact@v4 with: name: js path: assets/js - name: Push new version run: | git config --global user.email "actions@noreply.github.com" git config --global user.name "GitHub Action" git add assets/js (git commit -m "$(printf \ "Update binaries to latest nightly\n\nFrom %s" "${{ github.sha }}")" \ && git push origin gh-pages) \ || : # Ignore if nothing changed
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. - Cancel superseded runs when a branch or PR gets a newer push.
- 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.
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:
- Container pulls and builds
This workflow runs 2 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.