diff --git a/.azure-pipelines/esrp/sign.yml b/.azure-pipelines/esrp/sign.yml new file mode 100644 index 000000000..4e316076e --- /dev/null +++ b/.azure-pipelines/esrp/sign.yml @@ -0,0 +1,59 @@ +# Reusable step template for ESRP code signing via EsrpCodeSigning@6. +# +# Wraps a single signing operation with automatic cleanup of the +# CodeSignSummary-.md report ESRP CLI drops into the signing +# folder -- otherwise that file is packaged into the installer or +# uploaded as part of the pipeline artifact. +# +parameters: + - name: displayName + type: string + - name: folderPath + type: string + - name: pattern + type: string + - name: inlineOperation + type: string + # ESRP connection parameters (defaults use pipeline variables) + - name: connectedServiceName + type: string + default: $(esrpAppConnectionName) + - name: appRegistrationClientId + type: string + default: $(esrpClientId) + - name: appRegistrationTenantId + type: string + default: $(esrpTenantId) + - name: authAkvName + type: string + default: $(esrpKeyVaultName) + - name: authSignCertName + type: string + default: $(esrpSignReqCertName) + - name: serviceEndpointUrl + type: string + default: $(esrpEndpointUrl) + +steps: + - task: EsrpCodeSigning@6 + displayName: '${{ parameters.displayName }}' + inputs: + connectedServiceName: '${{ parameters.connectedServiceName }}' + useMSIAuthentication: true + appRegistrationClientId: '${{ parameters.appRegistrationClientId }}' + appRegistrationTenantId: '${{ parameters.appRegistrationTenantId }}' + authAkvName: '${{ parameters.authAkvName }}' + authSignCertName: '${{ parameters.authSignCertName }}' + serviceEndpointUrl: '${{ parameters.serviceEndpointUrl }}' + folderPath: '${{ parameters.folderPath }}' + pattern: '${{ parameters.pattern }}' + useMinimatch: true + signConfigType: inlineSignParams + inlineOperation: ${{ parameters.inlineOperation }} + + - task: PowerShell@2 + displayName: 'Clean up code signing artifacts (${{ parameters.displayName }})' + inputs: + targetType: inline + script: | + Remove-Item -Force "${{ parameters.folderPath }}\CodeSignSummary-*.md" -ErrorAction SilentlyContinue diff --git a/.azure-pipelines/release.yml b/.azure-pipelines/release.yml index 7350735bc..84b9a2b80 100644 --- a/.azure-pipelines/release.yml +++ b/.azure-pipelines/release.yml @@ -1,95 +1,317 @@ -name: $(date:yy)$(DayOfYear)$(rev:.r) -trigger: none -pr: none - -variables: - GVFSMajorAndMinorVersion: 2.0 - GVFSRevision: $(Build.BuildNumber) - BuildConfiguration: Release - TeamName: GVFS - -resources: - repositories: - - repository: MicroBuildTemplate - type: git - name: 1ESPipelineTemplates/MicroBuildTemplate - ref: refs/tags/release - - - repository: VFSForGit - type: github - name: microsoft/VFSForGit - ref: releases/shipped - endpoint: GitHub-VFSForGit - -extends: - template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate - parameters: - pool: - name: VSEng-MicroBuildVSStable - - featureFlags: - incrementalSDLBinaryAnalysis: false - disableNetworkIsolation: true - - sdl: - binskim: - enabled: false - justificationForDisabling: "Guardian and BinSkim do not support a suppression for InnoSetup installer file" - sourceRepositoriesToScan: - include: - - repository: VFSForGit - - stages: - - stage: Release - - jobs: - - job: Build - templateContext: - mb: - signing: - enabled: true - feedSource: 'https://pkgs.dev.azure.com/mseng/_packaging/MicroBuildToolset/nuget/v3/index.json' - signType: real - signWithProd: true - - outputs: - - output: pipelineArtifact - targetPath: $(Build.ArtifactStagingDirectory)\GVFS.Installers - artifactName: Installer - - output: pipelineArtifact - targetPath: $(Build.ArtifactStagingDirectory)\FastFetch - artifactName: FastFetch - - output: pipelineArtifact - targetPath: $(Build.ArtifactStagingDirectory)\Symbols - artifactName: Symbols - - output: pipelineArtifact - targetPath: $(Build.ArtifactStagingDirectory)\GVFS.FunctionalTests - artifactName: FunctionalTests - - steps: - - checkout: VFSForGit - displayName: 'Checkout VFS for Git' - path: vfsforgit\src - - - task: NuGetToolInstaller@1 - displayName: 'Use NuGet 6.x' - inputs: - versionSpec: '6.x' - - - script: | - $(Agent.BuildDirectory)\vfsforgit\src\scripts\Build.bat ^ - $(BuildConfiguration) ^ - $(GVFSMajorAndMinorVersion).$(GVFSRevision) ^ - detailed - displayName: 'Build and sign ($(BuildConfiguration))' - - - script: | - $(Agent.BuildDirectory)\vfsforgit\src\scripts\RunUnitTests.bat ^ - $(BuildConfiguration) - displayName: 'Run unit tests' - - - script: | - $(Agent.BuildDirectory)\vfsforgit\src\scripts\CreateBuildArtifacts.bat ^ - $(BuildConfiguration) ^ - $(Build.ArtifactStagingDirectory) - displayName: 'Create artifacts' +name: $(date:yy)$(DayOfYear)$(rev:.r) +trigger: none +pr: none + +# +# Release pipeline for VFS for Git. +# +# Builds the Windows x64 installer, ESRP-signs the inner Payload binaries and +# the outer SetupGVFS installer, stages all release artifacts, and (optionally) +# publishes a draft GitHub Release. +# +# Designed to be run manually from Azure DevOps, typically against the +# `releases/shipped` branch. Triggers are intentionally `none`; PR/CI builds +# are handled by the GitHub Actions workflow at .github/workflows/build.yaml. +# + +resources: + repositories: + - repository: 1ESPipelines + type: git + name: 1ESPipelineTemplates/1ESPipelineTemplates + ref: refs/tags/release + +parameters: + - name: 'esrp' + type: boolean + default: true + displayName: 'Enable ESRP code signing' + - name: 'github' + type: boolean + default: true + displayName: 'Enable GitHub release publishing' + +variables: + - name: 'GVFSMajorAndMinorVersion' + value: '2.0' + - name: 'GVFSRevision' + value: $(Build.BuildNumber) + - name: 'GVFSVersion' + value: $(GVFSMajorAndMinorVersion).$(GVFSRevision) + - name: 'BuildConfiguration' + value: 'Release' + - name: 'OutDir' + value: $(Agent.BuildDirectory)\vfsforgit\out + - name: 'esrpAppConnectionName' + value: '1ESGitClient-ESRP-App' + - name: 'githubConnectionName' + value: 'GitHub-VFSForGit' + # ESRP signing variables set in the pipeline settings: + # - esrpEndpointUrl + # - esrpClientId + # - esrpTenantId + # - esrpKeyVaultName + # - esrpSignReqCertName + +extends: + template: v1/1ES.Official.PipelineTemplate.yml@1ESPipelines + parameters: + featureFlags: + incrementalSDLBinaryAnalysis: false + disableNetworkIsolation: true + + sdl: + sourceAnalysisPool: + name: GitClientPME-1ESHostedPool-intel-pc + image: win-x86_64-ado1es + os: windows + binskim: + enabled: false + justificationForDisabling: "Guardian and BinSkim do not support a suppression for InnoSetup installer file" + + stages: + - stage: build + displayName: 'Build and Sign' + jobs: + - job: Build + displayName: 'Build VFS for Git (Windows x64)' + pool: + name: GitClientPME-1ESHostedPool-intel-pc + image: win-x86_64-ado1es + os: windows + templateContext: + outputParentDirectory: $(Build.ArtifactStagingDirectory) + outputs: + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)\GVFS.Installers + artifactName: Installer + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)\FastFetch + artifactName: FastFetch + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)\Symbols + artifactName: Symbols + - output: pipelineArtifact + targetPath: $(Build.ArtifactStagingDirectory)\GVFS.FunctionalTests + artifactName: FunctionalTests + + steps: + - checkout: self + displayName: 'Checkout VFS for Git' + path: vfsforgit/src + + - task: UseDotNet@2 + displayName: 'Use .NET SDK (global.json)' + inputs: + useGlobalJson: true + workingDirectory: $(Build.SourcesDirectory) + + - task: NuGetToolInstaller@1 + displayName: 'Use NuGet 6.x' + inputs: + versionSpec: '6.x' + + - task: PowerShell@2 + displayName: 'Install VS C++ workload (NativeAOT prerequisite)' + inputs: + filePath: $(Build.SourcesDirectory)\.azure-pipelines\scripts\install-vs-cpp-workload.ps1 + + - task: PowerShell@2 + displayName: 'Enable Projected File System (ProjFS)' + inputs: + filePath: $(Build.SourcesDirectory)\.azure-pipelines\scripts\enable-projfs.ps1 + + - script: | + $(Build.SourcesDirectory)\scripts\Build.bat ^ + $(BuildConfiguration) ^ + $(GVFSVersion) ^ + detailed + env: + # Skip the Inno Setup compile step inside Build.bat so that + # the Payload binaries can be ESRP-signed before they get + # packaged into the installer. The installer is built in a + # dedicated step further down, after signing. + SkipCreateInstaller: 'true' + displayName: 'Build ($(BuildConfiguration))' + + - script: | + $(Build.SourcesDirectory)\scripts\RunUnitTests.bat ^ + $(BuildConfiguration) + displayName: 'Run unit tests' + + # ESRP signing of the standalone binaries (Payload + FastFetch). + # The installer hasn't been built yet, so it can be packaged from + # signed binaries in a single Inno Setup pass. + - ${{ if eq(parameters.esrp, true) }}: + - template: .azure-pipelines/esrp/sign.yml@self + parameters: + displayName: 'Sign VFS for Git binaries' + folderPath: $(OutDir)\GVFS.Payload\bin\$(BuildConfiguration)\win-x64 + pattern: | + GitHooksLoader.exe + GVFS.exe + GVFS.Hooks.exe + GVFS.Mount.exe + GVFS.PostIndexChangedHook.exe + GVFS.ReadObjectHook.exe + GVFS.Service.exe + GVFS.VirtualFileSystemHook.exe + inlineOperation: | + [ + { + "KeyCode": "CP-230012", + "OperationCode": "SigntoolSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "OpusName": "Microsoft", + "OpusInfo": "https://www.microsoft.com", + "FileDigest": "/fd SHA256", + "PageHash": "/NPH", + "TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + }, + { + "KeyCode": "CP-230012", + "OperationCode": "SigntoolVerify", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": {} + } + ] + + - template: .azure-pipelines/esrp/sign.yml@self + parameters: + displayName: 'Sign FastFetch' + folderPath: $(OutDir)\FastFetch\bin\$(BuildConfiguration)\net10.0-windows10.0.17763.0\win-x64\publish + pattern: 'FastFetch.exe' + inlineOperation: | + [ + { + "KeyCode": "CP-230012", + "OperationCode": "SigntoolSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "OpusName": "Microsoft", + "OpusInfo": "https://www.microsoft.com", + "FileDigest": "/fd SHA256", + "PageHash": "/NPH", + "TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + }, + { + "KeyCode": "CP-230012", + "OperationCode": "SigntoolVerify", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": {} + } + ] + + # Build the installer (Inno Setup compile) now that the Payload + # binaries are signed. --no-dependencies ensures the Payload's + # layout step does NOT re-run and overwrite our signed binaries + # with unsigned originals from each project's individual bin + # folder. + - script: | + dotnet build "$(Build.SourcesDirectory)\GVFS\GVFS.Installers\GVFS.Installers.csproj" ^ + -c $(BuildConfiguration) ^ + --no-restore --no-dependencies ^ + -p:GVFSVersion=$(GVFSVersion) || EXIT /B 1 + displayName: 'Build VFS for Git installer' + + - ${{ if eq(parameters.esrp, true) }}: + - template: .azure-pipelines/esrp/sign.yml@self + parameters: + displayName: 'Sign VFS for Git installer' + folderPath: $(OutDir)\GVFS.Installers\bin\$(BuildConfiguration)\win-x64 + pattern: 'SetupGVFS.*.exe' + inlineOperation: | + [ + { + "KeyCode": "CP-230012", + "OperationCode": "SigntoolSign", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": { + "OpusName": "Microsoft", + "OpusInfo": "https://www.microsoft.com", + "FileDigest": "/fd SHA256", + "PageHash": "/NPH", + "TimeStamp": "/tr \"http://rfc3161.gtm.corp.microsoft.com/TSS/HttpTspServer\" /td sha256" + } + }, + { + "KeyCode": "CP-230012", + "OperationCode": "SigntoolVerify", + "ToolName": "sign", + "ToolVersion": "1.0", + "Parameters": {} + } + ] + + - script: | + $(Build.SourcesDirectory)\scripts\CreateBuildArtifacts.bat ^ + $(BuildConfiguration) ^ + $(Build.ArtifactStagingDirectory) + displayName: 'Stage artifacts' + + - stage: release + displayName: 'Release' + dependsOn: [build] + # Only publish a draft GitHub release when ESRP signing was enabled in + # this run -- otherwise we would risk uploading unsigned installer + # binaries to the public release workflow. + condition: and(succeeded(), eq('${{ parameters.github }}', true), eq('${{ parameters.esrp }}', true)) + jobs: + - job: github + displayName: 'Publish GitHub release' + pool: + name: GitClientPME-1ESHostedPool-intel-pc + image: win-x86_64-ado1es + os: windows + templateContext: + type: releaseJob + isProduction: true + inputs: + - input: pipelineArtifact + artifactName: Installer + targetPath: $(Pipeline.Workspace)/assets/Installer + - input: pipelineArtifact + artifactName: Symbols + targetPath: $(Pipeline.Workspace)/assets/Symbols + steps: + - task: CopyFiles@2 + displayName: 'Gather PDB files' + inputs: + SourceFolder: $(Pipeline.Workspace)/assets/Symbols + Contents: '**/*.pdb' + TargetFolder: $(Pipeline.Workspace)/_pdbs + - task: ArchiveFiles@2 + displayName: 'Prepare PDB files for upload' + inputs: + rootFolderOrFile: $(Pipeline.Workspace)/_pdbs + includeRootFolder: false + archiveType: zip + archiveFile: $(Pipeline.Workspace)/_final/Symbols.zip + replaceExistingArchive: true + - task: CopyFiles@2 + displayName: 'Prepare installer for upload' + inputs: + SourceFolder: $(Pipeline.Workspace)/assets/Installer + Contents: 'SetupGVFS.*.exe' + TargetFolder: $(Pipeline.Workspace)/_final + - task: GitHubRelease@1 + displayName: 'Create draft GitHub Release' + inputs: + gitHubConnection: $(githubConnectionName) + repositoryName: microsoft/VFSForGit + tag: 'v$(GVFSVersion)' + tagSource: userSpecifiedTag + title: 'VFS for Git $(GVFSVersion)' + isDraft: true + isPreRelease: true + addChangeLog: true + assets: | + $(Pipeline.Workspace)/_final/* diff --git a/.azure-pipelines/scripts/enable-projfs.ps1 b/.azure-pipelines/scripts/enable-projfs.ps1 new file mode 100644 index 000000000..e4836b737 --- /dev/null +++ b/.azure-pipelines/scripts/enable-projfs.ps1 @@ -0,0 +1,45 @@ +<# +.SYNOPSIS + Enable the Windows Projected File System (ProjFS) optional feature. + +.DESCRIPTION + VFS for Git -- both the runtime and several unit tests -- P/Invokes + into ProjectedFSLib.dll (e.g. PrjDoesNameContainWildCards). That DLL + is only present on disk when the 'Client-ProjFS' Windows optional + feature is enabled. Hosted CI images do not enable it by default, + so unit tests fail with: + + System.DllNotFoundException : Unable to load DLL + 'ProjectedFSLib.dll' or one of its dependencies. + + This script is a no-op when the feature is already enabled. +#> + +#Requires -Version 5 +#Requires -RunAsAdministrator + +[CmdletBinding()] +param() + +$ErrorActionPreference = 'Stop' + +$featureName = 'Client-ProjFS' + +$feature = Get-WindowsOptionalFeature -Online -FeatureName $featureName -ErrorAction Stop +if ($feature.State -eq 'Enabled') { + Write-Host "INFO: Windows optional feature '$featureName' is already enabled." + exit 0 +} + +Write-Host "INFO: Enabling Windows optional feature '$featureName'..." +$result = Enable-WindowsOptionalFeature -Online -FeatureName $featureName -NoRestart -ErrorAction Stop + +if ($result.RestartNeeded) { + # The pipeline runs unit tests immediately after this script which P/Invoke + # into ProjectedFSLib.dll. If the OS reports a reboot is required to make + # the feature usable, the build agent is in an inconsistent state and the + # tests will fail unpredictably -- so fail fast here instead. + throw "Windows optional feature '$featureName' was enabled but a restart is required to take effect; failing the build." +} else { + Write-Host "INFO: Windows optional feature '$featureName' is now enabled." +} diff --git a/.azure-pipelines/scripts/install-vs-cpp-workload.ps1 b/.azure-pipelines/scripts/install-vs-cpp-workload.ps1 new file mode 100644 index 000000000..8ab9a5dcd --- /dev/null +++ b/.azure-pipelines/scripts/install-vs-cpp-workload.ps1 @@ -0,0 +1,167 @@ +# +# Ensure a Visual Studio 2022 (or newer) install with the "Desktop +# development with C++" workload is present on the build agent. +# +# .NET NativeAOT publishing (used by every product-facing managed VFS for +# Git project via PublishAot=true in Directory.Build.props) requires the +# C++ build tools from this workload at publish time. The native VFS +# projects also build against the v143 toolset, which ships with VS 2022. +# +# This script handles three situations: +# 1. A VS 2022+ install with the C++ workload is already present +# -> exit early. +# 2. A VS 2022+ install (any product) is present but the C++ workload +# is missing -> modify that install to add it. +# 3. No VS 2022+ install at all -> install VS Build Tools 2022 with +# the VC tools workload. (An older VS install, e.g. VS 2019, is +# ignored here -- we leave it alone and install VS 2022 alongside.) +# +# vswhere.exe is bootstrapped from GitHub if not already on disk. +# +# Workload presence is verified via vswhere's -requires/-requiresAny +# rather than by probing for individual files like link.exe; the +# documented prerequisite is the workload itself, not any specific +# implementation detail of NativeAOT. +# +# See https://aka.ms/nativeaot-prerequisites for the full prerequisite list. +# + +$ErrorActionPreference = 'Stop' + +# Force TLS 1.2+ for downloads (Windows PowerShell 5.1 may default to 1.0/1.1 +# on older OS images, which fails against modern HTTPS endpoints). +[Net.ServicePointManager]::SecurityProtocol = + [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12 + +$vsRoot = "${env:ProgramFiles(x86)}\Microsoft Visual Studio" +$vsInstallerDir = Join-Path $vsRoot 'Installer' +$vswherePath = Join-Path $vsInstallerDir 'vswhere.exe' +$setupExePath = Join-Path $vsInstallerDir 'setup.exe' + +$vswhereDownloadUrl = 'https://github.com/microsoft/vswhere/releases/latest/download/vswhere.exe' +$buildToolsDownloadUrl = 'https://aka.ms/vs/17/release/vs_BuildTools.exe' + +# The native VFS projects build against the v143 toolset, which ships with +# Visual Studio 2022 (product line 17.x). VS 2019 (16.x) carries v142 and +# is not sufficient -- so all vswhere queries below are scoped to 17.0+. +$minVsVersion = '[17.0,)' + +# Either of these workloads provides the C++ build tools we need. +# Microsoft.VisualStudio.Workload.NativeDesktop = "Desktop development with C++" (Community/Pro/Enterprise). +# Microsoft.VisualStudio.Workload.VCTools = "C++ build tools" (Build Tools). +$cppWorkloads = @( + 'Microsoft.VisualStudio.Workload.NativeDesktop', + 'Microsoft.VisualStudio.Workload.VCTools' +) + +function Get-VsWhere { + if (Test-Path $script:vswherePath) { + return $script:vswherePath + } + $dest = Join-Path $env:TEMP 'vswhere.exe' + Write-Host "vswhere.exe not found at '$script:vswherePath'; downloading from $script:vswhereDownloadUrl..." + Invoke-WebRequest -Uri $script:vswhereDownloadUrl -OutFile $dest -UseBasicParsing + Write-Host "Downloaded vswhere to: $dest" + return $dest +} + +function Find-VsInstall { + param( + [Parameter(Mandatory = $true)] [string] $VswhereExe, + [string[]] $RequiredWorkloads + ) + $vswhereArgs = @('-latest', '-prerelease', '-products', '*', '-version', $script:minVsVersion, '-format', 'json') + if ($RequiredWorkloads -and $RequiredWorkloads.Count -gt 0) { + $vswhereArgs += '-requires' + $vswhereArgs += $RequiredWorkloads + if ($RequiredWorkloads.Count -gt 1) { + $vswhereArgs += '-requiresAny' + } + } + $output = & $VswhereExe @vswhereArgs + if ($LASTEXITCODE -ne 0) { + throw "vswhere.exe failed with exit code $LASTEXITCODE" + } + if (-not $output) { return $null } + $installs = $output | ConvertFrom-Json + if (-not $installs -or $installs.Count -eq 0) { return $null } + return $installs[0] +} + +function Invoke-VsSetup { + param( + [string] $ExePath, + [string[]] $ArgumentList, + [string] $Description + ) + Write-Host "Running $Description : `"$ExePath`" $($ArgumentList -join ' ')" + $proc = Start-Process -FilePath $ExePath -ArgumentList $ArgumentList -Wait -PassThru -NoNewWindow + Write-Host "$Description exit code: $($proc.ExitCode)" + # 0 = success, 3010 = success but reboot required. + if ($proc.ExitCode -ne 0 -and $proc.ExitCode -ne 3010) { + throw "$Description failed with exit code $($proc.ExitCode)" + } +} + +# --- Locate or bootstrap vswhere --- +$vswhereExe = Get-VsWhere + +# --- Quick exit if a VS install with the C++ workload is already present --- +$existing = Find-VsInstall -VswhereExe $vswhereExe -RequiredWorkloads $cppWorkloads +if ($existing) { + Write-Host "VS install with C++ workload already present: $($existing.installationPath) ($($existing.productId))" + exit 0 +} + +# --- Find any VS install (regardless of workloads) --- +$install = Find-VsInstall -VswhereExe $vswhereExe + +# --- If no VS 2022+ install at all, install VS Build Tools 2022 with the VC workload --- +if (-not $install) { + Write-Host "No Visual Studio 2022 (or newer) installation found; installing VS Build Tools 2022 with the C++ workload..." + $bootstrapper = Join-Path $env:TEMP 'vs_BuildTools.exe' + Write-Host "Downloading VS Build Tools bootstrapper from $buildToolsDownloadUrl..." + Invoke-WebRequest -Uri $buildToolsDownloadUrl -OutFile $bootstrapper -UseBasicParsing + Write-Host "Downloaded bootstrapper to: $bootstrapper" + + Invoke-VsSetup -ExePath $bootstrapper -Description 'VS Build Tools install' -ArgumentList @( + '--add', 'Microsoft.VisualStudio.Workload.VCTools', + '--includeRecommended', + '--quiet', + '--norestart', + '--wait', + '--nocache' + ) +} else { + # --- Existing VS install without C++ workload: modify it --- + # Build Tools needs Microsoft.VisualStudio.Workload.VCTools; full Visual + # Studio (Community/Pro/Enterprise) needs Microsoft.VisualStudio.Workload.NativeDesktop. + $workload = if ($install.productId -eq 'Microsoft.VisualStudio.Product.BuildTools') { + 'Microsoft.VisualStudio.Workload.VCTools' + } else { + 'Microsoft.VisualStudio.Workload.NativeDesktop' + } + Write-Host "Existing VS install at $($install.installationPath) ($($install.productId)) lacks the C++ workload; adding '$workload'..." + + if (-not (Test-Path $setupExePath)) { + throw "Visual Studio Installer setup.exe not found at '$setupExePath'" + } + + Invoke-VsSetup -ExePath $setupExePath -Description 'VS Installer modify' -ArgumentList @( + 'modify', + '--installPath', $install.installationPath, + '--add', $workload, + '--includeRecommended', + '--quiet', + '--norestart', + '--wait', + '--nocache' + ) +} + +# --- Final verification: vswhere must now report an install with the workload --- +$verified = Find-VsInstall -VswhereExe $vswhereExe -RequiredWorkloads $cppWorkloads +if (-not $verified) { + throw "Workload install reported success but vswhere still does not report a VS install with the C++ workload" +} +Write-Host "VS install with C++ workload now present: $($verified.installationPath) ($($verified.productId))" diff --git a/Directory.Packages.props b/Directory.Packages.props index faf9cf3ae..e72ceb6e6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -24,7 +24,6 @@ - diff --git a/GVFS/FastFetch/FastFetch.csproj b/GVFS/FastFetch/FastFetch.csproj index e99f7b785..a8faae5ea 100644 --- a/GVFS/FastFetch/FastFetch.csproj +++ b/GVFS/FastFetch/FastFetch.csproj @@ -12,14 +12,6 @@ - - - - - - Microsoft400 - false - diff --git a/GVFS/GVFS.Installers/GVFS.Installers.csproj b/GVFS/GVFS.Installers/GVFS.Installers.csproj index 5961b569b..e48c1229e 100644 --- a/GVFS/GVFS.Installers/GVFS.Installers.csproj +++ b/GVFS/GVFS.Installers/GVFS.Installers.csproj @@ -12,7 +12,6 @@ - @@ -25,14 +24,7 @@ - - - Microsoft400 - false - - - - + diff --git a/GVFS/GVFS.Payload/GVFS.Payload.csproj b/GVFS/GVFS.Payload/GVFS.Payload.csproj index c87428e9f..e400a2a94 100644 --- a/GVFS/GVFS.Payload/GVFS.Payload.csproj +++ b/GVFS/GVFS.Payload/GVFS.Payload.csproj @@ -11,10 +11,9 @@ - - + @@ -22,20 +21,5 @@ - - - Microsoft400 - false - - - diff --git a/GVFS/GVFS.Payload/layout.bat b/GVFS/GVFS.Payload/layout.bat index e1ff77270..fbaf9ea7c 100644 --- a/GVFS/GVFS.Payload/layout.bat +++ b/GVFS/GVFS.Payload/layout.bat @@ -59,6 +59,8 @@ RMDIR /S /Q %OUTPUT%\x86 REM Remove stray managed artifacts (AOT binaries don't need these) DEL /Q %OUTPUT%\*.runtimeconfig.json 2>nul DEL /Q %OUTPUT%\*.deps.json 2>nul +REM Remove VS C++ code-analysis marker files generated next to native exes +DEL /S /Q %OUTPUT%\*.lastcodeanalysissucceeded 2>nul REM Remove orphaned managed PDBs (these libraries are compiled into AOT exes) DEL /Q %OUTPUT%\GVFS.Common.pdb 2>nul DEL /Q %OUTPUT%\GVFS.Platform.Windows.pdb 2>nul diff --git a/scripts/Build.bat b/scripts/Build.bat index 32ab6f565..905359390 100644 --- a/scripts/Build.bat +++ b/scripts/Build.bat @@ -70,8 +70,8 @@ IF DEFINED MSBUILD_EXEC ( /p:SolutionDir="%VFS_SRCDIR%\\" || GOTO ERROR ) ) ELSE ( - ECHO WARNING: Could not find VS MSBuild. Native C++ projects will not be built. - ECHO Install Visual Studio with the C++ workload to build native projects. + ECHO ERROR: Could not find VS MSBuild. Install Visual Studio with the C++ workload to build native projects. + EXIT /B 1 ) ECHO ^*****************************