Releases workflow (prometheus-community/windows_exporter)
The Releases workflow from prometheus-community/windows_exporter, 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 Releases workflow from the prometheus-community/windows_exporter 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: Releases
# Trigger on releases.
on:
push:
branches:
- master
pull_request:
workflow_dispatch:
release:
types:
- published
permissions:
contents: write
packages: write
env:
VERSION_PROMU: '0.17.0'
jobs:
build:
runs-on: windows-2025
environment: build
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: '0'
- uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0
with:
# renovate: golang=go
go-version: '1.26.4'
- name: Install WiX
run: |
dotnet tool install --global wix --version 5.0.2
- name: Install WiX extensions
run: |
wix extension add -g WixToolset.Util.wixext/5.0.2
wix extension add -g WixToolset.Ui.wixext/5.0.2
wix extension add -g WixToolset.Firewall.wixext/5.0.2
- name: Install Build deps
run: |
Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:VERSION_PROMU)/promu-$($Env:VERSION_PROMU).windows-amd64.zip -OutFile promu-$($Env:VERSION_PROMU).windows-amd64.zip
Expand-Archive -Path promu-$($Env:VERSION_PROMU).windows-amd64.zip -DestinationPath .
Copy-Item -Path promu-$($Env:VERSION_PROMU).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin"
# GOPATH\bin dir must be added to PATH else the `promu` commands won't be found
echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append
- name: Build
run: |
$ErrorActionPreference = "Stop"
$Version = git describe --tags --always
$Version = $Version -replace 'v', ''
# '+' symbols are invalid characters in image tags
$Version = $Version -replace '\+', '_'
$Version | Set-Content VERSION -PassThru
make build-all
# GH requires all files to have different names, so add version/arch to differentiate
foreach($Arch in "amd64", "arm64") {
Move-Item output\$Arch\windows_exporter.exe output\windows_exporter-$Version-$Arch.exe
}
Get-ChildItem -Path output
- name: Sign build artifacts
if: ${{ (github.event_name != 'pull_request' && github.repository == 'prometheus-community/windows_exporter') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'prometheus-community/windows_exporter') }}
run: |
$ErrorActionPreference = "Stop"
$Version = Get-Content VERSION
$b64 = $env:CODE_SIGN_KEY
$filename = 'windows_exporter_CodeSign.pfx'
$bytes = [Convert]::FromBase64String($b64)
[IO.File]::WriteAllBytes($filename, $bytes)
$basePath = "C:\Program Files (x86)\Windows Kits\10\bin"
$latestSigntool = Get-ChildItem -Path $basePath -Directory |
Where-Object { $_.Name -match "^\d+\.\d+\.\d+\.\d+$" } |
Sort-Object { [Version]$_.Name } -Descending |
Select-Object -First 1 |
ForEach-Object { Join-Path $_.FullName "x64\signtool.exe" }
if (Test-Path $latestSigntool) {
Write-Output $latestSigntool
} else {
Write-Output "signtool.exe not found"
}
foreach($Arch in "amd64", "arm64") {
& $latestSigntool sign /v /tr "http://timestamp.digicert.com" /d "Prometheus exporter for Windows machines" /td SHA256 /fd SHA256 /a /f "windows_exporter_CodeSign.pfx" /p $env:CODE_SIGN_PASSWORD "output\windows_exporter-$Version-$Arch.exe"
}
rm windows_exporter_CodeSign.pfx
env:
CODE_SIGN_KEY: ${{ secrets.CODE_SIGN_KEY }}
CODE_SIGN_PASSWORD: ${{ secrets.CODE_SIGN_PASSWORD }}
- name: Build Release Artifacts
run: |
$ErrorActionPreference = "Stop"
$Version = Get-Content VERSION
foreach($Arch in "amd64", "arm64") {
Write-Host "Building windows_exporter $Version msi for $Arch"
.\installer\build.ps1 -PathToExecutable .\output\windows_exporter-$Version-$Arch.exe -Version $Version -Arch "$Arch"
}
Move-Item installer\*.msi output\
Get-ChildItem -Path output\ g
- name: Sign installer artifacts
if: ${{ (github.event_name != 'pull_request' && github.repository == 'prometheus-community/windows_exporter') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'prometheus-community/windows_exporter') }}
run: |
$ErrorActionPreference = "Stop"
$Version = Get-Content VERSION
$b64 = $env:CODE_SIGN_KEY
$filename = 'windows_exporter_CodeSign.pfx'
$bytes = [Convert]::FromBase64String($b64)
[IO.File]::WriteAllBytes($filename, $bytes)
$basePath = "C:\Program Files (x86)\Windows Kits\10\bin"
$latestSigntool = Get-ChildItem -Path $basePath -Directory |
Where-Object { $_.Name -match "^\d+\.\d+\.\d+\.\d+$" } |
Sort-Object { [Version]$_.Name } -Descending |
Select-Object -First 1 |
ForEach-Object { Join-Path $_.FullName "x64\signtool.exe" }
if (Test-Path $latestSigntool) {
Write-Output $latestSigntool
} else {
Write-Output "signtool.exe not found"
}
foreach($Arch in "amd64", "arm64") {
& $latestSigntool sign /v /tr "http://timestamp.digicert.com" /d "Prometheus exporter for Windows machines" /td SHA256 /fd SHA256 /a /f "windows_exporter_CodeSign.pfx" /p $env:CODE_SIGN_PASSWORD "output\windows_exporter-$Version-$Arch.msi"
}
rm windows_exporter_CodeSign.pfx
env:
CODE_SIGN_KEY: ${{ secrets.CODE_SIGN_KEY }}
CODE_SIGN_PASSWORD: ${{ secrets.CODE_SIGN_PASSWORD }}
- name: Generate checksums
run: |
promu checksum output
cat output\sha256sums.txt
- name: Upload Artifacts
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: windows_exporter_binaries
path: |
output\windows_exporter-*.exe
output\windows_exporter-*.msi
- name: Release
if: startsWith(github.ref, 'refs/tags/')
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
$TagName = $env:GITHUB_REF -replace 'refs/tags/', ''
Get-ChildItem -Path output\* -Include @('windows_exporter*.msi', 'windows_exporter*.exe', 'sha256sums.txt') | Foreach-Object {gh release upload $TagName $_}
docker:
name: Build docker images
runs-on: ubuntu-latest
needs:
- build
env:
DOCKER_BUILD_SUMMARY: false
DOCKER_BUILD_RECORD_UPLOAD: false
steps:
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
with:
fetch-depth: '0'
- name: Download Artifacts
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
with:
name: windows_exporter_binaries
- name: Login to Docker Hub
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
username: ${{ secrets.DOCKER_HUB_LOGIN }}
password: ${{ secrets.DOCKER_HUB_PASSWORD }}
- name: Login to quay.io
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
registry: quay.io
username: ${{ secrets.QUAY_IO_LOGIN }}
password: ${{ secrets.QUAY_IO_PASSWORD }}
- name: Login to GitHub container registry
if: ${{ github.event_name != 'pull_request' }}
uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0
with:
registry: ghcr.io
username: ${{ github.repository_owner }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Docker meta
id: meta
uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0
with:
images: |
ghcr.io/prometheus-community/windows-exporter
docker.io/prometheuscommunity/windows-exporter
quay.io/prometheuscommunity/windows-exporter
tags: |
type=semver,pattern={{version}}
type=ref,event=branch
type=ref,event=pr
labels: |
org.opencontainers.image.title=windows_exporter
org.opencontainers.image.description=A Prometheus exporter for Windows machines.
org.opencontainers.image.vendor=The Prometheus Community
org.opencontainers.image.licenses=MIT
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0
- name: Build and push
uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0
with:
context: .
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
platforms: windows/amd64
annotations: ${{ steps.meta.outputs.labels }}
The same workflow, on Latchkey
Removes redundant runs and caps runaway jobs. Added and changed lines are highlighted.
name: Releases # Trigger on releases. on: push: branches: - master pull_request: workflow_dispatch: release: types: - published permissions: contents: write packages: write env: VERSION_PROMU: '0.17.0' concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: build: timeout-minutes: 30 runs-on: windows-2025 environment: build steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: '0' - uses: actions/setup-go@924ae3a1cded613372ab5595356fb5720e22ba16 # v6.5.0 with: # renovate: golang=go go-version: '1.26.4' - name: Install WiX run: | dotnet tool install --global wix --version 5.0.2 - name: Install WiX extensions run: | wix extension add -g WixToolset.Util.wixext/5.0.2 wix extension add -g WixToolset.Ui.wixext/5.0.2 wix extension add -g WixToolset.Firewall.wixext/5.0.2 - name: Install Build deps run: | Invoke-WebRequest -Uri https://github.com/prometheus/promu/releases/download/v$($Env:VERSION_PROMU)/promu-$($Env:VERSION_PROMU).windows-amd64.zip -OutFile promu-$($Env:VERSION_PROMU).windows-amd64.zip Expand-Archive -Path promu-$($Env:VERSION_PROMU).windows-amd64.zip -DestinationPath . Copy-Item -Path promu-$($Env:VERSION_PROMU).windows-amd64\promu.exe -Destination "$(go env GOPATH)\bin" # GOPATH\bin dir must be added to PATH else the `promu` commands won't be found echo "$(go env GOPATH)\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append - name: Build run: | $ErrorActionPreference = "Stop" $Version = git describe --tags --always $Version = $Version -replace 'v', '' # '+' symbols are invalid characters in image tags $Version = $Version -replace '\+', '_' $Version | Set-Content VERSION -PassThru make build-all # GH requires all files to have different names, so add version/arch to differentiate foreach($Arch in "amd64", "arm64") { Move-Item output\$Arch\windows_exporter.exe output\windows_exporter-$Version-$Arch.exe } Get-ChildItem -Path output - name: Sign build artifacts if: ${{ (github.event_name != 'pull_request' && github.repository == 'prometheus-community/windows_exporter') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'prometheus-community/windows_exporter') }} run: | $ErrorActionPreference = "Stop" $Version = Get-Content VERSION $b64 = $env:CODE_SIGN_KEY $filename = 'windows_exporter_CodeSign.pfx' $bytes = [Convert]::FromBase64String($b64) [IO.File]::WriteAllBytes($filename, $bytes) $basePath = "C:\Program Files (x86)\Windows Kits\10\bin" $latestSigntool = Get-ChildItem -Path $basePath -Directory | Where-Object { $_.Name -match "^\d+\.\d+\.\d+\.\d+$" } | Sort-Object { [Version]$_.Name } -Descending | Select-Object -First 1 | ForEach-Object { Join-Path $_.FullName "x64\signtool.exe" } if (Test-Path $latestSigntool) { Write-Output $latestSigntool } else { Write-Output "signtool.exe not found" } foreach($Arch in "amd64", "arm64") { & $latestSigntool sign /v /tr "http://timestamp.digicert.com" /d "Prometheus exporter for Windows machines" /td SHA256 /fd SHA256 /a /f "windows_exporter_CodeSign.pfx" /p $env:CODE_SIGN_PASSWORD "output\windows_exporter-$Version-$Arch.exe" } rm windows_exporter_CodeSign.pfx env: CODE_SIGN_KEY: ${{ secrets.CODE_SIGN_KEY }} CODE_SIGN_PASSWORD: ${{ secrets.CODE_SIGN_PASSWORD }} - name: Build Release Artifacts run: | $ErrorActionPreference = "Stop" $Version = Get-Content VERSION foreach($Arch in "amd64", "arm64") { Write-Host "Building windows_exporter $Version msi for $Arch" .\installer\build.ps1 -PathToExecutable .\output\windows_exporter-$Version-$Arch.exe -Version $Version -Arch "$Arch" } Move-Item installer\*.msi output\ Get-ChildItem -Path output\ g - name: Sign installer artifacts if: ${{ (github.event_name != 'pull_request' && github.repository == 'prometheus-community/windows_exporter') || (github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == 'prometheus-community/windows_exporter') }} run: | $ErrorActionPreference = "Stop" $Version = Get-Content VERSION $b64 = $env:CODE_SIGN_KEY $filename = 'windows_exporter_CodeSign.pfx' $bytes = [Convert]::FromBase64String($b64) [IO.File]::WriteAllBytes($filename, $bytes) $basePath = "C:\Program Files (x86)\Windows Kits\10\bin" $latestSigntool = Get-ChildItem -Path $basePath -Directory | Where-Object { $_.Name -match "^\d+\.\d+\.\d+\.\d+$" } | Sort-Object { [Version]$_.Name } -Descending | Select-Object -First 1 | ForEach-Object { Join-Path $_.FullName "x64\signtool.exe" } if (Test-Path $latestSigntool) { Write-Output $latestSigntool } else { Write-Output "signtool.exe not found" } foreach($Arch in "amd64", "arm64") { & $latestSigntool sign /v /tr "http://timestamp.digicert.com" /d "Prometheus exporter for Windows machines" /td SHA256 /fd SHA256 /a /f "windows_exporter_CodeSign.pfx" /p $env:CODE_SIGN_PASSWORD "output\windows_exporter-$Version-$Arch.msi" } rm windows_exporter_CodeSign.pfx env: CODE_SIGN_KEY: ${{ secrets.CODE_SIGN_KEY }} CODE_SIGN_PASSWORD: ${{ secrets.CODE_SIGN_PASSWORD }} - name: Generate checksums run: | promu checksum output cat output\sha256sums.txt - name: Upload Artifacts uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: windows_exporter_binaries path: | output\windows_exporter-*.exe output\windows_exporter-*.msi - name: Release if: startsWith(github.ref, 'refs/tags/') env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | $TagName = $env:GITHUB_REF -replace 'refs/tags/', '' Get-ChildItem -Path output\* -Include @('windows_exporter*.msi', 'windows_exporter*.exe', 'sha256sums.txt') | Foreach-Object {gh release upload $TagName $_} docker: timeout-minutes: 30 name: Build docker images runs-on: latchkey-small needs: - build env: DOCKER_BUILD_SUMMARY: false DOCKER_BUILD_RECORD_UPLOAD: false steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 with: fetch-depth: '0' - name: Download Artifacts uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: windows_exporter_binaries - name: Login to Docker Hub if: ${{ github.event_name != 'pull_request' }} uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: username: ${{ secrets.DOCKER_HUB_LOGIN }} password: ${{ secrets.DOCKER_HUB_PASSWORD }} - name: Login to quay.io if: ${{ github.event_name != 'pull_request' }} uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: registry: quay.io username: ${{ secrets.QUAY_IO_LOGIN }} password: ${{ secrets.QUAY_IO_PASSWORD }} - name: Login to GitHub container registry if: ${{ github.event_name != 'pull_request' }} uses: docker/login-action@af1e73f918a031802d376d3c8bbc3fe56130a9b0 # v4.4.0 with: registry: ghcr.io username: ${{ github.repository_owner }} password: ${{ secrets.GITHUB_TOKEN }} - name: Docker meta id: meta uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: | ghcr.io/prometheus-community/windows-exporter docker.io/prometheuscommunity/windows-exporter quay.io/prometheuscommunity/windows-exporter tags: | type=semver,pattern={{version}} type=ref,event=branch type=ref,event=pr labels: | org.opencontainers.image.title=windows_exporter org.opencontainers.image.description=A Prometheus exporter for Windows machines. org.opencontainers.image.vendor=The Prometheus Community org.opencontainers.image.licenses=MIT - name: Set up Docker Buildx uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4.2.0 - name: Build and push uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7.3.0 with: context: . push: ${{ github.event_name != 'pull_request' }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} platforms: windows/amd64 annotations: ${{ steps.meta.outputs.labels }}
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:
- 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.