Skip to content
Latchkey

Test, build and deploy workflow (streamlink/streamlink-twitch-gui)

The Test, build and deploy workflow from streamlink/streamlink-twitch-gui, explained and optimized by Latchkey.

D

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.

Grade your own workflow free or run it on Latchkey →
Source: streamlink/streamlink-twitch-gui.github/workflows/main.ymlLicense MITView source

What it does

This is the Test, build and deploy workflow from the streamlink/streamlink-twitch-gui 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

workflow (.yml)
name: Test, build and deploy

on:
  push: {}
  pull_request: {}

env:
  CI: true
  NODE_VERSION: 20

jobs:
  test:
    name: Test
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - windows-latest
    runs-on: ${{ matrix.os }}
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          fetch-depth: 0
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: ${{ env.NODE_VERSION }}
      - name: Lint (line terminators)
        if: startsWith(matrix.os, 'ubuntu')
        run: "! grep 'with CRLF line terminators' <(git ls-files | file -nNf-)"
      - name: Lint (unicode bidirectional control characters)
        if: startsWith(matrix.os, 'ubuntu')
        run: "! git grep -EIn $'[\\u2066\\u2067\\u2068\\u2069\\u202A\\u202B\\u202C\\u202D\\u202E]'"
      - name: Lint (file permissions)
        if: startsWith(matrix.os, 'ubuntu')
        run: "! grep -Ev '^644' <(git ls-files src/ build/tasks/ | xargs stat '--format=%a %n')"
      - name: NW.js cache
        if: startsWith(github.ref, 'refs/tags/') != true
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
        with:
          path: build/cache/
          key: nwjs-${{ matrix.os }}-${{ hashFiles('build/tasks/configs/nwjs.js') }}
      - name: Install dependencies
        shell: bash
        run: yarn install --pure-lockfile --no-progress --non-interactive
      - name: Test
        shell: bash
        run: |
          if [[ "$(uname)" == "Linux" ]]; then
            xvfb-run --auto-servernum yarn run grunt test:coverage
          else
            yarn run grunt test:coverage
          fi
      - name: I18n
        if: startsWith(matrix.os, 'ubuntu')
        run: yarn run grunt webpack:i18n
      - name: Build
        run: yarn run grunt clean:tmp_prod webpack:prod
      - name: Upload coverage data
        uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
        with:
          name: os:${{ matrix.os }}
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

  release:
    name: New release
    if: github.repository == 'streamlink/streamlink-twitch-gui' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
    needs:
      - test
    runs-on: ubuntu-24.04
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          fetch-depth: 0
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          node-version: ${{ env.NODE_VERSION }}
      - name: Prepare env vars
        run: |
          echo "SOURCE_DATE_EPOCH=$(git show -s --format=%ct "${GITHUB_REF}")" >> $GITHUB_ENV
      - name: Install dependencies
        run: |
          yarn install --pure-lockfile --no-progress --non-interactive
          sudo apt-get install pigz nsis appstream{,-util}
          ./.github/workflows/install-wine.sh
      - name: Build
        run: yarn run grunt clean:tmp_prod webpack:prod
      - name: Compile & package
        run: yarn run grunt clean:dist dist:all
      - name: Deploy
        env:
          RELEASES_API_KEY: ${{ secrets.GITHUB_TOKEN }}
        run: yarn run grunt deploy:github

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: Test, build and deploy
 
on:
  push: {}
  pull_request: {}
 
env:
  CI: true
  NODE_VERSION: 20
 
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true
 
jobs:
  test:
    name: Test
    strategy:
      fail-fast: false
      matrix:
        os:
          - ubuntu-latest
          - windows-latest
    runs-on: ${{ matrix.os }}
    timeout-minutes: 60
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          fetch-depth: 0
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          cache: 'npm'
          node-version: ${{ env.NODE_VERSION }}
      - name: Lint (line terminators)
        if: startsWith(matrix.os, 'ubuntu')
        run: "! grep 'with CRLF line terminators' <(git ls-files | file -nNf-)"
      - name: Lint (unicode bidirectional control characters)
        if: startsWith(matrix.os, 'ubuntu')
        run: "! git grep -EIn $'[\\u2066\\u2067\\u2068\\u2069\\u202A\\u202B\\u202C\\u202D\\u202E]'"
      - name: Lint (file permissions)
        if: startsWith(matrix.os, 'ubuntu')
        run: "! grep -Ev '^644' <(git ls-files src/ build/tasks/ | xargs stat '--format=%a %n')"
      - name: NW.js cache
        if: startsWith(github.ref, 'refs/tags/') != true
        uses: actions/cache@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
        with:
          path: build/cache/
          key: nwjs-${{ matrix.os }}-${{ hashFiles('build/tasks/configs/nwjs.js') }}
      - name: Install dependencies
        shell: bash
        run: yarn install --pure-lockfile --no-progress --non-interactive
      - name: Test
        shell: bash
        run: |
          if [[ "$(uname)" == "Linux" ]]; then
            xvfb-run --auto-servernum yarn run grunt test:coverage
          else
            yarn run grunt test:coverage
          fi
      - name: I18n
        if: startsWith(matrix.os, 'ubuntu')
        run: yarn run grunt webpack:i18n
      - name: Build
        run: yarn run grunt clean:tmp_prod webpack:prod
      - name: Upload coverage data
        uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0
        with:
          name: os:${{ matrix.os }}
        env:
          CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
 
  release:
    timeout-minutes: 30
    name: New release
    if: github.repository == 'streamlink/streamlink-twitch-gui' && github.event_name == 'push' && startsWith(github.ref, 'refs/tags/')
    needs:
      - test
    runs-on: latchkey-small
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
        with:
          fetch-depth: 0
      - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0
        with:
          cache: 'npm'
          node-version: ${{ env.NODE_VERSION }}
      - name: Prepare env vars
        run: |
          echo "SOURCE_DATE_EPOCH=$(git show -s --format=%ct "${GITHUB_REF}")" >> $GITHUB_ENV
      - name: Install dependencies
        run: |
          yarn install --pure-lockfile --no-progress --non-interactive
          sudo apt-get install pigz nsis appstream{,-util}
          ./.github/workflows/install-wine.sh
      - name: Build
        run: yarn run grunt clean:tmp_prod webpack:prod
      - name: Compile & package
        run: yarn run grunt clean:dist dist:all
      - name: Deploy
        env:
          RELEASES_API_KEY: ${{ secrets.GITHUB_TOKEN }}
        run: yarn run grunt deploy:github
 

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 2 jobs (3 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