prod workflow (CesiumGS/cesium)
The prod workflow from CesiumGS/cesium, explained and optimized by Latchkey.
CI health: D - needs work
Point runs-on at Latchkey and get caching, run de-duplication, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the prod workflow from the CesiumGS/cesium 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: prod
on:
push:
branches:
- "cesium.com"
env:
PROD: true
AWS_ACCESS_KEY_ID: ${{ secrets.PROD_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: us-east-1
BRANCH: ${{ github.ref_name }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
GITHUB_REPO: ${{ github.repository }}
GITHUB_SHA: ${{ github.sha }}
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- name: install node 22
uses: actions/setup-node@v6
with:
node-version: "22"
- name: npm install
run: npm install
- name: lint *.js
run: npm run eslint
- name: lint *.md
run: npm run markdownlint
- name: format code
run: npm run prettier-check
- name: build
run: npm run build
- name: tsc
run: npm run tsc
- name: sg test
run: npm exec --package=@ast-grep/cli --offline -- sg test
- name: sg scan
run: npm exec --package=@ast-grep/cli --offline -- sg scan --context 3
deploy-archive:
runs-on: ubuntu-latest
needs: [lint]
steps:
- uses: actions/checkout@v7
- name: install node 22
uses: actions/setup-node@v6
with:
node-version: "22"
- name: npm install
run: npm install
- name: build website release
run: npm run website-release
- name: build types
run: npm run build-ts
- name: build sandcastle
# We need to rebuild Sandcastle or the origins will be wrong and not load
env:
# We specifically want this to NOT build for production in order to get relative routes
# to the rest of the archive release files.
# This also mimics how the zip was generated locally during the release process
PROD: false
run: npm run build-sandcastle -- --outer-origin="https://cesium.com"
- name: deploy to cesium.com
if: ${{ env.AWS_ACCESS_KEY_ID != '' }}
# Download zip from the Github release and unzip to Build/release/
# Publish that unzipped code to the bucket for https://cesium.com/downloads/cesiumjs/releases/[version]/... urls
# Publish sandcastle nested into the bucket for the archive
run: |
curl -LO $(curl https://api.github.com/repos/CesiumGS/cesium/releases/latest -H "Authorization: ${GITHUB_TOKEN}" | jq -r '.assets[0].browser_download_url')
unzip Cesium-$(cat package.json | jq -r '.version' | sed 's/\.0$//').zip -d Build/release/ -x "Apps"
aws s3 sync Build/release/ s3://cesium-website/cesiumjs/releases/$(cat package.json | jq -r '.version' | sed 's/\.0$//')/ \
--cache-control "public, max-age=1800" \
--exclude "Apps/Sandcastle2/*" \
--delete
aws s3 sync Apps/Sandcastle2/ s3://cesium-website/cesiumjs/releases/$(cat package.json | jq -r '.version' | sed 's/\.0$//')/Apps/Sandcastle2/ --cache-control "public, max-age=1800" --delete
deploy-docs:
runs-on: ubuntu-latest
needs: [lint]
steps:
- uses: actions/checkout@v7
- name: install node 22
uses: actions/setup-node@v6
with:
node-version: "22"
- name: npm install
run: npm install
- name: build docs
run: npm run build-docs
- name: deploy to cesium.com
if: ${{ env.AWS_ACCESS_KEY_ID != '' }}
# Publish the documentation files to the bucket for https://cesium.com/learn/cesiumjs/ref-doc/
run: |
aws s3 sync Build/Documentation/ s3://cesium-website/cesiumjs/ref-doc/ --cache-control "public, max-age=1800" --delete
deploy-cesium-viewer:
runs-on: ubuntu-latest
needs: [lint]
steps:
- uses: actions/checkout@v7
- name: install node 22
uses: actions/setup-node@v6
with:
node-version: "22"
- name: npm install
run: npm install
- name: build website release
run: npm run website-release
- name: build cesium viewer
run: npm run build-cesium-viewer
- name: deploy to cesium.com
if: ${{ env.AWS_ACCESS_KEY_ID != '' }}
# Publish the simple viewer app to the bucket for https://cesium.com/cesiumjs/cesium-viewer/
run: |
aws s3 sync Build/CesiumViewer/ s3://cesium-website/cesiumjs/cesium-viewer/ --cache-control "public, max-age=1800" --delete
deploy-sandcastle:
runs-on: ubuntu-latest
needs: [lint]
steps:
- uses: actions/checkout@v7
- name: install node 22
uses: actions/setup-node@v6
with:
node-version: "22"
- name: npm install
run: npm install
- name: build website release
run: npm run website-release
- name: build types
run: npm run build-ts
- name: build apps
run: npm run build-sandcastle -- --outer-origin="https://sandcastle.cesium.com"
- name: deploy to sandcastle.cesium.com
if: ${{ env.AWS_ACCESS_KEY_ID != '' }}
# Publish sandcastle to the bucket for https://sandcastle.cesium.com/
run: |
aws s3 sync Build/Sandcastle2/ s3://cesium-sandcastle-website/ --cache-control "public, max-age=1800" --delete
delete-old-ion-token:
runs-on: ubuntu-latest
needs: [deploy-cesium-viewer, deploy-sandcastle]
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v7
- name: install node 22
uses: actions/setup-node@v6
with:
node-version: "22"
- name: npm install
working-directory: ./.github/actions/update-tokens
run: npm install
- name: run script
env:
ION_TOKEN_CONTROLLER_TOKEN: ${{ secrets.ION_TOKEN_CONTROLLER_TOKEN }}
working-directory: "./.github/actions/update-tokens"
run: node ionTokenDeleter.js --update
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: prod on: push: branches: - "cesium.com" env: PROD: true AWS_ACCESS_KEY_ID: ${{ secrets.PROD_AWS_ACCESS_KEY_ID }} AWS_SECRET_ACCESS_KEY: ${{ secrets.PROD_AWS_SECRET_ACCESS_KEY }} AWS_REGION: us-east-1 BRANCH: ${{ github.ref_name }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} GITHUB_REPO: ${{ github.repository }} GITHUB_SHA: ${{ github.sha }} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: lint: timeout-minutes: 30 runs-on: latchkey-small steps: - uses: actions/checkout@v7 - name: install node 22 uses: actions/setup-node@v6 with: cache: 'npm' node-version: "22" - name: npm install run: npm install - name: lint *.js run: npm run eslint - name: lint *.md run: npm run markdownlint - name: format code run: npm run prettier-check - name: build run: npm run build - name: tsc run: npm run tsc - name: sg test run: npm exec --package=@ast-grep/cli --offline -- sg test - name: sg scan run: npm exec --package=@ast-grep/cli --offline -- sg scan --context 3 deploy-archive: timeout-minutes: 30 runs-on: latchkey-small needs: [lint] steps: - uses: actions/checkout@v7 - name: install node 22 uses: actions/setup-node@v6 with: cache: 'npm' node-version: "22" - name: npm install run: npm install - name: build website release run: npm run website-release - name: build types run: npm run build-ts - name: build sandcastle # We need to rebuild Sandcastle or the origins will be wrong and not load env: # We specifically want this to NOT build for production in order to get relative routes # to the rest of the archive release files. # This also mimics how the zip was generated locally during the release process PROD: false run: npm run build-sandcastle -- --outer-origin="https://cesium.com" - name: deploy to cesium.com if: ${{ env.AWS_ACCESS_KEY_ID != '' }} # Download zip from the Github release and unzip to Build/release/ # Publish that unzipped code to the bucket for https://cesium.com/downloads/cesiumjs/releases/[version]/... urls # Publish sandcastle nested into the bucket for the archive run: | curl -LO $(curl https://api.github.com/repos/CesiumGS/cesium/releases/latest -H "Authorization: ${GITHUB_TOKEN}" | jq -r '.assets[0].browser_download_url') unzip Cesium-$(cat package.json | jq -r '.version' | sed 's/\.0$//').zip -d Build/release/ -x "Apps" aws s3 sync Build/release/ s3://cesium-website/cesiumjs/releases/$(cat package.json | jq -r '.version' | sed 's/\.0$//')/ \ --cache-control "public, max-age=1800" \ --exclude "Apps/Sandcastle2/*" \ --delete aws s3 sync Apps/Sandcastle2/ s3://cesium-website/cesiumjs/releases/$(cat package.json | jq -r '.version' | sed 's/\.0$//')/Apps/Sandcastle2/ --cache-control "public, max-age=1800" --delete deploy-docs: timeout-minutes: 30 runs-on: latchkey-small needs: [lint] steps: - uses: actions/checkout@v7 - name: install node 22 uses: actions/setup-node@v6 with: cache: 'npm' node-version: "22" - name: npm install run: npm install - name: build docs run: npm run build-docs - name: deploy to cesium.com if: ${{ env.AWS_ACCESS_KEY_ID != '' }} # Publish the documentation files to the bucket for https://cesium.com/learn/cesiumjs/ref-doc/ run: | aws s3 sync Build/Documentation/ s3://cesium-website/cesiumjs/ref-doc/ --cache-control "public, max-age=1800" --delete deploy-cesium-viewer: timeout-minutes: 30 runs-on: latchkey-small needs: [lint] steps: - uses: actions/checkout@v7 - name: install node 22 uses: actions/setup-node@v6 with: cache: 'npm' node-version: "22" - name: npm install run: npm install - name: build website release run: npm run website-release - name: build cesium viewer run: npm run build-cesium-viewer - name: deploy to cesium.com if: ${{ env.AWS_ACCESS_KEY_ID != '' }} # Publish the simple viewer app to the bucket for https://cesium.com/cesiumjs/cesium-viewer/ run: | aws s3 sync Build/CesiumViewer/ s3://cesium-website/cesiumjs/cesium-viewer/ --cache-control "public, max-age=1800" --delete deploy-sandcastle: timeout-minutes: 30 runs-on: latchkey-small needs: [lint] steps: - uses: actions/checkout@v7 - name: install node 22 uses: actions/setup-node@v6 with: cache: 'npm' node-version: "22" - name: npm install run: npm install - name: build website release run: npm run website-release - name: build types run: npm run build-ts - name: build apps run: npm run build-sandcastle -- --outer-origin="https://sandcastle.cesium.com" - name: deploy to sandcastle.cesium.com if: ${{ env.AWS_ACCESS_KEY_ID != '' }} # Publish sandcastle to the bucket for https://sandcastle.cesium.com/ run: | aws s3 sync Build/Sandcastle2/ s3://cesium-sandcastle-website/ --cache-control "public, max-age=1800" --delete delete-old-ion-token: timeout-minutes: 30 runs-on: latchkey-small needs: [deploy-cesium-viewer, deploy-sandcastle] permissions: contents: write pull-requests: write steps: - uses: actions/checkout@v7 - name: install node 22 uses: actions/setup-node@v6 with: cache: 'npm' node-version: "22" - name: npm install working-directory: ./.github/actions/update-tokens run: npm install - name: run script env: ION_TOKEN_CONTROLLER_TOKEN: ${{ secrets.ION_TOKEN_CONTROLLER_TOKEN }} working-directory: "./.github/actions/update-tokens" run: node ionTokenDeleter.js --update
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.
- 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
- Network fetches
This workflow runs 6 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.