Skip to content

Migrate CI from AppVeyor to GitHub Actions - #454

Merged
nefarius merged 5 commits into
masterfrom
new-gh-ci
Jul 27, 2026
Merged

Migrate CI from AppVeyor to GitHub Actions#454
nefarius merged 5 commits into
masterfrom
new-gh-ci

Conversation

@nefarius

@nefarius nefarius commented Jul 27, 2026

Copy link
Copy Markdown
Owner

Add a windows-2022 build workflow (x64/ARM64/x86 matrix) with vcpkg NuGet binary caching and a tag-triggered draft release job, replacing the self-hosted AppVeyor worker.

Decouple build/Build.cs from AppVeyor: DmfSolution always resolves to the DMF submodule, BuildDmf takes an explicit TargetPlatform parameter instead of reading AppVeyor.Instance, Compile/PublishControlApp stamp versions from the BUILD_VERSION env var, and DownloadAppVeyorArtifacts is replaced by DownloadCiArtifacts using gh run download.

appveyor.yml is intentionally left in place until a tagged GitHub Actions run has been verified against a same-commit AppVeyor build.

Summary by CodeRabbit

  • Build & Release
    • Migrated CI builds and draft release creation from AppVeyor to GitHub Actions.
    • Windows builds run on x64, ARM64, and x86 with per-platform version stamping, artifact publishing, and conditional signing.
    • Release drafts now download artifacts from the corresponding GitHub Actions run and publish the installer/executable asset set.
  • Documentation
    • Updated setup instructions and README badges to use GitHub CLI and GitHub Actions run IDs.
  • Build Configuration
    • Switched CI artifact-download inputs/behavior to GitHub Actions run-based artifacts; disabled package generation during CI builds.
  • Chores
    • Refreshed the build schema to reflect the new CI artifact target name and options.

Add a windows-2022 build workflow (x64/ARM64/x86 matrix) with vcpkg
NuGet binary caching and a tag-triggered draft release job, replacing
the self-hosted AppVeyor worker.

Decouple build/Build.cs from AppVeyor: DmfSolution always resolves to
the DMF submodule, BuildDmf takes an explicit TargetPlatform parameter
instead of reading AppVeyor.Instance, Compile/PublishControlApp stamp
versions from the BUILD_VERSION env var, and DownloadAppVeyorArtifacts
is replaced by DownloadCiArtifacts using gh run download.

appveyor.yml is intentionally left in place until a tagged GitHub
Actions run has been verified against a same-commit AppVeyor build.

Co-authored-by: Cursor <cursoragent@cursor.com>
@coderabbitai

coderabbitai Bot commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: fbb856e6-59b2-4175-8711-b461f99c3b85

📥 Commits

Reviewing files that changed from the base of the PR and between 908150f and 174a836.

📒 Files selected for processing (1)
  • build/Build.cs
🚧 Files skipped from review as they are similar to previous changes (1)
  • build/Build.cs

📝 Walkthrough

Walkthrough

Adds a GitHub Actions build and release workflow, updates NUKE build and artifact-download targets for GitHub Actions, stamps CI versions, disables CI package generation, and replaces AppVeyor references in schemas, documentation, and setup instructions.

Changes

CI migration

Layer / File(s) Summary
Build matrix and draft release
.github/workflows/build.yml, Directory.Build.props
Adds Windows builds for x64, ARM64, and x86, uploads platform artifacts, creates tag-triggered draft releases, and disables package generation during CI.
Platform and version integration
build/Build.cs
Adds GitHub Actions CI parameters, maps target platforms, skips 32-bit CI targets where required, and propagates BUILD_VERSION into managed project and ControlApp version metadata.
CI artifact download contract and repository updates
.nuke/build.schema.json, build/Build.cs, setup/README.md, README.md
Replaces AppVeyor artifact configuration and downloading with GitHub Actions run downloads, optional signing, updated release instructions, and GitHub Actions repository badges and attribution.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Developer
  participant GitHubActions
  participant BuildJob
  participant ArtifactStorage
  participant ReleaseJob
  Developer->>GitHubActions: Push, tag, pull request, or manual dispatch
  GitHubActions->>BuildJob: Run platform matrix
  BuildJob->>ArtifactStorage: Upload platform artifacts
  ReleaseJob->>ArtifactStorage: Download dshidmini artifacts
  ReleaseJob->>GitHubActions: Create draft release with CAB and EXE files
