Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion .github/workflows/build-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,13 @@ on:

jobs:
build:
runs-on: windows-latest
# Pinned, not windows-latest. windows-latest now provisions
# windows-2025-vs2026, and WinDevices.dll links the dynamic CRT
# (MSVCP140 / VCRUNTIME140), so a binary built with a newer toolset
# requires a redistributable at least as new on the target machine.
# Every other component in this program builds on VS 2022, so the
# native library is built on VS 2022 here too.
runs-on: windows-2022
strategy:
matrix:
config: [Debug, Release]
Expand Down
17 changes: 12 additions & 5 deletions .github/workflows/increment-version.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,10 @@ jobs:

build-and-release:
needs: increment-version
runs-on: windows-latest
# Pinned to VS 2022: this job runs install.cmd and ships the resulting
# binaries as release assets, so it must use the same toolset as the
# rest of the program rather than whatever windows-latest points at.
runs-on: windows-2022
permissions:
contents: write
actions: read
Expand All @@ -225,10 +228,14 @@ jobs:
fetch-depth: 0
fetch-tags: true

- name: Setup CMake
uses: jwlawson/actions-setup-cmake@v1.14
with:
cmake-version: '3.29'
# Use the CMake preinstalled on the runner image rather than pinning a
# version. windows-latest moved to windows-2025-vs2026, and a CMake
# older than the image's Visual Studio cannot name its generator: it
# silently falls back to NMake Makefiles, and install.cmd then fails
# with "CMAKE_CXX_COMPILER not set". Same fix as build-test.yaml.
- name: Report CMake version
shell: cmd
run: cmake --version

- name: Build and Install Debug
shell: cmd
Expand Down
60 changes: 56 additions & 4 deletions .github/workflows/publish-nuget.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,21 @@ on:
push:
tags:
- 'v*'

# Version Increment pushes its tag using GITHUB_TOKEN, and events created
# with that token deliberately do not start other workflows, so the tag
# push above never fires for an automated release. workflow_run is not a
# token-created event: it fires when the other workflow finishes, so the
# release path reaches here without a stored PAT.
#
# Kept as a trigger on this file rather than a reusable workflow called
# from Version Increment, because the Trusted Publisher policy is bound to
# this workflow's file name.
workflow_run:
workflows: ["Version Increment"]
types:
- completed

workflow_dispatch:
inputs:
version:
Expand All @@ -23,7 +38,16 @@ on:

jobs:
pack:
runs-on: windows-latest
# Pinned to VS 2022 deliberately. The native library shipped inside the
# package links the dynamic CRT, so its toolset sets the minimum
# Visual C++ Redistributable every consumer's machine must carry.
# windows-latest is now windows-2025-vs2026, which would silently raise
# that floor for every downstream deployment.
runs-on: windows-2022

# workflow_run fires whatever the outcome of the run that triggered it,
# so a failed Version Increment must not reach the publisher.
if: github.event_name != 'workflow_run' || github.event.workflow_run.conclusion == 'success'

permissions:
contents: read
Expand All @@ -36,11 +60,39 @@ jobs:
- name: Checkout source code
uses: actions/checkout@v4
with:
# Deliberately no `ref:`. A workflow_run job is privileged — it
# holds id-token: write and can mint a nuget.org publishing token —
# and this job then builds what it checks out. Checking out
# workflow_run.head_sha would run code from a commit this workflow
# did not choose, in that privileged context: the pattern CodeQL
# flags as actions/untrusted-checkout, and a real escalation path
# to publishing a package.
#
# The default checkout gives the default branch, which is trusted.
# Version Increment tags a commit on that branch, so the tag is
# present. If the branch has moved past the tag in between, the
# exact-tag guard below refuses to publish rather than releasing a
# mislabelled package, which is the correct failure.
#
# Version is derived from the Git tag, so the full history and all
# tags must be present.
fetch-depth: 0
fetch-tags: true

# One place decides whether this run publishes, so the three steps
# below cannot drift apart. A tag push and a completed Version
# Increment both publish; a manual dispatch publishes only when asked.
- name: Decide whether to publish
id: gate
shell: pwsh
run: |
$publish =
'${{ github.event_name }}' -eq 'workflow_run' -or
'${{ github.ref }}'.StartsWith('refs/tags/v') -or
'${{ inputs.publish }}' -eq 'true'
Write-Host "event=${{ github.event_name }} ref=${{ github.ref }} publish=$publish"
"publish=$($publish.ToString().ToLower())" | Out-File $env:GITHUB_OUTPUT -Append

# The version is derived with `git describe --tags --abbrev=0`, which
# returns the nearest *ancestor* tag. On a branch that has moved past
# its last tag that silently produces a package claiming a version its
Expand All @@ -50,7 +102,7 @@ jobs:
# This is not hypothetical: 0.1.1 was published from a main that was
# six commits ahead of the v0.1.1 tag.
- name: Require HEAD to be exactly at a tag
if: (startsWith(github.ref, 'refs/tags/v') || inputs.publish) && inputs.version == ''
if: steps.gate.outputs.publish == 'true' && inputs.version == ''
shell: pwsh
run: |
$tag = git describe --exact-match --tags HEAD 2>$null
Expand Down Expand Up @@ -136,14 +188,14 @@ explicit version input to publish deliberately.
# against owner TorinKS, repository WinDeviceslib and workflow file
# publish-nuget.yaml. Renaming this file invalidates that policy.
- name: NuGet login (Trusted Publishing)
if: startsWith(github.ref, 'refs/tags/v') || inputs.publish
if: steps.gate.outputs.publish == 'true'
id: nuget_login
uses: NuGet/login@v1
with:
user: ${{ vars.NUGET_USER }}

- name: Push to nuget.org
if: startsWith(github.ref, 'refs/tags/v') || inputs.publish
if: steps.gate.outputs.publish == 'true'
shell: pwsh
env:
TEMP_NUGET_KEY: ${{ steps.nuget_login.outputs.NUGET_API_KEY }}
Expand Down
Loading