diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..be49daba
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,169 @@
+name: 'Build'
+
+on:
+ push:
+ branches:
+ - master
+ tags:
+ - 'v*'
+ paths-ignore:
+ - '**/*.md'
+ - '**/*.aip'
+ - '.vscode/**'
+ - '**/*.json'
+ - 'setup/**'
+ pull_request:
+ branches:
+ - master
+ workflow_dispatch:
+
+concurrency:
+ group: build-${{ github.ref }}
+ cancel-in-progress: ${{ github.ref_type != 'tag' }}
+
+env:
+ # Offset chosen to stay well above the last AppVeyor build counter (3.3.1251.0) at time of migration.
+ BUILD_VERSION_OFFSET: 2000
+ DOTNET_CLI_TELEMETRY_OPTOUT: 'true'
+ DOTNET_NOLOGO: 'true'
+ SCPLIB_ENABLE_TELEMETRY: 'false'
+ # Disabled by default; enabled per-job below only when the VCPKG_NUGET_TOKEN secret is present.
+ # GITHUB_TOKEN cannot push new packages under a personal-account GitHub Packages namespace, so a
+ # PAT with read:packages/write:packages is required. See:
+ # https://github.com/microsoft/vcpkg/issues/47470
+ VCPKG_BINARY_SOURCES: 'clear'
+
+jobs:
+ build:
+ name: 'Platform: ${{ matrix.platform }}'
+ runs-on: windows-2022
+ permissions:
+ contents: read
+ env:
+ # Secrets can't be referenced directly in `if:` conditions, only in `env:`/`with:`,
+ # so promote it here and check env.VCPKG_NUGET_TOKEN in the step below instead.
+ VCPKG_NUGET_TOKEN: ${{ secrets.VCPKG_NUGET_TOKEN }}
+ strategy:
+ fail-fast: false
+ matrix:
+ platform: [x64, ARM64, x86]
+ outputs:
+ build-version: ${{ steps.version.outputs.build-version }}
+ steps:
+ - name: 'Checkout'
+ uses: actions/checkout@v4
+ with:
+ submodules: recursive
+ lfs: true
+ persist-credentials: false
+
+ - name: 'Compute build version'
+ id: version
+ shell: pwsh
+ run: |
+ $buildVersion = "3.3.$([int]$env:BUILD_VERSION_OFFSET + ${{ github.run_number }}).0"
+ echo "BUILD_VERSION=$buildVersion" >> $env:GITHUB_ENV
+ echo "build-version=$buildVersion" >> $env:GITHUB_OUTPUT
+ Write-Output "Building version $buildVersion"
+
+ - name: 'Bootstrap vcpkg'
+ shell: cmd
+ run: .\XInputBridge\vcpkg\bootstrap-vcpkg.bat -disableMetrics
+
+ - name: 'Configure vcpkg NuGet binary cache'
+ if: ${{ env.VCPKG_NUGET_TOKEN != '' }}
+ shell: pwsh
+ run: |
+ $nugetExe = & .\XInputBridge\vcpkg\vcpkg.exe fetch nuget | Select-Object -Last 1
+ & $nugetExe sources add `
+ -Source "https://nuget.pkg.github.com/nefarius/index.json" `
+ -StorePasswordInClearText `
+ -Name "GitHubPackages" `
+ -UserName "nefarius" `
+ -Password "$env:VCPKG_NUGET_TOKEN"
+ & $nugetExe setapikey "$env:VCPKG_NUGET_TOKEN" `
+ -Source "https://nuget.pkg.github.com/nefarius/index.json"
+ echo "VCPKG_BINARY_SOURCES=clear;nuget,https://nuget.pkg.github.com/nefarius/index.json,readwrite" >> $env:GITHUB_ENV
+
+ - name: 'Cache NuGet packages'
+ uses: actions/cache@v4
+ with:
+ path: ~/.nuget/packages
+ key: nuget-${{ runner.os }}-${{ hashFiles('**/*.csproj', 'nuget.config') }}
+ restore-keys: |
+ nuget-${{ runner.os }}-
+
+ - name: 'Install vpatch'
+ run: dotnet tool install --global Nefarius.Tools.Vpatch
+
+ - name: 'Stamp version into driver and XInputBridge'
+ shell: cmd
+ run: |
+ vpatch --stamp-version "%BUILD_VERSION%" --target-file ".\driver\dshidmini.vcxproj" --vcxproj.inf-time-stamp
+ vpatch --stamp-version "%BUILD_VERSION%" --target-file ".\driver\dshidmini.rc" --resource.file-version --resource.product-version
+ vpatch --stamp-version "%BUILD_VERSION%" --target-file ".\XInputBridge\XInputBridge.rc" --resource.file-version --resource.product-version
+
+ - name: 'Restore managed projects'
+ # msbuild's /t:Rebuild over the whole solution does not implicitly restore SDK-style
+ # projects; these two dotnet restore calls also transitively restore the SDK project
+ # referenced by both. Mirrors appveyor.yml's former before_build steps.
+ shell: cmd
+ run: |
+ dotnet restore .\ControlApp\
+ dotnet restore .\ipctest\
+
+ - name: 'Build'
+ shell: cmd
+ run: .\build.cmd --target-platform ${{ matrix.platform }}
+
+ - name: 'Publish ControlApp'
+ if: matrix.platform == 'x64'
+ shell: cmd
+ run: .\build.cmd PublishControlApp --skip Compile
+
+ - name: 'Pack driver CAB'
+ if: matrix.platform != 'x86'
+ shell: cmd
+ run: makecab.exe /f .\DsHidMini_${{ matrix.platform }}.ddf
+
+ - name: 'Upload artifacts'
+ uses: actions/upload-artifact@v4
+ with:
+ name: dshidmini-${{ matrix.platform }}
+ if-no-files-found: error
+ path: |
+ disk1/*.cab
+ bin/**/dshidmini/*.inf
+ bin/**/dshidmini/*.cat
+ bin/**/dshidmini/*.dll
+ bin/**/*.pdb
+ bin/**/*.dll
+ bin/*.exe
+
+ release:
+ name: 'Draft release'
+ needs: build
+ if: github.ref_type == 'tag'
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ steps:
+ - name: 'Download artifacts'
+ uses: actions/download-artifact@v4
+ with:
+ path: artifacts
+ pattern: dshidmini-*
+
+ - name: 'Create draft release'
+ env:
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ REF_NAME: ${{ github.ref_name }}
+ run: |
+ gh release create "$REF_NAME" \
+ --repo "${{ github.repository }}" \
+ --title "$REF_NAME (build ${{ needs.build.outputs.build-version }})" \
+ --draft \
+ --generate-notes \
+ artifacts/dshidmini-x64/disk1/*.cab \
+ artifacts/dshidmini-ARM64/disk1/*.cab \
+ artifacts/dshidmini-x64/bin/*.exe
diff --git a/.nuke/build.schema.json b/.nuke/build.schema.json
index f9a2c48f..0a7bbaff 100644
--- a/.nuke/build.schema.json
+++ b/.nuke/build.schema.json
@@ -28,7 +28,7 @@
"BuildSetup",
"Clean",
"Compile",
- "DownloadAppVeyorArtifacts",
+ "DownloadCiArtifacts",
"PublishControlApp",
"Restore",
"SignProductionBinaries"
@@ -107,11 +107,11 @@
"properties": {
"ArtifactsPath": {
"type": "string",
- "description": "Output path for DownloadAppVeyorArtifacts artifacts. Default: ./artifacts"
+ "description": "Output path for DownloadCiArtifacts artifacts. Default: ./artifacts"
},
"BuildVersion": {
"type": "string",
- "description": "Build version or branch for DownloadAppVeyorArtifacts (AppVeyor artifact download)"
+ "description": "GitHub Actions run ID for DownloadCiArtifacts artifact download"
},
"Configuration": {
"type": "string",
@@ -123,7 +123,7 @@
},
"NoSigning": {
"type": "boolean",
- "description": "Skip signing in DownloadAppVeyorArtifacts"
+ "description": "Skip signing in DownloadCiArtifacts"
},
"SetupVersion": {
"type": "string",
@@ -137,9 +137,9 @@
"type": "string",
"description": "Path to a solution file that is automatically loaded"
},
- "Token": {
+ "TargetPlatform": {
"type": "string",
- "description": "AppVeyor API token for DownloadAppVeyorArtifacts artifact download"
+ "description": "Target platform for BuildDmf on CI (x64, ARM64 or x86). Not needed for local builds."
}
}
},
diff --git a/Directory.Build.props b/Directory.Build.props
index e899db2c..1fb2a48f 100644
--- a/Directory.Build.props
+++ b/Directory.Build.props
@@ -14,6 +14,9 @@
true
+
+ false
true
true
snupkg
diff --git a/README.md b/README.md
index 31bfe3a7..631a2e56 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@
#
DsHidMini
-[](https://ci.appveyor.com/project/nefarius/dshidmini/branch/master) [](https://somsubhra.github.io/github-release-stats/?username=nefarius&repository=DsHidMini)  [](https://discord.nefarius.at/) [](https://docs.nefarius.at/)
+[](https://github.com/nefarius/DsHidMini/actions/workflows/build.yml) [](https://somsubhra.github.io/github-release-stats/?username=nefarius&repository=DsHidMini)  [](https://discord.nefarius.at/) [](https://docs.nefarius.at/)
Virtual HID Mini user-mode driver for Sony DualShock 3 controllers on Windows 10/11.
@@ -84,4 +84,4 @@ Pre-built binaries and instructions: [releases](https://github.com/nefarius/DsHi
- **Related:** [ScpToolkit](https://github.com/nefarius/ScpToolkit), [FireShock](https://github.com/nefarius/FireShock), [AirBender](https://github.com/nefarius/AirBender), [WireShock](https://github.com/nefarius/WireShock), [EmuController](https://github.com/FirstPlatoLV/EmuController), [USB_Host_Shield_2.0 PS3 Info](https://github.com/felis/USB_Host_Shield_2.0/wiki/PS3-Information#USB)
- **Dependencies:** [DMF](https://github.com/microsoft/DMF), [cJSON](https://github.com/DaveGamble/cJSON), [HIDAPI](https://github.com/libusb/hidapi)
- **References:** [Eleccelerator DualShock 3](http://eleccelerator.com/wiki/index.php?title=DualShock_3), [HID Usage Tables](https://usb.org/sites/default/files/documents/hut1_12v2.pdf), [The HID Page](http://janaxelson.com/hidpage.htm), [CircumSpector/Research Sony DS3](https://github.com/CircumSpector/Research/tree/master/Sony%20DualShock%203), [linux hid-sony](https://github.com/torvalds/linux/blob/master/drivers/hid/hid-sony.c)
-- **DevOps:** [AppVeyor](https://www.appveyor.com/), [NUKE](https://nuke.build/)
+- **DevOps:** [GitHub Actions](https://github.com/features/actions), [NUKE](https://nuke.build/)
diff --git a/build/Build.cs b/build/Build.cs
index 242e5d49..1a3dc6c5 100644
--- a/build/Build.cs
+++ b/build/Build.cs
@@ -1,15 +1,11 @@
using System;
using System.Collections.Generic;
-using System.Diagnostics;
using System.IO;
using System.Linq;
-using System.Net.Http;
-using System.Text.Json;
using JetBrains.Annotations;
using Nuke.Common;
-using Nuke.Common.CI.AppVeyor;
using Nuke.Common.Execution;
using Nuke.Common.IO;
using Nuke.Common.ProjectModel;
@@ -27,16 +23,16 @@ class Build : NukeBuild
[Solution]
readonly Solution Solution;
- [Parameter("Build version or branch for DownloadAppVeyorArtifacts (AppVeyor artifact download)")]
- readonly string BuildVersion = "";
+ [Parameter("Target platform for BuildDmf on CI (x64, ARM64 or x86). Not needed for local builds.")]
+ readonly string TargetPlatform = "";
- [Parameter("AppVeyor API token for DownloadAppVeyorArtifacts artifact download")]
- readonly string Token = "";
+ [Parameter("GitHub Actions run ID for DownloadCiArtifacts artifact download")]
+ readonly string BuildVersion = "";
- [Parameter("Output path for DownloadAppVeyorArtifacts artifacts. Default: ./artifacts")]
+ [Parameter("Output path for DownloadCiArtifacts artifacts. Default: ./artifacts")]
readonly string ArtifactsPath = "./artifacts";
- [Parameter("Skip signing in DownloadAppVeyorArtifacts")]
+ [Parameter("Skip signing in DownloadCiArtifacts")]
readonly bool NoSigning;
[Parameter("Setup version for BuildSetup (e.g. 3.0.0)")]
@@ -48,16 +44,18 @@ class Build : NukeBuild
[NuGetPackage("Nefarius.Tools.WDKWhere", "wdkwhere.dll", Framework = "net8.0")]
readonly Tool WdkWhere;
- const string AppVeyorApiUrl = "https://ci.appveyor.com/api";
const string SignTimestampUrl = "http://timestamp.digicert.com";
const string SignCertName = "Nefarius Software Solutions e.U.";
- AbsolutePath DmfSolution => IsLocalBuild
- ? Solution.Directory / "DMF/Dmf.sln"
- : "C:/projects/DMF/Dmf.sln";
+ AbsolutePath DmfSolution => Solution.Directory / "DMF/Dmf.sln";
AbsolutePath ResolvedArtifactsPath => (AbsolutePath)Path.GetFullPath(Path.Combine(RootDirectory, ArtifactsPath));
+ ///
+ /// Version stamp propagated from CI (BUILD_VERSION env var, set from github.run_number). Empty for local builds.
+ ///
+ static string BuildVersionStamp => Environment.GetEnvironmentVariable("BUILD_VERSION");
+
///
/// Runs Microsoft's SignTool with the provided command-line arguments, using the explicit SignToolPath when available or delegating to the WdkWhere tool otherwise.
///
@@ -112,19 +110,22 @@ void InvokeSignTool(string arguments)
}
else
{
- string appVeyorPlatform = AppVeyor.Instance?.Platform;
- if (appVeyorPlatform == MSBuildTargetPlatform.x86 ||
- appVeyorPlatform == MSBuildTargetPlatform.Win32)
+ if (string.IsNullOrWhiteSpace(TargetPlatform))
+ {
+ throw new InvalidOperationException(
+ "TargetPlatform must be set on CI, e.g. --target-platform x64.");
+ }
+
+ if (string.Equals(TargetPlatform, "x86", StringComparison.OrdinalIgnoreCase) ||
+ string.Equals(TargetPlatform, "Win32", StringComparison.OrdinalIgnoreCase))
{
Log.Warning("DMF dropped 32-Bit support, skipping build");
return;
}
- MSBuildTargetPlatform platform = appVeyorPlatform switch
- {
- "ARM64" => "ARM64",
- _ => MSBuildTargetPlatform.x64
- };
+ MSBuildTargetPlatform platform = string.Equals(TargetPlatform, "ARM64", StringComparison.OrdinalIgnoreCase)
+ ? (MSBuildTargetPlatform)"ARM64"
+ : MSBuildTargetPlatform.x64;
buildCombinations = [(Configuration, platform)];
}
@@ -159,6 +160,22 @@ void InvokeSignTool(string arguments)
.SetNodeReuse(IsLocalBuild)
.SetVerbosity(MSBuildVerbosity.Minimal);
+ // On CI, MSBuild must be told the solution platform explicitly. AppVeyor's "platform:" matrix
+ // axis set a $env:PLATFORM variable that MSBuild picks up implicitly for the unset Platform
+ // property; GitHub Actions has no such variable, so without this MSBuild falls back to
+ // "Any CPU", which dshidmini.sln maps to a Release|x64 build of the driver project for every
+ // leg (including x86), pulling in a DMF x64 lib that BuildDmf never produced for that leg.
+ if (!IsLocalBuild)
+ {
+ if (string.IsNullOrWhiteSpace(TargetPlatform))
+ {
+ throw new InvalidOperationException(
+ "TargetPlatform must be set on CI, e.g. --target-platform x64.");
+ }
+
+ settings = settings.SetTargetPlatform((MSBuildTargetPlatform)TargetPlatform);
+ }
+
// Aggressively silence C# warnings for local Nuke builds (nullability, CS8981, XML docs, etc.)
if (IsLocalBuild)
{
@@ -167,6 +184,17 @@ void InvokeSignTool(string arguments)
settings = settings.SetProperty("NoWarn", noWarn.Replace(";", "%3B"));
}
+ // Stamps managed projects (ControlApp, SDK, ipctest, installer) with the CI build version,
+ // replacing AppVeyor's dotnet_csproj auto-patching. C++ projects ignore unknown properties.
+ if (!string.IsNullOrWhiteSpace(BuildVersionStamp))
+ {
+ settings = settings
+ .SetProperty("Version", BuildVersionStamp)
+ .SetProperty("AssemblyVersion", BuildVersionStamp)
+ .SetProperty("FileVersion", BuildVersionStamp)
+ .SetProperty("InformationalVersion", BuildVersionStamp);
+ }
+
return settings;
});
});
@@ -194,6 +222,15 @@ void InvokeSignTool(string arguments)
"CS0219;CS1587;CS1591;CS8600;CS8601;CS8602;CS8603;CS8604;CS8618;CS8619;CS8622;CS8625;CS8629;CS8765;CS8767;CS8981";
s = s.SetProperty("NoWarn", noWarn.Replace(";", "%3B"));
+ if (!string.IsNullOrWhiteSpace(BuildVersionStamp))
+ {
+ s = s
+ .SetProperty("Version", BuildVersionStamp)
+ .SetProperty("AssemblyVersion", BuildVersionStamp)
+ .SetProperty("FileVersion", BuildVersionStamp)
+ .SetProperty("InformationalVersion", BuildVersionStamp);
+ }
+
return s
.SetProject(controlAppProjectPath)
.SetConfiguration(Configuration.Release)
@@ -208,120 +245,43 @@ void InvokeSignTool(string arguments)
});
///
- /// Download AppVeyor build artifacts (ARM64, x64, x86) and optionally sign CABs, EXEs, and driver/XInput DLLs.
- /// Requires BuildVersion and Token. Use --NoSigning to skip signing.
+ /// Download GitHub Actions build artifacts (ARM64, x64, x86) for a tagged run and optionally sign CABs, EXEs,
+ /// and driver/XInput DLLs. Requires BuildVersion (a GitHub Actions run ID) and the "gh" CLI to be authenticated
+ /// (run "gh auth login" once). Use --NoSigning to skip signing.
///
[UsedImplicitly]
- public Target DownloadAppVeyorArtifacts => _ => _
+ public Target DownloadCiArtifacts => _ => _
.Executes(() =>
{
- if (string.IsNullOrWhiteSpace(BuildVersion) || string.IsNullOrWhiteSpace(Token))
+ if (string.IsNullOrWhiteSpace(BuildVersion))
{
- throw new InvalidOperationException("DownloadAppVeyorArtifacts requires BuildVersion and Token.");
+ throw new InvalidOperationException(
+ "DownloadCiArtifacts requires BuildVersion (a GitHub Actions run ID, see the \"Build\" workflow run URL).");
}
string artifactsDir = ResolvedArtifactsPath;
Directory.CreateDirectory(artifactsDir);
- using HttpClient http = new();
- http.DefaultRequestHeaders.Add("Authorization", "Bearer " + Token);
-
- string projectUri = $"{AppVeyorApiUrl}/projects/nefarius/DsHidMini/build/{Uri.EscapeDataString(BuildVersion)}";
- Log.Information("Fetching build info: {Uri}", projectUri);
- string json = http.GetStringAsync(projectUri).GetAwaiter().GetResult();
- using (JsonDocument buildDoc = JsonDocument.Parse(json))
- {
- JsonElement build = buildDoc.RootElement.GetProperty("build");
- JsonElement jobs = build.GetProperty("jobs");
-
- string[] jobNames = ["Platform: ARM64", "Platform: x64", "Platform: x86"];
- foreach (string jobName in jobNames)
- {
- string? jobId = null;
- foreach (JsonElement job in jobs.EnumerateArray())
- {
- if (job.GetProperty("name").GetString() != jobName)
- continue;
- JsonElement jobIdEl = job.GetProperty("jobId");
- jobId = jobIdEl.ValueKind == JsonValueKind.String
- ? jobIdEl.GetString()!
- : jobIdEl.GetInt32().ToString();
- break;
- }
-
- if (string.IsNullOrEmpty(jobId))
- {
- Log.Warning("Job not found: {JobName}", jobName);
- continue;
- }
-
- string artifactsListUri = $"{AppVeyorApiUrl}/buildjobs/{jobId}/artifacts";
- string listJson = http.GetStringAsync(artifactsListUri).GetAwaiter().GetResult();
- using JsonDocument listDoc = JsonDocument.Parse(listJson);
- string artifactsDirFull = Path.GetFullPath(artifactsDir);
- string artifactsDirRoot = artifactsDirFull.TrimEnd(Path.DirectorySeparatorChar);
-
- foreach (JsonElement artifact in listDoc.RootElement.EnumerateArray())
- {
- string fileName = artifact.GetProperty("fileName").GetString()!;
- string fileNameDecoded = Uri.UnescapeDataString(fileName);
- string fileNameNormalized = fileNameDecoded.Replace('/', Path.DirectorySeparatorChar);
- string candidatePath = Path.Combine(artifactsDirFull, fileNameNormalized);
- string fullPath = Path.GetFullPath(candidatePath);
-
- if (!fullPath.StartsWith(artifactsDirRoot + Path.DirectorySeparatorChar, StringComparison.Ordinal)
- && fullPath != artifactsDirRoot)
- {
- Log.Error("Path traversal blocked: artifact fileName \"{FileName}\" resolves outside {ArtifactsDir}",
- fileName, artifactsDirFull);
- continue;
- }
-
- string fileNameEncoded = Uri.EscapeDataString(fileName);
- string downloadUri =
- $"{AppVeyorApiUrl}/buildjobs/{jobId}/artifacts/{fileNameEncoded}";
- Directory.CreateDirectory(Path.GetDirectoryName(fullPath)!);
- byte[] bytes = http.GetByteArrayAsync(downloadUri).GetAwaiter().GetResult();
- File.WriteAllBytes(fullPath, bytes);
- Log.Information("Downloaded {File}", fullPath);
- }
- }
- }
+ ProcessTasks.StartProcess("gh",
+ $"run download {BuildVersion} --repo nefarius/DsHidMini --dir \"{artifactsDir}\" --pattern \"dshidmini-*\"")
+ .AssertZeroExitCode();
if (!NoSigning)
{
- string[] files =
- [
- Path.Combine(artifactsDir, "disk1", "*.cab"), Path.Combine(artifactsDir, "bin", "*.exe"),
- Path.Combine(artifactsDir, "bin", "ARM64", "dshidmini", "dshidmini.dll"),
- Path.Combine(artifactsDir, "bin", "x64", "dshidmini", "dshidmini.dll"),
- Path.Combine(artifactsDir, "bin", "x64", "XInput1_3.dll"),
- Path.Combine(artifactsDir, "bin", "ARM64", "XInput1_3.dll"),
- Path.Combine(artifactsDir, "bin", "x86", "XInput1_3.dll")
- ];
- List existingFiles = new();
- foreach (string pattern in files)
- {
- string dir = Path.GetDirectoryName(pattern)!;
- string search = Path.GetFileName(pattern);
- if (search.Contains('*'))
- {
- if (Directory.Exists(dir))
- {
- existingFiles.AddRange(Directory.GetFiles(dir, search));
- }
- }
- else if (File.Exists(pattern))
- {
- existingFiles.Add(pattern);
- }
- }
-
+ string[] patterns = ["*.cab", "*.exe", "dshidmini.dll", "XInput1_3.dll"];
+ List existingFiles = patterns
+ .SelectMany(pattern => Directory.GetFiles(artifactsDir, pattern, SearchOption.AllDirectories))
+ .ToList();
+
if (existingFiles.Count > 0)
{
InvokeSignTool(
$"sign /v /n \"{SignCertName}\" /tr {SignTimestampUrl} /fd sha256 /td sha256 {string.Join(" ", existingFiles.Select(f => $"\"{f}\""))}");
}
+ else
+ {
+ Log.Warning("No files found to sign under {ArtifactsDir}", artifactsDir);
+ }
}
Log.Information("Helper job names for sign portal:");
diff --git a/setup/README.md b/setup/README.md
index 53da81b5..d8798cb2 100644
--- a/setup/README.md
+++ b/setup/README.md
@@ -6,12 +6,13 @@ This project generates an MSI package containing x64 and ARM64 driver editions u
Commands/scripts are to be run from solution root directory.
-- Tag a release and let it build on CI
+- Tag a release and let it build on CI (the "Build" GitHub Actions workflow)
+- Authenticate the GitHub CLI once with `gh auth login` (needs `repo` scope)
- Use
```PowerShell
- nuke download-appveyor-artifacts -token $appVeyorToken -buildversion "3.3.1251.0"
+ nuke download-ci-artifacts -buildversion ""
```
- to download the tagged release
+ to download the tagged release (the run ID is the numeric ID in the workflow run URL)
- Submit the `*.cab` files to MS Partner Portal for signing
- Place the signed files in `.\artifacts\drivers` directory
- Run