Loading

Possibly related PRs

  • nefarius/DsHidMini#420: Updates NUKE CI artifact-download wiring and replaces AppVeyor-oriented configuration with GitHub Actions-oriented configuration.

Poem

A bunny watches builds align,
x64 and ARM hop down the line.
CABs and EXEs lift in flight,
Draft releases glow bright.
GitHub guides each trail—
My ears applaud the CI tale!

🚥 Pre-merge checks | ✅ 4
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: moving CI from AppVeyor to GitHub Actions.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
build/Build.cs (1)

147-184: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Pass TargetPlatform into the solution rebuild Compile is invoked with --target-platform from the workflow, but its MSBuild call only sets Configuration. Since dshidmini.sln defines x64, ARM64, and x86 solution platforms, this can fall back to the solution default instead of rebuilding the requested architecture.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build/Build.cs` around lines 147 - 184, Update the Compile target’s
MSBuildSettings construction to pass the requested TargetPlatform alongside
Configuration when rebuilding the Solution. Use the existing TargetPlatform
value from the workflow so the solution selects the corresponding x64, ARM64, or
x86 platform instead of its default.
🧹 Nitpick comments (4)
build/Build.cs (3)

26-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

BuildVersion (run ID) and BuildVersionStamp (semantic version) share a confusingly similar name.

BuildVersion (Lines 29-30) is a GitHub Actions run ID consumed only by DownloadCiArtifacts, while BuildVersionStamp (Line 57) reads BUILD_VERSION and is an actual semantic version (e.g. 3.3.2015.0) used to stamp assemblies. A user could easily pass a version string to -buildversion expecting it to set the assembly version, or vice versa. Consider renaming the CLI parameter (e.g. RunId) to disambiguate.

Also applies to: 57-57

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build/Build.cs` around lines 26 - 36, Rename the CLI parameter field
BuildVersion used by DownloadCiArtifacts to an unambiguous run-ID name such as
RunId, and update all references, parameter metadata, and call sites
accordingly. Keep BuildVersionStamp unchanged as the semantic assembly version
sourced from BUILD_VERSION.

171-181: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated version-stamp property block.

The same four SetProperty calls (Version/AssemblyVersion/FileVersion/InformationalVersion) gated by !string.IsNullOrWhiteSpace(BuildVersionStamp) appear in both Compile and PublishControlApp. Extract a small helper (e.g. returning the property dictionary, or an extension method applying it to any settings builder) to avoid drift between the two call sites.

Also applies to: 209-217

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build/Build.cs` around lines 171 - 181, The version-stamp logic is duplicated
between Compile and PublishControlApp. Extract the shared BuildVersionStamp
validation and Version, AssemblyVersion, FileVersion, and InformationalVersion
assignments into a helper reusable by both methods, then replace both inline
blocks with that helper while preserving the existing behavior for blank stamps.

113-129: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Unrecognized TargetPlatform values silently default to x64.

Any value other than "ARM64"/"x86"/"Win32" (e.g. a typo like "X64x") silently falls through to MSBuildTargetPlatform.x64 instead of failing loudly, which could mask a CI misconfiguration.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@build/Build.cs` around lines 113 - 129, Update the TargetPlatform handling in
the build configuration flow to validate accepted values explicitly: allow ARM64
and x64, continue skipping x86/Win32, and throw an InvalidOperationException for
any other value instead of defaulting to MSBuildTargetPlatform.x64. Preserve
case-insensitive matching and the existing buildCombinations assignment for
valid platforms.
.github/workflows/build.yml (1)

