diff --git a/dev/Templates/Dotnet/Test-DotnetNewTemplates.ps1 b/dev/Templates/Dotnet/Test-DotnetNewTemplates.ps1 index e9c02679a9..2be6926f3f 100644 --- a/dev/Templates/Dotnet/Test-DotnetNewTemplates.ps1 +++ b/dev/Templates/Dotnet/Test-DotnetNewTemplates.ps1 @@ -453,31 +453,95 @@ function Get-LatestOfficialWasdkVersion { $sourceFeed = 'https://microsoft.pkgs.visualstudio.com/ProjectReunion/_packaging/Project.Reunion.nuget.internal/nuget/v3/flat2/microsoft.windowsappsdk/index.json' $excludedVersionPrefixes = @('2.63.') $token = $env:SYSTEM_ACCESSTOKEN - if ([string]::IsNullOrWhiteSpace($token)) { - Write-Warning "SYSTEM_ACCESSTOKEN is not set; cannot query the package source for versions." - return $null - } try { - [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 - $response = Invoke-RestMethod -Uri $sourceFeed -Headers @{ Authorization = "Bearer $token" } -TimeoutSec 30 -ErrorAction Stop - $latest = $null - foreach ($v in $response.versions) { - if ($v -match '-') { continue } # skip prerelease - $excluded = $false - foreach ($p in $excludedVersionPrefixes) { if ($v.StartsWith($p)) { $excluded = $true; break } } - if ($excluded) { continue } - $parsed = $null - if (-not [version]::TryParse($v, [ref]$parsed)) { continue } - if (($null -eq $latest) -or ($parsed -gt $latest.Ver)) { - $latest = [pscustomobject]@{ Raw = $v; Ver = $parsed } + # SYSTEM_ACCESSTOKEN is a pipeline variable. Use nuget CLI when running outside of pipeline runs + if ([string]::IsNullOrWhiteSpace($token)) { + Write-Warning "SYSTEM_ACCESSTOKEN is not set; cannot query package source for latest official Microsoft.WindowsAppSDK version. Using NuGet CLI instead" + $packageId = 'Microsoft.WindowsAppSDK' + $sourceFeed = 'https://microsoft.pkgs.visualstudio.com/ProjectReunion/_packaging/Project.Reunion.nuget.internal/nuget/v3/index.json' + $json = & dotnet package search $packageId ` + --source $sourceFeed ` + --exact-match ` + --format json ` + --verbosity quiet + + if ($LASTEXITCODE -ne 0) { + throw "dotnet package search failed with exit code $LASTEXITCODE." } - } - if ($latest) { - Write-Host "Latest official Microsoft.WindowsAppSDK = $($latest.Raw) (excluded prerelease and $($excludedVersionPrefixes -join ', ')*)" + + $response = $json | ConvertFrom-Json + + $problems = @() + + if ($response.PSObject.Properties['problems']) { + $problems += @($response.problems) + } + + foreach ($result in @($response.searchResult)) { + if ($result.PSObject.Properties['problems']) { + $problems += @($result.problems) + } + } + + if ($problems.Count -gt 0) { + throw ($problems | ForEach-Object { $_.text } | Join-String -Separator "`n") + } + + $versions = foreach ($result in @($response.searchResult)) { + foreach ($package in @($result.packages)) { + if ($package.id -ine $packageId) { + continue + } + + if ($package.PSObject.Properties['version']) { + $package.version + } + elseif ($package.PSObject.Properties['latestVersion']) { + $package.latestVersion + } + } + } + $latest = $versions | + Where-Object { + $version = $_ + -not ($excludedVersionPrefixes | Where-Object { + $version.StartsWith($_) + }) + } | + ForEach-Object { + [pscustomobject]@{ + Raw = $_ + Ver = [version]$_ + } + } | + Sort-Object Ver -Descending | + Select-Object -First 1 + return $latest.Raw } - Write-Warning "No official Microsoft.WindowsAppSDK version found on the package source." - return $null + else + { + [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 + $response = Invoke-RestMethod -Uri $sourceFeed -Headers @{ Authorization = "Bearer $token" } -TimeoutSec 30 -ErrorAction Stop + $latest = $null + foreach ($v in $response.versions) { + if ($v -match '-') { continue } # skip prerelease + $excluded = $false + foreach ($p in $excludedVersionPrefixes) { if ($v.StartsWith($p)) { $excluded = $true; break } } + if ($excluded) { continue } + $parsed = $null + if (-not [version]::TryParse($v, [ref]$parsed)) { continue } + if (($null -eq $latest) -or ($parsed -gt $latest.Ver)) { + $latest = [pscustomobject]@{ Raw = $v; Ver = $parsed } + } + } + if ($latest) { + Write-Host "Latest official Microsoft.WindowsAppSDK = $($latest.Raw) (excluded prerelease and $($excludedVersionPrefixes -join ', ')*)" + return $latest.Raw + } + Write-Warning "No official Microsoft.WindowsAppSDK version found on the package source." + return $null + } } catch { Write-Warning "Failed to query the package source for versions: $($_.Exception.Message)" diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/BlankApp/ProjectTemplate.csproj b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/BlankApp/ProjectTemplate.csproj index 335a7f49ba..121711f2cd 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/BlankApp/ProjectTemplate.csproj +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/BlankApp/ProjectTemplate.csproj @@ -21,9 +21,9 @@ - - - + + + diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WapProjTemplate.wapproj b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WapProjTemplate.wapproj index 4f99481659..700188c0c7 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WapProjTemplate.wapproj +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WapProjTemplate.wapproj @@ -42,11 +42,11 @@ $guid1$ - $targetplatformversion$ - $targetplatformminversion$ + $ext_targetplatformversion$ + $ext_targetplatformminversion$ $ext_DotNetVersion$-windows$(TargetPlatformVersion);$(AssetTargetFallback) $currentuiculturename$ - $if$($includeKeyFile$==true) + $if$($ext_includeKeyFile$==true) $projectname$_TemporaryKey.pfx $endif$ false @@ -56,7 +56,7 @@ Designer - $if$($includeKeyFile$==true) + $if$($ext_includeKeyFile$==true) $endif$ diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WinUI.Desktop.Cs.WapProj.vstemplate b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WinUI.Desktop.Cs.WapProj.vstemplate index 5520e98b34..21850532c4 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WinUI.Desktop.Cs.WapProj.vstemplate +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WapProj/WinUI.Desktop.Cs.WapProj.vstemplate @@ -40,19 +40,9 @@ Wide310x150Logo.scale-200.png - - Microsoft.VisualStudio.Universal.TemplateWizards, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - Microsoft.VisualStudio.Universal.TemplateWizards.PlatformVersion.Wizard - Microsoft.VisualStudio.WinRT.TemplateWizards, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a Microsoft.VisualStudio.WinRT.TemplateWizards.UpdatePublisherInManifestWizard - - 10.0.17763.0 - true - true - true - diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WinUI.Desktop.Cs.PackagedApp.vstemplate b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WinUI.Desktop.Cs.PackagedApp.vstemplate index 0f22e1f822..a559a4ed99 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WinUI.Desktop.Cs.PackagedApp.vstemplate +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CSharp/PackagedApp/WinUI.Desktop.Cs.PackagedApp.vstemplate @@ -26,10 +26,23 @@ + + + WapProj\WinUI.Desktop.Cs.WapProj.vstemplate BlankApp\WinUI.Desktop.Cs.BlankApp.vstemplate + + Microsoft.VisualStudio.Universal.TemplateWizards, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + Microsoft.VisualStudio.Universal.TemplateWizards.PlatformVersion.Wizard + + + 10.0.17763.0 + true + true + true + diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/Package-managed.appxmanifest b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/Package-managed.appxmanifest index 6dfdf482cb..3ee00ff8e4 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/Package-managed.appxmanifest +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/Package-managed.appxmanifest @@ -11,7 +11,7 @@ diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WapProjTemplate.wapproj b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WapProjTemplate.wapproj index de6d40d79d..7036f3c298 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WapProjTemplate.wapproj +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WapProjTemplate.wapproj @@ -43,10 +43,10 @@ $guid1$ - $targetplatformversion$ - $targetplatformminversion$ + $ext_targetplatformversion$ + $ext_targetplatformminversion$ $currentuiculturename$ - $if$($includeKeyFile$==true) + $if$($ext_includeKeyFile$==true) $projectname$_TemporaryKey.pfx $endif$ false @@ -56,7 +56,7 @@ Designer - $if$($includeKeyFile$==true) + $if$($ext_includeKeyFile$==true) $endif$ diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WinUI.Desktop.CppWinRT.WapProj.vstemplate b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WinUI.Desktop.CppWinRT.WapProj.vstemplate index 1e8db89c9d..88b1740baa 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WinUI.Desktop.CppWinRT.WapProj.vstemplate +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WapProj/WinUI.Desktop.CppWinRT.WapProj.vstemplate @@ -39,21 +39,8 @@ - - Microsoft.VisualStudio.Universal.TemplateWizards, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - Microsoft.VisualStudio.Universal.TemplateWizards.PlatformVersion.Wizard - - - - Microsoft.VisualStudio.WinRT.TemplateWizards, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a - Microsoft.VisualStudio.WinRT.TemplateWizards.UpdatePublisherInManifestWizard - WindowsAppSDK.Cpp.Extension.Dev17, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null WindowsAppSDK.TemplateUtilities.NuGetPackageInstaller - - 10.0.17763.0 - true - diff --git a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WinUI.Desktop.CppWinRT.PackagedApp.vstemplate b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WinUI.Desktop.CppWinRT.PackagedApp.vstemplate index 08c4b03884..5ab8a9dfb2 100644 --- a/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WinUI.Desktop.CppWinRT.PackagedApp.vstemplate +++ b/dev/Templates/Source/ProjectTemplates/Desktop/CppWinRT/PackagedApp/WinUI.Desktop.CppWinRT.PackagedApp.vstemplate @@ -27,5 +27,18 @@ WapProj\WinUI.Desktop.CppWinRT.WapProj.vstemplate BlankApp\WinUI.Desktop.CppWinRT.BlankApp.vstemplate - + + + + Microsoft.VisualStudio.WinRT.TemplateWizards, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + Microsoft.VisualStudio.WinRT.TemplateWizards.UpdatePublisherInManifestWizard + + + Microsoft.VisualStudio.Universal.TemplateWizards, Version=16.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + Microsoft.VisualStudio.Universal.TemplateWizards.PlatformVersion.Wizard + + + 10.0.17763.0 + true + diff --git a/dev/Templates/VSIX/build-local-VSIX-package/Build-VSIX-Local.ps1 b/dev/Templates/VSIX/build-local-VSIX-package/Build-VSIX-Local.ps1 index 28e2639933..21d54645b1 100644 --- a/dev/Templates/VSIX/build-local-VSIX-package/Build-VSIX-Local.ps1 +++ b/dev/Templates/VSIX/build-local-VSIX-package/Build-VSIX-Local.ps1 @@ -49,6 +49,10 @@ .PARAMETER SkipRestore Skip NuGet restore (useful if you've already restored). +.PARAMETER MsBuildVersion + Visual Studio version to target for MSBuild. Default: 17 (Visual Studio 2022). + Set to 18 for Visual Studio 2026. + .EXAMPLE .\Build-VSIX-Local.ps1 # Build the LocalDev VSIX (default). Then install with .\Install-LocalDev-VSIX.ps1 @@ -82,7 +86,10 @@ param( [string]$OptionalVSIXVersion = "", - [switch]$SkipRestore + [switch]$SkipRestore, + + [ValidateSet(17, 18)] + [double]$MsBuildVersion = 17 ) Set-StrictMode -Version 2.0 @@ -122,9 +129,10 @@ function Find-MSBuild { exit 1 } - $msbuildPath = & $vswherePath -latest -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe" 2>$null | Select-Object -First 1 + $range = '[{0},{1})' -f $MsBuildVersion, ($MsBuildVersion + 1) + $msbuildPath = & $vswherePath -version $range -requires Microsoft.Component.MSBuild -find "MSBuild\**\Bin\MSBuild.exe" 2>$null | Select-Object -First 1 if (-not $msbuildPath -or -not (Test-Path $msbuildPath)) { - Write-Err "MSBuild.exe not found. Please install Visual Studio 2022+ with the '.NET desktop development' workload." + Write-Err "MSBuild.exe not found. Please install Visual Studio $MsBuildVersion with the '.NET desktop development' workload." exit 1 } @@ -420,6 +428,44 @@ function Invoke-MSBuildBuild { } } +function Test-VsixContainsTemplates { + param( + [string]$Path + ) + + Add-Type -AssemblyName System.IO.Compression.FileSystem + + $archive = [System.IO.Compression.ZipFile]::OpenRead($Path) + try { + $projectTemplates = @( + $archive.Entries | Where-Object { + $_.FullName.StartsWith("ProjectTemplates/", [System.StringComparison]::OrdinalIgnoreCase) -and + $_.FullName.EndsWith(".vstemplate", [System.StringComparison]::OrdinalIgnoreCase) + } + ) + $itemTemplates = @( + $archive.Entries | Where-Object { + $_.FullName.StartsWith("ItemTemplates/", [System.StringComparison]::OrdinalIgnoreCase) -and + $_.FullName.EndsWith(".vstemplate", [System.StringComparison]::OrdinalIgnoreCase) + } + ) + + if ($projectTemplates.Count -eq 0 -or $itemTemplates.Count -eq 0) { + Write-Err "VSIX template validation failed: $Path" + Write-Err " Project templates: $($projectTemplates.Count)" + Write-Err " Item templates : $($itemTemplates.Count)" + Write-Err "The selected Visual Studio/MSBuild toolset may not support packaging these templates." + return $false + } + + Write-Step "Verified templates in $($archive.Entries.Count)-entry VSIX: $($projectTemplates.Count) project, $($itemTemplates.Count) item" + return $true + } + finally { + $archive.Dispose() + } +} + function Copy-VsixOutput { param( [string]$DeploymentType @@ -446,6 +492,10 @@ function Copy-VsixOutput { foreach ($vsix in $vsixFiles) { if (-not $seen.ContainsKey($vsix.Name)) { $seen[$vsix.Name] = $vsix + if (-not (Test-VsixContainsTemplates -Path $vsix.FullName)) { + exit 1 + } + # Rename to include version: WindowsAppSDK.Cs.Extension.Dev17.Component.vsix # -> WindowsAppSDK.Cs.Extension.Dev17.Component.99.2026.0416.1640.vsix $newName = $vsix.BaseName + ".$OptionalVSIXVersion.vsix" diff --git a/dev/Templates/VSIX/build-local-VSIX-package/build-install-localdev-vsix.ps1 b/dev/Templates/VSIX/build-local-VSIX-package/build-install-localdev-vsix.ps1 index 124566d1d7..97fd602f08 100644 --- a/dev/Templates/VSIX/build-local-VSIX-package/build-install-localdev-vsix.ps1 +++ b/dev/Templates/VSIX/build-local-VSIX-package/build-install-localdev-vsix.ps1 @@ -26,6 +26,10 @@ .PARAMETER UninstallFirst Run VSIXInstaller /uninstall before installing for a clean reinstall. +.PARAMETER MsBuildVersion + Visual Studio version to target for MSBuild. Default: 17 (Visual Studio 2022). + Set to 18 for Visual Studio 2026. + .EXAMPLE .\build-install-localdev-vsix.ps1 # Build + install LocalDev C# + C++ to all VS 17+. @@ -44,7 +48,10 @@ param( [string]$VsVersionRange = '[17.0,)', - [switch]$UninstallFirst + [switch]$UninstallFirst, + + [ValidateSet(17, 18)] + [double]$MsBuildVersion = 17 ) Set-StrictMode -Version 2.0 @@ -86,7 +93,7 @@ if ($SkipBuild) { } Push-Location $scriptDir try { - & $buildScript -Deployment LocalDev + & $buildScript -Deployment LocalDev -MsBuildVersion $MsBuildVersion if ($LASTEXITCODE -ne 0) { Write-Err "Build-VSIX-Local.ps1 exited with code $LASTEXITCODE" exit $LASTEXITCODE