From 74592086e6c1e9db47b35239d62d7733139d54c7 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Fri, 8 May 2026 22:42:16 -0700 Subject: [PATCH 01/10] Add complete release --- Inc/Keyboard.h | 4 +- Inc/Mouse.h | 4 +- build/completerelease.ps1 | 274 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+), 4 deletions(-) create mode 100644 build/completerelease.ps1 diff --git a/Inc/Keyboard.h b/Inc/Keyboard.h index f2e97ce6..55395bda 100644 --- a/Inc/Keyboard.h +++ b/Inc/Keyboard.h @@ -520,14 +520,14 @@ namespace DirectX #ifdef USING_COREWINDOW DIRECTX_TOOLKIT_API void __cdecl SetWindow(ABI::Windows::UI::Core::ICoreWindow* window); #ifdef __cplusplus_winrt - DIRECTX_TOOLKIT_API inline void __cdecl SetWindow(Windows::UI::Core::CoreWindow^ window) + inline void __cdecl SetWindow(Windows::UI::Core::CoreWindow^ window) { // See https://msdn.microsoft.com/en-us/library/hh755802.aspx SetWindow(reinterpret_cast(window)); } #endif #ifdef CPPWINRT_VERSION - DIRECTX_TOOLKIT_API inline void __cdecl SetWindow(winrt::Windows::UI::Core::CoreWindow window) + inline void __cdecl SetWindow(winrt::Windows::UI::Core::CoreWindow window) { // See https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi SetWindow(reinterpret_cast(winrt::get_abi(window))); diff --git a/Inc/Mouse.h b/Inc/Mouse.h index 97675cf8..5151c802 100644 --- a/Inc/Mouse.h +++ b/Inc/Mouse.h @@ -154,14 +154,14 @@ namespace DirectX #ifdef USING_COREWINDOW DIRECTX_TOOLKIT_API void __cdecl SetWindow(ABI::Windows::UI::Core::ICoreWindow* window); #ifdef __cplusplus_winrt - DIRECTX_TOOLKIT_API inline void __cdecl SetWindow(Windows::UI::Core::CoreWindow^ window) + inline void __cdecl SetWindow(Windows::UI::Core::CoreWindow^ window) { // See https://msdn.microsoft.com/en-us/library/hh755802.aspx SetWindow(reinterpret_cast(window)); } #endif #ifdef CPPWINRT_VERSION - DIRECTX_TOOLKIT_API inline void __cdecl SetWindow(winrt::Windows::UI::Core::CoreWindow window) + inline void __cdecl SetWindow(winrt::Windows::UI::Core::CoreWindow window) { // See https://docs.microsoft.com/en-us/windows/uwp/cpp-and-winrt-apis/interop-winrt-abi SetWindow(reinterpret_cast(winrt::get_abi(window))); diff --git a/build/completerelease.ps1 b/build/completerelease.ps1 new file mode 100644 index 00000000..aa804a73 --- /dev/null +++ b/build/completerelease.ps1 @@ -0,0 +1,274 @@ +<# + +.NOTES +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. + +.SYNOPSIS +Completes the release process by creating verified GitHub tags and a release. + +.DESCRIPTION +Creates GPG-signed annotated tags on both the DirectXTK12 repository and the +DirectXTK12 test suite repository (Tests/), then publishes a GitHub release on +the DirectXTK12 repository using the signed tag. + +Tags are signed locally with 'git tag -s', which requires GPG signing to be +configured in git and the signing key to be registered with GitHub. This +produces the Verified badge in the GitHub UI. + +Run this script after the release PR (prepared by preparerelease.ps1) has been +merged into the main branch. + +.PARAMETER PAT +GitHub Personal Access Token with 'repo' scope, used to publish the GitHub +release on microsoft/DirectXTK12. Can also be provided via the GITHUB_TOKEN +environment variable. If neither is provided, the script attempts to obtain a +token from the 'gh' CLI. + +.PARAMETER SkipTestRepo +If set, skips creating a tag on the test suite repository (Tests/). + +.PARAMETER WhatIf +Shows what would happen without creating tags, pushing, or publishing a release. + +.LINK +https://github.com/microsoft/DirectXTK12/wiki + +#> + +param( + [string]$PAT = "", + [switch]$SkipTestRepo, + [switch]$WhatIf +) + +$reporoot = Split-Path -Path $PSScriptRoot -Parent +$readme = Join-Path $reporoot "README.md" +$history = Join-Path $reporoot "CHANGELOG.md" +$testsroot = Join-Path $reporoot "Tests" + +#--- Validate script location --- + +if ((-Not (Test-Path $readme)) -Or (-Not (Test-Path $history))) { + Write-Error "ERROR: Unexpected location of script file!" -ErrorAction Stop +} + +#--- Validate local repo state --- + +$branch = git -C $reporoot branch --show-current +if ($branch -ne "main") { + Write-Error "ERROR: Must be on the 'main' branch (currently on '$branch')!" -ErrorAction Stop +} + +Write-Host "Fetching from origin..." +git -C $reporoot fetch -q origin +if ($LastExitCode -ne 0) { + Write-Error "ERROR: Failed to fetch from origin!" -ErrorAction Stop +} + +$headHash = git -C $reporoot rev-parse HEAD +$remoteHash = git -C $reporoot rev-parse "origin/main" +if ($headHash -ne $remoteHash) { + Write-Error "ERROR: Local 'main' is not in sync with origin. Run 'git pull' first." -ErrorAction Stop +} + +#--- Derive release info from README.md --- + +$rawreleasedate = $(Get-Content $readme) | Select-String -Pattern "^## [A-Z][a-z]+ \d+,?\s*\d{4}" | Select-Object -First 1 +if ([string]::IsNullOrEmpty($rawreleasedate)) { + Write-Error "ERROR: Failed to find a release date header in README.md!" -ErrorAction Stop +} + +$releasename = ($rawreleasedate.ToString() -replace '^## ', '').Trim() + +try { + $releaseDateTime = [datetime]::Parse($releasename) +} +catch { + Write-Error "ERROR: Failed to parse release date '$releasename': $_" -ErrorAction Stop +} + +$releasetag = (Get-Date -Date $releaseDateTime -Format "MMMyyyy").ToLower() + +Write-Host " Release Name: $releasename" +Write-Host " Release Tag: $releasetag" + +#--- Extract release notes from CHANGELOG.md --- + +$changelog = Get-Content $history +$notesStart = -1 +$notesEnd = $changelog.Count - 1 + +for ($i = 0; $i -lt $changelog.Count; $i++) { + if ($changelog[$i] -match "^### $([regex]::Escape($releasename))") { + $notesStart = $i + 1 + } + elseif ($notesStart -ge 0 -and $changelog[$i] -match "^### ") { + $notesEnd = $i - 1 + break + } +} + +if ($notesStart -lt 0) { + Write-Error "ERROR: Could not find release notes for '$releasename' in CHANGELOG.md!" -ErrorAction Stop +} + +$releaseNotes = (($changelog[$notesStart..$notesEnd] | Where-Object { $_ -ne "" }) -join "`n").Trim() + +Write-Host "Release Notes:" +Write-Host $releaseNotes +Write-Host "" + +#--- Acquire GitHub token --- + +if ($PAT.Length -eq 0) { + $PAT = [string]$env:GITHUB_TOKEN +} + +if ($PAT.Length -eq 0) { + try { + $ghToken = & gh auth token 2>$null + if ($LASTEXITCODE -eq 0 -and -not [string]::IsNullOrWhiteSpace($ghToken)) { + $PAT = $ghToken.Trim() + Write-Host "Using token from 'gh' CLI." + } + } + catch { + # gh CLI not available + } +} + +if ($PAT.Length -eq 0) { + Write-Error "ERROR: No GitHub token found. Provide -PAT, set GITHUB_TOKEN, or sign in with 'gh auth login'." -ErrorAction Stop +} + +$apiHeaders = @{ + "Accept" = "application/vnd.github+json" + "Authorization" = "Bearer $PAT" + "X-GitHub-Api-Version" = "2022-11-28" +} + +#--- Helper: create a GPG-signed tag locally and push it --- + +function Push-SignedTag { + param( + [Parameter(Mandatory)] [string]$RepoPath, + [Parameter(Mandatory)] [string]$TagName, + [Parameter(Mandatory)] [string]$Message + ) + + # Check whether the tag already exists locally + $existing = git -C $RepoPath tag -l $TagName + if (-not [string]::IsNullOrEmpty($existing)) { + Write-Error "ERROR: Tag '$TagName' already exists in '$RepoPath'!" -ErrorAction Stop + } + + if ($WhatIf) { + Write-Host "[WhatIf] Would create signed tag '$TagName' in '$RepoPath' and push to origin" + return + } + + Write-Host "Creating signed tag '$TagName'..." + git -C $RepoPath tag -s $TagName -m $Message + if ($LastExitCode -ne 0) { + Write-Error "ERROR: Failed to create signed tag '$TagName'. Ensure GPG signing is configured." -ErrorAction Stop + } + + Write-Host "Pushing tag '$TagName' to origin..." + git -C $RepoPath push origin $TagName + if ($LastExitCode -ne 0) { + git -C $RepoPath tag -d $TagName 2>$null + Write-Error "ERROR: Failed to push tag '$TagName' to origin." -ErrorAction Stop + } +} + +#--- Helper: create a GitHub release --- + +function New-GitHubRelease { + param( + [Parameter(Mandatory)] [string]$Owner, + [Parameter(Mandatory)] [string]$Repo, + [Parameter(Mandatory)] [string]$TagName, + [Parameter(Mandatory)] [string]$ReleaseName, + [Parameter(Mandatory)] [string]$ReleaseBody + ) + + # Check whether a release already exists for this tag + $checkUri = "https://api.github.com/repos/$Owner/$Repo/releases/tags/$TagName" + $releaseExists = $false + + try { + $null = Invoke-RestMethod -Uri $checkUri -Method Get -Headers $apiHeaders -ErrorAction Stop + $releaseExists = $true + } + catch { + $sc = $null + try { $sc = [int]$_.Exception.Response.StatusCode } catch { } + if ($sc -ne 404) { + Write-Error "ERROR: Failed to check for existing release '$TagName' on ${Owner}/${Repo}: $_" -ErrorAction Stop + } + # 404 = no release exists yet, which is expected + } + + if ($releaseExists) { + Write-Error "ERROR: Release '$TagName' already exists on ${Owner}/${Repo}!" -ErrorAction Stop + } + + if ($WhatIf) { + Write-Host "[WhatIf] Would create release '$TagName' on ${Owner}/${Repo}" + return + } + + $payload = @{ + tag_name = $TagName + name = $ReleaseName + body = $ReleaseBody + draft = $false + prerelease = $false + make_latest = "true" + } | ConvertTo-Json + + Write-Host "Creating release '$TagName' on ${Owner}/${Repo}..." + + try { + $result = Invoke-RestMethod -Uri "https://api.github.com/repos/$Owner/$Repo/releases" ` + -Method Post -Headers $apiHeaders -Body $payload -ContentType "application/json" -ErrorAction Stop + Write-Host " Created: $($result.html_url)" + } + catch { + Write-Error "ERROR: Failed to create release '$TagName' on ${Owner}/${Repo}: $_" -ErrorAction Stop + } +} + +#--- Create verified tag and release on microsoft/DirectXTK12 --- + +Push-SignedTag -RepoPath $reporoot -TagName $releasetag -Message $releasename + +New-GitHubRelease ` + -Owner "microsoft" ` + -Repo "DirectXTK12" ` + -TagName $releasetag ` + -ReleaseName $releasename ` + -ReleaseBody $releaseNotes + +#--- Create verified tag on walbourn/directxtk12test --- + +if (-Not $SkipTestRepo) { + if (-Not (Test-Path $testsroot)) { + Write-Warning "WARNING: Tests/ folder not found at '$testsroot'. Skipping test suite tag." + } + else { + Push-SignedTag -RepoPath $testsroot -TagName $releasetag -Message $releasename + } +} + +#--- Done --- + +if (-Not $WhatIf) { + Write-Host "" + Write-Host "Release complete. Sync the new tags locally with:" + Write-Host " git pull --tags" + if (-Not $SkipTestRepo) { + Write-Host " git -C Tests pull --tags" + } +} \ No newline at end of file From 5ab59ade70753aeebf8e1ff46dcbeb4927866b86 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sat, 9 May 2026 11:39:32 -0700 Subject: [PATCH 02/10] Update VCPKG script --- build/updatevcpkg.ps1 | 180 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 180 insertions(+) create mode 100644 build/updatevcpkg.ps1 diff --git a/build/updatevcpkg.ps1 b/build/updatevcpkg.ps1 new file mode 100644 index 00000000..c13c7f1d --- /dev/null +++ b/build/updatevcpkg.ps1 @@ -0,0 +1,180 @@ +<# + +.NOTES +Copyright (c) Microsoft Corporation. +Licensed under the MIT License. + +.SYNOPSIS +Updates the vcpkg port for DirectXTK12 to match a GitHub release. + +.DESCRIPTION +This script updates the vcpkg port at D:\vcpkg\ports\directxtk12 to match a specific +GitHub release by tag. It updates the version-date in vcpkg.json, the tag and SHA512 +hashes in portfile.cmake for the source archive, MakeSpriteFont.exe, xwbtool.exe, +and xwbtool_arm64.exe. + +.PARAMETER Tag +The GitHub release tag (e.g., 'may2026', 'mar2026'). Defaults to the latest tag. + +.LINK +https://github.com/microsoft/DirectXTK12/wiki + +#> + +param( + [string]$Tag = "" +) + +$repoRoot = Split-Path -Path $PSScriptRoot -Parent +$readme = Join-Path $repoRoot "README.md" +$portDir = "D:\vcpkg\ports\directxtk12" +$vcpkgJson = Join-Path $portDir "vcpkg.json" +$portfile = Join-Path $portDir "portfile.cmake" + +if (-Not (Test-Path $readme)) { + Write-Error "ERROR: Cannot find README.md at $readme" -ErrorAction Stop +} + +if ((-Not (Test-Path $vcpkgJson)) -Or (-Not (Test-Path $portfile))) { + Write-Error "ERROR: Cannot find vcpkg port files at $portDir" -ErrorAction Stop +} + +# Determine tag from latest git tag if not provided +if ($Tag.Length -eq 0) { + $Tag = (git --no-pager -C $repoRoot tag --sort=-creatordate | Select-Object -First 1).Trim() + if ($Tag.Length -eq 0) { + Write-Error "ERROR: Failed to determine latest tag!" -ErrorAction Stop + } +} + +Write-Host "Release Tag: $Tag" + +# Parse release date from README.md (format: "## Month Day, Year") +$rawReleaseDate = (Get-Content $readme) | Select-String -Pattern "^##\s+[A-Z][a-z]+\s+\d+,?\s+\d{4}" | Select-Object -First 1 +if ([string]::IsNullOrEmpty($rawReleaseDate)) { + Write-Error "ERROR: Failed to find release date in README.md!" -ErrorAction Stop +} + +$releaseDateStr = ($rawReleaseDate -replace '^##\s+', '').Trim() +$releaseDate = [datetime]::Parse($releaseDateStr, [System.Globalization.CultureInfo]::InvariantCulture) +$versionDate = $releaseDate.ToString("yyyy-MM-dd") + +Write-Host "Release Date: $releaseDateStr" +Write-Host "Version Date: $versionDate" + +# --- Update vcpkg.json --- +Write-Host "`nUpdating vcpkg.json..." + +$jsonContent = Get-Content $vcpkgJson -Raw +$jsonContent = $jsonContent -replace '"version-date":\s*"[^"]*"', "`"version-date`": `"$versionDate`"" +$jsonContent = $jsonContent -replace ',\s*"port-version":\s*\d+', '' +$jsonContent = $jsonContent -replace '"port-version":\s*\d+,?\s*', '' +Set-Content -Path $vcpkgJson -Value $jsonContent -NoNewline + +Write-Host " version-date set to $versionDate" + +# --- Update portfile.cmake tag --- +Write-Host "`nUpdating portfile.cmake tag..." + +$portContent = Get-Content $portfile -Raw +$portContent = $portContent -replace 'set\(DIRECTXTK_TAG\s+\S+\)', "set(DIRECTXTK_TAG $Tag)" +Set-Content -Path $portfile -Value $portContent -NoNewline + +Write-Host " Tag set to $Tag" + +# --- Download and hash source archive --- +$ProgressPreference = 'SilentlyContinue' +$tempDir = Join-Path $Env:Temp $(New-Guid) +New-Item -Type Directory -Path $tempDir | Out-Null + +$sourceUrl = "https://github.com/Microsoft/DirectXTK12/archive/refs/tags/$Tag.tar.gz" +$sourcePath = Join-Path $tempDir "$Tag.tar.gz" + +Write-Host "`nDownloading source archive from $sourceUrl..." +try { + Invoke-WebRequest -Uri $sourceUrl -OutFile $sourcePath -ErrorAction Stop +} +catch { + Write-Error "ERROR: Failed to download source archive!" -ErrorAction Stop +} + +$sourceHash = (Get-FileHash -Path $sourcePath -Algorithm SHA512).Hash.ToLower() +Write-Host " Source SHA512: $sourceHash" + +# Replace SHA512 in vcpkg_from_github block +$portContent = Get-Content $portfile -Raw +$portContent = $portContent -replace '(vcpkg_from_github\s*\([^)]*SHA512\s+)[0-9a-fA-F]+', "`${1}$sourceHash" +Set-Content -Path $portfile -Value $portContent -NoNewline + +# --- Download and hash MakeSpriteFont.exe --- +$makespriteFontUrl = "https://github.com/Microsoft/DirectXTK12/releases/download/$Tag/MakeSpriteFont.exe" +$makespriteFontPath = Join-Path $tempDir "MakeSpriteFont.exe" + +Write-Host "`nDownloading MakeSpriteFont.exe from $makespriteFontUrl..." +try { + Invoke-WebRequest -Uri $makespriteFontUrl -OutFile $makespriteFontPath -ErrorAction Stop +} +catch { + Write-Error "ERROR: Failed to download MakeSpriteFont.exe!" -ErrorAction Stop +} + +$makespriteFontHash = (Get-FileHash -Path $makespriteFontPath -Algorithm SHA512).Hash.ToLower() +Write-Host " MakeSpriteFont.exe SHA512: $makespriteFontHash" + +# --- Download and hash XWBTool.exe --- +$xwbtoolUrl = "https://github.com/Microsoft/DirectXTK12/releases/download/$Tag/XWBTool.exe" +$xwbtoolPath = Join-Path $tempDir "XWBTool.exe" + +Write-Host "`nDownloading XWBTool.exe from $xwbtoolUrl..." +try { + Invoke-WebRequest -Uri $xwbtoolUrl -OutFile $xwbtoolPath -ErrorAction Stop +} +catch { + Write-Error "ERROR: Failed to download XWBTool.exe!" -ErrorAction Stop +} + +$xwbtoolHash = (Get-FileHash -Path $xwbtoolPath -Algorithm SHA512).Hash.ToLower() +Write-Host " XWBTool.exe SHA512: $xwbtoolHash" + +# --- Download and hash XWBTool_arm64.exe --- +$xwbtoolArm64Url = "https://github.com/Microsoft/DirectXTK12/releases/download/$Tag/XWBTool_arm64.exe" +$xwbtoolArm64Path = Join-Path $tempDir "XWBTool_arm64.exe" + +Write-Host "`nDownloading XWBTool_arm64.exe from $xwbtoolArm64Url..." +try { + Invoke-WebRequest -Uri $xwbtoolArm64Url -OutFile $xwbtoolArm64Path -ErrorAction Stop +} +catch { + Write-Error "ERROR: Failed to download XWBTool_arm64.exe!" -ErrorAction Stop +} + +$xwbtoolArm64Hash = (Get-FileHash -Path $xwbtoolArm64Path -Algorithm SHA512).Hash.ToLower() +Write-Host " XWBTool_arm64.exe SHA512: $xwbtoolArm64Hash" + +# --- Replace SHA512 hashes for tool binaries in portfile --- +$portContent = Get-Content $portfile -Raw + +# Match the vcpkg_download_distfile block for MakeSpriteFont.exe +$portContent = $portContent -replace ` + '(vcpkg_download_distfile\s*\(\s*\n\s*MAKESPRITEFONT_EXE\s*\n\s*URLS\s+"[^"]*MakeSpriteFont\.exe"\s*\n\s*FILENAME\s+"[^"]*"\s*\n\s*SHA512\s+)[0-9a-fA-F]+', ` + "`${1}$makespriteFontHash" + +# Match the vcpkg_download_distfile block for XWBTool.exe (x64) +$portContent = $portContent -replace ` + '(vcpkg_download_distfile\s*\(\s*\n\s*XWBTOOL_EXE\s*\n\s*URLS\s+"[^"]*XWBTool\.exe"\s*\n\s*FILENAME\s+"[^"]*"\s*\n\s*SHA512\s+)[0-9a-fA-F]+', ` + "`${1}$xwbtoolHash" + +# Match the vcpkg_download_distfile block for XWBTool_arm64.exe +$portContent = $portContent -replace ` + '(vcpkg_download_distfile\s*\(\s*\n\s*XWBTOOL_EXE\s*\n\s*URLS\s+"[^"]*XWBTool_arm64\.exe"\s*\n\s*FILENAME\s+"[^"]*"\s*\n\s*SHA512\s+)[0-9a-fA-F]+', ` + "`${1}$xwbtoolArm64Hash" + +Set-Content -Path $portfile -Value $portContent -NoNewline + +# --- Cleanup --- +Remove-Item -Recurse -Force $tempDir + +Write-Host "`nvcpkg port updated successfully!" +Write-Host "`nUpdated files:" +Write-Host " $vcpkgJson" +Write-Host " $portfile" From cb75d075ee57c6e502228b17b35e85a4d9aa64b7 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sat, 9 May 2026 12:49:20 -0700 Subject: [PATCH 03/10] Code review --- build/updatevcpkg.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/updatevcpkg.ps1 b/build/updatevcpkg.ps1 index c13c7f1d..27eaeaed 100644 --- a/build/updatevcpkg.ps1 +++ b/build/updatevcpkg.ps1 @@ -178,3 +178,8 @@ Write-Host "`nvcpkg port updated successfully!" Write-Host "`nUpdated files:" Write-Host " $vcpkgJson" Write-Host " $portfile" + +$portContent = Get-Content $portfile -Raw +if ($portContent -match '\bPATCHES\b') { + Write-Warning "This port includes patches. Review them to either remove or update." +} From c129bb8132f4a35d5efda1d9dc6a2fb3ff9b49ac Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sat, 9 May 2026 21:56:29 -0700 Subject: [PATCH 04/10] Pick powershell lint --- .github/linters/.powershell-psscriptanalyzer.psd1 | 2 +- build/completerelease.ps1 | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/linters/.powershell-psscriptanalyzer.psd1 b/.github/linters/.powershell-psscriptanalyzer.psd1 index b7719936..27e65c80 100644 --- a/.github/linters/.powershell-psscriptanalyzer.psd1 +++ b/.github/linters/.powershell-psscriptanalyzer.psd1 @@ -1,5 +1,5 @@ # PSScriptAnalyzerSettings.psd1 @{ Severity=@('Error','Warning') - ExcludeRules=@('PSAvoidUsingWriteHost') + ExcludeRules=@('PSAvoidUsingWriteHost', 'PSUseShouldProcessForStateChangingFunctions') } diff --git a/build/completerelease.ps1 b/build/completerelease.ps1 index aa804a73..738617b9 100644 --- a/build/completerelease.ps1 +++ b/build/completerelease.ps1 @@ -36,6 +36,7 @@ https://github.com/microsoft/DirectXTK12/wiki #> +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '')] param( [string]$PAT = "", [switch]$SkipTestRepo, From d8d16a3afdafa0f165d8ded650e10ef84d2b645e Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sat, 9 May 2026 22:55:37 -0700 Subject: [PATCH 05/10] Add release checklist to copilot instructions --- .github/copilot-instructions.md | 40 ++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2f10e37c..2f67e8e7 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -17,17 +17,17 @@ These instructions define how GitHub Copilot should assist with this project. Th - You can make use of the nuget.org packages **directxtk12_desktop_win10** or **directxtk12_uwp**. - You can also use the library source code directly in your project or as a git submodule. -> If you are new to DirectX, you may want to start with [DirectX Tool Kit for DirectX 11](https://github.com/microsoft/DirectXTK/wiki/Getting-Started) to learn many important concepts for Direct3D programming, HLSL shaders, and the code patterns used in this project with a more 'noobie friendly' API. +> If you are new to DirectX, you may want to start with [DirectX Tool Kit for DirectX 11](https://github.com/microsoft/DirectXTK/wiki/Getting-Started) to learn many important concepts for Direct3D programming, HLSL shaders, and the code patterns used in this project with a more 'newbie friendly' API. ## General Guidelines - **Code Style**: The project uses an .editorconfig file to enforce coding standards. Follow the rules defined in `.editorconfig` for indentation, line endings, and other formatting. Additional information can be found on the wiki at [Implementation](https://github.com/microsoft/DirectXTK12/wiki/Implementation). The library's public API requires C++11, and the project builds with C++17 (`CMAKE_CXX_STANDARD 17`). This code is designed to build with Visual Studio 2022, Visual Studio 2026, clang for Windows v12 or later, or MinGW 12.2. > Notable `.editorconfig` rules: C/C++ and HLSL files use 4-space indentation, `crlf` line endings, and `latin1` charset — avoid non-ASCII characters in source files. HLSL files have separate indent/spacing rules defined in `.editorconfig`. - **Documentation**: The project provides documentation in the form of wiki pages available at [Documentation](https://github.com/microsoft/DirectXTK12/wiki/). The audio, input, and math implementations are identical to the DirectX Tool Kit for DirectX 11. -- **Error Handling**: Use C++ exceptions for error handling and uses RAII smart pointers to ensure resources are properly managed. For some functions that return HRESULT error codes, they are marked `noexcept`, use `std::nothrow` for memory allocation, and should not throw exceptions. +- **Error Handling**: Use C++ exceptions for error handling and use RAII smart pointers to ensure resources are properly managed. For some functions that return HRESULT error codes, they are marked `noexcept`, use `std::nothrow` for memory allocation, and should not throw exceptions. - **Testing**: Unit tests for this project are implemented in this repository [Test Suite](https://github.com/walbourn/directxtk12test/) and can be run using CTest per the instructions at [Test Documentation](https://github.com/walbourn/directxtk12test/wiki). See [test copilot instructions](https://github.com/walbourn/directxtk12test/blob/main/.github/copilot-instructions.md) for additional information on the tests. - **Security**: This project uses secure coding practices from the Microsoft Secure Coding Guidelines, and is subject to the `SECURITY.md` file in the root of the repository. Functions that read input from image files, geometry files, and audio files are subject to OneFuzz fuzz testing to ensure they are secure against malformed files. -- **Dependencies**: The project uses CMake and VCPKG for managing dependencies, making optional use of DirectXMath, DirectX-Headers, DirectX 12 Agility SDK, GameInput, and XAudio2Redist. The project can be built without these dependencies, relying on the Windows SDK for core functionality. CMake build options include `BUILD_GAMEINPUT`, `BUILD_WGI`, and `BUILD_XINPUT` for alternative input backends. Additional CMake build options include `BUILD_MIXED_DX11` for DX11 toolkit interop which removes shared code from the DX12 library as it will be present in the DX11 library to avoid link conflicts. +- **Dependencies**: The project uses CMake and VCPKG for managing dependencies, making optional use of DirectXMath, DirectX-Headers, DirectX 12 Agility SDK, GameInput, and XAudio2Redist. The project can be built without these dependencies, relying on the Windows SDK for core functionality. CMake build options include `BUILD_GAMEINPUT`, `BUILD_WGI`, and `BUILD_XINPUT` for alternative input backends. Additional CMake build options include `BUILD_MIXED_DX11` for DX11 toolkit interop which removes shared code from the DX12 library as it will be present in the DX11 library to avoid link conflicts. - **Continuous Integration**: This project implements GitHub Actions for continuous integration, ensuring that all code changes are tested and validated before merging. This includes building the project for a number of configurations and toolsets, running a subset of unit tests, and static code analysis including GitHub super-linter, CodeQL, and MSVC Code Analysis. - **Code of Conduct**: The project adheres to the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). All contributors are expected to follow this code of conduct in all interactions related to the project. @@ -60,7 +60,7 @@ wiki/ # Local clone of the GitHub wiki documentation repository. - Make use of `assert` for debugging checks, but be sure to validate input parameters in release builds. - Make use of the `DebugTrace` helper to log diagnostic messages, particularly at the point of throwing an exception. - Explicitly `= delete` copy constructors and copy-assignment operators on all classes that use the pImpl idiom. -- Explicitly utilize `= default` or `=delete` for copy constructors, assignment operators, move constructors and move-assignment operators where appropriate. +- Explicitly utilize `= default` or `= delete` for copy constructors, assignment operators, move constructors and move-assignment operators where appropriate. - Use 16-byte alignment (`_aligned_malloc` / `_aligned_free`) to support SIMD operations in the implementation, but do not expose this requirement in public APIs. - All implementation `.cpp` files include `pch.h` as their first include (precompiled header). MinGW builds skip precompiled headers. - `Model` and related classes require RTTI (`/GR` on MSVC, `__GXX_RTTI` on GCC/Clang). The CMake build enables `/GR` automatically; do not disable RTTI when using `Model`. @@ -206,8 +206,7 @@ Every source file (`.cpp`, `.h`, `.hlsl`, `.fx`, etc.) must begin with this bloc ``` Section separators within files use: -- Major sections: `//--------------------------------------------------------------------------------------` -- Subsections: `//--------------------------------------------------------------------------------------` +- `//--------------------------------------------------------------------------------------` The project does **not** use Doxygen. API documentation is maintained exclusively on the GitHub wiki. @@ -269,7 +268,7 @@ When creating documentation: - The code targets Win32 desktop applications for Windows 10 or later, Xbox One, Xbox Series X|S, and Universal Windows Platform (UWP) apps for Windows 10 and Windows 11. - Portability and conformance of the code is validated by building with Visual C++, clang/LLVM for Windows, and MinGW. - For PC development using the *Microsoft GDK*, the project provides MSBuild solution `DirectXTK_GDKW_2022.sln` for the x64 or ARM64 architectures. -- The MSBuild solution `DirectXTK_GDK_2022.sln` is for *Microsoft GDK with Xbox Extensions* development for both PC using the legacy Gaming.Desktop.x64 custom platform as well Xbox using Gaming.Xbox.*.x64 platforms. +- The MSBuild solution `DirectXTK_GDK_2022.sln` is for *Microsoft GDK with Xbox Extensions* development for both PC using the legacy Gaming.Desktop.x64 custom platform as well as Xbox using Gaming.Xbox.*.x64 platforms. - For Xbox development, the project provides MSBuild solution `DirectXTK_GDKX_2022.sln` or `DirectXTK_GDKX_2026.slnx` for the *Microsoft GDK with Xbox Extensions* using Gaming.Xbox.*.x64 platforms. - The project ships MSBuild projects for Visual Studio 2022 (`.sln` / `.vcxproj`) and Visual Studio 2026 (`.slnx` / `.vcxproj`). VS 2019 projects have been retired. - The CMake build supports Xbox Series X|S (`scarlett`) and Xbox One (`xboxone`) via the `XBOX_CONSOLE_TARGET` variable. @@ -302,7 +301,7 @@ Use these established guards — do not invent new ones: | `GAMEINPUT_API_VERSION` | GameInput SDK version detection for API-level feature checks | | `USING_PIX_CUSTOM_MEMORY_EVENTS` | PIX custom memory event integration in GraphicsMemory | -> `_M_ARM`/ `__arm__` is legacy 32-bit ARM which is deprecated. +> `_M_ARM` / `__arm__` is legacy 32-bit ARM which is deprecated. ## Code Review Instructions @@ -328,3 +327,28 @@ When reviewing documentation, do the following: - Review the public interface defined in the `Inc` folder. - Read the documentation on the wiki located in [this git repository](https://github.com/microsoft/DirectXTK12.wiki.git). - Report any specific gaps in the documentation compared to the public interface. + +## Release Process + +1. Ensure all changes are merged into the `main` branch and that all tests pass. +2. Git pull the local repository to ensure it is up to date with the `main` branch. +3. Run the PowerShell script `build\preparerelease.ps1` which will generate a topic branch for the release, update the version number in `CMakeLists.txt`, the `README.md` file, the release notes in the nuspec files, and create a stub in the `CHANGELOG.md` file for the new release. +4. Edit the `CHANGELOG.md` file to update it with a summary of changes. +5. Submit the topic branch for review and merge into `main` once approved. Allow the GitHub Actions workflows and the Azure DevOps pipelines to complete successfully before proceeding. +6. Run the PowerShell script `build\compilerelease.ps1` which will set a tag on the project repo and the test repo, and create a release on GitHub with the release notes from `CHANGELOG.md`. +> Ensure you have set up GPG signing for your GitHub account so that the tags will be verified. +7. Git pull the local repository to ensure it is up to date with the `main` branch. Be sure to include `--tags`. +8. Push the `main` branch to the MSCodeHub mirror repository. Be sure to include `--tags`. +9. Create a PR on MSCodeHub from the `main` branch to the `release` branch. +10. Merge the PR on MSCodeHub to update the release branch, which will trigger the Azure DevOps pipeline to build the NuGet packages. +11. Edit the GitHub release and upload the signed binaries from the matching DirectXTK release to the release assets. +12. Download the GitHub source .zip archive from the release. Unzip and compare to the local repo to ensure it matches — keep in mind there may be some CR/LF differences. Run minisign on the .zip to generate a signature file, and upload the signature file to the release assets. +13. Validate the NuGet packages with by pushing the NuGet packages to a local Packages Source folder, and refreshing the NuGet packages from that folder. Then build using BuildAllSolutions.targets. +14. Run the PowerShell script `build\promotenuget.ps1` with the `-Release` parameter to promote the version to the Release view on the project-scoped ADO feed. +15. Run the MSCodeHub pipeline to publish the NuGet packages to nuget.org. The pipeline will automatically push the most recent package promoted to the Release view to nuget.org. +16. Git pull a local repository of VCPKG to `d:\vcpkg` in sync with the `main` branch of the VCPKG repository. +17. Run the PowerShell script `build\updatevcpkg.ps1` to update the DirectXTK12 port in VCPKG with the new release version. This will edit the files in `ports\directxtk12`. +18. Test the VCPKG port using all appropriate triplets and features. +19. Run `.\vcpkg --x-add-version directxtk12` to update the VCPKG versioning history. +20. Submit a PR to the VCPKG repository to update the DirectXTK12 port back to the main GitHub repo. The PR will be reviewed and merged by the VCPKG maintainers. +21. Update the GitHub release with links to the matching NuGet packages, the VCPKG port, and the winget manifests for the tools. From b7ea9bae99474e123bd593b16c7aa9e73f2fa15f Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sat, 9 May 2026 23:43:52 -0700 Subject: [PATCH 06/10] Pick lint --- .github/copilot-instructions.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 2f67e8e7..08673424 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -335,8 +335,7 @@ When reviewing documentation, do the following: 3. Run the PowerShell script `build\preparerelease.ps1` which will generate a topic branch for the release, update the version number in `CMakeLists.txt`, the `README.md` file, the release notes in the nuspec files, and create a stub in the `CHANGELOG.md` file for the new release. 4. Edit the `CHANGELOG.md` file to update it with a summary of changes. 5. Submit the topic branch for review and merge into `main` once approved. Allow the GitHub Actions workflows and the Azure DevOps pipelines to complete successfully before proceeding. -6. Run the PowerShell script `build\compilerelease.ps1` which will set a tag on the project repo and the test repo, and create a release on GitHub with the release notes from `CHANGELOG.md`. -> Ensure you have set up GPG signing for your GitHub account so that the tags will be verified. +6. Run the PowerShell script `build\compilerelease.ps1` which will set a tag on the project repo and the test repo, and create a release on GitHub with the release notes from `CHANGELOG.md`. Ensure you have set up GPG signing for your GitHub account so that the tags will be verified. 7. Git pull the local repository to ensure it is up to date with the `main` branch. Be sure to include `--tags`. 8. Push the `main` branch to the MSCodeHub mirror repository. Be sure to include `--tags`. 9. Create a PR on MSCodeHub from the `main` branch to the `release` branch. From f8952ab231f50c1005a8bceb5b3696b2608ac905 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sat, 9 May 2026 23:49:55 -0700 Subject: [PATCH 07/10] Pick lint --- .github/copilot-instructions.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 08673424..bbec8218 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -350,4 +350,5 @@ When reviewing documentation, do the following: 18. Test the VCPKG port using all appropriate triplets and features. 19. Run `.\vcpkg --x-add-version directxtk12` to update the VCPKG versioning history. 20. Submit a PR to the VCPKG repository to update the DirectXTK12 port back to the main GitHub repo. The PR will be reviewed and merged by the VCPKG maintainers. -21. Update the GitHub release with links to the matching NuGet packages, the VCPKG port, and the winget manifests for the tools. + +> When fully completed, be sure to update the GitHub release with links to the matching NuGet packages, the VCPKG port, and the winget manifests for the tools. From 270ea95796197f54687d7e8d53939b5228c3ff93 Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sun, 10 May 2026 13:43:11 -0700 Subject: [PATCH 08/10] Fix typo --- .github/copilot-instructions.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index bbec8218..b12a2ff0 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -335,7 +335,7 @@ When reviewing documentation, do the following: 3. Run the PowerShell script `build\preparerelease.ps1` which will generate a topic branch for the release, update the version number in `CMakeLists.txt`, the `README.md` file, the release notes in the nuspec files, and create a stub in the `CHANGELOG.md` file for the new release. 4. Edit the `CHANGELOG.md` file to update it with a summary of changes. 5. Submit the topic branch for review and merge into `main` once approved. Allow the GitHub Actions workflows and the Azure DevOps pipelines to complete successfully before proceeding. -6. Run the PowerShell script `build\compilerelease.ps1` which will set a tag on the project repo and the test repo, and create a release on GitHub with the release notes from `CHANGELOG.md`. Ensure you have set up GPG signing for your GitHub account so that the tags will be verified. +6. Run the PowerShell script `build\completerelease.ps1` which will set a tag on the project repo and the test repo, and create a release on GitHub with the release notes from `CHANGELOG.md`. Ensure you have set up GPG signing for your GitHub account so that the tags will be verified. 7. Git pull the local repository to ensure it is up to date with the `main` branch. Be sure to include `--tags`. 8. Push the `main` branch to the MSCodeHub mirror repository. Be sure to include `--tags`. 9. Create a PR on MSCodeHub from the `main` branch to the `release` branch. From 7e4f89eb34f82cfe68eceab74b2aa541840f6c7a Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sun, 10 May 2026 13:55:29 -0700 Subject: [PATCH 09/10] COde review --- build/preparerelease.ps1 | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/build/preparerelease.ps1 b/build/preparerelease.ps1 index b4f32057..7ca5c8a6 100644 --- a/build/preparerelease.ps1 +++ b/build/preparerelease.ps1 @@ -24,6 +24,7 @@ https://github.com/microsoft/DirectXTK12/wiki #> +[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingEmptyCatchBlock', '')] param( [string]$BaseBranch = "main", [string]$TargetBranch = $null, @@ -31,27 +32,27 @@ param( ) $reporoot = Split-Path -Path $PSScriptRoot -Parent -$cmake = $reporoot + "\CMakeLists.txt" -$readme = $reporoot + "\README.md" -$history = $reporoot + "\CHANGELOG.md" +$cmake = Join-Path $reporoot "CMakeLists.txt" +$readme = Join-Path $reporoot "README.md" +$history = Join-Path $reporoot "CHANGELOG.md" if ((-Not (Test-Path $cmake)) -Or (-Not (Test-Path $readme)) -Or (-Not (Test-Path $history))) { Write-Error "ERROR: Unexpected location of script file!" -ErrorAction Stop } -$branch = git branch --show-current +$branch = git -C $reporoot branch --show-current if ($branch -ne $BaseBranch) { Write-Error "ERROR: Must be in the $BaseBranch branch!" -ErrorAction Stop } -git pull -q +git -C $reporoot pull -q if ($LastExitCode -ne 0) { Write-Error "ERROR: Failed to sync branch!" -ErrorAction Stop } $version = Get-Content ($cmake) | Select-String -Pattern "set\(DIRECTXTK12_VERSION" -CaseSensitive if (-Not ($version -match "([0-9]?\.[0-9]?\.[0-9]?)")) { - Write-Error "ERROR: Failed to current version!" -ErrorAction Stop + Write-Error "ERROR: Failed to find current version!" -ErrorAction Stop } $version = $Matches.0 $rawversion = $version.replace('.','') @@ -68,11 +69,11 @@ else { $newversion = $newrawversion[0] + "." + $newrawversion[1] + "." + $newrawversion[2] -$rawreleasedate = $(Get-Content $readme) | Select-String -Pattern "\#\#\s.[A-Z][a-z]+\S.\d+,?\S.\d\d\d\d" +$rawreleasedate = $(Get-Content $readme) | Select-String -Pattern "^## [A-Z][a-z]+ (?:\d+,?\s+)?\d{4}" | Select-Object -First 1 if ([string]::IsNullOrEmpty($rawreleasedate)) { - Write-Error "ERROR: Failed to current release date!" -ErrorAction Stop + Write-Error "ERROR: Failed to find current release date!" -ErrorAction Stop } -$releasedate = $rawreleasedate -replace '## ','' +$releasedate = ($rawreleasedate.ToString() -replace '^## ', '').Trim() if($releasedate -eq $newreleasedate) { Write-Error ("ERROR: Release "+$releasedate+" already exists!") -ErrorAction Stop @@ -83,7 +84,7 @@ if ($TargetBranch -ne 'none') { $TargetBranch = $newreleasetag + "release" } - git checkout -b $TargetBranch + git -C $reporoot checkout -b $TargetBranch if ($LastExitCode -ne 0) { Write-Error "ERROR: Failed to create new topic branch!" -ErrorAction Stop } @@ -100,9 +101,9 @@ if($UpdateVersion) { (Get-Content $cmake).Replace("set(DIRECTXTK12_VERSION $version)","set(DIRECTXTK12_VERSION $newversion)") | Set-Content $cmake } -(Get-Content $readme).Replace("$rawreleasedate", "## $newreleasedate") | Set-Content $readme +(Get-Content $readme).Replace("## $releasedate", "## $newreleasedate") | Set-Content $readme -Get-ChildItem -Path ($reporoot + "\.nuget") -Filter *.nuspec | Foreach-Object { +Get-ChildItem -Path (Join-Path $reporoot ".nuget") -Filter *.nuspec | Foreach-Object { (Get-Content -Path $_.Fullname).Replace("$releasedate", "$newreleasedate") | Set-Content -Path $_.Fullname -Encoding utf8 } From 584b4c73074700f48be37f6a9ac05ef227dcb45c Mon Sep 17 00:00:00 2001 From: Chuck Walbourn Date: Sun, 10 May 2026 14:00:13 -0700 Subject: [PATCH 10/10] COde review --- build/promotenuget.ps1 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/build/promotenuget.ps1 b/build/promotenuget.ps1 index c844be36..36c5f996 100644 --- a/build/promotenuget.ps1 +++ b/build/promotenuget.ps1 @@ -74,7 +74,7 @@ foreach ($package in $packages) { try { Write-Host "Checking if $package version $Version exists..." - Invoke-RestMethod -Uri $uri -Method Get -Headers $headers + $null = Invoke-RestMethod -Uri $uri -Method Get -Headers $headers } catch { @@ -87,19 +87,19 @@ if (-not $allPackagesSucceeded) { Write-Error "##[error]Not all packages found. Aborting promotion." -ErrorAction Stop } -# Promote package to Prerelease view +# Promote packages to Prerelease view +$allPackagesSucceeded = $true foreach ($package in $packages) { $uri = $uriFormat -f $package, $Version try { - # Promote to Prerelease view Write-Host "Promoting $package version $Version to Prerelease view..." - Invoke-RestMethod -Uri $uri -Method Patch -Headers $headers -Body $bodyPrerelease + $null = Invoke-RestMethod -Uri $uri -Method Patch -Headers $headers -Body $bodyPrerelease } catch { - Write-Error "##[error]Package $package version $Version failed to promote" -ErrorAction Continue + Write-Error "##[error]Package $package version $Version failed to promote to Prerelease!" -ErrorAction Continue $allPackagesSucceeded = $false } } @@ -108,20 +108,20 @@ if (-not $allPackagesSucceeded) { Write-Error "##[error]Not all packages promoted to Prerelease." -ErrorAction Stop } -# Optionally promote package to Release view +# Optionally promote packages to Release view if ($Release.IsPresent) { + $allPackagesSucceeded = $true foreach ($package in $packages) { $uri = $uriFormat -f $package, $Version try { - # Promote to Release view Write-Host "Promoting $package version $Version to Release view..." - Invoke-RestMethod -Uri $uri -Method Patch -Headers $headers -Body $bodyRelease + $null = Invoke-RestMethod -Uri $uri -Method Patch -Headers $headers -Body $bodyRelease } catch { - Write-Error "##[error]Package $package version $Version failed to promote" -ErrorAction Continue + Write-Error "##[error]Package $package version $Version failed to promote to Release!" -ErrorAction Continue $allPackagesSucceeded = $false } }