24-30: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

vcpkg binary cache is writable from pull_request builds — cache-poisoning risk.

VCPKG_BINARY_SOURCES is readwrite and the job grants packages: write (Line 38) for every trigger, including pull_request (Lines 15-17). A malicious or compromised same-repo branch can push poisoned vcpkg binaries to the shared GitHub Packages feed, which trusted push/tag builds will then restore and trust. actions/cache@v4 (Line 79) is flagged for the same reason by static analysis.

Restrict write access to push/tag builds only, e.g. make the NuGet source mode conditional:

🔒 Suggested scoping
 env:
   BUILD_VERSION_OFFSET: 2000
   DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
   DOTNET_NOLOGO: 'true'
   SCPLIB_ENABLE_TELEMETRY: 'false'
-  VCPKG_BINARY_SOURCES: 'clear;nuget,https://nuget.pkg.github.com/nefarius/index.json,readwrite'
+  VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/nefarius/index.json,${{ github.event_name == 'pull_request' && 'read' || 'readwrite' }}"

Note permissions: itself doesn't support expressions, so packages: write will still be granted on PR runs; the env-level gate above is the practical mitigation.

Also applies to: 36-38, 78-84

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/build.yml around lines 24 - 30, Restrict vcpkg binary
cache writes to trusted push/tag builds by making VCPKG_BINARY_SOURCES use
read-only mode for pull_request runs and readwrite only for push or
tag-triggered runs. Update the workflow env configuration and the vcpkg cache
step using VCPKG_BINARY_SOURCES so PR builds cannot publish binaries, while
preserving read access and existing behavior for trusted builds.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yml:
- Around line 46-50: Update the actions/checkout@v4 step named “Checkout” to set
persist-credentials to false, while preserving the existing recursive submodule
and Git LFS options.
- Around line 138-149: Update the “Create draft release” step to pass
github.ref_name through a dedicated environment variable, then reference that
variable in the gh release create arguments for both the release identifier and
title. Remove direct github.ref_name interpolation from the run script while
preserving the existing repository, build-version, draft, notes, and artifact
arguments.

---

Outside diff comments:
In `@build/Build.cs`:
- Around line 147-184: Update the Compile target’s MSBuildSettings construction
to pass the requested TargetPlatform alongside Configuration when rebuilding the
Solution. Use the existing TargetPlatform value from the workflow so the
solution selects the corresponding x64, ARM64, or x86 platform instead of its
default.

---

Nitpick comments:
In @.github/workflows/build.yml:
- Around line 24-30: Restrict vcpkg binary cache writes to trusted push/tag
builds by making VCPKG_BINARY_SOURCES use read-only mode for pull_request runs
and readwrite only for push or tag-triggered runs. Update the workflow env
configuration and the vcpkg cache step using VCPKG_BINARY_SOURCES so PR builds
cannot publish binaries, while preserving read access and existing behavior for
trusted builds.

In `@build/Build.cs`:
- Around line 26-36: Rename the CLI parameter field BuildVersion used by
DownloadCiArtifacts to an unambiguous run-ID name such as RunId, and update all
references, parameter metadata, and call sites accordingly. Keep
BuildVersionStamp unchanged as the semantic assembly version sourced from
BUILD_VERSION.
- Around line 171-181: The version-stamp logic is duplicated between Compile and
PublishControlApp. Extract the shared BuildVersionStamp validation and Version,
AssemblyVersion, FileVersion, and InformationalVersion assignments into a helper
reusable by both methods, then replace both inline blocks with that helper while
preserving the existing behavior for blank stamps.
- Around line 113-129: Update the TargetPlatform handling in the build
configuration flow to validate accepted values explicitly: allow ARM64 and x64,
continue skipping x86/Win32, and throw an InvalidOperationException for any
other value instead of defaulting to MSBuildTargetPlatform.x64. Preserve
case-insensitive matching and the existing buildCombinations assignment for
valid platforms.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 22b5d15d-0cce-43a4-817a-7d191d6aedc7

