diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 1b8c58ce..0eae3250 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,14 +3,14 @@ "isRoot": true, "tools": { "powershell": { - "version": "7.5.0", + "version": "7.5.1", "commands": [ "pwsh" ], "rollForward": false }, "dotnet-coverage": { - "version": "17.13.1", + "version": "17.14.2", "commands": [ "dotnet-coverage" ], @@ -24,7 +24,7 @@ "rollForward": false }, "docfx": { - "version": "2.78.2", + "version": "2.78.3", "commands": [ "docfx" ], diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 6952a419..938b19f8 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,5 +1,5 @@ # Refer to https://hub.docker.com/_/microsoft-dotnet-sdk for available versions -FROM mcr.microsoft.com/dotnet/sdk:9.0.102-noble +FROM mcr.microsoft.com/dotnet/sdk:9.0.300-noble@sha256:9f7bd4d010026e15a57d9cf876f2f7d08c3eeed6a0ea987b8c5ba8c75e68e948 # Installing mono makes `dotnet test` work without errors even for net472. # But installing it takes a long time, so it's excluded by default. diff --git a/.github/actions/publish-artifacts/action.yaml b/.github/actions/publish-artifacts/action.yaml index 2a75c4d2..1f345fe6 100644 --- a/.github/actions/publish-artifacts/action.yaml +++ b/.github/actions/publish-artifacts/action.yaml @@ -14,46 +14,46 @@ runs: - name: 📢 Upload project.assets.json files if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: projectAssetsJson-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/projectAssetsJson continue-on-error: true - name: 📢 Upload variables - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: variables-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/Variables continue-on-error: true - name: 📢 Upload build_logs if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: build_logs-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/build_logs continue-on-error: true - name: 📢 Upload testResults if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: testResults-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/testResults continue-on-error: true - name: 📢 Upload coverageResults if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: coverageResults-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/coverageResults continue-on-error: true - name: 📢 Upload symbols - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: symbols-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/symbols continue-on-error: true - name: 📢 Upload deployables - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: deployables-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/deployables diff --git a/.github/renovate.json b/.github/renovate.json index 72080431..4789cb20 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -1,52 +1,9 @@ { "$schema": "https://docs.renovatebot.com/renovate-schema.json", - "extends": ["config:recommended"], - "semanticCommits": "disabled", - "labels": ["dependencies"], - "packageRules": [ - { - "matchPackageNames": ["nbgv", "nerdbank.gitversioning"], - "groupName": "nbgv and nerdbank.gitversioning updates" - }, - { - "matchPackageNames": ["xunit*"], - "groupName": "xunit" - }, - { - "matchDatasources": ["dotnet-version", "docker"], - "matchDepNames": ["dotnet-sdk", "mcr.microsoft.com/dotnet/sdk"], - "groupName": "Dockerfile and global.json updates" - }, - { - "matchPackageNames": ["*"], - "allowedVersions": "!/-g[a-f0-9]+$/" - }, - { - "matchPackageNames": [ - "System.Collections.Immutable", - "System.Composition*", - "System.Diagnostics.DiagnosticSource", - "System.IO.Pipelines", - "System.Reflection.Metadata", - "System.Text.Json", - "System.Threading.Tasks.Dataflow", - "Microsoft.Bcl.AsyncInterfaces" - ], - "allowedVersions": "<9.0", - "groupName": "Included in .NET runtime" - }, - { - "matchPackageNames": ["Microsoft.VisualStudio.Internal.MicroBuild*"], - "groupName": "microbuild" - }, - { - "matchPackageNames": ["Microsoft.VisualStudio.*"], - "groupName": "Visual Studio SDK" - }, - { - "matchPackageNames": ["Microsoft.VisualStudio.*"], - "matchUpdateTypes": ["patch"], - "enabled": false - } - ] + "extends": [ + "github>microsoft/vs-renovate-presets:microbuild", + "github>microsoft/vs-renovate-presets:vs_main_dependencies", + "github>microsoft/vs-renovate-presets:dotnet_packages_LTS" + ], + "packageRules": [] } diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 70b779b5..0a8f8215 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -25,7 +25,7 @@ jobs: url: ${{ steps.deployment.outputs.page_url }} runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 # avoid shallow clone so nbgv can do its work. - name: ⚙ Install prerequisites @@ -35,10 +35,10 @@ jobs: name: 📚 Generate documentation - name: Upload artifact - uses: actions/upload-pages-artifact@v3 + uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 with: path: docfx/_site - name: Deploy to GitHub Pages id: deployment - uses: actions/deploy-pages@v4 + uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 diff --git a/.github/workflows/libtemplate-update.yml b/.github/workflows/libtemplate-update.yml index 53df80ff..7d0a67a0 100644 --- a/.github/workflows/libtemplate-update.yml +++ b/.github/workflows/libtemplate-update.yml @@ -17,7 +17,7 @@ jobs: contents: write pull-requests: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 with: fetch-depth: 0 # avoid shallow clone so nbgv can do its work. diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 766ebaf5..00000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,88 +0,0 @@ -name: 🎁 Release - -on: - release: - types: [published] - workflow_dispatch: - inputs: - ship_run_id: - description: ID of the GitHub workflow run to ship - required: true - -run-name: ${{ github.ref_name }} - -permissions: - actions: read - contents: write - -jobs: - release: - runs-on: ubuntu-24.04 - steps: - - name: ⚙️ Initialization - shell: pwsh - run: | - if ('${{ secrets.NUGET_API_KEY }}') { - Write-Host "NUGET_API_KEY secret detected. NuGet packages will be pushed." - echo "NUGET_API_KEY_DEFINED=true" >> $env:GITHUB_ENV - } - - - name: 🔎 Search for build of ${{ github.ref }} - shell: pwsh - id: findrunid - env: - GH_TOKEN: ${{ github.token }} - run: | - if ('${{ inputs.ship_run_id }}') { - $runid = '${{ inputs.ship_run_id }}' - } else { - $restApiRoot = '/repos/${{ github.repository }}' - - # Resolve the tag reference to a commit sha - $resolvedRef = gh api ` - -H "Accept: application/vnd.github+json" ` - -H "X-GitHub-Api-Version: 2022-11-28" ` - $restApiRoot/git/ref/tags/${{ github.ref_name }} ` - | ConvertFrom-Json - $commitSha = $resolvedRef.object.sha - - Write-Host "Resolved ${{ github.ref_name }} to $commitSha" - - $releases = gh run list -R ${{ github.repository }} -c $commitSha -w .github/workflows/build.yml -s success --json databaseId,startedAt ` - | ConvertFrom-Json | Sort-Object startedAt -Descending - - if ($releases.length -eq 0) { - Write-Error "No successful builds found for ${{ github.ref }}." - } elseif ($releases.length -gt 1) { - Write-Warning "More than one successful run found for ${{ github.ref }}. Artifacts from the most recent successful run will ship." - } - - $runid = $releases[0].databaseId - } - - Write-Host "Using artifacts from run-id: $runid" - - Echo "runid=$runid" >> $env:GITHUB_OUTPUT - - - name: 🔻 Download deployables artifacts - uses: actions/download-artifact@v4 - with: - name: deployables-Linux - path: ${{ runner.temp }}/deployables - run-id: ${{ steps.findrunid.outputs.runid }} - github-token: ${{ github.token }} - - - name: 💽 Upload artifacts to release - shell: pwsh - if: ${{ github.event.release.assets_url }} != '' - env: - GH_TOKEN: ${{ github.token }} - run: | - Get-ChildItem '${{ runner.temp }}/deployables' |% { - Write-Host "Uploading $($_.Name) to release..." - gh release -R ${{ github.repository }} upload "${{ github.ref_name }}" $_.FullName - } - - - name: 🚀 Push NuGet packages - run: dotnet nuget push ${{ runner.temp }}/deployables/*.nupkg --source https://api.nuget.org/v3/index.json -k '${{ secrets.NUGET_API_KEY }}' - if: ${{ env.NUGET_API_KEY_DEFINED == 'true' }} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 58d4fb6a..158b7d92 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -82,3 +82,17 @@ Configuration is in the `.github/renovate.json` file. When changing the renovate.json file, follow [these validation steps](https://docs.renovatebot.com/config-validation/). If Renovate is not creating pull requests when you expect it to, check that the [Renovate GitHub App](https://github.com/apps/renovate) is configured for your account or repo. + +## Merging latest from Library.Template + +### Maintaining your repo based on this template + +The best way to keep your repo in sync with Library.Template's evolving features and best practices is to periodically merge the template into your repo: +` +```ps1 +git fetch +git checkout origin/main +.\tools\MergeFrom-Template.ps1 +# resolve any conflicts, then commit the merge commit. +git push origin -u HEAD +``` diff --git a/Directory.Build.props b/Directory.Build.props index 8d649c7e..df07c8bb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,6 +7,7 @@ $(RepoRootPath)bin\$(MSBuildProjectName)\ $(RepoRootPath)bin\Packages\$(Configuration)\NuGet\ $(RepoRootPath)bin\Packages\$(Configuration)\Vsix\$(Platform)\ + $(VSIXOutputPath) enable enable latest @@ -38,6 +39,11 @@ snupkg + + 13 + 16.9 + + @@ -56,4 +62,6 @@ $(RepositoryUrl)/releases/tag/v$(Version) + + diff --git a/Directory.Build.targets b/Directory.Build.targets index d1a3c22e..0e0366b5 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,9 +1,5 @@ - - 13 - 16.9 - @@ -12,6 +8,4 @@ - - diff --git a/Directory.Packages.props b/Directory.Packages.props index ddcdc05e..c71a6835 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -12,10 +12,10 @@ - + - - + + diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 00000000..0f876b3e --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,16 @@ +# Support + +## How to file issues and get help + +This project uses GitHub Issues to track bugs and feature requests. +Please search the existing issues before filing new issues to avoid duplicates. +For new issues, file your bug or feature request as a new Issue. + +Note that this repo is primarily used for Visual Studio and related products and support will be focused on those scenarios. + +## Microsoft Support Policy + +Microsoft support for this software is available only for its use in officially supported products such as Visual Studio. +Support and servicing is limited to the latest released version. +For more information, see [Visual Studio Product Lifecycle and Servicing](https://learn.microsoft.com/visualstudio/productinfo/vs-servicing). +Assisted support is available from a professional support engineer by opening a ticket with the [Microsoft assisted support team](https://support.serviceshub.microsoft.com/supportforbusiness/onboarding). diff --git a/azure-pipelines/NuGetSbom.props b/azure-pipelines/NuGetSbom.props new file mode 100644 index 00000000..dbfee864 --- /dev/null +++ b/azure-pipelines/NuGetSbom.props @@ -0,0 +1,6 @@ + + + true + 2 + + diff --git a/azure-pipelines/NuGetSbom.targets b/azure-pipelines/NuGetSbom.targets deleted file mode 100644 index a2599e88..00000000 --- a/azure-pipelines/NuGetSbom.targets +++ /dev/null @@ -1,12 +0,0 @@ - - - true - $(TargetsForTfmSpecificBuildOutput);IncludeSbomInNupkg - - - - - - - - diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 55c0b97a..ba91c5c7 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -71,6 +71,10 @@ parameters: type: boolean default: true +- name: PublishCodeCoverage + type: boolean + default: true + # Whether this is a special one-off build for inserting into VS for a validation insertion PR (that will never be merged). - name: SkipCodesignVerify type: boolean @@ -279,8 +283,16 @@ jobs: - macOS pool: ${{ parameters.windowsPool }} # Use Windows agent because PublishSymbols task requires it (https://github.com/microsoft/azure-pipelines-tasks/issues/13821). condition: succeededOrFailed() + variables: + ONEES_ENFORCED_CODEQL_ENABLED: false # CodeQL runs on build jobs, we don't need it here ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}: templateContext: + ${{ if not(parameters.RealSign) }}: + mb: + signing: # if the build is test-signed, install the signing plugin so that CSVTestSignPolicy.xml is available + enabled: true + zipSources: false + signType: test outputParentDirectory: $(Build.ArtifactStagingDirectory) outputs: - output: pipelineArtifact @@ -299,7 +311,7 @@ jobs: parameters: EnableLinuxBuild: ${{ parameters.EnableLinuxBuild }} EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }} - - ${{ if parameters.RunTests }}: + - ${{ if and(parameters.RunTests, parameters.PublishCodeCoverage) }}: - template: publish-codecoverage.yml parameters: EnableLinuxBuild: ${{ parameters.EnableLinuxBuild }} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 180e36c2..2abca9eb 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -8,7 +8,7 @@ parameters: steps: -- script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) -warnAsError -warnNotAsError:NU1901,NU1902,NU1903,NU1904 /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" +- script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) -warnAsError -warnNotAsError:NU1901,NU1902,NU1903,NU1904,LOCTASK002 /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" displayName: 🛠 dotnet build - ${{ if not(parameters.IsOptProf) }}: diff --git a/azure-pipelines/microbuild.after.yml b/azure-pipelines/microbuild.after.yml index e2107433..025de4f5 100644 --- a/azure-pipelines/microbuild.after.yml +++ b/azure-pipelines/microbuild.after.yml @@ -9,7 +9,7 @@ parameters: type: boolean steps: -- ${{ if not(parameters.SkipCodesignVerify) }}: # skip CodesignVerify on validation builds because we don't even test-sign nupkg's. +- ${{ if not(parameters.SkipCodesignVerify) }}: - task: MicroBuildCodesignVerify@3 displayName: 🔍 Verify Signed Files inputs: diff --git a/azure-pipelines/official.yml b/azure-pipelines/official.yml index e3240ca5..3d4852f3 100644 --- a/azure-pipelines/official.yml +++ b/azure-pipelines/official.yml @@ -29,6 +29,10 @@ parameters: displayName: Include APIScan with compliance tools type: boolean default: true +- name: PublishCodeCoverage + displayName: Publish code coverage + type: boolean + default: true resources: repositories: @@ -48,14 +52,14 @@ extends: codeSignValidation: enabled: true break: true - additionalTargetsGlobPattern: -|Variables-*\*.ps1;-|APIScanInputs-*\**;-|test_symbols-*\**;-|MicroBuild\** + additionalTargetsGlobPattern: -|Variables-*\*.ps1;-|LocBin-*\**;-|APIScanInputs-*\**;-|test_symbols-*\**;-|MicroBuild\** policheck: enabled: true exclusionsFile: $(System.DefaultWorkingDirectory)\azure-pipelines\PoliCheckExclusions.xml suppression: suppressionFile: $(System.DefaultWorkingDirectory)\azure-pipelines\falsepositives.gdnsuppress sbom: - enabled: true + enabled: false # Skip 1ES SBOM because microbuild has our own sbom system stages: - stage: Build variables: @@ -79,6 +83,7 @@ extends: os: macOS EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }} RunTests: ${{ parameters.RunTests }} + PublishCodeCoverage: ${{ parameters.PublishCodeCoverage }} - template: /azure-pipelines/prepare-insertion-stages.yml@self parameters: RealSign: true diff --git a/azure-pipelines/prepare-insertion-stages.yml b/azure-pipelines/prepare-insertion-stages.yml index ff752cd6..18eda020 100644 --- a/azure-pipelines/prepare-insertion-stages.yml +++ b/azure-pipelines/prepare-insertion-stages.yml @@ -18,6 +18,8 @@ stages: - job: symbol_archive displayName: Archive symbols pool: VSEngSS-MicroBuild2022-1ES + variables: + ONEES_ENFORCED_CODEQL_ENABLED: false # CodeQL runs on build stages, we don't need it here steps: - checkout: none - download: current @@ -61,6 +63,8 @@ stages: ${{ else }}: nuGetFeedType: internal publishVstsFeed: vs-impl # Leave this as-is, since non-signed builds must not be pushed to public feeds. + variables: + ONEES_ENFORCED_CODEQL_ENABLED: false # CodeQL runs on build stages, we don't need it here steps: - checkout: none - download: current diff --git a/azure-pipelines/unofficial.yml b/azure-pipelines/unofficial.yml index 32f8de41..6564ea45 100644 --- a/azure-pipelines/unofficial.yml +++ b/azure-pipelines/unofficial.yml @@ -36,6 +36,10 @@ parameters: displayName: Enable Production SDL type: boolean default: false +- name: PublishCodeCoverage + displayName: Publish code coverage + type: boolean + default: true resources: repositories: @@ -64,7 +68,7 @@ extends: enabled: ${{ parameters.EnableProductionSDL }} exclusionsFile: $(System.DefaultWorkingDirectory)\azure-pipelines\PoliCheckExclusions.xml sbom: - enabled: ${{ parameters.EnableProductionSDL }} + enabled: false # Skip 1ES SBOM because microbuild has our own sbom system stages: - stage: Build variables: @@ -88,3 +92,4 @@ extends: os: macOS EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }} RunTests: ${{ parameters.RunTests }} + PublishCodeCoverage: ${{ parameters.PublishCodeCoverage }} diff --git a/azure-pipelines/vs-insertion.yml b/azure-pipelines/vs-insertion.yml index fcfc0a71..9812bc25 100644 --- a/azure-pipelines/vs-insertion.yml +++ b/azure-pipelines/vs-insertion.yml @@ -32,6 +32,8 @@ extends: - job: insertion displayName: VS insertion pool: VSEngSS-MicroBuild2022-1ES + templateContext: + outputParentDirectory: $(Pipeline.Workspace)/CI steps: - checkout: none - powershell: Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" diff --git a/azure-pipelines/vs-validation.yml b/azure-pipelines/vs-validation.yml index 2fa5086d..3a40395e 100644 --- a/azure-pipelines/vs-validation.yml +++ b/azure-pipelines/vs-validation.yml @@ -5,6 +5,12 @@ trigger: none # We only want to trigger manually or based on resources pr: none +# parameters: +# - name: ShouldSkipOptimize # Uncomment this and references to it below when setting EnableOptProf to true in build.yml. +# displayName: Skip OptProf optimization +# type: boolean +# default: false + resources: repositories: - repository: MicroBuildTemplate @@ -26,16 +32,16 @@ extends: stages: - stage: Build variables: - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/ - BuildConfiguration: Release - SkipCodesignVerify: true + - template: /azure-pipelines/BuildStageVariables.yml@self + - name: SkipCodesignVerify + value: true jobs: - template: /azure-pipelines/build.yml@self parameters: Is1ESPT: true RealSign: false + # ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }} windowsPool: VSEngSS-MicroBuild2022-1ES linuxPool: name: AzurePipelines-EO diff --git a/global.json b/global.json index 20b589f8..3d0b9e2d 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "9.0.102", + "version": "9.0.300", "rollForward": "patch", "allowPrerelease": false }, diff --git a/test/Microsoft.VisualStudio.Validation.Tests/AssertDialogSuppression.cs b/test/Microsoft.VisualStudio.Validation.Tests/AssertDialogSuppression.cs index a67ebf85..7a571def 100644 --- a/test/Microsoft.VisualStudio.Validation.Tests/AssertDialogSuppression.cs +++ b/test/Microsoft.VisualStudio.Validation.Tests/AssertDialogSuppression.cs @@ -33,6 +33,14 @@ public AssertDialogSuppression() this.originalAssertUiSetting = assertDialogListener.AssertUiEnabled; assertDialogListener.AssertUiEnabled = false; } + + // Xunit.v3 v2 also adds a TraceListener that throws on failure, so remove that too. + // See also https://github.com/xunit/xunit/issues/3317. + // My mechanism for removing the listener is designed to work before and after that issue is resolved. + if (Trace.Listeners.OfType().FirstOrDefault() is { } listener) + { + Trace.Listeners.Remove(listener); + } #endif } diff --git a/tools/Get-3rdPartySymbolFiles.ps1 b/tools/Get-3rdPartySymbolFiles.ps1 new file mode 100644 index 00000000..ef6bbef2 --- /dev/null +++ b/tools/Get-3rdPartySymbolFiles.ps1 @@ -0,0 +1,91 @@ +Function Get-FileFromWeb([Uri]$Uri, $OutFile) { + $OutDir = Split-Path $OutFile + if (!(Test-Path $OutFile)) { + Write-Verbose "Downloading $Uri..." + if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir | Out-Null } + try { + (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) + } + finally { + # This try/finally causes the script to abort + } + } +} + +Function Unzip($Path, $OutDir) { + $OutDir = (New-Item -ItemType Directory -Path $OutDir -Force).FullName + Add-Type -AssemblyName System.IO.Compression.FileSystem + + # Start by extracting to a temporary directory so that there are no file conflicts. + [System.IO.Compression.ZipFile]::ExtractToDirectory($Path, "$OutDir.out") + + # Now move all files from the temp directory to $OutDir, overwriting any files. + Get-ChildItem -Path "$OutDir.out" -Recurse -File | ForEach-Object { + $destinationPath = Join-Path -Path $OutDir -ChildPath $_.FullName.Substring("$OutDir.out".Length).TrimStart([io.path]::DirectorySeparatorChar, [io.path]::AltDirectorySeparatorChar) + if (!(Test-Path -Path (Split-Path -Path $destinationPath -Parent))) { + New-Item -ItemType Directory -Path (Split-Path -Path $destinationPath -Parent) | Out-Null + } + Move-Item -Path $_.FullName -Destination $destinationPath -Force + } + Remove-Item -Path "$OutDir.out" -Recurse -Force +} + +Function Get-SymbolsFromPackage($id, $version) { + $symbolPackagesPath = "$PSScriptRoot/../obj/SymbolsPackages" + New-Item -ItemType Directory -Path $symbolPackagesPath -Force | Out-Null + $nupkgPath = Join-Path $symbolPackagesPath "$id.$version.nupkg" + $snupkgPath = Join-Path $symbolPackagesPath "$id.$version.snupkg" + $unzippedPkgPath = Join-Path $symbolPackagesPath "$id.$version" + Get-FileFromWeb -Uri "https://www.nuget.org/api/v2/package/$id/$version" -OutFile $nupkgPath + Get-FileFromWeb -Uri "https://www.nuget.org/api/v2/symbolpackage/$id/$version" -OutFile $snupkgPath + + Unzip -Path $nupkgPath -OutDir $unzippedPkgPath + Unzip -Path $snupkgPath -OutDir $unzippedPkgPath + + Get-ChildItem -Recurse -LiteralPath $unzippedPkgPath -Filter *.pdb | % { + # Collect the DLLs/EXEs as well. + $rootName = Join-Path $_.Directory $_.BaseName + if ($rootName.EndsWith('.ni')) { + $rootName = $rootName.Substring(0, $rootName.Length - 3) + } + + $dllPath = "$rootName.dll" + $exePath = "$rootName.exe" + if (Test-Path $dllPath) { + $BinaryImagePath = $dllPath + } + elseif (Test-Path $exePath) { + $BinaryImagePath = $exePath + } + else { + Write-Warning "`"$_`" found with no matching binary file." + $BinaryImagePath = $null + } + + if ($BinaryImagePath) { + Write-Output $BinaryImagePath + Write-Output $_.FullName + } + } +} + +Function Get-PackageVersion($id) { + $versionProps = [xml](Get-Content -LiteralPath $PSScriptRoot\..\Directory.Packages.props) + $version = $versionProps.Project.ItemGroup.PackageVersion | ? { $_.Include -eq $id } | % { $_.Version } + if (!$version) { + Write-Error "No package version found in Directory.Packages.props for the package '$id'" + } + + $version +} + +# All 3rd party packages for which symbols packages are expected should be listed here. +# These must all be sourced from nuget.org, as it is the only feed that supports symbol packages. +$3rdPartyPackageIds = @() + +$3rdPartyPackageIds | % { + $version = Get-PackageVersion $_ + if ($version) { + Get-SymbolsFromPackage -id $_ -version $version + } +} diff --git a/tools/Get-SymbolFiles.ps1 b/tools/Get-SymbolFiles.ps1 index b5063cec..70656c0f 100644 --- a/tools/Get-SymbolFiles.ps1 +++ b/tools/Get-SymbolFiles.ps1 @@ -43,7 +43,7 @@ $PDBs |% { } } |% { # Collect the DLLs/EXEs as well. - $rootName = "$($_.Directory)/$($_.BaseName)" + $rootName = Join-Path $_.Directory $_.BaseName if ($rootName.EndsWith('.ni')) { $rootName = $rootName.Substring(0, $rootName.Length - 3) } diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index e08571bc..402b4307 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -36,7 +36,11 @@ if (!(Test-Path $DotNetInstallScriptRoot)) { New-Item -ItemType Directory -Path $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot # Look up actual required .NET SDK version from global.json -$sdkVersion = & "$PSScriptRoot/variables/DotNetSdkVersion.ps1" +$sdks = @(New-Object PSObject -Property @{ Version = & "$PSScriptRoot/variables/DotNetSdkVersion.ps1" }) + +# Sometimes a repo requires extra SDKs to be installed (e.g. msbuild.locator scenarios running in tests). +# In such a circumstance, a precise SDK version or a channel can be added as in the example below: +# $sdks += New-Object PSObject -Property @{ Channel = '8.0' } If ($IncludeX86 -and ($IsMacOS -or $IsLinux)) { Write-Verbose "Ignoring -IncludeX86 switch because 32-bit runtimes are only supported on Windows." @@ -191,13 +195,16 @@ if ($InstallLocality -eq 'machine') { $DotNetInstallDir = '/usr/share/dotnet' } else { $restartRequired = $false - if ($PSCmdlet.ShouldProcess(".NET SDK $sdkVersion", "Install")) { - Install-DotNet -Version $sdkVersion -Architecture $arch - $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) - - if ($IncludeX86) { - Install-DotNet -Version $sdkVersion -Architecture x86 + $sdks |% { + if ($_.Version) { $version = $_.Version } else { $version = $_.Channel } + if ($PSCmdlet.ShouldProcess(".NET SDK $_", "Install")) { + Install-DotNet -Version $version -Architecture $arch $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + + if ($IncludeX86) { + Install-DotNet -Version $version -Architecture x86 + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } } } @@ -296,29 +303,33 @@ $DotNetInstallScriptPathExpression = "& '$DotNetInstallScriptPathExpression'" $anythingInstalled = $false $global:LASTEXITCODE = 0 -if ($PSCmdlet.ShouldProcess(".NET SDK $sdkVersion", "Install")) { - $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches" +$sdks |% { + if ($_.Version) { $parameters = '-Version', $_.Version } else { $parameters = '-Channel', $_.Channel } - if ($LASTEXITCODE -ne 0) { - Write-Error ".NET SDK installation failure: $LASTEXITCODE" - exit $LASTEXITCODE - } -} else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches -DryRun" -} - -if ($IncludeX86) { - if ($PSCmdlet.ShouldProcess(".NET x86 SDK $sdkVersion", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET SDK $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression $parameters -Architecture $arch -InstallDir $DotNetInstallDir $switches" if ($LASTEXITCODE -ne 0) { - Write-Error ".NET x86 SDK installation failure: $LASTEXITCODE" + Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression $parameters -Architecture $arch -InstallDir $DotNetInstallDir $switches -DryRun" + } + + if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET x86 SDK $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression $parameters -Architecture x86 -InstallDir $DotNetX86InstallDir $switches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET x86 SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression $parameters -Architecture x86 -InstallDir $DotNetX86InstallDir $switches -DryRun" + } } } diff --git a/tools/artifacts/symbols.ps1 b/tools/artifacts/symbols.ps1 index 9e2c7bd5..b5882678 100644 --- a/tools/artifacts/symbols.ps1 +++ b/tools/artifacts/symbols.ps1 @@ -1,7 +1,10 @@ $BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") +$3rdPartyPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../obj/SymbolsPackages") if (!(Test-Path $BinPath)) { return } $symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique +$3rdPartyFiles = & "$PSScriptRoot/../Get-3rdPartySymbolFiles.ps1" @{ "$BinPath" = $SymbolFiles; + "$3rdPartyPath" = $3rdPartyFiles; }