reusable-build workflow (ungoogled-software/ungoogled-chromium-windows)
The reusable-build workflow from ungoogled-software/ungoogled-chromium-windows, explained and optimized by Latchkey.
CI health: A - excellent
Point runs-on at Latchkey and get job timeouts, self-healing for flaky steps, and up to 58% lower cost, applied automatically.
What it does
This is the reusable-build workflow from the ungoogled-software/ungoogled-chromium-windows repository, a real project running GitHub Actions. It is shown here with attribution under its BSD-3-Clause license.
Below, Latchkey shows a faster, safer version produced by its optimization engine.
The workflow
name: reusable-build
on:
workflow_call:
inputs:
python-version:
type: string
required: false
default: '3.12'
x86:
type: boolean
required: false
default: false
arm:
type: boolean
required: false
default: false
jobs:
build-1:
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: false
from_artifact: false
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-2:
needs: build-1
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-3:
needs: build-2
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-4:
needs: build-3
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-5:
needs: build-4
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-6:
needs: build-5
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-7:
needs: build-6
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-8:
needs: build-7
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-9:
needs: build-8
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-10:
needs: build-9
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-11:
needs: build-10
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-12:
needs: build-11
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-13:
needs: build-12
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-14:
needs: build-13
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-15:
needs: build-14
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
build-16:
needs: build-15
runs-on: windows-2022
steps:
- uses: actions/checkout@v7
with:
submodules: 'recursive'
- name: Prepare
uses: ./.github/actions/prepare
with:
python-version: ${{ inputs.python-version }}
- name: Run Stage
id: stage
uses: ./.github/actions/stage
with:
finished: ${{ join(needs.*.outputs.finished) }}
from_artifact: true
x86: ${{ inputs.x86 }}
arm: ${{ inputs.arm }}
outputs:
finished: ${{ steps.stage.outputs.finished }}
complete:
needs: build-16
runs-on: ubuntu-latest
steps:
- name: Ensure build finished
run: |
if [ "${{ needs.build-16.outputs.finished }}" != "true" ]; then
echo "Build did not finish after 16 stages."
exit 1
fi
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: reusable-build on: workflow_call: inputs: python-version: type: string required: false default: '3.12' x86: type: boolean required: false default: false arm: type: boolean required: false default: false jobs: build-1: timeout-minutes: 30 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: false from_artifact: false x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-2: timeout-minutes: 30 needs: build-1 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-3: timeout-minutes: 30 needs: build-2 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-4: timeout-minutes: 30 needs: build-3 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-5: timeout-minutes: 30 needs: build-4 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-6: timeout-minutes: 30 needs: build-5 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-7: timeout-minutes: 30 needs: build-6 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-8: timeout-minutes: 30 needs: build-7 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-9: timeout-minutes: 30 needs: build-8 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-10: timeout-minutes: 30 needs: build-9 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-11: timeout-minutes: 30 needs: build-10 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-12: timeout-minutes: 30 needs: build-11 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-13: timeout-minutes: 30 needs: build-12 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-14: timeout-minutes: 30 needs: build-13 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-15: timeout-minutes: 30 needs: build-14 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} build-16: timeout-minutes: 30 needs: build-15 runs-on: windows-2022 steps: - uses: actions/checkout@v7 with: submodules: 'recursive' - name: Prepare uses: ./.github/actions/prepare with: python-version: ${{ inputs.python-version }} - name: Run Stage id: stage uses: ./.github/actions/stage with: finished: ${{ join(needs.*.outputs.finished) }} from_artifact: true x86: ${{ inputs.x86 }} arm: ${{ inputs.arm }} outputs: finished: ${{ steps.stage.outputs.finished }} complete: timeout-minutes: 30 needs: build-16 runs-on: latchkey-small steps: - name: Ensure build finished run: | if [ "${{ needs.build-16.outputs.finished }}" != "true" ]; then echo "Build did not finish after 16 stages." exit 1 fi
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. - Add a job timeout so a hung step cannot burn hours of runner time.
This workflow runs 17 jobs per trigger. On Latchkey the same minutes cost up to 58% less than GitHub-hosted, with zero queue time.