CI: npm smoke test workflow (lovell/sharp)
The CI: npm smoke test workflow from lovell/sharp, explained and optimized by Latchkey.
CI health: C - fair
Point runs-on at Latchkey and get run de-duplication, job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the CI: npm smoke test workflow from the lovell/sharp 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: "CI: npm smoke test"
on:
push:
tags:
- "v**"
permissions: {}
jobs:
release-smoke-test:
name: "${{ github.ref_name }} ${{ matrix.name }}"
runs-on: ${{ matrix.runs-on }}
strategy:
fail-fast: false
matrix:
include:
- name: linux-x64-node-npm
runs-on: ubuntu-24.04
runtime: node
package-manager: npm
- name: linux-x64-node-pnpm
runs-on: ubuntu-24.04
runtime: node
package-manager: pnpm
- name: linux-x64-node-yarn
runs-on: ubuntu-24.04
runtime: node
package-manager: yarn
- name: linux-x64-node-yarn-pnp
runs-on: ubuntu-24.04
runtime: node
package-manager: yarn-pnp
- name: linux-x64-node-yarn-v1
runs-on: ubuntu-24.04
runtime: node
package-manager: yarn-v1
- name: linux-x64-deno
runs-on: ubuntu-24.04
runtime: deno
- name: linux-x64-bun
runs-on: ubuntu-24.04
runtime: bun
- name: darwin-x64-node-npm
runs-on: macos-15-intel
runtime: node
package-manager: npm
- name: darwin-x64-node-yarn
runs-on: macos-15-intel
runtime: node
package-manager: yarn
- name: darwin-x64-node-yarn-pnp
runs-on: macos-15-intel
runtime: node
package-manager: yarn-pnp
- name: darwin-x64-node-yarn-v1
runs-on: macos-15-intel
runtime: node
package-manager: yarn-v1
- name: darwin-x64-deno
runs-on: macos-15-intel
runtime: deno
- name: darwin-x64-bun
runs-on: macos-15-intel
runtime: bun
- name: win32-x64-node-npm
runs-on: windows-2022
runtime: node
package-manager: npm
- name: win32-x64-node-pnpm
runs-on: windows-2022
runtime: node
package-manager: pnpm
- name: win32-x64-node-yarn
runs-on: windows-2022
runtime: node
package-manager: yarn
- name: win32-x64-node-yarn-pnp
runs-on: windows-2022
runtime: node
package-manager: yarn-pnp
- name: win32-x64-node-yarn-v1
runs-on: windows-2022
runtime: node
package-manager: yarn-v1
- name: win32-x64-deno
runs-on: windows-2022
runtime: deno
steps:
- name: Install Node.js
if: ${{ matrix.runtime == 'node' }}
uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
with:
node-version: 20
cache: ""
package-manager-cache: false
- name: Install pnpm
if: ${{ matrix.package-manager == 'pnpm' }}
uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9
with:
version: 11
- name: Install Deno
if: ${{ matrix.runtime == 'deno' }}
uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2.0.5
with:
deno-version: v2.x
- name: Install Bun
if: ${{ matrix.runtime == 'bun' }}
uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
with:
bun-version: latest
no-cache: true
- name: Version
id: version
uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0
with:
script: |
core.setOutput('semver', context.ref.replace('refs/tags/v',''))
- name: Create package.json
env:
SEMVER: ${{ steps.version.outputs.semver }}
shell: bash
run: |
cat <<EOF >package.json
{
"dependencies": {
"sharp": "${SEMVER}"
},
"type": "module"
}
EOF
- name: Create release.mjs
shell: bash
run: |
cat <<EOF >release.mjs
import { deepStrictEqual } from 'node:assert';
import sharp from 'sharp';
deepStrictEqual(['.jpg', '.jpeg', '.jpe', '.jfif'], sharp.format.jpeg.input.fileSuffix);
EOF
- name: Run with Node.js + npm
if: ${{ matrix.package-manager == 'npm' }}
run: |
npm install
node release.mjs
- name: Run with Node.js + pnpm
if: ${{ matrix.package-manager == 'pnpm' }}
run: |
pnpm config set minimumReleaseAge 0 --location=user
pnpm install
node release.mjs
- name: Run with Node.js + yarn
if: ${{ matrix.package-manager == 'yarn' }}
run: |
corepack enable
yarn set version stable
yarn config set enableImmutableInstalls false
yarn config set enableScripts false
yarn config set nodeLinker node-modules
yarn config set npmMinimalAgeGate 0
yarn install
node release.mjs
- name: Run with Node.js + yarn pnp
if: ${{ matrix.package-manager == 'yarn-pnp' }}
run: |
corepack enable
yarn set version stable
yarn config set enableImmutableInstalls false
yarn config set enableScripts false
yarn config set nodeLinker pnp
yarn config set npmMinimalAgeGate 0
yarn install
yarn node release.mjs
- name: Run with Node.js + yarn v1
if: ${{ matrix.package-manager == 'yarn-v1' }}
run: |
corepack enable
yarn set version classic
yarn install
node release.mjs
- name: Run with Deno
if: ${{ matrix.runtime == 'deno' }}
run: |
deno install --minimum-dependency-age=0
deno run --allow-env --allow-ffi --allow-read --allow-sys release.mjs
- name: Run with Bun
if: ${{ matrix.runtime == 'bun' }}
run: |
bun install --ignore-scripts
bun release.mjs
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: "CI: npm smoke test" on: push: tags: - "v**" permissions: {} concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: release-smoke-test: timeout-minutes: 30 name: "${{ github.ref_name }} ${{ matrix.name }}" runs-on: ${{ matrix.runs-on }} strategy: fail-fast: false matrix: include: - name: linux-x64-node-npm runs-on: latchkey-small runtime: node package-manager: npm - name: linux-x64-node-pnpm runs-on: latchkey-small runtime: node package-manager: pnpm - name: linux-x64-node-yarn runs-on: latchkey-small runtime: node package-manager: yarn - name: linux-x64-node-yarn-pnp runs-on: latchkey-small runtime: node package-manager: yarn-pnp - name: linux-x64-node-yarn-v1 runs-on: latchkey-small runtime: node package-manager: yarn-v1 - name: linux-x64-deno runs-on: latchkey-small runtime: deno - name: linux-x64-bun runs-on: latchkey-small runtime: bun - name: darwin-x64-node-npm runs-on: macos-15-intel runtime: node package-manager: npm - name: darwin-x64-node-yarn runs-on: macos-15-intel runtime: node package-manager: yarn - name: darwin-x64-node-yarn-pnp runs-on: macos-15-intel runtime: node package-manager: yarn-pnp - name: darwin-x64-node-yarn-v1 runs-on: macos-15-intel runtime: node package-manager: yarn-v1 - name: darwin-x64-deno runs-on: macos-15-intel runtime: deno - name: darwin-x64-bun runs-on: macos-15-intel runtime: bun - name: win32-x64-node-npm runs-on: windows-2022 runtime: node package-manager: npm - name: win32-x64-node-pnpm runs-on: windows-2022 runtime: node package-manager: pnpm - name: win32-x64-node-yarn runs-on: windows-2022 runtime: node package-manager: yarn - name: win32-x64-node-yarn-pnp runs-on: windows-2022 runtime: node package-manager: yarn-pnp - name: win32-x64-node-yarn-v1 runs-on: windows-2022 runtime: node package-manager: yarn-v1 - name: win32-x64-deno runs-on: windows-2022 runtime: deno steps: - name: Install Node.js if: ${{ matrix.runtime == 'node' }} uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: 20 cache: "" package-manager-cache: false - name: Install pnpm if: ${{ matrix.package-manager == 'pnpm' }} uses: pnpm/action-setup@0ebf47130e4866e96fce0953f49152a61190b271 # v6.0.9 with: version: 11 - name: Install Deno if: ${{ matrix.runtime == 'deno' }} uses: denoland/setup-deno@22d081ff2d3a40755e97629de92e3bcbfa7cf2ed # v2.0.5 with: deno-version: v2.x - name: Install Bun if: ${{ matrix.runtime == 'bun' }} uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0 with: bun-version: latest no-cache: true - name: Version id: version uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | core.setOutput('semver', context.ref.replace('refs/tags/v','')) - name: Create package.json env: SEMVER: ${{ steps.version.outputs.semver }} shell: bash run: | cat <<EOF >package.json { "dependencies": { "sharp": "${SEMVER}" }, "type": "module" } EOF - name: Create release.mjs shell: bash run: | cat <<EOF >release.mjs import { deepStrictEqual } from 'node:assert'; import sharp from 'sharp'; deepStrictEqual(['.jpg', '.jpeg', '.jpe', '.jfif'], sharp.format.jpeg.input.fileSuffix); EOF - name: Run with Node.js + npm if: ${{ matrix.package-manager == 'npm' }} run: | npm install node release.mjs - name: Run with Node.js + pnpm if: ${{ matrix.package-manager == 'pnpm' }} run: | pnpm config set minimumReleaseAge 0 --location=user pnpm install node release.mjs - name: Run with Node.js + yarn if: ${{ matrix.package-manager == 'yarn' }} run: | corepack enable yarn set version stable yarn config set enableImmutableInstalls false yarn config set enableScripts false yarn config set nodeLinker node-modules yarn config set npmMinimalAgeGate 0 yarn install node release.mjs - name: Run with Node.js + yarn pnp if: ${{ matrix.package-manager == 'yarn-pnp' }} run: | corepack enable yarn set version stable yarn config set enableImmutableInstalls false yarn config set enableScripts false yarn config set nodeLinker pnp yarn config set npmMinimalAgeGate 0 yarn install yarn node release.mjs - name: Run with Node.js + yarn v1 if: ${{ matrix.package-manager == 'yarn-v1' }} run: | corepack enable yarn set version classic yarn install node release.mjs - name: Run with Deno if: ${{ matrix.runtime == 'deno' }} run: | deno install --minimum-dependency-age=0 deno run --allow-env --allow-ffi --allow-read --allow-sys release.mjs - name: Run with Bun if: ${{ matrix.runtime == 'bun' }} run: | bun install --ignore-scripts bun release.mjs
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.
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 per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.