📥 Commits

Reviewing files that changed from the base of the PR and between 5f5f111 and 3aa1f4a.

📒 Files selected for processing (5)
  • .github/workflows/build.yml
  • .nuke/build.schema.json
  • README.md
  • build/Build.cs
  • setup/README.md

Comment thread .github/workflows/build.yml
Comment thread .github/workflows/build.yml
msbuild /t:Rebuild over the whole solution does not implicitly restore
SDK-style csproj projects, so ipctest, the IPC SDK, and ControlApp
failed with NETSDK1004 (missing project.assets.json). Restore build.cmd
skips this since Restore only runs as a PublishControlApp dependency.
Add back the explicit dotnet restore calls that appveyor.yml used to
run in before_build.

Also stop using GITHUB_TOKEN for the vcpkg NuGet binary cache: personal
GitHub accounts cannot push new packages with it (only update existing
ones), so every push silently failed. Gate the cache on an optional
VCPKG_NUGET_TOKEN secret (a PAT with read/write:packages) instead,
falling back to no remote cache when it is not configured.

Co-authored-by: Cursor <cursoragent@cursor.com>

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/build.yml:
- Around line 69-83: Replace the direct secrets reference in the step’s if
condition with an output from a preceding step. Add a prior step that checks
whether VCPKG_NUGET_TOKEN is present and writes a boolean step output, then gate
the PowerShell token configuration step on that output while preserving its
existing environment and commands.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: b77756b4-af6f-4717-9c08-32bc1f9dcf74

📥 Commits

Reviewing files that changed from the base of the PR and between 3aa1f4a and 9db6ecb.

📒 Files selected for processing (1)
  • .github/workflows/build.yml

Comment thread .github/workflows/build.yml Outdated
nefarius and others added 3 commits July 27, 2026 23:37
GitHub Actions rejects `secrets.X` inside if: expressions outright
(Unrecognized named-value: secrets), only env: and with: can reference
them. Promote VCPKG_NUGET_TOKEN to a job-level env var and check
env.VCPKG_NUGET_TOKEN in the step condition instead.

Co-authored-by: Cursor <cursoragent@cursor.com>
- Set persist-credentials: false on checkout; nothing in this job needs
  to push back to the repo with the checkout-persisted token.
- Fix expression injection: route github.ref_name through an env var
  instead of interpolating it directly into the release gh CLI script.
- Skip GeneratePackageOnBuild in CI (Directory.Build.props): it triggers
  NuGet packing as a side effect of building every csproj, including
  Nefarius.DsHidMini.IPC (net8.0-windows), which hits a known NU1012
  packing bug for Windows-specific TFMs on the unpinned/newer .NET SDK
  this runner resolves. Nothing consumes the CI-built .nupkg; it is a
  local/dev convenience only.

Co-authored-by: Cursor <cursoragent@cursor.com>
…form

Compile never passed an explicit Platform to MSBuild. On AppVeyor this was
masked because its "platform:" matrix axis set a $env:PLATFORM variable that
MSBuild picked up implicitly; GitHub Actions has no such variable, so
MSBuild fell back to "Any CPU", which dshidmini.sln maps to a Release|x64
driver build on every leg (including x86), linking against a DMF x64 lib
that BuildDmf never produces for the x86 leg. Pass --target-platform through
to MSBuild explicitly so each leg builds the driver configuration the .sln
actually defines for it.

Co-authored-by: Cursor <cursoragent@cursor.com>
@nefarius
nefarius merged commit 3c9d142 into master Jul 27, 2026
5 of 6 checks passed
@nefarius
nefarius deleted the new-gh-ci branch July 27, 2026 22:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant