From 05f49ce799c1f9cc696d53eea89699d80f59f833 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 16 Jun 2019 07:01:14 -0600 Subject: [PATCH 001/704] Initial commit --- .gitattributes | 63 ++++ .gitignore | 349 +++++++++++++++++++++++ .vscode/extensions.json | 18 ++ CONTRIBUTING.md | 24 ++ LICENSE | 21 ++ README.md | 31 ++ azure-pipelines.yml | 58 ++++ azure-pipelines/collect-deployables.yml | 15 + azure-pipelines/collect-logs.yml | 9 + azure-pipelines/dotnet.yml | 64 +++++ azure-pipelines/install-dependencies.yml | 25 ++ global.json | 5 + nuget.config | 8 + src/.editorconfig | 157 ++++++++++ src/Directory.Build.props | 35 +++ src/Directory.Build.targets | 8 + src/Library.Tests/CalculatorTests.cs | 28 ++ src/Library.Tests/Library.Tests.csproj | 29 ++ src/Library.Tests/app.config | 5 + src/Library/Calculator.cs | 29 ++ src/Library/Library.csproj | 10 + src/lib.template.sln | 28 ++ src/shipping.ruleset | 74 +++++ src/strongname.snk | Bin 0 -> 596 bytes src/stylecop.json | 15 + src/tests.ruleset | 83 ++++++ version.json | 8 + 27 files changed, 1199 insertions(+) create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .vscode/extensions.json create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE create mode 100644 README.md create mode 100644 azure-pipelines.yml create mode 100644 azure-pipelines/collect-deployables.yml create mode 100644 azure-pipelines/collect-logs.yml create mode 100644 azure-pipelines/dotnet.yml create mode 100644 azure-pipelines/install-dependencies.yml create mode 100644 global.json create mode 100644 nuget.config create mode 100644 src/.editorconfig create mode 100644 src/Directory.Build.props create mode 100644 src/Directory.Build.targets create mode 100644 src/Library.Tests/CalculatorTests.cs create mode 100644 src/Library.Tests/Library.Tests.csproj create mode 100644 src/Library.Tests/app.config create mode 100644 src/Library/Calculator.cs create mode 100644 src/Library/Library.csproj create mode 100644 src/lib.template.sln create mode 100644 src/shipping.ruleset create mode 100644 src/strongname.snk create mode 100644 src/stylecop.json create mode 100644 src/tests.ruleset create mode 100644 version.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..1ff0c423 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,63 @@ +############################################################################### +# Set default behavior to automatically normalize line endings. +############################################################################### +* text=auto + +############################################################################### +# Set default behavior for command prompt diff. +# +# This is need for earlier builds of msysgit that does not have it on by +# default for csharp files. +# Note: This is only used by command line +############################################################################### +#*.cs diff=csharp + +############################################################################### +# Set the merge driver for project and solution files +# +# Merging from the command prompt will add diff markers to the files if there +# are conflicts (Merging from VS is not affected by the settings below, in VS +# the diff markers are never inserted). Diff markers may cause the following +# file extensions to fail to load in VS. An alternative would be to treat +# these files as binary and thus will always conflict and require user +# intervention with every merge. To do so, just uncomment the entries below +############################################################################### +#*.sln merge=binary +#*.csproj merge=binary +#*.vbproj merge=binary +#*.vcxproj merge=binary +#*.vcproj merge=binary +#*.dbproj merge=binary +#*.fsproj merge=binary +#*.lsproj merge=binary +#*.wixproj merge=binary +#*.modelproj merge=binary +#*.sqlproj merge=binary +#*.wwaproj merge=binary + +############################################################################### +# behavior for image files +# +# image files are treated as binary by default. +############################################################################### +#*.jpg binary +#*.png binary +#*.gif binary + +############################################################################### +# diff behavior for common document formats +# +# Convert binary document formats to text before diffing them. This feature +# is only available from the command line. Turn it on by uncommenting the +# entries below. +############################################################################### +#*.doc diff=astextplain +#*.DOC diff=astextplain +#*.docx diff=astextplain +#*.DOCX diff=astextplain +#*.dot diff=astextplain +#*.DOT diff=astextplain +#*.pdf diff=astextplain +#*.PDF diff=astextplain +#*.rtf diff=astextplain +#*.RTF diff=astextplain diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..846c8c0a --- /dev/null +++ b/.gitignore @@ -0,0 +1,349 @@ +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ \ No newline at end of file diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 00000000..f910c687 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,18 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "ms-azure-devops.azure-pipelines", + "ms-vscode.csharp", + "k--kato.docomment", + "editorconfig.editorconfig", + "pflannery.vscode-versionlens", + "davidanson.vscode-markdownlint" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [ + + ] +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..2f36ba66 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,24 @@ +# Contributing + +This project has adopted the [Microsoft Open Source Code of +Conduct](https://opensource.microsoft.com/codeofconduct/). +For more information see the [Code of Conduct +FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or +contact [opencode@microsoft.com](mailto:opencode@microsoft.com) +with any additional questions or comments. + +## Prerequisites + +The only prerequisite for building, testing, and deploying from this repository +is the [.NET SDK](https://get.dot.net/). +You should install the version specified in `global.json` or a later version within +the same major.minor.Bxx "hundreds" band. +For example if 2.2.300 is specified, you may install 2.2.300, 2.2.301, or 2.2.310 +while the 2.2.400 version would not be considered compatible by .NET SDK. +See [.NET Core Versioning](https://docs.microsoft.com/en-us/dotnet/core/versions/) for more information. + +This repository can be built on Windows, Linux, and OSX. + +## Building + +Building, testing, and packing this repository can be done by using the standard dotnet CLI commands (e.g. `dotnet build`, `dotnet test`, `dotnet pack`, etc.). diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..3bb6360c --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) PLACEHOLDER + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 00000000..e99ca933 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +# Your Library + +***An awesome template for your awesome library*** + +![NuGet package](https://img.shields.io/badge/nuget-your--package--here-yellow.svg) +[![Build Status](https://dev.azure.com/andrewarnott/OSS/_apis/build/status/AArnott.Library.Template?branchName=master)](https://dev.azure.com/andrewarnott/OSS/_build/latest?definitionId=29&branchName=master) +[![codecov](https://codecov.io/gh/aarnott/library.template/branch/master/graph/badge.svg)](https://codecov.io/gh/aarnott/library.template) + +## Features + +* Follow the best and simplest patterns of build, pack and test with dotnet CLI. +* Static analyzers: [FxCop](https://docs.microsoft.com/en-us/visualstudio/code-quality/fxcop-analyzers?view=vs-2019) and [StyleCop](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) +* Read-only source tree (builds to top-level bin/obj folders) +* Auto-versioning (via [Nerdbank.GitVersioning](https://github.com/aarnott/nerdbank.gitversioning)) +* Azure Pipeline via YAML with all dependencies declared for long-term serviceability. +* Testing on .NET Framework, multiple .NET Core versions +* Testing on Windows, Linux and OSX +* Code coverage published to Azure Pipelines +* Code coverage published to codecov.io so GitHub PRs get code coverage results added as a PR comment + +## Consumption + +Once you've expanded this template for your own use, you should: + +1. Verify the license is suitable for your goal as it appears in the LICENSE and stylecop.json files + and the Directory.Build.props file's `PackageLicenseExpression` property. +1. Search the repo for all `PLACEHOLDER` occurrences and replace them. +1. Regenerate `src\strongname.snk` file: `sn -k src\strongname.snk` +1. Rename project files, directories, namespaces, and update sln file to match. +1. Reset or remove the `codecov_token` variable in `azure-pipelines.yml` +1. Reset or replace the badges at the top of this file. diff --git a/azure-pipelines.yml b/azure-pipelines.yml new file mode 100644 index 00000000..6d7cf769 --- /dev/null +++ b/azure-pipelines.yml @@ -0,0 +1,58 @@ +trigger: + branches: + include: + - master + - validate/* + paths: + exclude: + - doc/ + - '*.md' + - .vscode/ + +variables: + TreatWarningsAsErrors: true + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + BuildConfiguration: Release + BuildPlatform: Any CPU + codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # PLACEHOLDER - Get a new one from https://codecov.io/ + +jobs: +- job: Windows + pool: Hosted Windows 2019 with VS2019 + steps: + - template: azure-pipelines/install-dependencies.yml + + - powershell: | + dotnet tool install --tool-path .. nbgv + ../nbgv cloud + displayName: Set build number + workingDirectory: src + + - template: azure-pipelines/dotnet.yml + - template: azure-pipelines/collect-deployables.yml + - template: azure-pipelines/collect-logs.yml + + - task: NuGetCommand@2 + displayName: Push packages to CI feed + inputs: + command: push + packagesToPush: $(Build.ArtifactStagingDirectory)/deployables/*.nupkg;$(Build.ArtifactStagingDirectory)/deployables/*.snupkg + nuGetFeedType: internal + publishVstsFeed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # PLACEHOLDER + allowPackageConflicts: true + +- job: Linux + pool: + vmImage: Ubuntu 16.04 + steps: + - template: azure-pipelines/install-dependencies.yml + - template: azure-pipelines/dotnet.yml + - template: azure-pipelines/collect-logs.yml + +- job: macOS + pool: + vmImage: macOS 10.13 + steps: + - template: azure-pipelines/install-dependencies.yml + - template: azure-pipelines/dotnet.yml + - template: azure-pipelines/collect-logs.yml diff --git a/azure-pipelines/collect-deployables.yml b/azure-pipelines/collect-deployables.yml new file mode 100644 index 00000000..5d77acfc --- /dev/null +++ b/azure-pipelines/collect-deployables.yml @@ -0,0 +1,15 @@ +steps: +- task: CopyFiles@1 + inputs: + Contents: | + bin/Packages/$(BuildConfiguration)/* + TargetFolder: $(Build.ArtifactStagingDirectory)/deployables + flattenFolders: true + displayName: Collecting deployable artifacts + +- task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.ArtifactStagingDirectory)/deployables + ArtifactName: deployables + ArtifactType: Container + displayName: Publish deployables artifacts diff --git a/azure-pipelines/collect-logs.yml b/azure-pipelines/collect-logs.yml new file mode 100644 index 00000000..ab39d91f --- /dev/null +++ b/azure-pipelines/collect-logs.yml @@ -0,0 +1,9 @@ +steps: + +- task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.ArtifactStagingDirectory)/build_logs + ArtifactName: build_logs-$(Agent.JobName) + ArtifactType: Container + displayName: Publish build_logs artifacts + condition: succeededOrFailed() diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml new file mode 100644 index 00000000..f53bc803 --- /dev/null +++ b/azure-pipelines/dotnet.yml @@ -0,0 +1,64 @@ +steps: +- script: dotnet restore /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/restore.binlog" + displayName: dotnet restore + workingDirectory: src + +- script: dotnet build --no-restore -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" + displayName: dotnet build + workingDirectory: src + +- script: dotnet pack --no-build -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/pack.binlog" + displayName: dotnet pack + workingDirectory: src + +- script: dotnet test --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/net472.trx" /p:CollectCoverage=true + displayName: dotnet test -f net472 + workingDirectory: src + condition: eq(variables['Agent.OS'], 'Windows_NT') + +- script: dotnet test --no-build -c $(BuildConfiguration) -f netcoreapp2.0 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/netcoreapp2.0.trx" /p:CollectCoverage=true + displayName: dotnet test -f netcoreapp2.0 + workingDirectory: src + +- script: dotnet test --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/netcoreapp2.1.trx" /p:CollectCoverage=true + displayName: dotnet test -f netcoreapp2.1 + workingDirectory: src + +- script: dotnet test --no-build -c $(BuildConfiguration) -f netcoreapp2.2 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/netcoreapp2.2.trx" /p:CollectCoverage=true + displayName: dotnet test -f netcoreapp2.2 + workingDirectory: src + +- task: PublishTestResults@2 + displayName: Publish test results + inputs: + testRunner: VSTest + #mergeTestResults: true + testResultsFormat: trx + testResultsFiles: $(Build.ArtifactStagingDirectory)/testlogs/*.trx + failTaskOnFailedTests: true + +- task: PublishCodeCoverageResults@1 + displayName: Publish code coverage results to Azure DevOps + inputs: + codeCoverageTool: cobertura + summaryFileLocation: '**/coverage.cobertura.xml' + +- bash: bash <(curl -s https://codecov.io/bash) + displayName: Publish code coverage results to codecov.io + condition: ne(variables['codecov_token'], '') + +- task: CopyFiles@1 + inputs: + Contents: | + obj/**/project.assets.json + TargetFolder: $(Build.ArtifactStagingDirectory)/projectAssetsJson + displayName: Collecting project.assets.json artifacts + condition: succeededOrFailed() + +- task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.ArtifactStagingDirectory)/projectAssetsJson + ArtifactName: projectAssetsJson-$(Agent.JobName) + ArtifactType: Container + displayName: Publish projectAssetsJson artifacts + condition: succeededOrFailed() diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml new file mode 100644 index 00000000..80830cc7 --- /dev/null +++ b/azure-pipelines/install-dependencies.yml @@ -0,0 +1,25 @@ +steps: +- script: dotnet --info + displayName: .NET Core SDK/runtimes (on host) + workingDirectory: $(Agent.HomeDirectory) + +- task: UseDotNet@2 + displayName: Install .NET Core SDK 2.2.300 + inputs: + packageType: sdk + version: 2.2.300 + +- task: UseDotNet@2 + displayName: Install .NET Core runtime 2.0.x + inputs: + packageType: runtime + version: 2.0.x + +- task: UseDotNet@2 + displayName: Install .NET Core runtime 2.1.x + inputs: + packageType: runtime + version: 2.1.x + +- script: dotnet --info + displayName: .NET Core SDK/runtimes (explicitly installed) diff --git a/global.json b/global.json new file mode 100644 index 00000000..93238784 --- /dev/null +++ b/global.json @@ -0,0 +1,5 @@ +{ + "sdk": { + "version": "2.2.300" + } +} \ No newline at end of file diff --git a/nuget.config b/nuget.config new file mode 100644 index 00000000..4941d22b --- /dev/null +++ b/nuget.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 00000000..94cda0d5 --- /dev/null +++ b/src/.editorconfig @@ -0,0 +1,157 @@ +# EditorConfig is awesome:http://EditorConfig.org + +# top-most EditorConfig file +root = true + +# Don't use tabs for indentation. +[*] +indent_style = space + +# (Please don't specify an indent_size here; that has too many unintended consequences.) + +# Code files +[*.{cs,csx,vb,vbx,h,cpp,idl}] +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +# Xml project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +indent_size = 2 + +# Xml config files +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# Dotnet code style settings: +[*.{cs,vb}] +# Sort using and Import directives with System.* appearing first +dotnet_sort_system_directives_first = true +dotnet_style_qualification_for_field = true:warning +dotnet_style_qualification_for_property = true:warning +dotnet_style_qualification_for_method = true:warning +dotnet_style_qualification_for_event = true:warning + +# Use language keywords instead of framework type names for type references +dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion +dotnet_style_predefined_type_for_member_access = true:suggestion + +# Suggest more modern language features when available +dotnet_style_object_initializer = true:suggestion +dotnet_style_collection_initializer = true:suggestion +dotnet_style_coalesce_expression = true:suggestion +dotnet_style_null_propagation = true:suggestion +dotnet_style_explicit_tuple_names = true:suggestion + +# Non-private static fields are PascalCase +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style + +dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected +dotnet_naming_symbols.non_private_static_fields.required_modifiers = static + +dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case + +# Constants are PascalCase +dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_style.constant_style.capitalization = pascal_case + +# Static fields are camelCase +dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields +dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style + +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static + +dotnet_naming_style.static_field_style.capitalization = camel_case + +# Instance fields are camelCase +dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields +dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style + +dotnet_naming_symbols.instance_fields.applicable_kinds = field + +dotnet_naming_style.instance_field_style.capitalization = camel_case + +# Locals and parameters are camelCase +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Local functions are PascalCase +dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function + +dotnet_naming_style.local_function_style.capitalization = pascal_case + +# By default, name items with PascalCase +dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.all_members.applicable_kinds = * + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + +# CSharp code style settings: +[*.cs] +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + +# Prefer "var" everywhere +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion + +# Prefer method-like constructs to have a block body +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none + +# Prefer property-like constructs to have an expression-body +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none + +# Suggest more modern language features when available +csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion +csharp_style_pattern_matching_over_as_with_null_check = true:suggestion +csharp_style_inlined_variable_declaration = true:suggestion +csharp_style_throw_expression = true:suggestion +csharp_style_conditional_delegate_call = true:suggestion + +# Newline settings +csharp_new_line_before_open_brace = all +csharp_new_line_before_else = true +csharp_new_line_before_catch = true +csharp_new_line_before_finally = true +csharp_new_line_before_members_in_object_initializers = true +csharp_new_line_before_members_in_anonymous_types = true + +# Blocks are allowed +csharp_prefer_braces = true:silent diff --git a/src/Directory.Build.props b/src/Directory.Build.props new file mode 100644 index 00000000..c3f28530 --- /dev/null +++ b/src/Directory.Build.props @@ -0,0 +1,35 @@ + + + + Debug + $(MSBuildThisFileDirectory)..\obj\$(MSBuildProjectName)\ + $(MSBuildThisFileDirectory)..\bin\$(MSBuildProjectName)\ + $(MSBuildThisFileDirectory)..\bin\Packages\$(Configuration)\ + 7.3 + true + + true + $(MSBuildThisFileDirectory)\strongname.snk + + PLACEHOLDER + PLACEHOLDER + MIT + true + true + true + snupkg + $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets new file mode 100644 index 00000000..1ddcba6f --- /dev/null +++ b/src/Directory.Build.targets @@ -0,0 +1,8 @@ + + + cobertura + [xunit.*]* + + $(OutputPath)/ + + diff --git a/src/Library.Tests/CalculatorTests.cs b/src/Library.Tests/CalculatorTests.cs new file mode 100644 index 00000000..506ca1b8 --- /dev/null +++ b/src/Library.Tests/CalculatorTests.cs @@ -0,0 +1,28 @@ +// Copyright (c) PLACEHOLDER. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using Library; +using Xunit; +using Xunit.Abstractions; + +public class CalculatorTests +{ + private readonly ITestOutputHelper logger; + + public CalculatorTests(ITestOutputHelper logger) + { + this.logger = logger; + } + + [Fact] + public void AddOrSubtract() + { + // This tests aggregation of code coverage. +#if NETCOREAPP2_0 + Assert.Equal(3, Calculator.Add(1, 2)); +#else + Assert.Equal(-1, Calculator.Subtract(1, 2)); +#endif + } +} diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj new file mode 100644 index 00000000..fc885418 --- /dev/null +++ b/src/Library.Tests/Library.Tests.csproj @@ -0,0 +1,29 @@ + + + + net472;netcoreapp2.0;netcoreapp2.1;netcoreapp2.2 + false + $(NoWarn);CS1591 + true + ..\tests.ruleset + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + diff --git a/src/Library.Tests/app.config b/src/Library.Tests/app.config new file mode 100644 index 00000000..61890f05 --- /dev/null +++ b/src/Library.Tests/app.config @@ -0,0 +1,5 @@ + + + + + diff --git a/src/Library/Calculator.cs b/src/Library/Calculator.cs new file mode 100644 index 00000000..82679050 --- /dev/null +++ b/src/Library/Calculator.cs @@ -0,0 +1,29 @@ +// Copyright (c) PLACEHOLDER. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Library +{ + using System; + + /// + /// My first class. + /// + public static class Calculator + { + /// + /// Adds two integers. + /// + /// The first integer. + /// The second integer. + /// The sum of the two integers. + public static int Add(int a, int b) => a + b; + + /// + /// Subtracts one integer from another. + /// + /// The original integer. + /// The integer to subtract. + /// The difference between the two integers. + public static int Subtract(int a, int b) => a - b; + } +} diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj new file mode 100644 index 00000000..aa8cf2c6 --- /dev/null +++ b/src/Library/Library.csproj @@ -0,0 +1,10 @@ + + + + netstandard2.0 + ..\shipping.ruleset + + PLACEHOLDER + + + diff --git a/src/lib.template.sln b/src/lib.template.sln new file mode 100644 index 00000000..17645391 --- /dev/null +++ b/src/lib.template.sln @@ -0,0 +1,28 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 15 +VisualStudioVersion = 15.0.26124.0 +MinimumVisualStudioVersion = 15.0.26124.0 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library", "Library\Library.csproj", "{C06D702E-6FC7-453B-BDDF-608F825EC003}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library.Tests", "Library.Tests\Library.Tests.csproj", "{DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {C06D702E-6FC7-453B-BDDF-608F825EC003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C06D702E-6FC7-453B-BDDF-608F825EC003}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C06D702E-6FC7-453B-BDDF-608F825EC003}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C06D702E-6FC7-453B-BDDF-608F825EC003}.Release|Any CPU.Build.0 = Release|Any CPU + {DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection +EndGlobal diff --git a/src/shipping.ruleset b/src/shipping.ruleset new file mode 100644 index 00000000..72903546 --- /dev/null +++ b/src/shipping.ruleset @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/strongname.snk b/src/strongname.snk new file mode 100644 index 0000000000000000000000000000000000000000..a4d0a2ce39df5f7c284340b4a2c4690385c44208 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097Td7B6KsP|cl#<{bONo_!&t)QUG9wW^j zM1zvNAOI=XF}potSO>54lS%MGl8tv)xYTSw?~K<1McvNlJ;DITeY__C?><|;F`bgX zj;&2ME}KBWPb0zVSK+iW?{2`tzZR-#x0K_|t&0FhD+3urA!lNmCH;&b|?g|_AC39ox-0 zcV%KJis3}%`RVWSXN58fc}#LF$A#kcB2VWh=MH0zs+k7{ zQT<5V>NGhWzC7Jnt4A?n%Kk`fPt&FR4k~q{TSW%@D{plIpotzop}i+x`~C))*Vr-i zrW2)aE17f*=wCRa_#bHkYlQko_Jh)wN@;?yML9mYk)XZ`l6IQ*D7xZmmL=m(T|zMG i={(T>StYQl!YSPV literal 0 HcmV?d00001 diff --git a/src/stylecop.json b/src/stylecop.json new file mode 100644 index 00000000..f1d8168c --- /dev/null +++ b/src/stylecop.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": "PLACEHOLDER", + "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.", + "variables": { + "licenseName": "MIT", + "licenseFile": "LICENSE" + }, + "fileNamingConvention": "metadata", + "xmlHeader": false + } + } +} \ No newline at end of file diff --git a/src/tests.ruleset b/src/tests.ruleset new file mode 100644 index 00000000..c74c6ed3 --- /dev/null +++ b/src/tests.ruleset @@ -0,0 +1,83 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/version.json b/version.json new file mode 100644 index 00000000..38da1662 --- /dev/null +++ b/version.json @@ -0,0 +1,8 @@ +{ + "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "version": "0.1-beta", + "publicReleaseRefSpec": [ + "^refs/heads/master$", + "^refs/heads/v\\d+(?:\\.\\d+)?$" + ] +} \ No newline at end of file From 9a6c1df41cb75c41b7b5039aaddbe59456a93366 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 16 Jun 2019 21:32:09 -0600 Subject: [PATCH 002/704] Add VS Code whitespace settings --- .vscode/settings.json | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 00000000..f0cafc05 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,5 @@ +{ + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true +} From 26696c117d5f65dbcdf91209ae0b0816593cec4d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 16 Jun 2019 22:24:54 -0600 Subject: [PATCH 003/704] Add script for proper expansion Closes #3 --- Expand-Template.ps1 | 148 ++++++++++++++++++++++++++ LICENSE | 2 +- README.md | 13 +-- azure-pipelines.yml | 11 +- azure-pipelines/expand-template.yml | 10 ++ src/Directory.Build.props | 6 +- src/Library.Tests/CalculatorTests.cs | 2 +- src/{lib.template.sln => Library.sln} | 0 src/Library/Calculator.cs | 2 +- src/Library/Library.csproj | 2 - src/stylecop.json | 4 +- 11 files changed, 179 insertions(+), 21 deletions(-) create mode 100644 Expand-Template.ps1 create mode 100644 azure-pipelines/expand-template.yml rename src/{lib.template.sln => Library.sln} (100%) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 new file mode 100644 index 00000000..edde82a0 --- /dev/null +++ b/Expand-Template.ps1 @@ -0,0 +1,148 @@ +<# +.SYNOPSIS +Expands this template into an actual project, taking values for placeholders +.PARAMETER Name +The name of the library +#> +[CmdletBinding()] +Param( + [Parameter(Mandatory=$true)] + [string]$LibraryName, + [Parameter(Mandatory=$true)] + [string]$Author, + [Parameter()] + [string]$CodeCovToken, + [Parameter()] + [string]$CIFeed +) + +function Replace-Placeholders { + [CmdletBinding()] + param( + [Parameter(Mandatory=$true)] + [string]$Path, + [Parameter(Mandatory=$true)] + $Replacements + ) + + $Path = Resolve-Path $Path + Write-Host "Replacing tokens in `"$Path`"" + $content = Get-Content -Path $Path | Out-String + $Replacements.GetEnumerator() |% { + $modifiedContent = $content -replace $_.Key,$_.Value + if ($modifiedContent -eq $content) { + Write-Error "No $($_.Key) token found to replace." + } + $content = $modifiedContent + } + $content = $content.TrimEnd(("`r","`n")) + [System.IO.File]::WriteAllLines($Path, $content) # Don't use Set-Content because that adds a UTF8 BOM + git add $Path +} + +# Try to find sn.exe if it isn't on the PATH +$sn = Get-Command sn -ErrorAction SilentlyContinue +if (-not $sn) { + $snExes = Get-ChildItem -Recurse "${env:ProgramFiles(x86)}\Microsoft SDKs\Windows\sn.exe" + if ($snExes) { + $sn = Get-Command $snExes[0].FullName + } else { + Write-Error "sn command not found on PATH and SDK could not be found." + exit(1) + } +} + +# Verify all commands we use are on the PATH +('git','dotnet') |% { + if (-not (Get-Command $_ -ErrorAction SilentlyContinue)) { + Write-Error "$_ command not found on PATH." + exit(1) + } +} + +Push-Location $PSScriptRoot +try { + # Rename project directories and solution + Set-Location src + git mv Library.sln "$LibraryName.sln" + git mv Library/Library.csproj "Library/$LibraryName.csproj" + git mv Library "$LibraryName" + git mv Library.Tests/Library.Tests.csproj "Library.Tests/$LibraryName.Tests.csproj" + git mv Library.Tests "$LibraryName.Tests" + + # Refresh solution file both to update paths and give the projects unique GUIDs + dotnet sln remove Library/Library.csproj + dotnet sln remove Library.Tests/Library.Tests.csproj + dotnet sln add "$LibraryName" + dotnet sln add "$LibraryName.Tests" + git add "$LibraryName.sln" + + # Update project reference in test project. Add before removal to keep the same ItemGroup in place. + dotnet add "$LibraryName.Tests" reference "$LibraryName" + dotnet remove "$LibraryName.Tests" reference Library/Library.csproj + git add "$LibraryName.Tests/$LibraryName.Tests.csproj" + + # Establish a new strong-name key + & $sn.Path -k 2048 strongname.snk + git add strongname.snk + + Set-Location .. + + # Replace placeholders in source files + Replace-Placeholders -Path "src/$LibraryName/Calculator.cs" -Replacements @{ + 'Library'=$LibraryName + 'COMPANY-PLACEHOLDER'=$Author + } + Replace-Placeholders -Path "src/$LibraryName.Tests/CalculatorTests.cs" -Replacements @{ + 'Library'=$LibraryName + 'COMPANY-PLACEHOLDER'=$Author + } + Replace-Placeholders -Path "LICENSE" -Replacements @{ + 'COMPANY-PLACEHOLDER'=$Author + } + Replace-Placeholders -Path "src/stylecop.json" -Replacements @{ + 'COMPANY-PLACEHOLDER'=$Author + } + Replace-Placeholders -Path "src/Directory.Build.props" -Replacements @{ + 'COMPANY-PLACEHOLDER'=$Author + } + Replace-Placeholders -Path "README.md" -Replacements @{ + "(?m)^.*\[NuGet package\][^`r`n]*"="[![NuGet package](https://img.shields.io/nuget/v/$LibraryName.svg)](https://nuget.org/packages/$LibraryName)" + "(?m)^.*\[Build Status\].*`r?`n"="" + "(?m)^.*\[codecov\].*`r?`n"="" + } + + # Specially handle azure-pipelines.yml edits + $YmlReplacements = @{ + "(?m).*expand-template\.yml(?:\r)?\n" = "" + } + if ($CodeCovToken) { + $YmlReplacements['(codecov_token: ).*(#.*)'] = "`$1$CodeCovToken" + } else { + $YmlReplacements['(codecov_token: ).*(#.*)'] = "#`$1`$2" + } + if ($CIFeed) { + $YmlReplacements['(ci_feed: ).*(#.*)'] = "`$1$CIFeed" + } else { + $YmlReplacements['(ci_feed: ).*(#.*)'] = "#`$1`$2" + } + Replace-Placeholders -Path "azure-pipelines.yml" -Replacements $YmlReplacements + + # Self destruct + $Invocation = (Get-Variable MyInvocation -Scope 1).Value + git rm Expand-Template.ps1 + git rm :/azure-pipelines/expand-template.yml + + # Self-integrity check + Get-ChildItem -Recurse -File -Exclude bin,obj,README.md,Expand-Template.ps1 |? { -not $_.FullName.Contains("obj") } |% { + $PLACEHOLDERS = Get-Content -Path $_.FullName |? { $_.Contains('PLACEHOLDER') } + if ($PLACEHOLDERS) { + Write-Error "PLACEHOLDER discovered in $($_.FullName)" + } + } +} finally { + Pop-Location +} + +# When testing this script, all the changes can be quickly reverted with this command: +# git reset HEAD :/README.md :/LICENSE :/azure-pipelines.yml :/src :/azure-pipelines; git co -- :/README.md :/LICENSE :/azure-pipelines.yml :/src :/azure-pipelines; git clean -fd :/src diff --git a/LICENSE b/LICENSE index 3bb6360c..44122ac6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) PLACEHOLDER +Copyright (c) COMPANY-PLACEHOLDER Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index e99ca933..d05ac0d7 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,9 @@ ## Consumption -Once you've expanded this template for your own use, you should: - -1. Verify the license is suitable for your goal as it appears in the LICENSE and stylecop.json files - and the Directory.Build.props file's `PackageLicenseExpression` property. -1. Search the repo for all `PLACEHOLDER` occurrences and replace them. -1. Regenerate `src\strongname.snk` file: `sn -k src\strongname.snk` -1. Rename project files, directories, namespaces, and update sln file to match. -1. Reset or remove the `codecov_token` variable in `azure-pipelines.yml` +Once you've expanded this template for your own use, you should **run the `Expand-Template.ps1` script** to customize the template for your own project. + +Further customize your repo by: + +1. Verify the license is suitable for your goal as it appears in the LICENSE and stylecop.json files and the Directory.Build.props file's `PackageLicenseExpression` property. 1. Reset or replace the badges at the top of this file. diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 6d7cf769..a670bbef 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,13 +8,14 @@ trigger: - doc/ - '*.md' - .vscode/ - + variables: TreatWarningsAsErrors: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BuildConfiguration: Release BuildPlatform: Any CPU - codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # PLACEHOLDER - Get a new one from https://codecov.io/ + codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ + ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed jobs: - job: Windows @@ -31,6 +32,7 @@ jobs: - template: azure-pipelines/dotnet.yml - template: azure-pipelines/collect-deployables.yml - template: azure-pipelines/collect-logs.yml + - template: azure-pipelines/expand-template.yml - task: NuGetCommand@2 displayName: Push packages to CI feed @@ -38,8 +40,9 @@ jobs: command: push packagesToPush: $(Build.ArtifactStagingDirectory)/deployables/*.nupkg;$(Build.ArtifactStagingDirectory)/deployables/*.snupkg nuGetFeedType: internal - publishVstsFeed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # PLACEHOLDER + publishVstsFeed: $(ci_feed) allowPackageConflicts: true + condition: ne(variables['ci_feed'], '') - job: Linux pool: @@ -48,6 +51,7 @@ jobs: - template: azure-pipelines/install-dependencies.yml - template: azure-pipelines/dotnet.yml - template: azure-pipelines/collect-logs.yml + - template: azure-pipelines/expand-template.yml - job: macOS pool: @@ -56,3 +60,4 @@ jobs: - template: azure-pipelines/install-dependencies.yml - template: azure-pipelines/dotnet.yml - template: azure-pipelines/collect-logs.yml + - template: azure-pipelines/expand-template.yml diff --git a/azure-pipelines/expand-template.yml b/azure-pipelines/expand-template.yml new file mode 100644 index 00000000..74960e56 --- /dev/null +++ b/azure-pipelines/expand-template.yml @@ -0,0 +1,10 @@ +steps: +- script: git clean -fdx + displayName: Cleaning repo for template expansion +- powershell: ./Expand-Template.ps1 -LibraryName Calc -Author "Andrew Arnott" + displayName: Expanding template + failOnStderr: true +# TODO: Verify that all changes are staged to the git index +- script: dotnet build + workingDirectory: src + displayName: dotnet build (expanded template) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index c3f28530..7b354beb 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -11,8 +11,8 @@ true $(MSBuildThisFileDirectory)\strongname.snk - PLACEHOLDER - PLACEHOLDER + COMPANY-PLACEHOLDER + COMPANY-PLACEHOLDER MIT true true @@ -32,4 +32,4 @@ - \ No newline at end of file + diff --git a/src/Library.Tests/CalculatorTests.cs b/src/Library.Tests/CalculatorTests.cs index 506ca1b8..2166fb1f 100644 --- a/src/Library.Tests/CalculatorTests.cs +++ b/src/Library.Tests/CalculatorTests.cs @@ -1,4 +1,4 @@ -// Copyright (c) PLACEHOLDER. All rights reserved. +// Copyright (c) COMPANY-PLACEHOLDER. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; diff --git a/src/lib.template.sln b/src/Library.sln similarity index 100% rename from src/lib.template.sln rename to src/Library.sln diff --git a/src/Library/Calculator.cs b/src/Library/Calculator.cs index 82679050..9156a1a3 100644 --- a/src/Library/Calculator.cs +++ b/src/Library/Calculator.cs @@ -1,4 +1,4 @@ -// Copyright (c) PLACEHOLDER. All rights reserved. +// Copyright (c) COMPANY-PLACEHOLDER. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. namespace Library diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index aa8cf2c6..ae6eca97 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -3,8 +3,6 @@ netstandard2.0 ..\shipping.ruleset - - PLACEHOLDER diff --git a/src/stylecop.json b/src/stylecop.json index f1d8168c..37918949 100644 --- a/src/stylecop.json +++ b/src/stylecop.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", "settings": { "documentationRules": { - "companyName": "PLACEHOLDER", + "companyName": "COMPANY-PLACEHOLDER", "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.", "variables": { "licenseName": "MIT", @@ -12,4 +12,4 @@ "xmlHeader": false } } -} \ No newline at end of file +} From 159d180e61350798bbbc3fc94845ac0242a8fc11 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 18 Jun 2019 07:08:34 -0600 Subject: [PATCH 004/704] Fix test run names --- azure-pipelines/dotnet.yml | 42 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index f53bc803..3e294f0b 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -11,37 +11,45 @@ steps: displayName: dotnet pack workingDirectory: src -- script: dotnet test --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/net472.trx" /p:CollectCoverage=true +- task: DotNetCoreCLI@2 displayName: dotnet test -f net472 - workingDirectory: src + inputs: + command: test + arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + testRunTitle: net472-$(Agent.JobName) + workingDirectory: src condition: eq(variables['Agent.OS'], 'Windows_NT') -- script: dotnet test --no-build -c $(BuildConfiguration) -f netcoreapp2.0 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/netcoreapp2.0.trx" /p:CollectCoverage=true +- task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp2.0 - workingDirectory: src + inputs: + command: test + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + testRunTitle: netcoreapp2.0-$(Agent.JobName) + workingDirectory: src -- script: dotnet test --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/netcoreapp2.1.trx" /p:CollectCoverage=true +- task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp2.1 - workingDirectory: src - -- script: dotnet test --no-build -c $(BuildConfiguration) -f netcoreapp2.2 --filter "TestCategory!=FailsInCloudTest" -v n -l "trx;LogFileName=$(Build.ArtifactStagingDirectory)/testlogs/netcoreapp2.2.trx" /p:CollectCoverage=true + inputs: + command: test + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + testRunTitle: netcoreapp2.1-$(Agent.JobName) + workingDirectory: src + +- task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp2.2 - workingDirectory: src - -- task: PublishTestResults@2 - displayName: Publish test results inputs: - testRunner: VSTest - #mergeTestResults: true - testResultsFormat: trx - testResultsFiles: $(Build.ArtifactStagingDirectory)/testlogs/*.trx - failTaskOnFailedTests: true + command: test + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.2 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + testRunTitle: netcoreapp2.2-$(Agent.JobName) + workingDirectory: src - task: PublishCodeCoverageResults@1 displayName: Publish code coverage results to Azure DevOps inputs: codeCoverageTool: cobertura summaryFileLocation: '**/coverage.cobertura.xml' + failIfCoverageEmpty: true - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io From 42d3ae5b22f73214c17035277317bf324a430eeb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 20 Jun 2019 15:25:57 -0600 Subject: [PATCH 005/704] Fill in missing parameter docs in the ps1 script --- Expand-Template.ps1 | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index edde82a0..c1447d4c 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -1,8 +1,15 @@ <# .SYNOPSIS Expands this template into an actual project, taking values for placeholders -.PARAMETER Name -The name of the library +.PARAMETER LibraryName +The name of the library. Should consist only of alphanumeric characters and periods. +.PARAMETER Author +The name to use in copyright and owner notices. +.PARAMETER CodeCovToken +A token obtained from codecov.io for your repo. If not specified, code coverage results will not be published to codecov.io, +but can be added later by editing the Azure Pipelines YAML file. +.PARAMETER CIFeed +The `/{guid}` path to the Azure Pipelines artifact feed to push your nuget package to as part of your CI. #> [CmdletBinding()] Param( From 0f19c143cae80dbcf9079d18d6aba4592abbbd10 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 21 Jun 2019 07:32:46 -0600 Subject: [PATCH 006/704] Publish merged code coverage from all test runs on Windows agent Merge code coverage from all test runs on each agent. Although we capture that merged result from each agent as its own build artifact, we have to pick just one agent's merged result to publish to ADO as the summary file. --- azure-pipelines/dotnet.yml | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 3e294f0b..b86e4bd3 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -44,12 +44,27 @@ steps: testRunTitle: netcoreapp2.2-$(Agent.JobName) workingDirectory: src +- powershell: | + dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool + $Inputs = [string]::join(';', (Get-ChildItem bin/coverage.cobertura.xml -Recurse |% { Resolve-Path -Relative $_ })) + obj/reportgenerator -reports:"$Inputs" -targetdir:"$(Build.ArtifactStagingDirectory)/coverageResults" -reporttypes:Cobertura + displayName: Merge code coverage results + +- task: PublishBuildArtifacts@1 + inputs: + PathtoPublish: $(Build.ArtifactStagingDirectory)/coverageResults + ArtifactName: coverageResults-$(Agent.JobName) + ArtifactType: Container + displayName: Publish coverageResults artifacts + condition: succeededOrFailed() + - task: PublishCodeCoverageResults@1 displayName: Publish code coverage results to Azure DevOps inputs: codeCoverageTool: cobertura - summaryFileLocation: '**/coverage.cobertura.xml' + summaryFileLocation: $(Build.ArtifactStagingDirectory)/coverageResults/Cobertura.xml failIfCoverageEmpty: true + condition: eq(variables['Agent.OS'], 'Windows_NT') # We have to pick just one agent to publish the code coverage summary file (https://github.com/tonerdo/coverlet/issues/474#issuecomment-504446150) - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io From fc34ef4c21bed5c1c06c5df75800f74db297d03a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 21 Jun 2019 11:57:51 -0600 Subject: [PATCH 007/704] Merge code coverage from all test runs and agents (#9) --- azure-pipelines.yml | 11 ++++++++ azure-pipelines/dotnet.yml | 28 ++++++++++--------- azure-pipelines/publish-codecoverage.yml | 34 ++++++++++++++++++++++++ 3 files changed, 61 insertions(+), 12 deletions(-) create mode 100644 azure-pipelines/publish-codecoverage.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a670bbef..a41bc336 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -61,3 +61,14 @@ jobs: - template: azure-pipelines/dotnet.yml - template: azure-pipelines/collect-logs.yml - template: azure-pipelines/expand-template.yml + +- job: MergeCoverage + dependsOn: + - Windows + - Linux + - macOS + pool: + vmImage: Ubuntu 16.04 + steps: + - template: azure-pipelines/install-dependencies.yml + - template: azure-pipelines/publish-codecoverage.yml diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index b86e4bd3..72f3b5a2 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -44,11 +44,23 @@ steps: testRunTitle: netcoreapp2.2-$(Agent.JobName) workingDirectory: src +- task: CopyFiles@1 + inputs: + Contents: | + bin/**/coverage.cobertura.xml + obj/**/*.cs + TargetFolder: $(Build.ArtifactStagingDirectory)/coverageResults + displayName: Collecting coverage.cobertura.xml artifacts + condition: succeededOrFailed() + - powershell: | - dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool - $Inputs = [string]::join(';', (Get-ChildItem bin/coverage.cobertura.xml -Recurse |% { Resolve-Path -Relative $_ })) - obj/reportgenerator -reports:"$Inputs" -targetdir:"$(Build.ArtifactStagingDirectory)/coverageResults" -reporttypes:Cobertura - displayName: Merge code coverage results + Write-Host "Substituting $(System.DefaultWorkingDirectory) with {reporoot}" + $reports = Get-ChildItem "$(Build.ArtifactStagingDirectory)/coverageResults/coverage.cobertura.xml" -Recurse + $reports |% { + $content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape("$(System.DefaultWorkingDirectory)"), "{reporoot}" } + Set-Content -Path $_ -Value $content -Encoding UTF8 + } + displayName: Preparing code coverage reports for merging on another machine - task: PublishBuildArtifacts@1 inputs: @@ -58,14 +70,6 @@ steps: displayName: Publish coverageResults artifacts condition: succeededOrFailed() -- task: PublishCodeCoverageResults@1 - displayName: Publish code coverage results to Azure DevOps - inputs: - codeCoverageTool: cobertura - summaryFileLocation: $(Build.ArtifactStagingDirectory)/coverageResults/Cobertura.xml - failIfCoverageEmpty: true - condition: eq(variables['Agent.OS'], 'Windows_NT') # We have to pick just one agent to publish the code coverage summary file (https://github.com/tonerdo/coverlet/issues/474#issuecomment-504446150) - - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml new file mode 100644 index 00000000..fc530781 --- /dev/null +++ b/azure-pipelines/publish-codecoverage.yml @@ -0,0 +1,34 @@ +steps: +- task: DownloadBuildArtifacts@0 + displayName: Download Windows code coverage results + inputs: + artifactName: coverageResults-Windows + downloadPath: $(System.DefaultWorkingDirectory)/bin +- task: DownloadBuildArtifacts@0 + displayName: Download Linux code coverage results + inputs: + artifactName: coverageResults-Linux + downloadPath: $(System.DefaultWorkingDirectory)/bin +- task: DownloadBuildArtifacts@0 + displayName: Download macOS code coverage results + inputs: + artifactName: coverageResults-macOS + downloadPath: $(System.DefaultWorkingDirectory)/bin +- powershell: | + dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 + Copy-Item -Recurse $(System.DefaultWorkingDirectory)/bin/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj + Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" + $reports = Get-ChildItem -Recurse "$(System.DefaultWorkingDirectory)/bin/coverage.cobertura.xml" + $reports |% { + $content = Get-Content -Path $_ |% { $_.Replace("{reporoot}", "$(System.DefaultWorkingDirectory)") } + Set-Content -Path $_ -Value $content -Encoding UTF8 + } + $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ })) + obj/reportgenerator -reports:"$Inputs" -targetdir:coveragereport -reporttypes:Cobertura + displayName: Merge coverage +- task: PublishCodeCoverageResults@1 + displayName: Publish code coverage results to Azure DevOps + inputs: + codeCoverageTool: cobertura + summaryFileLocation: 'coveragereport/Cobertura.xml' + failIfCoverageEmpty: true From 753dd46974212dafd30b4e60d16f545a84ca695c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 24 Jun 2019 10:33:03 -0600 Subject: [PATCH 008/704] Avoid `var` when type is not apparent --- src/.editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/.editorconfig b/src/.editorconfig index 94cda0d5..03c2bcf3 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -126,7 +126,7 @@ csharp_indent_labels = flush_left # Prefer "var" everywhere csharp_style_var_for_built_in_types = true:suggestion csharp_style_var_when_type_is_apparent = true:suggestion -csharp_style_var_elsewhere = true:suggestion +csharp_style_var_elsewhere = false:warning # Prefer method-like constructs to have a block body csharp_style_expression_bodied_methods = false:none From e1d68f227cc93a873a8903bb25a78c58b979b2cf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 07:10:13 -0600 Subject: [PATCH 009/704] Update packages (#14) And a few path manipulating msbuild properties --- src/Directory.Build.props | 13 +++++++------ src/Library.Tests/Library.Tests.csproj | 12 +++--------- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 7b354beb..f4ef3297 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -2,9 +2,10 @@ Debug - $(MSBuildThisFileDirectory)..\obj\$(MSBuildProjectName)\ - $(MSBuildThisFileDirectory)..\bin\$(MSBuildProjectName)\ - $(MSBuildThisFileDirectory)..\bin\Packages\$(Configuration)\ + $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\')) + $(RepoRootPath)obj\$(MSBuildProjectName)\ + $(RepoRootPath)bin\$(MSBuildProjectName)\ + $(RepoRootPath)bin\Packages\$(Configuration)\ 7.3 true @@ -22,11 +23,11 @@ - - - + + + diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj index fc885418..b5f05f5f 100644 --- a/src/Library.Tests/Library.Tests.csproj +++ b/src/Library.Tests/Library.Tests.csproj @@ -14,16 +14,10 @@ - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - + + - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - + From 835ffb69827c68498e96caf0e27640eb939a48b2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 07:34:44 -0600 Subject: [PATCH 010/704] Drop .NET Core 2.0 targeting in test project (#13) Microsoft's long-term support for .NET Core 1.x and 2.0 [are over][LTS]. Customers targeting these versions are in a really bad place due to no security patches being offered and thus there are likely few to none out there. [LTS]: https://github.com/dotnet/core/blob/e2f22a7106860c0e5dc98bb36dc648a779944ad5/microsoft-support.md#net-core-releases --- azure-pipelines/dotnet.yml | 8 -------- src/Library.Tests/CalculatorTests.cs | 4 ++-- src/Library.Tests/Library.Tests.csproj | 2 +- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 72f3b5a2..fe055ef7 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -20,14 +20,6 @@ steps: workingDirectory: src condition: eq(variables['Agent.OS'], 'Windows_NT') -- task: DotNetCoreCLI@2 - displayName: dotnet test -f netcoreapp2.0 - inputs: - command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true - testRunTitle: netcoreapp2.0-$(Agent.JobName) - workingDirectory: src - - task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp2.1 inputs: diff --git a/src/Library.Tests/CalculatorTests.cs b/src/Library.Tests/CalculatorTests.cs index 2166fb1f..84fe9a97 100644 --- a/src/Library.Tests/CalculatorTests.cs +++ b/src/Library.Tests/CalculatorTests.cs @@ -18,8 +18,8 @@ public CalculatorTests(ITestOutputHelper logger) [Fact] public void AddOrSubtract() { - // This tests aggregation of code coverage. -#if NETCOREAPP2_0 + // This tests aggregation of code coverage across test runs. +#if NETCOREAPP2_1 Assert.Equal(3, Calculator.Add(1, 2)); #else Assert.Equal(-1, Calculator.Subtract(1, 2)); diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj index b5f05f5f..7323c8d9 100644 --- a/src/Library.Tests/Library.Tests.csproj +++ b/src/Library.Tests/Library.Tests.csproj @@ -1,7 +1,7 @@ - net472;netcoreapp2.0;netcoreapp2.1;netcoreapp2.2 + net472;netcoreapp2.1;netcoreapp2.2 false $(NoWarn);CS1591 true From 720653e55004b99971cf095cac2ade5748f41fed Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 08:35:27 -0600 Subject: [PATCH 011/704] Merge test results even on build/test failure --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a41bc336..79cc4269 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -69,6 +69,7 @@ jobs: - macOS pool: vmImage: Ubuntu 16.04 + condition: succeededOrFailed() steps: - template: azure-pipelines/install-dependencies.yml - template: azure-pipelines/publish-codecoverage.yml From 5806251694796175fbfa806406d27e8018c64eed Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 08:39:17 -0600 Subject: [PATCH 012/704] dotnet tool install resilience against authenticated feeds --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 79cc4269..5d87afbe 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -24,7 +24,7 @@ jobs: - template: azure-pipelines/install-dependencies.yml - powershell: | - dotnet tool install --tool-path .. nbgv + dotnet tool install --tool-path .. nbgv --ignore-failed-sources ../nbgv cloud displayName: Set build number workingDirectory: src From 3367e54100fa8ba0b58c7d394fa3b5c1dca03d3c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 17:37:37 -0600 Subject: [PATCH 013/704] Switch artifact collection and some variables to ps1 scripts --- .gitignore | 7 +-- azure-pipelines.yml | 6 +-- azure-pipelines/artifacts/Variables.ps1 | 40 ++++++++++++++ azure-pipelines/artifacts/_all.ps1 | 45 ++++++++++++++++ azure-pipelines/artifacts/_pipelines.ps1 | 52 +++++++++++++++++++ azure-pipelines/artifacts/build_logs.ps1 | 10 ++++ azure-pipelines/artifacts/coverageResults.ps1 | 20 +++++++ azure-pipelines/artifacts/deployables.ps1 | 11 ++++ .../artifacts/projectAssetsJson.ps1 | 7 +++ azure-pipelines/collect-deployables.yml | 15 ------ azure-pipelines/collect-logs.yml | 9 ---- azure-pipelines/dotnet.yml | 44 +++------------- azure-pipelines/install-dependencies.yml | 10 +++- .../variables/DotNetSdkVersion.ps1 | 2 + azure-pipelines/variables/_all.ps1 | 10 ++++ azure-pipelines/variables/_pipelines.ps1 | 15 ++++++ 16 files changed, 230 insertions(+), 73 deletions(-) create mode 100644 azure-pipelines/artifacts/Variables.ps1 create mode 100644 azure-pipelines/artifacts/_all.ps1 create mode 100644 azure-pipelines/artifacts/_pipelines.ps1 create mode 100644 azure-pipelines/artifacts/build_logs.ps1 create mode 100644 azure-pipelines/artifacts/coverageResults.ps1 create mode 100644 azure-pipelines/artifacts/deployables.ps1 create mode 100644 azure-pipelines/artifacts/projectAssetsJson.ps1 delete mode 100644 azure-pipelines/collect-deployables.yml delete mode 100644 azure-pipelines/collect-logs.yml create mode 100644 azure-pipelines/variables/DotNetSdkVersion.ps1 create mode 100644 azure-pipelines/variables/_all.ps1 create mode 100644 azure-pipelines/variables/_pipelines.ps1 diff --git a/.gitignore b/.gitignore index 846c8c0a..fc1d26fa 100644 --- a/.gitignore +++ b/.gitignore @@ -55,11 +55,6 @@ dlldata.c # Benchmark Results BenchmarkDotNet.Artifacts/ -# .NET Core -project.lock.json -project.fragment.lock.json -artifacts/ - # StyleCop StyleCopReport.xml @@ -346,4 +341,4 @@ ASALocalRun/ healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 -MigrationBackup/ \ No newline at end of file +MigrationBackup/ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5d87afbe..52451bc1 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,15 +30,13 @@ jobs: workingDirectory: src - template: azure-pipelines/dotnet.yml - - template: azure-pipelines/collect-deployables.yml - - template: azure-pipelines/collect-logs.yml - template: azure-pipelines/expand-template.yml - task: NuGetCommand@2 displayName: Push packages to CI feed inputs: command: push - packagesToPush: $(Build.ArtifactStagingDirectory)/deployables/*.nupkg;$(Build.ArtifactStagingDirectory)/deployables/*.snupkg + packagesToPush: $(Build.ArtifactStagingDirectory)/deployables-Windows/*.nupkg;$(Build.ArtifactStagingDirectory)/deployables-Windows/*.snupkg nuGetFeedType: internal publishVstsFeed: $(ci_feed) allowPackageConflicts: true @@ -50,7 +48,6 @@ jobs: steps: - template: azure-pipelines/install-dependencies.yml - template: azure-pipelines/dotnet.yml - - template: azure-pipelines/collect-logs.yml - template: azure-pipelines/expand-template.yml - job: macOS @@ -59,7 +56,6 @@ jobs: steps: - template: azure-pipelines/install-dependencies.yml - template: azure-pipelines/dotnet.yml - - template: azure-pipelines/collect-logs.yml - template: azure-pipelines/expand-template.yml - job: MergeCoverage diff --git a/azure-pipelines/artifacts/Variables.ps1 b/azure-pipelines/artifacts/Variables.ps1 new file mode 100644 index 00000000..cfcb7df5 --- /dev/null +++ b/azure-pipelines/artifacts/Variables.ps1 @@ -0,0 +1,40 @@ +# This artifact captures all variables defined in the ..\variables folder. +# It "snaps" the values of these variables where we can compute them during the build, +# and otherwise captures the scripts to run later during an Azure Pipelines environment release. + +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +$ArtifactBasePath = "$RepoRoot\obj\_artifacts" +$VariablesArtifactPath = "$ArtifactBasePath\variables" +if (-not (Test-Path $VariablesArtifactPath)) { New-Item -ItemType Directory -Path $VariablesArtifactPath | Out-Null } + +# Copy variables, either by value if the value is calculable now, or by script +Get-ChildItem -Path "$PSScriptRoot\..\variables" |% { + $value = $null + if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts + # First check the environment variables in case the variable was set in a queued build + if (Test-Path env:$($_.BaseName)) { + $value = Get-Content "env:$($_.BaseName)" + } + + # If that didn't give us anything, try executing the script right now from its original position + if (-not $value) { + $value = & $_.FullName + } + + if ($value) { + # We got something, so wrap it with quotes so it's treated like a literal value. + $value = "'$value'" + } + } + + # If that didn't get us anything, just copy the script itself + if (-not $value) { + $value = Get-Content -Path $_.FullName + } + + Set-Content -Path "$VariablesArtifactPath\$($_.Name)" -Value $value +} + +@{ + "$VariablesArtifactPath" = (Get-ChildItem $VariablesArtifactPath -Recurse); +} diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 new file mode 100644 index 00000000..bd5e9d34 --- /dev/null +++ b/azure-pipelines/artifacts/_all.ps1 @@ -0,0 +1,45 @@ +# This script returns all the artifacts that should be collected after a build. +# +# Each powershell artifact is expressed as an object with these properties: +# Source - the full path to the source file +# ArtifactName - the name of the artifact to upload to +# ContainerFolder - the relative path within the artifact in which the file should appear +# +# Each artifact aggregating .ps1 script should return a hashtable: +# Key = path to the directory from which relative paths within the artifact should be calculated +# Value = an array of paths (absolute or relative to the BaseDirectory) to files to include in the artifact. +# FileInfo objects are also allowed. + +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") + +Function EnsureTrailingSlash($path) { + if ($path.length -gt 0 -and !$path.EndsWith('\') -and !$path.EndsWith('/')) { + $path = $path + [IO.Path]::DirectorySeparatorChar + } + + $path.Replace('\', [IO.Path]::DirectorySeparatorChar) +} + +Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse |% { + $ArtifactName = $_.BaseName + + (& $_).GetEnumerator() |% { + $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key), [UriKind]::Absolute) + $_.Value |% { + if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { + $_ = $_.FullName + } + + $artifact = New-Object -TypeName PSObject + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ArtifactName -Value $ArtifactName + + $SourceFullPath = New-Object Uri ($BaseDirectory, $_) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Source -Value $SourceFullPath.LocalPath + + $RelativePath = [Uri]::UnescapeDataString($BaseDirectory.MakeRelative($SourceFullPath)) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) + + Write-Output $artifact + } + } +} diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 new file mode 100644 index 00000000..59dd2cf2 --- /dev/null +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -0,0 +1,52 @@ +# This script translates all the artifacts described by _all.ps1 +# into commands that instruct VSTS to actually collect those artifacts. + +param ( + [string]$ArtifactNameSuffix +) + +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +if (!$env:BUILDCONFIGURATION) { throw "BUILDCONFIGURATION environment variable must be set." } +if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { + $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY +} else { + $ArtifactStagingFolder = "$RepoRoot\obj\_artifacts" + if (Test-Path $ArtifactStagingFolder) { + Remove-Item $ArtifactStagingFolder -Recurse -Force + } +} + +function Create-SymbolicLink { + param ( + $Link, + $Target + ) + + if ($Link -eq $Target) { + return + } + + if (Test-Path $Link) { Remove-Item $Link } + $LinkContainer = Split-Path $Link -Parent + if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer } + Write-Verbose "Linking $Link to $Target" + ln $Target $Link +} + +# Stage all artifacts +$Artifacts = & "$PSScriptRoot\_all.ps1" +$Artifacts |% { + $DestinationFolder = (Join-Path (Join-Path $ArtifactStagingFolder "$($_.ArtifactName)$ArtifactNameSuffix") $_.ContainerFolder).TrimEnd('\') + $Name = "$(Split-Path $_.Source -Leaf)" + + #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow + + if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null } + if (Test-Path -PathType Leaf $_.Source) { # skip folders + Create-SymbolicLink -Link "$DestinationFolder\$Name" -Target $_.Source + } +} + +$Artifacts |% { $_.ArtifactName } | Get-Unique |% { + Write-Host "##vso[artifact.upload containerfolder=$_$ArtifactNameSuffix;artifactname=$_$ArtifactNameSuffix;]$ArtifactStagingFolder/$_$ArtifactNameSuffix" +} diff --git a/azure-pipelines/artifacts/build_logs.ps1 b/azure-pipelines/artifacts/build_logs.ps1 new file mode 100644 index 00000000..5ba801c5 --- /dev/null +++ b/azure-pipelines/artifacts/build_logs.ps1 @@ -0,0 +1,10 @@ +if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { + $artifactsRoot = $env:BUILD_ARTIFACTSTAGINGDIRECTORY +} else { + $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") + $artifactsRoot = "$RepoRoot\bin" +} + +@{ + "$artifactsRoot/build_logs" = (Get-ChildItem -Recurse "$artifactsRoot/build_logs") +} diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 new file mode 100644 index 00000000..36189f33 --- /dev/null +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -0,0 +1,20 @@ +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") + +# Prepare code coverage reports for merging on another machine +if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) { + Write-Host "Substituting $env:SYSTEM_DEFAULTWORKINGDIRECTORY with `"{reporoot}`"" + $reports = Get-ChildItem "$RepoRoot/bin/coverage.cobertura.xml" -Recurse + $reports |% { + $content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape($env:SYSTEM_DEFAULTWORKINGDIRECTORY), "{reporoot}" } + Set-Content -Path $_ -Value $content -Encoding UTF8 + } +} else { + Write-Warning "Azure Pipelines not detected. Machine-neutral token replacement skipped." +} + +@{ + $RepoRoot = ( + (Get-ChildItem "$RepoRoot\bin\coverage.cobertura.xml" -Recurse) + + (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) + ); +} diff --git a/azure-pipelines/artifacts/deployables.ps1 b/azure-pipelines/artifacts/deployables.ps1 new file mode 100644 index 00000000..893df6dd --- /dev/null +++ b/azure-pipelines/artifacts/deployables.ps1 @@ -0,0 +1,11 @@ +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +$BuildConfiguration = $env:BUILDCONFIGURATION +if (!$BuildConfiguration) { + $BuildConfiguration = 'Debug' +} + +$PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" + +@{ + "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) +} diff --git a/azure-pipelines/artifacts/projectAssetsJson.ps1 b/azure-pipelines/artifacts/projectAssetsJson.ps1 new file mode 100644 index 00000000..5e9217bd --- /dev/null +++ b/azure-pipelines/artifacts/projectAssetsJson.ps1 @@ -0,0 +1,7 @@ +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") + +@{ + "$RepoRoot\obj" = ( + (Get-ChildItem "$RepoRoot\obj\project.assets.json" -Recurse) + ); +} diff --git a/azure-pipelines/collect-deployables.yml b/azure-pipelines/collect-deployables.yml deleted file mode 100644 index 5d77acfc..00000000 --- a/azure-pipelines/collect-deployables.yml +++ /dev/null @@ -1,15 +0,0 @@ -steps: -- task: CopyFiles@1 - inputs: - Contents: | - bin/Packages/$(BuildConfiguration)/* - TargetFolder: $(Build.ArtifactStagingDirectory)/deployables - flattenFolders: true - displayName: Collecting deployable artifacts - -- task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/deployables - ArtifactName: deployables - ArtifactType: Container - displayName: Publish deployables artifacts diff --git a/azure-pipelines/collect-logs.yml b/azure-pipelines/collect-logs.yml deleted file mode 100644 index ab39d91f..00000000 --- a/azure-pipelines/collect-logs.yml +++ /dev/null @@ -1,9 +0,0 @@ -steps: - -- task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/build_logs - ArtifactName: build_logs-$(Agent.JobName) - ArtifactType: Container - displayName: Publish build_logs artifacts - condition: succeededOrFailed() diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index fe055ef7..668083e7 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -36,48 +36,20 @@ steps: testRunTitle: netcoreapp2.2-$(Agent.JobName) workingDirectory: src -- task: CopyFiles@1 +- task: PowerShell@2 inputs: - Contents: | - bin/**/coverage.cobertura.xml - obj/**/*.cs - TargetFolder: $(Build.ArtifactStagingDirectory)/coverageResults - displayName: Collecting coverage.cobertura.xml artifacts + filePath: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true + displayName: Update pipeline variables based on build outputs condition: succeededOrFailed() -- powershell: | - Write-Host "Substituting $(System.DefaultWorkingDirectory) with {reporoot}" - $reports = Get-ChildItem "$(Build.ArtifactStagingDirectory)/coverageResults/coverage.cobertura.xml" -Recurse - $reports |% { - $content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape("$(System.DefaultWorkingDirectory)"), "{reporoot}" } - Set-Content -Path $_ -Value $content -Encoding UTF8 - } - displayName: Preparing code coverage reports for merging on another machine - -- task: PublishBuildArtifacts@1 +- task: PowerShell@2 inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/coverageResults - ArtifactName: coverageResults-$(Agent.JobName) - ArtifactType: Container - displayName: Publish coverageResults artifacts + filePath: azure-pipelines/artifacts/_pipelines.ps1 + arguments: -ArtifactNameSuffix "-$(Agent.JobName)" + displayName: Publish artifacts condition: succeededOrFailed() - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') - -- task: CopyFiles@1 - inputs: - Contents: | - obj/**/project.assets.json - TargetFolder: $(Build.ArtifactStagingDirectory)/projectAssetsJson - displayName: Collecting project.assets.json artifacts - condition: succeededOrFailed() - -- task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/projectAssetsJson - ArtifactName: projectAssetsJson-$(Agent.JobName) - ArtifactType: Container - displayName: Publish projectAssetsJson artifacts - condition: succeededOrFailed() diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 80830cc7..5b0b8c3a 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -1,13 +1,19 @@ steps: +- task: PowerShell@2 + inputs: + filePath: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true + displayName: Set pipeline variables based on source + - script: dotnet --info displayName: .NET Core SDK/runtimes (on host) workingDirectory: $(Agent.HomeDirectory) - task: UseDotNet@2 - displayName: Install .NET Core SDK 2.2.300 + displayName: Install .NET Core SDK inputs: packageType: sdk - version: 2.2.300 + version: $(DotNetSdkVersion) - task: UseDotNet@2 displayName: Install .NET Core runtime 2.0.x diff --git a/azure-pipelines/variables/DotNetSdkVersion.ps1 b/azure-pipelines/variables/DotNetSdkVersion.ps1 new file mode 100644 index 00000000..b213fbc2 --- /dev/null +++ b/azure-pipelines/variables/DotNetSdkVersion.ps1 @@ -0,0 +1,2 @@ +$globalJson = Get-Content -Path "$PSScriptRoot\..\..\global.json" | ConvertFrom-Json +$globalJson.sdk.version diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1 new file mode 100644 index 00000000..680a3398 --- /dev/null +++ b/azure-pipelines/variables/_all.ps1 @@ -0,0 +1,10 @@ +# This script returns a hashtable of build variables that should be set +# at the start of a build or release definition's execution. + +$vars = @{} + +Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" |% { + $vars[$_.BaseName] = & $_ +} + +$vars diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 new file mode 100644 index 00000000..b3fde25d --- /dev/null +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -0,0 +1,15 @@ +# This script translates the variables returned by the _all.ps1 script +# into commands that instruct VSTS to actually set those variables for other VSTS tasks to consume. + +# The build or release definition may have set these variables to override +# what the build would do. So only set them if they have not already been set. + +(& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { + if (Test-Path -Path "env:$($_.Key.ToUpper())") { + Write-Host "Skipping setting $($_.Key) because variable is already set." -ForegroundColor Cyan + } else { + Write-Host "$($_.Key)=$($_.Value)" -ForegroundColor Yellow + Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" + Set-Item -Path "env:$($_.Key)" -Value $_.Value + } +} From baea971aa13cdb2d7e56ae7ab643b96613972894 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 23:01:20 -0600 Subject: [PATCH 014/704] Publish merged code coverage even when some inputs fail --- azure-pipelines/publish-codecoverage.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index fc530781..b9b7b72a 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -4,16 +4,19 @@ steps: inputs: artifactName: coverageResults-Windows downloadPath: $(System.DefaultWorkingDirectory)/bin + continueOnError: true - task: DownloadBuildArtifacts@0 displayName: Download Linux code coverage results inputs: artifactName: coverageResults-Linux downloadPath: $(System.DefaultWorkingDirectory)/bin + continueOnError: true - task: DownloadBuildArtifacts@0 displayName: Download macOS code coverage results inputs: artifactName: coverageResults-macOS downloadPath: $(System.DefaultWorkingDirectory)/bin + continueOnError: true - powershell: | dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 Copy-Item -Recurse $(System.DefaultWorkingDirectory)/bin/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj From 70c8febd704082f5f235a36d112ca4b78f082804 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 23:01:47 -0600 Subject: [PATCH 015/704] Push nuget package to CI only if all agents succeed --- azure-pipelines.yml | 13 ++----------- azure-pipelines/publish-deployables.yml | 15 +++++++++++++++ 2 files changed, 17 insertions(+), 11 deletions(-) create mode 100644 azure-pipelines/publish-deployables.yml diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 52451bc1..8bff4e89 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -32,16 +32,6 @@ jobs: - template: azure-pipelines/dotnet.yml - template: azure-pipelines/expand-template.yml - - task: NuGetCommand@2 - displayName: Push packages to CI feed - inputs: - command: push - packagesToPush: $(Build.ArtifactStagingDirectory)/deployables-Windows/*.nupkg;$(Build.ArtifactStagingDirectory)/deployables-Windows/*.snupkg - nuGetFeedType: internal - publishVstsFeed: $(ci_feed) - allowPackageConflicts: true - condition: ne(variables['ci_feed'], '') - - job: Linux pool: vmImage: Ubuntu 16.04 @@ -58,7 +48,7 @@ jobs: - template: azure-pipelines/dotnet.yml - template: azure-pipelines/expand-template.yml -- job: MergeCoverage +- job: WrapUp dependsOn: - Windows - Linux @@ -69,3 +59,4 @@ jobs: steps: - template: azure-pipelines/install-dependencies.yml - template: azure-pipelines/publish-codecoverage.yml + - template: azure-pipelines/publish-deployables.yml diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml new file mode 100644 index 00000000..85c76e7b --- /dev/null +++ b/azure-pipelines/publish-deployables.yml @@ -0,0 +1,15 @@ +steps: +- task: DownloadBuildArtifacts@0 + displayName: Download deployables + inputs: + artifactName: deployables-Windows + downloadPath: $(System.DefaultWorkingDirectory)/bin +- task: DotNetCoreCLI@2 + displayName: Push packages to CI feed + inputs: + command: push + packagesToPush: $(System.DefaultWorkingDirectory)/bin/deployables-Windows/*.nupkg + nuGetFeedType: internal + publishVstsFeed: $(ci_feed) + allowPackageConflicts: true + condition: and(succeeded(), ne(variables['ci_feed'], '')) From e4cbe719a90f11a3b7545ffe90a56607322e8771 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 7 Jul 2019 21:42:35 -0600 Subject: [PATCH 016/704] Add init.ps1 and Install-DotNetSdk.ps1 scripts Closes #12 --- .gitattributes | 3 +++ CONTRIBUTING.md | 5 ++++ init.ps1 | 9 +++++++ tools/Install-DotNetSdk.ps1 | 54 +++++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+) create mode 100644 init.ps1 create mode 100644 tools/Install-DotNetSdk.ps1 diff --git a/.gitattributes b/.gitattributes index 1ff0c423..9b6ea624 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,6 +3,9 @@ ############################################################################### * text=auto +# Ensure bash shell scripts use LF line endings +*.sh eol=lf + ############################################################################### # Set default behavior for command prompt diff. # diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2f36ba66..4834cebf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -17,8 +17,13 @@ For example if 2.2.300 is specified, you may install 2.2.300, 2.2.301, or 2.2.31 while the 2.2.400 version would not be considered compatible by .NET SDK. See [.NET Core Versioning](https://docs.microsoft.com/en-us/dotnet/core/versions/) for more information. +All dependencies can be installed by running the `init.ps1` script at the root of the repository +using Windows PowerShell or [PowerShell Core][pwsh] (on any OS). + This repository can be built on Windows, Linux, and OSX. ## Building Building, testing, and packing this repository can be done by using the standard dotnet CLI commands (e.g. `dotnet build`, `dotnet test`, `dotnet pack`, etc.). + +[pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-6 diff --git a/init.ps1 b/init.ps1 new file mode 100644 index 00000000..6f0a0776 --- /dev/null +++ b/init.ps1 @@ -0,0 +1,9 @@ +<# +.SYNOPSIS +Installs dependencies required to build and test the projects in this repository. +#> +[CmdletBinding(SupportsShouldProcess=$true)] +Param ( +) + +& "$PSScriptRoot\tools\Install-DotNetSdk.ps1" diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 new file mode 100644 index 00000000..ca73cb76 --- /dev/null +++ b/tools/Install-DotNetSdk.ps1 @@ -0,0 +1,54 @@ +<# +.SYNOPSIS +Installs the .NET SDK specified in the global.json file at the root of this repository, +along with supporting .NET Core runtimes used for testing. +#> +[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] +Param ( +) + +$DotNetInstallScriptRoot = Resolve-Path $PSScriptRoot\..\obj +$sdkVersion = & "$PSScriptRoot\..\azure-pipelines\variables\DotNetSdkVersion.ps1" + +if ($IsMacOS -or $IsLinux) { + $DownloadUri = "https://dot.net/v1/dotnet-install.sh" + $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" +} else { + $DownloadUri = "https://dot.net/v1/dotnet-install.ps1" + $DotNetInstallScriptPath = "$DotNetInstallScriptRoot\dotnet-install.ps1" +} + +if (-not (Test-Path $DotNetInstallScriptPath)) { + Invoke-WebRequest -Uri $DownloadUri -OutFile $DotNetInstallScriptPath + chmod +x $DotNetInstallScriptPath +} + +if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + & $DotNetInstallScriptPath -Version $sdkVersion -Architecture x64 +} else { + & $DotNetInstallScriptPath -Version $sdkVersion -Architecture x64 -DryRun +} + +# Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. +$runtimeVersions = @() +Get-ChildItem "$PSScriptRoot\..\src\*.*proj" -Recurse |% { + $projXml = [xml](Get-Content -Path $_) + $targetFrameworks = $projXml.Project.PropertyGroup.TargetFramework + if (!$targetFrameworks) { + $targetFrameworks = $projXml.Project.PropertyGroup.TargetFrameworks + if ($targetFrameworks) { + $targetFrameworks = $targetFrameworks.Split(';') + } + } + $targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% { + $runtimeVersions += $Matches[1] + } +} + +$runtimeVersions | Get-Unique |% { + if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + & $DotNetInstallScriptPath -Channel $_ -Runtime dotnet -Architecture x64 + } else { + & $DotNetInstallScriptPath -Channel $_ -Runtime dotnet -Architecture x64 -DryRun + } +} From 45cb59eadbda46815ca7ee052c5d8a113d9560fc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 8 Jul 2019 08:50:38 -0600 Subject: [PATCH 017/704] install-dependencies.yml now shares init.ps1 script --- CONTRIBUTING.md | 5 ++ azure-pipelines/expand-template.yml | 4 +- azure-pipelines/install-dependencies.yml | 26 +------- init.ps1 | 12 +++- tools/Install-DotNetSdk.ps1 | 82 +++++++++++++++++++++--- 5 files changed, 95 insertions(+), 34 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4834cebf..f2f4a8ca 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,6 +7,11 @@ FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. +## Best practices + +* Use Windows PowerShell or [PowerShell Core][pwsh] (including on Linux/OSX) to run .ps1 scripts. + Some scripts set environment variables to help you, but they are only retained if you use PowerShell as your shell. + ## Prerequisites The only prerequisite for building, testing, and deploying from this repository diff --git a/azure-pipelines/expand-template.yml b/azure-pipelines/expand-template.yml index 74960e56..708534d5 100644 --- a/azure-pipelines/expand-template.yml +++ b/azure-pipelines/expand-template.yml @@ -1,5 +1,7 @@ steps: -- script: git clean -fdx +- script: | + dotnet build-server shutdown + git clean -fdx displayName: Cleaning repo for template expansion - powershell: ./Expand-Template.ps1 -LibraryName Calc -Author "Andrew Arnott" displayName: Expanding template diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 5b0b8c3a..38fa5c08 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -5,27 +5,5 @@ steps: failOnStderr: true displayName: Set pipeline variables based on source -- script: dotnet --info - displayName: .NET Core SDK/runtimes (on host) - workingDirectory: $(Agent.HomeDirectory) - -- task: UseDotNet@2 - displayName: Install .NET Core SDK - inputs: - packageType: sdk - version: $(DotNetSdkVersion) - -- task: UseDotNet@2 - displayName: Install .NET Core runtime 2.0.x - inputs: - packageType: runtime - version: 2.0.x - -- task: UseDotNet@2 - displayName: Install .NET Core runtime 2.1.x - inputs: - packageType: runtime - version: 2.1.x - -- script: dotnet --info - displayName: .NET Core SDK/runtimes (explicitly installed) +- powershell: .\init.ps1 + displayName: Install prerequisites diff --git a/init.ps1 b/init.ps1 index 6f0a0776..41e5556b 100644 --- a/init.ps1 +++ b/init.ps1 @@ -1,9 +1,19 @@ <# .SYNOPSIS Installs dependencies required to build and test the projects in this repository. +.DESCRIPTION +This does not require elevation, as the dependencies are installed in per-user locations. +.PARAMETER InstallLocality +A value indicating whether dependencies should be installed locally to the repo or at a per-user location. +Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. +Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. +When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. +Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. #> [CmdletBinding(SupportsShouldProcess=$true)] Param ( + [ValidateSet('repo','user')] + [string]$InstallLocality='user' ) -& "$PSScriptRoot\tools\Install-DotNetSdk.ps1" +& "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index ca73cb76..9db8558f 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -2,20 +2,56 @@ .SYNOPSIS Installs the .NET SDK specified in the global.json file at the root of this repository, along with supporting .NET Core runtimes used for testing. +.DESCRIPTION +This does not require elevation, as the SDK and runtimes are installed locally to this repo location. +.PARAMETER InstallLocality +A value indicating whether dependencies should be installed locally to the repo or at a per-user location. +Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. +Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. +When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. +Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( + [ValidateSet('repo','user')] + [string]$InstallLocality='user' ) -$DotNetInstallScriptRoot = Resolve-Path $PSScriptRoot\..\obj -$sdkVersion = & "$PSScriptRoot\..\azure-pipelines\variables\DotNetSdkVersion.ps1" +$DotNetInstallScriptRoot = "$PSScriptRoot/../obj" +if (!(Test-Path $DotNetInstallScriptRoot)) { mkdir $DotNetInstallScriptRoot | Out-Null } + +$switches = @( + '-Architecture','x64' +) +$envVars = @{ + # For locally installed dotnet, skip first time experience which takes a long time + 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' = 'true'; +} + +$DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot +if ($InstallLocality -eq 'repo') { + $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet" +} elseif ($env:AGENT_TOOLSDIRECTORY) { + $DotNetInstallDir = "$env:AGENT_TOOLSDIRECTORY/dotnet" +} else { + $DotNetInstallDir = Join-Path $HOME .dotnet +} + +Write-Host "Installing .NET Core SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue + +if ($DotNetInstallDir) { + $switches += '-InstallDir',$DotNetInstallDir + $envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0' + $envVars['DOTNET_ROOT'] = $DotNetInstallDir +} +$sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" if ($IsMacOS -or $IsLinux) { $DownloadUri = "https://dot.net/v1/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { $DownloadUri = "https://dot.net/v1/dotnet-install.ps1" - $DotNetInstallScriptPath = "$DotNetInstallScriptRoot\dotnet-install.ps1" + $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } if (-not (Test-Path $DotNetInstallScriptPath)) { @@ -24,9 +60,9 @@ if (-not (Test-Path $DotNetInstallScriptPath)) { } if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - & $DotNetInstallScriptPath -Version $sdkVersion -Architecture x64 + Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" } else { - & $DotNetInstallScriptPath -Version $sdkVersion -Architecture x64 -DryRun + Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" } # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. @@ -37,7 +73,7 @@ Get-ChildItem "$PSScriptRoot\..\src\*.*proj" -Recurse |% { if (!$targetFrameworks) { $targetFrameworks = $projXml.Project.PropertyGroup.TargetFrameworks if ($targetFrameworks) { - $targetFrameworks = $targetFrameworks.Split(';') + $targetFrameworks = $targetFrameworks -Split ';' } } $targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% { @@ -45,10 +81,40 @@ Get-ChildItem "$PSScriptRoot\..\src\*.*proj" -Recurse |% { } } +$switches += '-Runtime','dotnet' + $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - & $DotNetInstallScriptPath -Channel $_ -Runtime dotnet -Architecture x64 + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" } else { - & $DotNetInstallScriptPath -Channel $_ -Runtime dotnet -Architecture x64 -DryRun + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" + } +} + +Write-Host "Environment variables to be set:" -ForegroundColor Blue +$envVars + +if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) { + if ($env:TF_BUILD) { + Write-Host "Azure Pipelines detected. Logging commands will be used to propagate environment variables and prepend path." + } + + $envVars.GetEnumerator() |% { + Set-Item -Path env:$($_.Key) -Value $_.Value + + # If we're running in Azure Pipelines, set these environment variables + if ($env:TF_BUILD) { + Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" + } + } + + if ($IsMacOS -or $IsLinux) { + $env:PATH = "${DotNetInstallDir}:$env:PATH" + } else { + $env:PATH = "$DotNetInstallDir;$env:PATH" + } + + if ($env:TF_BUILD) { + Write-Host "##vso[task.prependpath]$DotNetInstallDir" } } From e4753b7b235a6969dc2be8d6b1d8bda7fafb8adc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 9 Jul 2019 21:45:34 -0600 Subject: [PATCH 018/704] Add -Squash switch to Expand-Template.ps1 --- Expand-Template.ps1 | 14 +++++++++++++- azure-pipelines/expand-template.yml | 5 ++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index c1447d4c..7558ca51 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -10,6 +10,8 @@ A token obtained from codecov.io for your repo. If not specified, code coverage but can be added later by editing the Azure Pipelines YAML file. .PARAMETER CIFeed The `/{guid}` path to the Azure Pipelines artifact feed to push your nuget package to as part of your CI. +.PARAMETER Squash +A switch that causes all of git history to be squashed to just one initial commit for the template, and one for its expansion. #> [CmdletBinding()] Param( @@ -20,7 +22,9 @@ Param( [Parameter()] [string]$CodeCovToken, [Parameter()] - [string]$CIFeed + [string]$CIFeed, + [Parameter()] + [switch]$Squash ) function Replace-Placeholders { @@ -69,6 +73,11 @@ if (-not $sn) { Push-Location $PSScriptRoot try { + if ($Squash) { + git reset --soft $(git rev-list --max-parents=0 HEAD) + git commit --amend -qm "Initial template from https://github.com/AArnott/Library.Template" + } + # Rename project directories and solution Set-Location src git mv Library.sln "$LibraryName.sln" @@ -147,6 +156,9 @@ try { Write-Error "PLACEHOLDER discovered in $($_.FullName)" } } + + # Commit the changes + git commit -qm "Expanded template for $LibraryName" -m "This expansion done by the (now removed) Expand-Template.ps1 script." } finally { Pop-Location } diff --git a/azure-pipelines/expand-template.yml b/azure-pipelines/expand-template.yml index 708534d5..2d9ea7b3 100644 --- a/azure-pipelines/expand-template.yml +++ b/azure-pipelines/expand-template.yml @@ -3,7 +3,10 @@ steps: dotnet build-server shutdown git clean -fdx displayName: Cleaning repo for template expansion -- powershell: ./Expand-Template.ps1 -LibraryName Calc -Author "Andrew Arnott" +- powershell: | + git config user.name "test user" + git config user.email "andrewarnott@gmail.com" + ./Expand-Template.ps1 -LibraryName Calc -Author "Andrew Arnott" displayName: Expanding template failOnStderr: true # TODO: Verify that all changes are staged to the git index From 18164cfa4ecefc40d937a652c98dda68ff22ddc8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 10 Jul 2019 15:25:10 -0600 Subject: [PATCH 019/704] Add timeout to codecov publish step I saw this hang for a long time once, presumably when codecov.io was down. --- azure-pipelines/dotnet.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 668083e7..1ca019a0 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -53,3 +53,4 @@ steps: - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') + timeoutInMinutes: 3 From f4b75c2ffb7394ee4661f333c565d7446b70ffb5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Jul 2019 09:39:31 -0600 Subject: [PATCH 020/704] Tests ruleset inherits from shipping one --- src/tests.ruleset | 72 ++--------------------------------------------- 1 file changed, 2 insertions(+), 70 deletions(-) diff --git a/src/tests.ruleset b/src/tests.ruleset index c74c6ed3..4b4708a1 100644 --- a/src/tests.ruleset +++ b/src/tests.ruleset @@ -1,75 +1,7 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - @@ -80,4 +12,4 @@ - \ No newline at end of file + From 26871ccaeafb1ce4d0c26ee08137bf39883c47ff Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Jul 2019 13:17:52 -0600 Subject: [PATCH 021/704] Move jobs into build.yml --- Expand-Template.ps1 | 6 +++-- azure-pipelines.yml | 43 +----------------------------------- azure-pipelines/build.yml | 46 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 44 deletions(-) create mode 100644 azure-pipelines/build.yml diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index 7558ca51..c050aba3 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -128,10 +128,12 @@ try { "(?m)^.*\[codecov\].*`r?`n"="" } - # Specially handle azure-pipelines.yml edits - $YmlReplacements = @{ + # Specially handle azure-pipelines .yml edits + Replace-Placeholders -Path "azure-pipelines/build.yml" -Replacements @{ "(?m).*expand-template\.yml(?:\r)?\n" = "" } + + $YmlReplacements = @{} if ($CodeCovToken) { $YmlReplacements['(codecov_token: ).*(#.*)'] = "`$1$CodeCovToken" } else { diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 8bff4e89..f158ff52 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,45 +18,4 @@ variables: ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed jobs: -- job: Windows - pool: Hosted Windows 2019 with VS2019 - steps: - - template: azure-pipelines/install-dependencies.yml - - - powershell: | - dotnet tool install --tool-path .. nbgv --ignore-failed-sources - ../nbgv cloud - displayName: Set build number - workingDirectory: src - - - template: azure-pipelines/dotnet.yml - - template: azure-pipelines/expand-template.yml - -- job: Linux - pool: - vmImage: Ubuntu 16.04 - steps: - - template: azure-pipelines/install-dependencies.yml - - template: azure-pipelines/dotnet.yml - - template: azure-pipelines/expand-template.yml - -- job: macOS - pool: - vmImage: macOS 10.13 - steps: - - template: azure-pipelines/install-dependencies.yml - - template: azure-pipelines/dotnet.yml - - template: azure-pipelines/expand-template.yml - -- job: WrapUp - dependsOn: - - Windows - - Linux - - macOS - pool: - vmImage: Ubuntu 16.04 - condition: succeededOrFailed() - steps: - - template: azure-pipelines/install-dependencies.yml - - template: azure-pipelines/publish-codecoverage.yml - - template: azure-pipelines/publish-deployables.yml +- template: azure-pipelines/build.yml diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml new file mode 100644 index 00000000..75b7e0c3 --- /dev/null +++ b/azure-pipelines/build.yml @@ -0,0 +1,46 @@ +parameters: + windowsPool: Hosted Windows 2019 with VS2019 + +jobs: +- job: Windows + pool: ${{ parameters.windowsPool }} + steps: + - template: install-dependencies.yml + + - powershell: | + dotnet tool install --tool-path .. nbgv --ignore-failed-sources + ../nbgv cloud + displayName: Set build number + workingDirectory: src + + - template: dotnet.yml + - template: expand-template.yml + +- job: Linux + pool: + vmImage: Ubuntu 16.04 + steps: + - template: install-dependencies.yml + - template: dotnet.yml + - template: expand-template.yml + +- job: macOS + pool: + vmImage: macOS 10.13 + steps: + - template: install-dependencies.yml + - template: dotnet.yml + - template: expand-template.yml + +- job: WrapUp + dependsOn: + - Windows + - Linux + - macOS + pool: + vmImage: Ubuntu 16.04 + condition: succeededOrFailed() + steps: + - template: install-dependencies.yml + - template: publish-codecoverage.yml + - template: publish-deployables.yml From 1263ef34db6d2d749f4cdd33696f1bae4ec27fb6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Jul 2019 13:32:27 -0600 Subject: [PATCH 022/704] Move nbgv installation in azp outside the src dir The Agent.ToolsDirectory is a popular place to put versioned tools like this. --- .gitignore | 3 +++ azure-pipelines/build.yml | 5 ++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index fc1d26fa..e353101d 100644 --- a/.gitignore +++ b/.gitignore @@ -342,3 +342,6 @@ healthchecksdb # Backup folder for Package Reference Convert tool in Visual Studio 2017 MigrationBackup/ + +# dotnet tool local install directory +.store/ diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 75b7e0c3..3ee5b0b9 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -8,10 +8,9 @@ jobs: - template: install-dependencies.yml - powershell: | - dotnet tool install --tool-path .. nbgv --ignore-failed-sources - ../nbgv cloud + dotnet tool install --tool-path $(Agent.ToolsDirectory) nbgv --ignore-failed-sources + $(Agent.ToolsDirectory)/nbgv cloud displayName: Set build number - workingDirectory: src - template: dotnet.yml - template: expand-template.yml From ecb32a2ad6a0625bcaebec9bfcf44945cc63258d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Jul 2019 13:33:09 -0600 Subject: [PATCH 023/704] Don't deploy packages to CI feed on PR builds --- azure-pipelines/publish-deployables.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index 85c76e7b..cdd85292 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -4,6 +4,7 @@ steps: inputs: artifactName: deployables-Windows downloadPath: $(System.DefaultWorkingDirectory)/bin + - task: DotNetCoreCLI@2 displayName: Push packages to CI feed inputs: @@ -12,4 +13,4 @@ steps: nuGetFeedType: internal publishVstsFeed: $(ci_feed) allowPackageConflicts: true - condition: and(succeeded(), ne(variables['ci_feed'], '')) + condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) From 13ab120e7f6f448092bffbff7d5ffc39b475ef70 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Jul 2019 13:33:44 -0600 Subject: [PATCH 024/704] Make azp/artifacts only warn when they can't find files --- azure-pipelines/artifacts/_all.ps1 | 37 +++++++++++-------- azure-pipelines/artifacts/build_logs.ps1 | 2 + azure-pipelines/artifacts/coverageResults.ps1 | 4 +- azure-pipelines/artifacts/deployables.ps1 | 2 + .../artifacts/projectAssetsJson.ps1 | 8 ++-- 5 files changed, 33 insertions(+), 20 deletions(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index bd5e9d34..6f62be5c 100644 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -23,23 +23,28 @@ Function EnsureTrailingSlash($path) { Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse |% { $ArtifactName = $_.BaseName - (& $_).GetEnumerator() |% { - $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key), [UriKind]::Absolute) - $_.Value |% { - if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { - $_ = $_.FullName + $fileGroups = & $_ + if (!$fileGroups -or $fileGroups.Count -eq 0) { + Write-Warning "No files found for the `"$ArtifactName`" artifact." + } else { + $fileGroups.GetEnumerator() | % { + $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key), [UriKind]::Absolute) + $_.Value | % { + if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { + $_ = $_.FullName + } + + $artifact = New-Object -TypeName PSObject + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ArtifactName -Value $ArtifactName + + $SourceFullPath = New-Object Uri ($BaseDirectory, $_) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Source -Value $SourceFullPath.LocalPath + + $RelativePath = [Uri]::UnescapeDataString($BaseDirectory.MakeRelative($SourceFullPath)) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) + + Write-Output $artifact } - - $artifact = New-Object -TypeName PSObject - Add-Member -InputObject $artifact -MemberType NoteProperty -Name ArtifactName -Value $ArtifactName - - $SourceFullPath = New-Object Uri ($BaseDirectory, $_) - Add-Member -InputObject $artifact -MemberType NoteProperty -Name Source -Value $SourceFullPath.LocalPath - - $RelativePath = [Uri]::UnescapeDataString($BaseDirectory.MakeRelative($SourceFullPath)) - Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) - - Write-Output $artifact } } } diff --git a/azure-pipelines/artifacts/build_logs.ps1 b/azure-pipelines/artifacts/build_logs.ps1 index 5ba801c5..b55ba48f 100644 --- a/azure-pipelines/artifacts/build_logs.ps1 +++ b/azure-pipelines/artifacts/build_logs.ps1 @@ -5,6 +5,8 @@ if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { $artifactsRoot = "$RepoRoot\bin" } +if (!(Test-Path $artifactsRoot/build_logs)) { return } + @{ "$artifactsRoot/build_logs" = (Get-ChildItem -Recurse "$artifactsRoot/build_logs") } diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 index 36189f33..619ac0f3 100644 --- a/azure-pipelines/artifacts/coverageResults.ps1 +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -9,9 +9,11 @@ if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) { Set-Content -Path $_ -Value $content -Encoding UTF8 } } else { - Write-Warning "Azure Pipelines not detected. Machine-neutral token replacement skipped." + Write-Warning "coverageResults: Azure Pipelines not detected. Machine-neutral token replacement skipped." } +if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } + @{ $RepoRoot = ( (Get-ChildItem "$RepoRoot\bin\coverage.cobertura.xml" -Recurse) + diff --git a/azure-pipelines/artifacts/deployables.ps1 b/azure-pipelines/artifacts/deployables.ps1 index 893df6dd..94c48cdd 100644 --- a/azure-pipelines/artifacts/deployables.ps1 +++ b/azure-pipelines/artifacts/deployables.ps1 @@ -6,6 +6,8 @@ if (!$BuildConfiguration) { $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" +if (!(Test-Path $PackagesRoot)) { return } + @{ "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) } diff --git a/azure-pipelines/artifacts/projectAssetsJson.ps1 b/azure-pipelines/artifacts/projectAssetsJson.ps1 index 5e9217bd..d2e85ffb 100644 --- a/azure-pipelines/artifacts/projectAssetsJson.ps1 +++ b/azure-pipelines/artifacts/projectAssetsJson.ps1 @@ -1,7 +1,9 @@ -$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +$ObjRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\obj") + +if (!(Test-Path $ObjRoot)) { return } @{ - "$RepoRoot\obj" = ( - (Get-ChildItem "$RepoRoot\obj\project.assets.json" -Recurse) + "$ObjRoot" = ( + (Get-ChildItem "$ObjRoot\project.assets.json" -Recurse) ); } From 3731857e1e4baa0782fedcd803fc7b5424598f9b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Jul 2019 13:58:00 -0600 Subject: [PATCH 025/704] Collect symbols artifact and publish to ADO --- azure-pipelines/Convert-PDB.ps1 | 37 ++++++++++++++++ azure-pipelines/Get-NuGetTool.ps1 | 21 +++++++++ azure-pipelines/artifacts/symbols.ps1 | 64 +++++++++++++++++++++++++++ azure-pipelines/dotnet.yml | 9 ++++ 4 files changed, 131 insertions(+) create mode 100644 azure-pipelines/Convert-PDB.ps1 create mode 100644 azure-pipelines/Get-NuGetTool.ps1 create mode 100644 azure-pipelines/artifacts/symbols.ps1 diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1 new file mode 100644 index 00000000..00549f71 --- /dev/null +++ b/azure-pipelines/Convert-PDB.ps1 @@ -0,0 +1,37 @@ +<# +.SYNOPSIS + Builds all projects in this repo. +.PARAMETER DllPath + The path to the DLL whose PDB is to be converted. +.PARAMETER PdbPath + The path to the PDB to convert. May be omitted if the DLL was compiled on this machine and the PDB is still at its original path. +.PARAMETER OutputPath + The path of the output PDB to write. +#> +#Function Convert-PortableToWindowsPDB() { + Param( + [Parameter(Mandatory=$true,Position=0)] + [string]$DllPath, + [Parameter()] + [string]$PdbPath, + [Parameter(Mandatory=$true,Position=1)] + [string]$OutputPath + ) + + $version = '1.1.0-beta1-64128-01' + $baseDir = "$PSScriptRoot\..\obj\tools" + $pdb2pdbpath = "$baseDir\pdb2pdb.$version\tools\Pdb2Pdb.exe" + if (-not (Test-Path $pdb2pdbpath)) { + if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } + $baseDir = (Resolve-Path $baseDir).Path # Normalize it + & (& $PSScriptRoot\Get-NuGetTool.ps1) install pdb2pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://dotnet.myget.org/F/symreader-converter/api/v3/index.json | Out-Null + } + + $args = $DllPath,'/out',$OutputPath,'/nowarn','0021' + if ($PdbPath) { + $args += '/pdb',$PdbPath + } + + Write-Verbose "$pdb2pdbpath $args" + & $pdb2pdbpath $args +#} diff --git a/azure-pipelines/Get-NuGetTool.ps1 b/azure-pipelines/Get-NuGetTool.ps1 new file mode 100644 index 00000000..59d6187a --- /dev/null +++ b/azure-pipelines/Get-NuGetTool.ps1 @@ -0,0 +1,21 @@ +<# +.SYNOPSIS + Downloads the NuGet.exe tool and returns the path to it. +.PARAMETER NuGetVersion + The version of the NuGet tool to acquire. +#> +Param( + [Parameter()] + [string]$NuGetVersion='5.0.2' +) + +$binaryToolsPath = "$PSScriptRoot\..\obj\tools\nuget.$NuGetVersion" +if (!(Test-Path $binaryToolsPath)) { $null = New-Item -Type Directory -Path $binaryToolsPath } +$nugetPath = "$binaryToolsPath\nuget.exe" + +if (!(Test-Path $nugetPath)) { + Write-Host "Downloading nuget.exe $NuGetVersion..." -ForegroundColor Yellow + Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/v$NuGetVersion/NuGet.exe" -OutFile $nugetPath | Out-Null +} + +Write-Output (Resolve-Path $nugetPath).Path diff --git a/azure-pipelines/artifacts/symbols.ps1 b/azure-pipelines/artifacts/symbols.ps1 new file mode 100644 index 00000000..50491368 --- /dev/null +++ b/azure-pipelines/artifacts/symbols.ps1 @@ -0,0 +1,64 @@ +Function Get-SymbolFiles { + [CmdletBinding()] + param ( + [parameter(Mandatory=$true)] + [string]$Path + ) + + $WindowsPdbSubDirName = "symstore" + + $ActivityName = "Collecting symbols from $Path" + Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" + $PDBs = Get-ChildItem -rec "$Path\*.pdb" |? { $_.FullName -notmatch "unittest|tests|\W$WindowsPdbSubDirName\W" } + Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" + $PDBsByHash = @{} + $i = 0 + $PDBs |% { + Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length) + $hash = Get-FileHash $_ + $i++ + Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash + Write-Output $_ + } | Sort-Object CreationTime |% { + # De-dupe based on hash. Prefer the first match so we take the first built copy. + if (-not $PDBsByHash.ContainsKey($_.Hash)) { + $PDBsByHash.Add($_.Hash, $_.FullName) + Write-Output $_ + } + } |% { + # Collect the DLLs/EXEs as well. + $dllPath = "$($_.Directory)\$($_.BaseName).dll" + $exePath = "$($_.Directory)\$($_.BaseName).exe" + if (Test-Path $dllPath) { + $BinaryImagePath = $dllPath + } elseif (Test-Path $exePath) { + $BinaryImagePath = $exePath + } + + Write-Output $BinaryImagePath + + # Convert the PDB to legacy Windows PDBs + Write-Host "Converting PDB for $_" -ForegroundColor DarkGray + $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" + if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } + & "$PSScriptRoot\..\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb" + if ($LASTEXITCODE -ne 0) { + Write-Warning "PDB conversion of `"$_`" failed." + } + + Write-Output "$WindowsPdbDir\$($_.BaseName).pdb" + } +} + +# This doesn't work off Windows, nor do we need to convert symbols on multiple OS agents +if ($IsMacOS -or $IsLinux) { + return; +} + +$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin") +if (!(Test-Path $BinPath)) { return } +$symbolfiles = Get-SymbolFiles -Path $BinPath | Get-Unique + +@{ + "$BinPath" = $SymbolFiles; +} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 1ca019a0..e14c1bbb 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -50,6 +50,15 @@ steps: displayName: Publish artifacts condition: succeededOrFailed() +- task: PublishSymbols@2 + inputs: + SymbolsFolder: $(Build.ArtifactStagingDirectory)/symbols-Windows + SearchPattern: '**/*.pdb' + IndexSources: false + SymbolServerType: TeamServices + displayName: Publish symbols to symbol server + condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Agent.OS'], 'Windows_NT')) + - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') From 46d8abc111c18c3ffba75a3ab8e4f379eda2cef2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Jul 2019 22:03:09 -0600 Subject: [PATCH 026/704] Don't fail build when codecov.io is down --- azure-pipelines/dotnet.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index e14c1bbb..6641ebb9 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -63,3 +63,4 @@ steps: displayName: Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') timeoutInMinutes: 3 + continueOnError: true From 1ae312b50b3247ef07ae48a9b98f0c897b40ef2b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 13 Jul 2019 01:25:59 -0600 Subject: [PATCH 027/704] Stop calling chmod on Windows Not all custom Windows agents have this available. --- tools/Install-DotNetSdk.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 9db8558f..3061edf8 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -56,7 +56,9 @@ if ($IsMacOS -or $IsLinux) { if (-not (Test-Path $DotNetInstallScriptPath)) { Invoke-WebRequest -Uri $DownloadUri -OutFile $DotNetInstallScriptPath - chmod +x $DotNetInstallScriptPath + if ($IsMacOS -or $IsLinux) { + chmod +x $DotNetInstallScriptPath + } } if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { From 8bd008e9cef9a7499a767bb30c9fd14f78f97f73 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 13 Jul 2019 01:42:22 -0600 Subject: [PATCH 028/704] Avoid ln on Windows Some custom Windows agents don't have this --- azure-pipelines/artifacts/_pipelines.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index 59dd2cf2..dce2d5a8 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -30,7 +30,11 @@ function Create-SymbolicLink { $LinkContainer = Split-Path $Link -Parent if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer } Write-Verbose "Linking $Link to $Target" - ln $Target $Link + if ($IsMacOS -or $IsLinux) { + ln $Target $Link + } else { + cmd /c mklink $Link $Target + } } # Stage all artifacts From 354c7db5d602f3e7e6436b3b8cd28e00193e1685 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 13 Jul 2019 01:46:28 -0600 Subject: [PATCH 029/704] Install nbgv to Agent.TempDirectory Avoids errors when nbgv is already installed on a custom agent --- azure-pipelines/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 3ee5b0b9..7e18277e 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -8,8 +8,8 @@ jobs: - template: install-dependencies.yml - powershell: | - dotnet tool install --tool-path $(Agent.ToolsDirectory) nbgv --ignore-failed-sources - $(Agent.ToolsDirectory)/nbgv cloud + dotnet tool install --tool-path $(Agent.TempDirectory) nbgv --ignore-failed-sources + $(Agent.TempDirectory)/nbgv cloud displayName: Set build number - template: dotnet.yml From 2da189df18af52ab540789cd9f1a0430feb87d4a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 13 Jul 2019 01:49:37 -0600 Subject: [PATCH 030/704] Display dotnet --info after prereq installation --- azure-pipelines/install-dependencies.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 38fa5c08..2e6a3234 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -5,5 +5,7 @@ steps: failOnStderr: true displayName: Set pipeline variables based on source -- powershell: .\init.ps1 +- powershell: | + .\init.ps1 + dotnet --info displayName: Install prerequisites From 00bcb28bfc4095207bab694ca2ae8a71810733be Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 15 Jul 2019 10:35:04 -0600 Subject: [PATCH 031/704] Add init.cmd, nbgv tool improvements, etc. --- azure-pipelines/Get-nbgv.ps1 | 29 +++++++++++++++++++++++ azure-pipelines/artifacts/_pipelines.ps1 | 1 - azure-pipelines/build.yml | 10 +++++--- azure-pipelines/install-dependencies.yml | 11 +++++---- azure-pipelines/nbgv.nuget.config | 7 ++++++ azure-pipelines/variables/_all.ps1 | 1 + init.cmd | 3 +++ tools/Install-DotNetSdk.ps1 | 30 +++++++++++++++++------- 8 files changed, 74 insertions(+), 18 deletions(-) create mode 100644 azure-pipelines/Get-nbgv.ps1 create mode 100644 azure-pipelines/nbgv.nuget.config create mode 100644 init.cmd diff --git a/azure-pipelines/Get-nbgv.ps1 b/azure-pipelines/Get-nbgv.ps1 new file mode 100644 index 00000000..bc9c11c8 --- /dev/null +++ b/azure-pipelines/Get-nbgv.ps1 @@ -0,0 +1,29 @@ +<# +.SYNOPSIS + Gets the path to the nbgv CLI tool, installing it if necessary. +#> +Param( +) + +$existingTool = Get-Command "nbgv" -ErrorAction SilentlyContinue +if ($existingTool) { + return $existingTool.Path +} + +if ($env:AGENT_TEMPDIRECTORY) { + $toolInstallDir = "$env:AGENT_TEMPDIRECTORY/$env:BUILD_BUILDID" +} else { + $toolInstallDir = "$PSScriptRoot/obj/tools" +} + +$toolPath = "$toolInstallDir/nbgv" +if (!(Test-Path $toolPath)) { New-Item -Path $toolPath -ItemType Directory | Out-Null } +$toolPath = (Resolve-Path $toolPath).Path + +if (!(Get-Command $toolPath -ErrorAction SilentlyContinue)) { + Write-Host "Installing nbgv to $toolInstallDir" + dotnet tool install --tool-path "$toolInstallDir" nbgv --configfile "$PSScriptRoot\nbgv.nuget.config" | Out-Null +} + +# Normalize the path on the way out. +return (Get-Command $toolPath).Path diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index dce2d5a8..270a9604 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -6,7 +6,6 @@ param ( ) $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") -if (!$env:BUILDCONFIGURATION) { throw "BUILDCONFIGURATION environment variable must be set." } if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY } else { diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 7e18277e..6eeca905 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -5,11 +5,11 @@ jobs: - job: Windows pool: ${{ parameters.windowsPool }} steps: + - checkout: self + clean: true # "all" doesn't work, but "true" does, despite YAML docs - template: install-dependencies.yml - - powershell: | - dotnet tool install --tool-path $(Agent.TempDirectory) nbgv --ignore-failed-sources - $(Agent.TempDirectory)/nbgv cloud + - powershell: '& (azure-pipelines\Get-nbgv.ps1) cloud' displayName: Set build number - template: dotnet.yml @@ -19,6 +19,8 @@ jobs: pool: vmImage: Ubuntu 16.04 steps: + - checkout: self + clean: true # "all" doesn't work, but "true" does, despite YAML docs - template: install-dependencies.yml - template: dotnet.yml - template: expand-template.yml @@ -40,6 +42,8 @@ jobs: vmImage: Ubuntu 16.04 condition: succeededOrFailed() steps: + - checkout: self + clean: true # "all" doesn't work, but "true" does, despite YAML docs - template: install-dependencies.yml - template: publish-codecoverage.yml - template: publish-deployables.yml diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 2e6a3234..beacc44d 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -1,11 +1,12 @@ steps: -- task: PowerShell@2 - inputs: - filePath: azure-pipelines/variables/_pipelines.ps1 - failOnStderr: true - displayName: Set pipeline variables based on source - powershell: | .\init.ps1 dotnet --info displayName: Install prerequisites + +- task: PowerShell@2 + inputs: + filePath: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true + displayName: Set pipeline variables based on source diff --git a/azure-pipelines/nbgv.nuget.config b/azure-pipelines/nbgv.nuget.config new file mode 100644 index 00000000..765346e5 --- /dev/null +++ b/azure-pipelines/nbgv.nuget.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1 index 680a3398..ed099792 100644 --- a/azure-pipelines/variables/_all.ps1 +++ b/azure-pipelines/variables/_all.ps1 @@ -4,6 +4,7 @@ $vars = @{} Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" |% { + Write-Host "Computing $($_.BaseName) variable" $vars[$_.BaseName] = & $_ } diff --git a/init.cmd b/init.cmd new file mode 100644 index 00000000..5bef08da --- /dev/null +++ b/init.cmd @@ -0,0 +1,3 @@ +@set PS1UnderCmd=1 +powershell.exe -ExecutionPolicy bypass -Command "& '%~dpn0.ps1'" %* +@set PS1UnderCmd= diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 3061edf8..2eccce41 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -93,14 +93,17 @@ $runtimeVersions | Get-Unique |% { } } -Write-Host "Environment variables to be set:" -ForegroundColor Blue -$envVars - if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) { if ($env:TF_BUILD) { Write-Host "Azure Pipelines detected. Logging commands will be used to propagate environment variables and prepend path." } + if ($IsMacOS -or $IsLinux) { + $envVars['PATH'] = "${DotNetInstallDir}:$env:PATH" + } else { + $envVars['PATH'] = "$DotNetInstallDir;$env:PATH" + } + $envVars.GetEnumerator() |% { Set-Item -Path env:$($_.Key) -Value $_.Value @@ -110,13 +113,22 @@ if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these } } - if ($IsMacOS -or $IsLinux) { - $env:PATH = "${DotNetInstallDir}:$env:PATH" - } else { - $env:PATH = "$DotNetInstallDir;$env:PATH" - } - if ($env:TF_BUILD) { Write-Host "##vso[task.prependpath]$DotNetInstallDir" } } + +if ($env:PS1UnderCmd -eq '1') { + Write-Warning "Environment variable changes will be lost because you're running under cmd.exe. Run these commands manually:" + $envVars.GetEnumerator() |% { + if ($_.Key -eq 'PATH') { + # Special case this one for readability + Write-Host "SET PATH=$DotNetInstallDir;%PATH%" + } else { + Write-Host "SET $($_.Key)=$($_.Value)" + } + } +} else { + Write-Host "Environment variables set:" -ForegroundColor Blue + $envVars +} From 0691c8d0a1fda51e45e6d21bb9e73eefe74b3e0c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 16 Jul 2019 12:32:54 -0600 Subject: [PATCH 032/704] Avoid error when exactly one coverage.cobertura.xml file is found --- azure-pipelines/artifacts/coverageResults.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 index 619ac0f3..7d1e9a35 100644 --- a/azure-pipelines/artifacts/coverageResults.ps1 +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -16,7 +16,7 @@ if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } @{ $RepoRoot = ( - (Get-ChildItem "$RepoRoot\bin\coverage.cobertura.xml" -Recurse) + + @(Get-ChildItem "$RepoRoot\bin\coverage.cobertura.xml" -Recurse) + (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) ); } From 5e96a0b15c66226b05727ae79b1595936ff30f04 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 16 Jul 2019 14:51:24 -0600 Subject: [PATCH 033/704] Fix feed auth failure when merging reports It's important to always explicitly specify a nuget.config file when using dotnet tool install so that if a nuget.config file is present with feeds that require authentication, they are not tried. --- azure-pipelines/Get-nbgv.ps1 | 2 +- .../{nbgv.nuget.config => justnugetorg.nuget.config} | 0 azure-pipelines/publish-codecoverage.yml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename azure-pipelines/{nbgv.nuget.config => justnugetorg.nuget.config} (100%) diff --git a/azure-pipelines/Get-nbgv.ps1 b/azure-pipelines/Get-nbgv.ps1 index bc9c11c8..8459995f 100644 --- a/azure-pipelines/Get-nbgv.ps1 +++ b/azure-pipelines/Get-nbgv.ps1 @@ -22,7 +22,7 @@ $toolPath = (Resolve-Path $toolPath).Path if (!(Get-Command $toolPath -ErrorAction SilentlyContinue)) { Write-Host "Installing nbgv to $toolInstallDir" - dotnet tool install --tool-path "$toolInstallDir" nbgv --configfile "$PSScriptRoot\nbgv.nuget.config" | Out-Null + dotnet tool install --tool-path "$toolInstallDir" nbgv --configfile "$PSScriptRoot\justnugetorg.nuget.config" | Out-Null } # Normalize the path on the way out. diff --git a/azure-pipelines/nbgv.nuget.config b/azure-pipelines/justnugetorg.nuget.config similarity index 100% rename from azure-pipelines/nbgv.nuget.config rename to azure-pipelines/justnugetorg.nuget.config diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index b9b7b72a..5d987c83 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -18,7 +18,7 @@ steps: downloadPath: $(System.DefaultWorkingDirectory)/bin continueOnError: true - powershell: | - dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 + dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(System.DefaultWorkingDirectory)/bin/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" $reports = Get-ChildItem -Recurse "$(System.DefaultWorkingDirectory)/bin/coverage.cobertura.xml" From 5ee62bfe3556f392e9e1bfddcf2b25fd640e2b9e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 22 Jul 2019 09:48:42 -0600 Subject: [PATCH 034/704] Add support for Azure Artifact authenticated feeds --- CONTRIBUTING.md | 6 +++ azure-pipelines/Get-NuGetTool.ps1 | 9 ++-- azure-pipelines/Get-TempToolsPath.ps1 | 13 +++++ azure-pipelines/Set-EnvVars.ps1 | 39 +++++++++++++++ azure-pipelines/build.yml | 2 + azure-pipelines/dotnet.yml | 3 -- azure-pipelines/install-dependencies.yml | 5 +- init.ps1 | 39 ++++++++++++++- nuget.config | 2 +- tools/Install-NuGetCredProvider.ps1 | 62 ++++++++++++++++++++++++ 10 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 azure-pipelines/Get-TempToolsPath.ps1 create mode 100644 azure-pipelines/Set-EnvVars.ps1 create mode 100644 tools/Install-NuGetCredProvider.ps1 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f2f4a8ca..0893b308 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -27,6 +27,12 @@ using Windows PowerShell or [PowerShell Core][pwsh] (on any OS). This repository can be built on Windows, Linux, and OSX. +## Package restore + +The easiest way to restore packages may be to run `init.ps1` which automatically authenticates +to the feeds that packages for this repo come from, if any. +`dotnet restore` or `nuget restore` also work but may require extra steps to authenticate to any applicable feeds. + ## Building Building, testing, and packing this repository can be done by using the standard dotnet CLI commands (e.g. `dotnet build`, `dotnet test`, `dotnet pack`, etc.). diff --git a/azure-pipelines/Get-NuGetTool.ps1 b/azure-pipelines/Get-NuGetTool.ps1 index 59d6187a..fdf3ed55 100644 --- a/azure-pipelines/Get-NuGetTool.ps1 +++ b/azure-pipelines/Get-NuGetTool.ps1 @@ -9,13 +9,14 @@ Param( [string]$NuGetVersion='5.0.2' ) -$binaryToolsPath = "$PSScriptRoot\..\obj\tools\nuget.$NuGetVersion" -if (!(Test-Path $binaryToolsPath)) { $null = New-Item -Type Directory -Path $binaryToolsPath } -$nugetPath = "$binaryToolsPath\nuget.exe" +$toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" +$binaryToolsPath = Join-Path $toolsPath $NuGetVersion +if (!(Test-Path $binaryToolsPath)) { $null = mkdir $binaryToolsPath } +$nugetPath = Join-Path $binaryToolsPath nuget.exe if (!(Test-Path $nugetPath)) { Write-Host "Downloading nuget.exe $NuGetVersion..." -ForegroundColor Yellow Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/v$NuGetVersion/NuGet.exe" -OutFile $nugetPath | Out-Null } -Write-Output (Resolve-Path $nugetPath).Path +return (Resolve-Path $nugetPath).Path diff --git a/azure-pipelines/Get-TempToolsPath.ps1 b/azure-pipelines/Get-TempToolsPath.ps1 new file mode 100644 index 00000000..97c552c0 --- /dev/null +++ b/azure-pipelines/Get-TempToolsPath.ps1 @@ -0,0 +1,13 @@ +if ($env:AGENT_TOOLSDIRECTORY) { + $path = "$env:AGENT_TOOLSDIRECTORY\vs-platform\tools" +} elseif ($env:localappdata) { + $path = "$env:localappdata\vs-platform\tools" +} else { + $path = "$PSScriptRoot\..\obj\tools" +} + +if (!(Test-Path $path)) { + New-Item -ItemType Directory -Path $Path | Out-Null +} + +(Resolve-Path $path).Path diff --git a/azure-pipelines/Set-EnvVars.ps1 b/azure-pipelines/Set-EnvVars.ps1 new file mode 100644 index 00000000..313cecff --- /dev/null +++ b/azure-pipelines/Set-EnvVars.ps1 @@ -0,0 +1,39 @@ +<# +.SYNOPSIS + Set environment variables in the environment. + Azure Pipeline and CMD environments are considered. +.PARAMETER Variables + A hashtable of variables to be set. +.OUTPUTS + A boolean indicating whether the environment variables can be expected to propagate to the caller's environment. +#> +[CmdletBinding(SupportsShouldProcess=$true)] +Param( + [Parameter(Mandatory=$true, Position=1)] + $Variables +) + +if ($Variables.Count -eq 0) { + return $true +} + +$cmdInstructions = !$env:TF_BUILD -and $env:PS1UnderCmd -eq '1' +if ($cmdInstructions) { + Write-Warning "Environment variables have been set that will be lost because you're running under cmd.exe" + Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue +} + +$Variables.GetEnumerator() |% { + Set-Item -Path env:$($_.Key) -Value $_.Value + + # If we're running in Azure Pipelines, set these environment variables + if ($env:TF_BUILD) { + Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" + } + + if ($cmdInstructions) { + Write-Host "SET $($_.Key)=$($_.Value)" + } +} + +return !$cmdInstructions diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 6eeca905..f81d7f14 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -45,5 +45,7 @@ jobs: - checkout: self clean: true # "all" doesn't work, but "true" does, despite YAML docs - template: install-dependencies.yml + parameters: + initArgs: -NoRestore - template: publish-codecoverage.yml - template: publish-deployables.yml diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 6641ebb9..96569224 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -1,7 +1,4 @@ steps: -- script: dotnet restore /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/restore.binlog" - displayName: dotnet restore - workingDirectory: src - script: dotnet build --no-restore -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" displayName: dotnet build diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index beacc44d..8da07957 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -1,7 +1,10 @@ +parameters: + initArgs: + steps: - powershell: | - .\init.ps1 + .\init.ps1 -AccessToken '$(System.AccessToken)' ${{ parameters['initArgs'] }} dotnet --info displayName: Install prerequisites diff --git a/init.ps1 b/init.ps1 index 41e5556b..17389cbc 100644 --- a/init.ps1 +++ b/init.ps1 @@ -9,11 +9,46 @@ Per-user allows sharing the installed dependencies across repositories and allow Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. +.PARAMETER NoPrerequisites +Skips the installation of prerequisite software (e.g. SDKs, tools). +.PARAMETER NoRestore +Skips the package restore step. +.PARAMETER AccessToken +An optional access token for authenticating to Azure Artifacts authenticated feeds. #> [CmdletBinding(SupportsShouldProcess=$true)] Param ( [ValidateSet('repo','user')] - [string]$InstallLocality='user' + [string]$InstallLocality='user', + [Parameter()] + [switch]$NoPrerequisites, + [Parameter()] + [switch]$NoRestore, + [Parameter()] + [string]$AccessToken ) -& "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality +if (!$NoPrerequisites) { + & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken + & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality +} + +Push-Location $PSScriptRoot +try { + $HeaderColor = 'Green' + + if (!$NoRestore) { + Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor + dotnet restore src + if ($lastexitcode -ne 0) { + throw "Failure while restoring packages." + } + } +} +catch { + Write-Error $error[0] + exit $lastexitcode +} +finally { + Pop-Location +} diff --git a/nuget.config b/nuget.config index 4941d22b..d068efcf 100644 --- a/nuget.config +++ b/nuget.config @@ -3,6 +3,6 @@ - + diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 new file mode 100644 index 00000000..df450dc7 --- /dev/null +++ b/tools/Install-NuGetCredProvider.ps1 @@ -0,0 +1,62 @@ +<# +.SYNOPSIS + Downloads and installs the Microsoft Artifacts Credential Provider + from https://github.com/microsoft/artifacts-credprovider + to assist in authenticating to Azure Artifact feeds in interactive development + or unattended build agents. +.PARAMETER AccessToken + An optional access token for authenticating to Azure Artifacts authenticated feeds. +#> +[CmdletBinding()] +Param ( + [Parameter()] + [string]$AccessToken +) + +$toolsPath = & "$PSScriptRoot\..\azure-pipelines\Get-TempToolsPath.ps1" + +if ($IsMacOS -or $IsLinux) { + $installerScript = "installcredprovider.sh" + $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh" +} else { + $installerScript = "installcredprovider.ps1" + $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1" +} + +$installerScript = Join-Path $toolsPath $installerScript + +if (!(Test-Path $installerScript)) { + Invoke-WebRequest $sourceUrl -OutFile $installerScript +} + +$installerScript = (Resolve-Path $installerScript).Path + +if ($IsMacOS -or $IsLinux) { + chmod u+x $installerScript +} + +& $installerScript + +if ($AccessToken) { + $endpoints = @() + + $nugetConfig = [xml](Get-Content -Path "$PSScriptRoot\..\nuget.config") + + $nugetConfig.configuration.packageSources.add |? { $_.value -match '^https://pkgs\.dev\.azure\.com/' } |% { + $endpoint = New-Object -TypeName PSObject + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name endpoint -Value $_.value + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name username -Value ado + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name password -Value $AccessToken + $endpoints += $endpoint + } + + $auth = New-Object -TypeName PSObject + Add-Member -InputObject $auth -MemberType NoteProperty -Name endpointCredentials -Value $endpoints + + $authJson = ConvertTo-Json -InputObject $auth + $envVars = @{ + 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'=$authJson; + } + + & "$PSScriptRoot\..\azure-pipelines\Set-EnvVars.ps1" -Variables $envVars | Out-Null +} From a7959d73f580b59b62b49b5fb526e1d4d0bc0115 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 28 Jul 2019 17:07:53 -0600 Subject: [PATCH 035/704] Add option to install SDKs machine-wide --- init.ps1 | 7 ++- tools/Install-DotNetSdk.ps1 | 106 ++++++++++++++++++++++++++++-------- 2 files changed, 89 insertions(+), 24 deletions(-) diff --git a/init.ps1 b/init.ps1 index 17389cbc..599cfb47 100644 --- a/init.ps1 +++ b/init.ps1 @@ -2,13 +2,16 @@ .SYNOPSIS Installs dependencies required to build and test the projects in this repository. .DESCRIPTION -This does not require elevation, as the dependencies are installed in per-user locations. +This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, +unless `-InstallLocality machine` is specified. .PARAMETER InstallLocality A value indicating whether dependencies should be installed locally to the repo or at a per-user location. Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. +Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. +Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. .PARAMETER NoPrerequisites Skips the installation of prerequisite software (e.g. SDKs, tools). .PARAMETER NoRestore @@ -18,7 +21,7 @@ An optional access token for authenticating to Azure Artifacts authenticated fee #> [CmdletBinding(SupportsShouldProcess=$true)] Param ( - [ValidateSet('repo','user')] + [ValidateSet('repo','user','machine')] [string]$InstallLocality='user', [Parameter()] [switch]$NoPrerequisites, diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 2eccce41..a5d52eed 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -3,22 +3,102 @@ Installs the .NET SDK specified in the global.json file at the root of this repository, along with supporting .NET Core runtimes used for testing. .DESCRIPTION -This does not require elevation, as the SDK and runtimes are installed locally to this repo location. +This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, +unless `-InstallLocality machine` is specified. .PARAMETER InstallLocality A value indicating whether dependencies should be installed locally to the repo or at a per-user location. Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. +Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. +Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( - [ValidateSet('repo','user')] + [ValidateSet('repo','user','machine')] [string]$InstallLocality='user' ) -$DotNetInstallScriptRoot = "$PSScriptRoot/../obj" -if (!(Test-Path $DotNetInstallScriptRoot)) { mkdir $DotNetInstallScriptRoot | Out-Null } +$DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools" +if (!(Test-Path $DotNetInstallScriptRoot)) { New-Item -ItemType Directory -Path $DotNetInstallScriptRoot | Out-Null } +$DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot + +# Look up actual required .NET Core SDK version from global.json +$sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" + +# Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. +$runtimeVersions = @() +Get-ChildItem "$PSScriptRoot\..\src\*.*proj" -Recurse |% { + $projXml = [xml](Get-Content -Path $_) + $targetFrameworks = $projXml.Project.PropertyGroup.TargetFramework + if (!$targetFrameworks) { + $targetFrameworks = $projXml.Project.PropertyGroup.TargetFrameworks + if ($targetFrameworks) { + $targetFrameworks = $targetFrameworks -Split ';' + } + } + $targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% { + $runtimeVersions += $Matches[1] + } +} + +Function Get-FileFromWeb([Uri]$Uri, $OutDir) { + $OutFile = Join-Path $OutDir $Uri.Segments[-1] + if (!(Test-Path $OutFile)) { + Write-Verbose "Downloading $Uri..." + try { + (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) + } finally { + # This try/finally causes the script to abort + } + } + + $OutFile +} + +Function Get-InstallerExe($Version, [switch]$Runtime) { + $sdkOrRuntime = 'Sdk' + if ($Runtime) { $sdkOrRuntime = 'Runtime' } + + # Get the latest/actual version for the specified one + if (([Version]$Version).Build -eq -1) { + $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/latest.version") + $Version = $versionInfo[-1] + } + + Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-x64.exe" -OutDir "$DotNetInstallScriptRoot" +} + +Function Install-DotNet($Version, [switch]$Runtime) { + if ($Runtime) { $sdkSubstring = '' } else { $sdkSubstring = 'SDK ' } + Write-Host "Downloading .NET Core $sdkSubstring$Version..." + $Installer = Get-InstallerExe -Version $Version -Runtime:$Runtime + Write-Host "Installing .NET Core $sdkSubstring$Version..." + cmd /c start /wait $Installer /install /quiet + if ($LASTEXITCODE -ne 0) { + throw "Failure to install .NET Core SDK" + } +} + +if ($InstallLocality -eq 'machine') { + if ($IsMacOS -or $IsLinux) { + Write-Error "Installing the .NET Core SDK or runtime at a machine-wide location is only supported by this script on Windows." + exit 1 + } + + if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + Install-DotNet -Version $sdkVersion + } + + $runtimeVersions |% { + if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + Install-DotNet -Version $_ -Runtime + } + } + + return +} $switches = @( '-Architecture','x64' @@ -28,7 +108,6 @@ $envVars = @{ 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' = 'true'; } -$DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot if ($InstallLocality -eq 'repo') { $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet" } elseif ($env:AGENT_TOOLSDIRECTORY) { @@ -44,7 +123,6 @@ if ($DotNetInstallDir) { $envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0' $envVars['DOTNET_ROOT'] = $DotNetInstallDir } -$sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" if ($IsMacOS -or $IsLinux) { $DownloadUri = "https://dot.net/v1/dotnet-install.sh" @@ -67,22 +145,6 @@ if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" } -# Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. -$runtimeVersions = @() -Get-ChildItem "$PSScriptRoot\..\src\*.*proj" -Recurse |% { - $projXml = [xml](Get-Content -Path $_) - $targetFrameworks = $projXml.Project.PropertyGroup.TargetFramework - if (!$targetFrameworks) { - $targetFrameworks = $projXml.Project.PropertyGroup.TargetFrameworks - if ($targetFrameworks) { - $targetFrameworks = $targetFrameworks -Split ';' - } - } - $targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% { - $runtimeVersions += $Matches[1] - } -} - $switches += '-Runtime','dotnet' $runtimeVersions | Get-Unique |% { From 3ce68babff89107f16755b99e6ef05f96685af15 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 28 Jul 2019 21:07:54 -0600 Subject: [PATCH 036/704] Fix Get-nbgv.ps1 on Mac/Linux --- azure-pipelines/Get-nbgv.ps1 | 7 +++---- azure-pipelines/build.yml | 2 +- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/azure-pipelines/Get-nbgv.ps1 b/azure-pipelines/Get-nbgv.ps1 index 8459995f..925eecdd 100644 --- a/azure-pipelines/Get-nbgv.ps1 +++ b/azure-pipelines/Get-nbgv.ps1 @@ -13,16 +13,15 @@ if ($existingTool) { if ($env:AGENT_TEMPDIRECTORY) { $toolInstallDir = "$env:AGENT_TEMPDIRECTORY/$env:BUILD_BUILDID" } else { - $toolInstallDir = "$PSScriptRoot/obj/tools" + $toolInstallDir = "$PSScriptRoot/../obj/tools" } $toolPath = "$toolInstallDir/nbgv" -if (!(Test-Path $toolPath)) { New-Item -Path $toolPath -ItemType Directory | Out-Null } -$toolPath = (Resolve-Path $toolPath).Path +if (!(Test-Path $toolInstallDir)) { New-Item -Path $toolInstallDir -ItemType Directory | Out-Null } if (!(Get-Command $toolPath -ErrorAction SilentlyContinue)) { Write-Host "Installing nbgv to $toolInstallDir" - dotnet tool install --tool-path "$toolInstallDir" nbgv --configfile "$PSScriptRoot\justnugetorg.nuget.config" | Out-Null + dotnet tool install --tool-path "$toolInstallDir" nbgv --configfile "$PSScriptRoot/justnugetorg.nuget.config" | Out-Null } # Normalize the path on the way out. diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index f81d7f14..bc7facfa 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -9,7 +9,7 @@ jobs: clean: true # "all" doesn't work, but "true" does, despite YAML docs - template: install-dependencies.yml - - powershell: '& (azure-pipelines\Get-nbgv.ps1) cloud' + - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud' displayName: Set build number - template: dotnet.yml From 109cb712d6d68aad3bcaf26209c7ed26b8abc50c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 29 Jul 2019 07:01:49 -0600 Subject: [PATCH 037/704] Clean on mac agent too --- azure-pipelines/build.yml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index bc7facfa..05e32a18 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -6,7 +6,7 @@ jobs: pool: ${{ parameters.windowsPool }} steps: - checkout: self - clean: true # "all" doesn't work, but "true" does, despite YAML docs + clean: true - template: install-dependencies.yml - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud' @@ -20,7 +20,7 @@ jobs: vmImage: Ubuntu 16.04 steps: - checkout: self - clean: true # "all" doesn't work, but "true" does, despite YAML docs + clean: true - template: install-dependencies.yml - template: dotnet.yml - template: expand-template.yml @@ -29,6 +29,8 @@ jobs: pool: vmImage: macOS 10.13 steps: + - checkout: self + clean: true - template: install-dependencies.yml - template: dotnet.yml - template: expand-template.yml @@ -43,7 +45,7 @@ jobs: condition: succeededOrFailed() steps: - checkout: self - clean: true # "all" doesn't work, but "true" does, despite YAML docs + clean: true - template: install-dependencies.yml parameters: initArgs: -NoRestore From bea56a3333705f9c8cd8dd5d0f6e439ea398662d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 29 Jul 2019 08:46:14 -0600 Subject: [PATCH 038/704] Add nuget package copyright metadata --- src/Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index f4ef3297..475d57b8 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,5 +1,4 @@ - - + Debug $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\')) @@ -14,6 +13,7 @@ COMPANY-PLACEHOLDER COMPANY-PLACEHOLDER + © COMPANY-PLACEHOLDER. All rights reserved. MIT true true From 2bbbf08ee728b4e72a4224ff94f9854a2150d315 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 29 Jul 2019 08:54:24 -0600 Subject: [PATCH 039/704] Switch to 'download' syntax --- azure-pipelines/publish-codecoverage.yml | 22 ++++++++-------------- azure-pipelines/publish-deployables.yml | 8 +++----- 2 files changed, 11 insertions(+), 19 deletions(-) diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 5d987c83..6d367de9 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -1,27 +1,21 @@ steps: -- task: DownloadBuildArtifacts@0 +- download: current + artifact: coverageResults-Windows displayName: Download Windows code coverage results - inputs: - artifactName: coverageResults-Windows - downloadPath: $(System.DefaultWorkingDirectory)/bin continueOnError: true -- task: DownloadBuildArtifacts@0 +- download: current + artifact: coverageResults-Linux displayName: Download Linux code coverage results - inputs: - artifactName: coverageResults-Linux - downloadPath: $(System.DefaultWorkingDirectory)/bin continueOnError: true -- task: DownloadBuildArtifacts@0 +- download: current + artifact: coverageResults-macOS displayName: Download macOS code coverage results - inputs: - artifactName: coverageResults-macOS - downloadPath: $(System.DefaultWorkingDirectory)/bin continueOnError: true - powershell: | dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 --configfile azure-pipelines/justnugetorg.nuget.config - Copy-Item -Recurse $(System.DefaultWorkingDirectory)/bin/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj + Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" - $reports = Get-ChildItem -Recurse "$(System.DefaultWorkingDirectory)/bin/coverage.cobertura.xml" + $reports = Get-ChildItem -Recurse "$(Pipeline.Workspace)/coverage.cobertura.xml" $reports |% { $content = Get-Content -Path $_ |% { $_.Replace("{reporoot}", "$(System.DefaultWorkingDirectory)") } Set-Content -Path $_ -Value $content -Encoding UTF8 diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index cdd85292..3f6bb9da 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -1,15 +1,13 @@ steps: -- task: DownloadBuildArtifacts@0 +- download: current displayName: Download deployables - inputs: - artifactName: deployables-Windows - downloadPath: $(System.DefaultWorkingDirectory)/bin + artifact: deployables-Windows - task: DotNetCoreCLI@2 displayName: Push packages to CI feed inputs: command: push - packagesToPush: $(System.DefaultWorkingDirectory)/bin/deployables-Windows/*.nupkg + packagesToPush: $(Pipeline.Workspace)/deployables-Windows/*.nupkg nuGetFeedType: internal publishVstsFeed: $(ci_feed) allowPackageConflicts: true From c52d5ff380c256be1362a3e7d6da209cf1d80f57 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 1 Aug 2019 12:55:23 -0600 Subject: [PATCH 040/704] Update package references --- src/Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 475d57b8..8f62479f 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -23,9 +23,9 @@ - + - + From a66b8ad7f5034766b8d876348d550680e9fda596 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 1 Aug 2019 16:06:04 -0600 Subject: [PATCH 041/704] Don't break build when package conflicts happen in CI DotNetCliTool doesn't support the allowPackageConflicts parameter. --- azure-pipelines/publish-deployables.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index 3f6bb9da..a89f389f 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -3,7 +3,7 @@ steps: displayName: Download deployables artifact: deployables-Windows -- task: DotNetCoreCLI@2 +- task: NuGetCommand@2 displayName: Push packages to CI feed inputs: command: push From 747490e372cd36a440bcf0c83a0a8bf75d493e1e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 1 Aug 2019 17:18:50 -0600 Subject: [PATCH 042/704] Fix up VSTS references to Azure Pipelines --- azure-pipelines/artifacts/_pipelines.ps1 | 2 +- azure-pipelines/variables/_pipelines.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index 270a9604..7451ab11 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -1,5 +1,5 @@ # This script translates all the artifacts described by _all.ps1 -# into commands that instruct VSTS to actually collect those artifacts. +# into commands that instruct Azure Pipelines to actually collect those artifacts. param ( [string]$ArtifactNameSuffix diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index b3fde25d..9fa0c16b 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -1,5 +1,5 @@ # This script translates the variables returned by the _all.ps1 script -# into commands that instruct VSTS to actually set those variables for other VSTS tasks to consume. +# into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume. # The build or release definition may have set these variables to override # what the build would do. So only set them if they have not already been set. From 4ed1fa825f5f77ee04a11fab2bef44607b8205ce Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 4 Aug 2019 06:30:58 -0600 Subject: [PATCH 043/704] Add support for nuget feeds using old style URLs --- tools/Install-NuGetCredProvider.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 index df450dc7..ba70f2bd 100644 --- a/tools/Install-NuGetCredProvider.ps1 +++ b/tools/Install-NuGetCredProvider.ps1 @@ -42,7 +42,7 @@ if ($AccessToken) { $nugetConfig = [xml](Get-Content -Path "$PSScriptRoot\..\nuget.config") - $nugetConfig.configuration.packageSources.add |? { $_.value -match '^https://pkgs\.dev\.azure\.com/' } |% { + $nugetConfig.configuration.packageSources.add |? { ($_.value -match '^https://pkgs\.dev\.azure\.com/') -or ($_.value -match '^https://[\w\-]+\.pkgs\.visualstudio\.com/') } |% { $endpoint = New-Object -TypeName PSObject Add-Member -InputObject $endpoint -MemberType NoteProperty -Name endpoint -Value $_.value Add-Member -InputObject $endpoint -MemberType NoteProperty -Name username -Value ado From 02c4f0bb21a0fa9b57e8321f86118a5f234f35c8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 5 Aug 2019 09:26:04 -0600 Subject: [PATCH 044/704] Skip net472 tests after a build failure --- azure-pipelines/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 96569224..21b189f2 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -15,7 +15,7 @@ steps: arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true testRunTitle: net472-$(Agent.JobName) workingDirectory: src - condition: eq(variables['Agent.OS'], 'Windows_NT') + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp2.1 From 6957e47ebdb45d635db0721353870d49032ef992 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 5 Aug 2019 12:42:53 -0600 Subject: [PATCH 045/704] Update .NET Core SDK to 2.2.401 --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 93238784..3d26ee65 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.2.300" + "version": "2.2.401" } -} \ No newline at end of file +} From fe7fee63e1c044ea141b04418dae57ae7cc847b6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 7 Aug 2019 09:13:36 -0600 Subject: [PATCH 046/704] Fix formatting of xml and json files --- src/.editorconfig => .editorconfig | 0 .vscode/extensions.json | 32 ++++++++++++++---------------- nuget.config | 4 ++-- 3 files changed, 17 insertions(+), 19 deletions(-) rename src/.editorconfig => .editorconfig (100%) diff --git a/src/.editorconfig b/.editorconfig similarity index 100% rename from src/.editorconfig rename to .editorconfig diff --git a/.vscode/extensions.json b/.vscode/extensions.json index f910c687..8b1c54d6 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,18 +1,16 @@ { - // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. - // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp - - // List of extensions which should be recommended for users of this workspace. - "recommendations": [ - "ms-azure-devops.azure-pipelines", - "ms-vscode.csharp", - "k--kato.docomment", - "editorconfig.editorconfig", - "pflannery.vscode-versionlens", - "davidanson.vscode-markdownlint" - ], - // List of extensions recommended by VS Code that should not be recommended for users of this workspace. - "unwantedRecommendations": [ - - ] -} \ No newline at end of file + // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // List of extensions which should be recommended for users of this workspace. + "recommendations": [ + "ms-azure-devops.azure-pipelines", + "ms-vscode.csharp", + "k--kato.docomment", + "editorconfig.editorconfig", + "pflannery.vscode-versionlens", + "davidanson.vscode-markdownlint", + "dotjoshjohnson.xml" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] +} diff --git a/nuget.config b/nuget.config index d068efcf..1ee7a2bc 100644 --- a/nuget.config +++ b/nuget.config @@ -1,8 +1,8 @@ - + - + From 8f108fe64a258c923ab3322fe802c3c50651390b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 9 Aug 2019 10:15:03 -0600 Subject: [PATCH 047/704] Update NB.GV to 3.0.25 --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 8f62479f..8c337275 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -26,7 +26,7 @@ - + From 5847f0ae57e1277afff053774a11f7b64bb2b678 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 9 Aug 2019 13:51:24 -0600 Subject: [PATCH 048/704] Use a local package cache This ensures that restore always uses the sources in nuget.config rather than a cache that happens to be on the local box. It helps avoid bugs that are not caught till a build suddenly fails on some machine somewhere because it didn't happen to have a package cached locally from some other source. It also mitigates the risk on private build agents that a package cache is "poisoned" by some build already done on that agent with other package sources where the id/version of a package collides but the contents are not actually identical. --- nuget.config | 3 +++ 1 file changed, 3 insertions(+) diff --git a/nuget.config b/nuget.config index 1ee7a2bc..4949867c 100644 --- a/nuget.config +++ b/nuget.config @@ -1,5 +1,8 @@ + + + From 364dfe9f316b1ed9fb950bdb8dc51c361bb83a99 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 11 Aug 2019 23:15:23 -0600 Subject: [PATCH 049/704] When squashing, record the original commit ID --- Expand-Template.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index c050aba3..89614a2d 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -74,8 +74,9 @@ if (-not $sn) { Push-Location $PSScriptRoot try { if ($Squash) { + $originalCommitId = git rev-parse HEAD git reset --soft $(git rev-list --max-parents=0 HEAD) - git commit --amend -qm "Initial template from https://github.com/AArnott/Library.Template" + git commit --amend -qm "Initial template from https://github.com/AArnott/Library.Template" -m "Original commit from template $originalCommitId" } # Rename project directories and solution From 4705734f048b74f2dedb26799b157dcb7d74571e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 16 Aug 2019 16:48:54 -0600 Subject: [PATCH 050/704] Fix nuget install Get packages into a subdirectory and use nuget.exe 5.2.0 so it works with the credential provider. --- azure-pipelines/Get-NuGetTool.ps1 | 2 +- nuget.config | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/Get-NuGetTool.ps1 b/azure-pipelines/Get-NuGetTool.ps1 index fdf3ed55..623bb6f0 100644 --- a/azure-pipelines/Get-NuGetTool.ps1 +++ b/azure-pipelines/Get-NuGetTool.ps1 @@ -6,7 +6,7 @@ #> Param( [Parameter()] - [string]$NuGetVersion='5.0.2' + [string]$NuGetVersion='5.2.0' ) $toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" diff --git a/nuget.config b/nuget.config index 4949867c..38588711 100644 --- a/nuget.config +++ b/nuget.config @@ -2,6 +2,7 @@ + From 4ecab1957dd720fb5110f882475090d8a540aad3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 16 Aug 2019 16:54:28 -0600 Subject: [PATCH 051/704] Redirect Only divert global package cache in Azure Pipelines On local machines, file locks on the global package cache can cause `git clean -fdx` to fail. It also causes package restore times to be longer on local boxes after cleaning. The extra protection afforded by a diverted package cache is good, but is probably sufficient to provide only in Azure Pipelines, or explicitly by the user when they want it. --- azure-pipelines.yml | 1 + nuget.config | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f158ff52..539df93a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -16,6 +16,7 @@ variables: BuildPlatform: Any CPU codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed + NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages jobs: - template: azure-pipelines/build.yml diff --git a/nuget.config b/nuget.config index 38588711..c0173d1b 100644 --- a/nuget.config +++ b/nuget.config @@ -1,7 +1,6 @@ - From 8931dfb7818bb7e5173cbdd991d8af2c2a6699ca Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 16 Aug 2019 17:03:52 -0600 Subject: [PATCH 052/704] Download nuget.exe much more quickly Invoke-WebRequest is a terribly slow way to download files. --- azure-pipelines/Get-NuGetTool.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Get-NuGetTool.ps1 b/azure-pipelines/Get-NuGetTool.ps1 index 623bb6f0..4431adb9 100644 --- a/azure-pipelines/Get-NuGetTool.ps1 +++ b/azure-pipelines/Get-NuGetTool.ps1 @@ -16,7 +16,7 @@ $nugetPath = Join-Path $binaryToolsPath nuget.exe if (!(Test-Path $nugetPath)) { Write-Host "Downloading nuget.exe $NuGetVersion..." -ForegroundColor Yellow - Invoke-WebRequest -Uri "https://dist.nuget.org/win-x86-commandline/v$NuGetVersion/NuGet.exe" -OutFile $nugetPath | Out-Null + (New-Object System.Net.WebClient).DownloadFile("https://dist.nuget.org/win-x86-commandline/v$NuGetVersion/NuGet.exe", $nugetPath) } return (Resolve-Path $nugetPath).Path From 5cc44c4f2bbfd483104621a636e924a2e0544dc4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 10 Sep 2019 17:19:48 -0600 Subject: [PATCH 053/704] Improve Azure Pipelines build reliability This works around a bug that causes our Windows agent to very frequently fail in the nuget credential provider. --- init.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/init.ps1 b/init.ps1 index 599cfb47..e01f3aed 100644 --- a/init.ps1 +++ b/init.ps1 @@ -36,6 +36,10 @@ if (!$NoPrerequisites) { & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality } +# Workaround nuget credential provider bug that causes very unreliable package restores on Azure Pipelines +$env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS=20 +$env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS=20 + Push-Location $PSScriptRoot try { $HeaderColor = 'Green' From 70dcacac07c281ebe1e60ce5acbb5a22e1449df7 Mon Sep 17 00:00:00 2001 From: Eilon Lipton Date: Tue, 17 Sep 2019 15:22:46 -0700 Subject: [PATCH 054/704] Use HTTPS URLs wherever possible --- .vscode/extensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 8b1c54d6..c5b615df 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,5 +1,5 @@ { - // See http://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp // List of extensions which should be recommended for users of this workspace. "recommendations": [ From 4641b826b0717b388f241a7eeda281f344d7042a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 21 Sep 2019 21:53:35 -0600 Subject: [PATCH 055/704] Fix auto-build of validate/* branches --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 539df93a..c4c3f607 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,7 +2,7 @@ trigger: branches: include: - master - - validate/* + - 'validate/*' paths: exclude: - doc/ From a77d264bbc72eb0f201c2fc14db40525746417d9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 25 Sep 2019 06:26:38 -0600 Subject: [PATCH 056/704] Suppress an unreasonable static analysis rule for tests --- src/tests.ruleset | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tests.ruleset b/src/tests.ruleset index 4b4708a1..a1365976 100644 --- a/src/tests.ruleset +++ b/src/tests.ruleset @@ -12,4 +12,7 @@ + + + From dfc7dea7c1e5b534a59206b8e9ab5996313c7cd3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 25 Sep 2019 06:26:43 -0600 Subject: [PATCH 057/704] Add a bunch of useful solution items --- src/Library.sln | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/src/Library.sln b/src/Library.sln index 17645391..09dfb1fe 100644 --- a/src/Library.sln +++ b/src/Library.sln @@ -1,20 +1,30 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.26124.0 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.29322.22 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library", "Library\Library.csproj", "{C06D702E-6FC7-453B-BDDF-608F825EC003}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library", "Library\Library.csproj", "{C06D702E-6FC7-453B-BDDF-608F825EC003}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Library.Tests", "Library.Tests\Library.Tests.csproj", "{DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library.Tests", "Library.Tests\Library.Tests.csproj", "{DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1CE9670B-D5FF-46A7-9D00-24E70E6ED48B}" + ProjectSection(SolutionItems) = preProject + ..\.editorconfig = ..\.editorconfig + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets + ..\global.json = ..\global.json + ..\nuget.config = ..\nuget.config + shipping.ruleset = shipping.ruleset + stylecop.json = stylecop.json + tests.ruleset = tests.ruleset + ..\version.json = ..\version.json + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU Release|Any CPU = Release|Any CPU EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {C06D702E-6FC7-453B-BDDF-608F825EC003}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {C06D702E-6FC7-453B-BDDF-608F825EC003}.Debug|Any CPU.Build.0 = Debug|Any CPU @@ -25,4 +35,10 @@ Global {DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}.Release|Any CPU.ActiveCfg = Release|Any CPU {DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {E3944F6A-384B-4B0F-B93F-3BD513DC57BD} + EndGlobalSection EndGlobal From 3c52f6060a928ea6a5297bcabdaf927bdc921cf3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 25 Sep 2019 06:26:06 -0600 Subject: [PATCH 058/704] Enable C# 8 nullable features Also update to 3.0 .NET Core SDK as required for the nullable feature. --- global.json | 2 +- src/Directory.Build.props | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 3d26ee65..79422f0c 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "2.2.401" + "version": "3.0.100" } } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 8c337275..9c875502 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -5,7 +5,8 @@ $(RepoRootPath)obj\$(MSBuildProjectName)\ $(RepoRootPath)bin\$(MSBuildProjectName)\ $(RepoRootPath)bin\Packages\$(Configuration)\ - 7.3 + 8.0 + enable true true From a2556bf66ce72ef84c33077b94a9c83100d88e37 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Oct 2019 08:35:23 -0600 Subject: [PATCH 059/704] Fix Install-DotNetSdk on machines without IE configured --- tools/Install-DotNetSdk.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index a5d52eed..50687706 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -63,7 +63,7 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { # Get the latest/actual version for the specified one if (([Version]$Version).Build -eq -1) { - $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/latest.version") + $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/latest.version" -UseBasicParsing) $Version = $versionInfo[-1] } @@ -133,7 +133,7 @@ if ($IsMacOS -or $IsLinux) { } if (-not (Test-Path $DotNetInstallScriptPath)) { - Invoke-WebRequest -Uri $DownloadUri -OutFile $DotNetInstallScriptPath + Invoke-WebRequest -Uri $DownloadUri -OutFile $DotNetInstallScriptPath -UseBasicParsing if ($IsMacOS -or $IsLinux) { chmod +x $DotNetInstallScriptPath } From f78ee0462a078f4190fa7e811e3a86105f545d61 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 14 Nov 2019 21:43:54 -0700 Subject: [PATCH 060/704] Capture exit codes within init.cmd from ps1 script --- init.cmd | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/init.cmd b/init.cmd index 5bef08da..970285c2 100644 --- a/init.cmd +++ b/init.cmd @@ -1,3 +1,4 @@ -@set PS1UnderCmd=1 -powershell.exe -ExecutionPolicy bypass -Command "& '%~dpn0.ps1'" %* -@set PS1UnderCmd= +@echo off +SETLOCAL +set PS1UnderCmd=1 +powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }" From 7248b76f71de8ba2afa097d129367d784c371159 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 14 Nov 2019 21:44:06 -0700 Subject: [PATCH 061/704] Add Expand-Template.cmd stub --- Expand-Template.cmd | 4 ++++ Expand-Template.ps1 | 13 +++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) create mode 100644 Expand-Template.cmd diff --git a/Expand-Template.cmd b/Expand-Template.cmd new file mode 100644 index 00000000..970285c2 --- /dev/null +++ b/Expand-Template.cmd @@ -0,0 +1,4 @@ +@echo off +SETLOCAL +set PS1UnderCmd=1 +powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }" diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index 89614a2d..5225f878 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -149,11 +149,11 @@ try { # Self destruct $Invocation = (Get-Variable MyInvocation -Scope 1).Value - git rm Expand-Template.ps1 + git rm Expand-Template.* git rm :/azure-pipelines/expand-template.yml # Self-integrity check - Get-ChildItem -Recurse -File -Exclude bin,obj,README.md,Expand-Template.ps1 |? { -not $_.FullName.Contains("obj") } |% { + Get-ChildItem -Recurse -File -Exclude bin,obj,README.md,Expand-Template.* |? { -not $_.FullName.Contains("obj") } |% { $PLACEHOLDERS = Get-Content -Path $_.FullName |? { $_.Contains('PLACEHOLDER') } if ($PLACEHOLDERS) { Write-Error "PLACEHOLDER discovered in $($_.FullName)" @@ -162,6 +162,15 @@ try { # Commit the changes git commit -qm "Expanded template for $LibraryName" -m "This expansion done by the (now removed) Expand-Template.ps1 script." + + Write-Host -ForegroundColor Green "Template successfully expanded." + + if ($env:PS1UnderCmd) { + # We're running under the Expand-Template.cmd script. + # Since we just deleted it from disk cmd.exe will complain. Just advise the user it's OK. + Write-Host -ForegroundColor Green 'Disregard an error you may see: "The batch file cannot be found." We just cleaned up after ourselves.' + } + } finally { Pop-Location } From 65c7a0b46f10e72cf2f73e169956da9b15170e4c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 14 Nov 2019 22:01:51 -0700 Subject: [PATCH 062/704] Fix synopsis of Convert-PDB.ps1 script Fixes #24 --- azure-pipelines/Convert-PDB.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1 index 00549f71..a3212213 100644 --- a/azure-pipelines/Convert-PDB.ps1 +++ b/azure-pipelines/Convert-PDB.ps1 @@ -1,6 +1,6 @@ <# .SYNOPSIS - Builds all projects in this repo. + Converts between Windows PDB and Portable PDB formats. .PARAMETER DllPath The path to the DLL whose PDB is to be converted. .PARAMETER PdbPath From d6fe2405533b5f5da639dfb65e1ef5e8dfabf4ee Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 14 Nov 2019 22:03:46 -0700 Subject: [PATCH 063/704] Add comment explaining where to get the guid from Fixes #28 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c4c3f607..2dbb2cbb 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,7 @@ variables: BuildConfiguration: Release BuildPlatform: Any CPU codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ - ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed + ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed. Learn more at https://github.com/AArnott/Library.Template/issues/28 NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages jobs: From 51d643cbab57eb43bc15d294e153c7ce40b76e9f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 22 Nov 2019 09:02:44 -0700 Subject: [PATCH 064/704] Avoid restoring packages under -whatif --- init.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init.ps1 b/init.ps1 index e01f3aed..f8ca00a5 100644 --- a/init.ps1 +++ b/init.ps1 @@ -44,7 +44,7 @@ Push-Location $PSScriptRoot try { $HeaderColor = 'Green' - if (!$NoRestore) { + if (!$NoRestore -and $PSCmdlet.ShouldProcess("NuGet packages", "Restore")) { Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor dotnet restore src if ($lastexitcode -ne 0) { From 5a6c63701f386823b6e12d4a0052d3ced73ae332 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 4 Dec 2019 13:03:21 -0700 Subject: [PATCH 065/704] Fix and add to the init.ps1 description docs --- init.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/init.ps1 b/init.ps1 index f8ca00a5..9dfb6afb 100644 --- a/init.ps1 +++ b/init.ps1 @@ -2,8 +2,9 @@ .SYNOPSIS Installs dependencies required to build and test the projects in this repository. .DESCRIPTION -This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, -unless `-InstallLocality machine` is specified. +This MAY not require elevation, as the SDK and runtimes are installed to a per-user location, +unless the `-InstallLocality` switch is specified directing to a per-repo or per-machine location. +See detailed help on that switch for more information. .PARAMETER InstallLocality A value indicating whether dependencies should be installed locally to the repo or at a per-user location. Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. From b79e0301b39153cbd09dca06767c7264178e274e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 11 Dec 2019 17:13:57 -0700 Subject: [PATCH 066/704] Use AGENT_TEMPDIRECTORY for tools AGENT_TOOLSDIRECTORY may not be cleaned between each build, so AGENT_TEMPDIRECTORY which certainly is cleaned is a better place to put files that might need newer versions downloaded and/or installed each time. --- azure-pipelines/Get-TempToolsPath.ps1 | 6 +++--- azure-pipelines/Get-nbgv.ps1 | 6 +----- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/azure-pipelines/Get-TempToolsPath.ps1 b/azure-pipelines/Get-TempToolsPath.ps1 index 97c552c0..bb3da8e3 100644 --- a/azure-pipelines/Get-TempToolsPath.ps1 +++ b/azure-pipelines/Get-TempToolsPath.ps1 @@ -1,7 +1,7 @@ -if ($env:AGENT_TOOLSDIRECTORY) { - $path = "$env:AGENT_TOOLSDIRECTORY\vs-platform\tools" +if ($env:AGENT_TEMPDIRECTORY) { + $path = "$env:AGENT_TEMPDIRECTORY\$env:BUILD_BUILDID" } elseif ($env:localappdata) { - $path = "$env:localappdata\vs-platform\tools" + $path = "$env:localappdata\gitrepos\tools" } else { $path = "$PSScriptRoot\..\obj\tools" } diff --git a/azure-pipelines/Get-nbgv.ps1 b/azure-pipelines/Get-nbgv.ps1 index 925eecdd..a5be2cf7 100644 --- a/azure-pipelines/Get-nbgv.ps1 +++ b/azure-pipelines/Get-nbgv.ps1 @@ -10,11 +10,7 @@ if ($existingTool) { return $existingTool.Path } -if ($env:AGENT_TEMPDIRECTORY) { - $toolInstallDir = "$env:AGENT_TEMPDIRECTORY/$env:BUILD_BUILDID" -} else { - $toolInstallDir = "$PSScriptRoot/../obj/tools" -} +$toolInstallDir = & "$PSScriptRoot/Get-TempToolsPath.ps1" $toolPath = "$toolInstallDir/nbgv" if (!(Test-Path $toolInstallDir)) { New-Item -Path $toolInstallDir -ItemType Directory | Out-Null } From 153cd7d1aaa4738c163e1ad2ee813075183890b0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 11 Dec 2019 17:31:06 -0700 Subject: [PATCH 067/704] Upgrade NuGet credprovider in Azure Pipelines On private agents where it may exist from a prior build, it's important that we update it to whatever the latest version is. --- azure-pipelines/install-dependencies.yml | 2 +- init.ps1 | 7 ++++++- tools/Install-NuGetCredProvider.ps1 | 6 +++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 8da07957..9257db85 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -4,7 +4,7 @@ parameters: steps: - powershell: | - .\init.ps1 -AccessToken '$(System.AccessToken)' ${{ parameters['initArgs'] }} + .\init.ps1 -AccessToken '$(System.AccessToken)' ${{ parameters['initArgs'] }} -UpgradePrerequisites dotnet --info displayName: Install prerequisites diff --git a/init.ps1 b/init.ps1 index 9dfb6afb..ae4ce9a6 100644 --- a/init.ps1 +++ b/init.ps1 @@ -15,6 +15,9 @@ Per-repo can lead to file locking issues when dotnet.exe is left running as a bu Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. .PARAMETER NoPrerequisites Skips the installation of prerequisite software (e.g. SDKs, tools). +.PARAMETER UpgradePrerequisites +Takes time to install prerequisites even if they are already present in case they need to be upgraded. +No effect if -NoPrerequisites is specified. .PARAMETER NoRestore Skips the package restore step. .PARAMETER AccessToken @@ -27,13 +30,15 @@ Param ( [Parameter()] [switch]$NoPrerequisites, [Parameter()] + [switch]$UpgradePrerequisites, + [Parameter()] [switch]$NoRestore, [Parameter()] [string]$AccessToken ) if (!$NoPrerequisites) { - & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken + & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality } diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 index ba70f2bd..0a8d77f6 100644 --- a/tools/Install-NuGetCredProvider.ps1 +++ b/tools/Install-NuGetCredProvider.ps1 @@ -4,11 +4,15 @@ from https://github.com/microsoft/artifacts-credprovider to assist in authenticating to Azure Artifact feeds in interactive development or unattended build agents. +.PARAMETER Force + Forces install of the CredProvider plugin even if one already exists. This is useful to upgrade an older version. .PARAMETER AccessToken An optional access token for authenticating to Azure Artifacts authenticated feeds. #> [CmdletBinding()] Param ( + [Parameter()] + [switch]$Force, [Parameter()] [string]$AccessToken ) @@ -35,7 +39,7 @@ if ($IsMacOS -or $IsLinux) { chmod u+x $installerScript } -& $installerScript +& $installerScript -Force:$Force if ($AccessToken) { $endpoints = @() From be9bbd097fb0410325e1d896f9d3a55f2280e64b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 18 Dec 2019 13:50:18 -0700 Subject: [PATCH 068/704] Update package refs Also stop packing pdb in main nupkg --- src/Directory.Build.props | 9 ++++----- src/Library.Tests/Library.Tests.csproj | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 9c875502..f6d3c9ce 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -20,14 +20,13 @@ true true snupkg - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - - - - + + + + diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj index 7323c8d9..08f74be7 100644 --- a/src/Library.Tests/Library.Tests.csproj +++ b/src/Library.Tests/Library.Tests.csproj @@ -14,8 +14,8 @@ - - + + From e888eb54024e259c801b9b37d363d08ef3eb3f1c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 24 Dec 2019 13:23:35 -0700 Subject: [PATCH 069/704] Bump SDK version to 3.1 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 79422f0c..e9aac8c2 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "3.0.100" + "version": "3.1.100" } } From 35bf0941b3900c248c745588f62d711a3bf6860c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 24 Dec 2019 13:36:35 -0700 Subject: [PATCH 070/704] Test on .NET Core 3.1 .NET Core 2.2 is no longer supported. Testing on 2.1 and 3.1 focus testing on LTS releases of .NET Core. --- azure-pipelines/dotnet.yml | 6 +++--- src/Library.Tests/Library.Tests.csproj | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 21b189f2..9d910d2d 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -26,11 +26,11 @@ steps: workingDirectory: src - task: DotNetCoreCLI@2 - displayName: dotnet test -f netcoreapp2.2 + displayName: dotnet test -f netcoreapp3.1 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.2 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true - testRunTitle: netcoreapp2.2-$(Agent.JobName) + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + testRunTitle: netcoreapp3.1-$(Agent.JobName) workingDirectory: src - task: PowerShell@2 diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj index 08f74be7..78ebcfd4 100644 --- a/src/Library.Tests/Library.Tests.csproj +++ b/src/Library.Tests/Library.Tests.csproj @@ -1,7 +1,7 @@ - net472;netcoreapp2.1;netcoreapp2.2 + net472;netcoreapp2.1;netcoreapp3.1 false $(NoWarn);CS1591 true From 56ab8cb586bb555875acdfe597465ef75aec5dcb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 24 Dec 2019 14:35:30 -0700 Subject: [PATCH 071/704] Use latest StyleCop As necessary for nullable ref type syntax to not flag as warnings in StyleCop --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index f6d3c9ce..ddd8ae60 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -27,7 +27,7 @@ - + From 366d5df26c31eb212dc49c970ec77597874b5fc3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Jan 2020 14:59:28 -0700 Subject: [PATCH 072/704] Start with GitHub Actions (#34) --- .github/workflows/build.yml | 99 ++++++++++++++++++++++++ Expand-Template.ps1 | 3 +- README.md | 4 +- azure-pipelines.yml | 1 - azure-pipelines/Set-EnvVars.ps1 | 46 ++++++++++- azure-pipelines/artifacts/Variables.ps1 | 10 +-- azure-pipelines/artifacts/_pipelines.ps1 | 49 +----------- azure-pipelines/artifacts/_stage_all.ps1 | 59 ++++++++++++++ azure-pipelines/build.yml | 4 +- azure-pipelines/variables/_pipelines.ps1 | 8 +- tools/Install-DotNetSdk.ps1 | 38 +-------- 11 files changed, 222 insertions(+), 99 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 azure-pipelines/artifacts/_stage_all.ps1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..4e991873 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,99 @@ +name: CI + +on: + push: + branches: + - master + - microbuild + - validate/* + pull_request: + +env: + TreatWarningsAsErrors: true + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + BUILDCONFIGURATION: Release + codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ + ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed. Learn more at https://github.com/AArnott/Library.Template/issues/28 +# NUGET_PACKAGES: ${{ env.GITHUB_WORKSPACE }}/.nuget/packages + +jobs: + build: + + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: + - ubuntu-18.04 + - macos-latest + - windows-latest + + steps: + - uses: actions/checkout@v2 + - name: Deep clone + run: git fetch --prune --unshallow origin HEAD + - name: Install prerequisites + run: | + ./init.ps1 -UpgradePrerequisites + dotnet --info + shell: pwsh + - name: Set pipeline variables based on source + run: azure-pipelines/variables/_pipelines.ps1 + shell: pwsh + - name: build + run: dotnet build src --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/build.binlog" + - name: pack + run: dotnet pack src --no-build -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/pack.binlog" + - name: test + run: dotnet test src --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + - name: Update pipeline variables based on build outputs + run: azure-pipelines/variables/_pipelines.ps1 + shell: pwsh + - name: Collect artifacts + run: azure-pipelines/artifacts/_stage_all.ps1 + shell: pwsh + - name: Upload project.assets.json files + if: always() + uses: actions/upload-artifact@v1 + with: + name: projectAssetsJson-${{ runner.os }} + path: obj/_artifacts/projectAssetsJson + continue-on-error: true + - name: Upload variables + uses: actions/upload-artifact@v1 + with: + name: variables + path: obj/_artifacts/variables + if: runner.os == 'Windows' + continue-on-error: true + - name: Upload build_logs + if: always() + uses: actions/upload-artifact@v1 + with: + name: build_logs-${{ runner.os }} + path: obj/_artifacts/build_logs + continue-on-error: true + - name: Upload coverageResults + if: always() + uses: actions/upload-artifact@v1 + with: + name: coverageResults-${{ runner.os }} + path: obj/_artifacts/coverageResults + continue-on-error: true + - name: Upload symbols + uses: actions/upload-artifact@v1 + with: + name: symbols + path: obj/_artifacts/symbols + if: runner.os == 'Windows' + continue-on-error: true + - name: Upload deployables + uses: actions/upload-artifact@v1 + with: + name: deployables + path: obj/_artifacts/deployables + if: runner.os == 'Windows' + - name: Publish code coverage results to codecov.io + run: bash <(curl -s https://codecov.io/bash) + shell: bash + timeout-minutes: 3 + continue-on-error: true diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index 5225f878..aa4f5ec2 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -125,7 +125,8 @@ try { } Replace-Placeholders -Path "README.md" -Replacements @{ "(?m)^.*\[NuGet package\][^`r`n]*"="[![NuGet package](https://img.shields.io/nuget/v/$LibraryName.svg)](https://nuget.org/packages/$LibraryName)" - "(?m)^.*\[Build Status\].*`r?`n"="" + "(?m)^.*\[Azure Pipelines status\].*`r?`n"="" + "(?m)^.*\[GitHub Actions status\].*`r?`n"="" "(?m)^.*\[codecov\].*`r?`n"="" } diff --git a/README.md b/README.md index d05ac0d7..0c3bcf59 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,9 @@ ***An awesome template for your awesome library*** ![NuGet package](https://img.shields.io/badge/nuget-your--package--here-yellow.svg) -[![Build Status](https://dev.azure.com/andrewarnott/OSS/_apis/build/status/AArnott.Library.Template?branchName=master)](https://dev.azure.com/andrewarnott/OSS/_build/latest?definitionId=29&branchName=master) + +[![Azure Pipelines status](https://dev.azure.com/andrewarnott/OSS/_apis/build/status/AArnott.Library.Template?branchName=master)](https://dev.azure.com/andrewarnott/OSS/_build/latest?definitionId=29&branchName=master) +![GitHub Actions status](https://github.com/aarnott/Library.Template/workflows/CI/badge.svg) [![codecov](https://codecov.io/gh/aarnott/library.template/branch/master/graph/badge.svg)](https://codecov.io/gh/aarnott/library.template) ## Features diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2dbb2cbb..c6eeb7b6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -13,7 +13,6 @@ variables: TreatWarningsAsErrors: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BuildConfiguration: Release - BuildPlatform: Any CPU codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed. Learn more at https://github.com/AArnott/Library.Template/issues/28 NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages diff --git a/azure-pipelines/Set-EnvVars.ps1 b/azure-pipelines/Set-EnvVars.ps1 index 313cecff..907659a7 100644 --- a/azure-pipelines/Set-EnvVars.ps1 +++ b/azure-pipelines/Set-EnvVars.ps1 @@ -10,30 +10,70 @@ [CmdletBinding(SupportsShouldProcess=$true)] Param( [Parameter(Mandatory=$true, Position=1)] - $Variables + $Variables, + [string[]]$PrependPath ) if ($Variables.Count -eq 0) { return $true } -$cmdInstructions = !$env:TF_BUILD -and $env:PS1UnderCmd -eq '1' +$cmdInstructions = !$env:TF_BUILD -and !$env:GITHUB_ACTIONS -and $env:PS1UnderCmd -eq '1' if ($cmdInstructions) { Write-Warning "Environment variables have been set that will be lost because you're running under cmd.exe" Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue +} else { + Write-Host "Environment variables set:" -ForegroundColor Blue + $envVars + if ($PrependPath) { + Write-Host "Paths prepended to PATH: $PrependPath" + } +} + +if ($env:TF_BUILD) { + Write-Host "Azure Pipelines detected. Logging commands will be used to propagate environment variables and prepend path." +} + +if ($env:GITHUB_ACTIONS) { + Write-Host "GitHub Actions detected. Logging commands will be used to propagate environment variables and prepend path." } $Variables.GetEnumerator() |% { Set-Item -Path env:$($_.Key) -Value $_.Value - # If we're running in Azure Pipelines, set these environment variables + # If we're running in a cloud CI, set these environment variables so they propagate. if ($env:TF_BUILD) { Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" } + if ($env:GITHUB_ACTIONS) { + Write-Host "::set-env name=$($_.Key)::$($_.Value)" + } if ($cmdInstructions) { Write-Host "SET $($_.Key)=$($_.Value)" } } +$pathDelimiter = ';' +if ($IsMacOS -or $IsLinux) { + $pathDelimiter = ':' +} + +if ($PrependPath) { + $PrependPath |% { + $newPathValue = "$_$pathDelimiter$env:PATH" + Set-Item -Path env:PATH -Value $newPathValue + if ($cmdInstructions) { + Write-Host "SET PATH=$newPathValue" + } + + if ($env:TF_BUILD) { + Write-Host "##vso[task.prependpath]$_" + } + if ($env:GITHUB_ACTIONS) { + Write-Host "::add-path::$_" + } + } +} + return !$cmdInstructions diff --git a/azure-pipelines/artifacts/Variables.ps1 b/azure-pipelines/artifacts/Variables.ps1 index cfcb7df5..2ee09d42 100644 --- a/azure-pipelines/artifacts/Variables.ps1 +++ b/azure-pipelines/artifacts/Variables.ps1 @@ -2,13 +2,13 @@ # It "snaps" the values of these variables where we can compute them during the build, # and otherwise captures the scripts to run later during an Azure Pipelines environment release. -$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") -$ArtifactBasePath = "$RepoRoot\obj\_artifacts" -$VariablesArtifactPath = "$ArtifactBasePath\variables" +$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot (Join-Path .. ..))) +$ArtifactBasePath = Join-Path $RepoRoot (Join-Path obj _artifacts) +$VariablesArtifactPath = Join-Path $ArtifactBasePath variables if (-not (Test-Path $VariablesArtifactPath)) { New-Item -ItemType Directory -Path $VariablesArtifactPath | Out-Null } # Copy variables, either by value if the value is calculable now, or by script -Get-ChildItem -Path "$PSScriptRoot\..\variables" |% { +Get-ChildItem -Path (Join-Path $PSScriptRoot (Join-Path .. variables)) |% { $value = $null if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts # First check the environment variables in case the variable was set in a queued build @@ -32,7 +32,7 @@ Get-ChildItem -Path "$PSScriptRoot\..\variables" |% { $value = Get-Content -Path $_.FullName } - Set-Content -Path "$VariablesArtifactPath\$($_.Name)" -Value $value + Set-Content -Path (Join-Path $VariablesArtifactPath $_.Name) -Value $value } @{ diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index 7451ab11..5bca7c6c 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -5,51 +5,6 @@ param ( [string]$ArtifactNameSuffix ) -$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") -if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { - $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY -} else { - $ArtifactStagingFolder = "$RepoRoot\obj\_artifacts" - if (Test-Path $ArtifactStagingFolder) { - Remove-Item $ArtifactStagingFolder -Recurse -Force - } -} - -function Create-SymbolicLink { - param ( - $Link, - $Target - ) - - if ($Link -eq $Target) { - return - } - - if (Test-Path $Link) { Remove-Item $Link } - $LinkContainer = Split-Path $Link -Parent - if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer } - Write-Verbose "Linking $Link to $Target" - if ($IsMacOS -or $IsLinux) { - ln $Target $Link - } else { - cmd /c mklink $Link $Target - } -} - -# Stage all artifacts -$Artifacts = & "$PSScriptRoot\_all.ps1" -$Artifacts |% { - $DestinationFolder = (Join-Path (Join-Path $ArtifactStagingFolder "$($_.ArtifactName)$ArtifactNameSuffix") $_.ContainerFolder).TrimEnd('\') - $Name = "$(Split-Path $_.Source -Leaf)" - - #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow - - if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null } - if (Test-Path -PathType Leaf $_.Source) { # skip folders - Create-SymbolicLink -Link "$DestinationFolder\$Name" -Target $_.Source - } -} - -$Artifacts |% { $_.ArtifactName } | Get-Unique |% { - Write-Host "##vso[artifact.upload containerfolder=$_$ArtifactNameSuffix;artifactname=$_$ArtifactNameSuffix;]$ArtifactStagingFolder/$_$ArtifactNameSuffix" +& "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% { + Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" } diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 new file mode 100644 index 00000000..a05db529 --- /dev/null +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -0,0 +1,59 @@ +# This script links all the artifacts described by _all.ps1 +# into a staging directory, reading for uploading to a cloud build artifact store. +# It returns a sequence of objects with Name and Path properties. + +param ( + [string]$ArtifactNameSuffix +) + +$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot (Join-Path .. ..))) +if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { + $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY +} else { + $ArtifactStagingFolder = Join-Path $RepoRoot (Join-Path obj _artifacts) + if (Test-Path $ArtifactStagingFolder) { + Remove-Item $ArtifactStagingFolder -Recurse -Force + } +} + +function Create-SymbolicLink { + param ( + $Link, + $Target + ) + + if ($Link -eq $Target) { + return + } + + if (Test-Path $Link) { Remove-Item $Link } + $LinkContainer = Split-Path $Link -Parent + if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer } + Write-Verbose "Linking $Link to $Target" + if ($IsMacOS -or $IsLinux) { + ln $Target $Link | Out-Null + } else { + cmd /c mklink $Link $Target | Out-Null + } +} + +# Stage all artifacts +$Artifacts = & "$PSScriptRoot\_all.ps1" +$Artifacts |% { + $DestinationFolder = (Join-Path (Join-Path $ArtifactStagingFolder "$($_.ArtifactName)$ArtifactNameSuffix") $_.ContainerFolder).TrimEnd('\') + $Name = "$(Split-Path $_.Source -Leaf)" + + #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow + + if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null } + if (Test-Path -PathType Leaf $_.Source) { # skip folders + Create-SymbolicLink -Link (Join-Path $DestinationFolder $Name) -Target $_.Source + } +} + +$Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } | Get-Unique |% { + $artifact = New-Object -TypeName PSObject + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Name -Value $_ + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Path -Value (Join-Path $ArtifactStagingFolder $_) + Write-Output $artifact +} diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 05e32a18..e1a73d4d 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -17,7 +17,7 @@ jobs: - job: Linux pool: - vmImage: Ubuntu 16.04 + vmImage: Ubuntu 18.04 steps: - checkout: self clean: true @@ -41,7 +41,7 @@ jobs: - Linux - macOS pool: - vmImage: Ubuntu 16.04 + vmImage: Ubuntu 18.04 condition: succeededOrFailed() steps: - checkout: self diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index 9fa0c16b..28230b81 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -5,11 +5,15 @@ # what the build would do. So only set them if they have not already been set. (& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { - if (Test-Path -Path "env:$($_.Key.ToUpper())") { + if (Test-Path -Path "env:$($_.Key)") { Write-Host "Skipping setting $($_.Key) because variable is already set." -ForegroundColor Cyan } else { Write-Host "$($_.Key)=$($_.Value)" -ForegroundColor Yellow - Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" + if ($env:TF_BUILD) { + Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" + } elseif ($env:GITHUB_ACTIONS) { + Write-Host "::set-env name=$($_.Key)::$($_.Value)" + } Set-Item -Path "env:$($_.Key)" -Value $_.Value } } diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 50687706..f29cb0a6 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -156,41 +156,5 @@ $runtimeVersions | Get-Unique |% { } if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) { - if ($env:TF_BUILD) { - Write-Host "Azure Pipelines detected. Logging commands will be used to propagate environment variables and prepend path." - } - - if ($IsMacOS -or $IsLinux) { - $envVars['PATH'] = "${DotNetInstallDir}:$env:PATH" - } else { - $envVars['PATH'] = "$DotNetInstallDir;$env:PATH" - } - - $envVars.GetEnumerator() |% { - Set-Item -Path env:$($_.Key) -Value $_.Value - - # If we're running in Azure Pipelines, set these environment variables - if ($env:TF_BUILD) { - Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" - } - } - - if ($env:TF_BUILD) { - Write-Host "##vso[task.prependpath]$DotNetInstallDir" - } -} - -if ($env:PS1UnderCmd -eq '1') { - Write-Warning "Environment variable changes will be lost because you're running under cmd.exe. Run these commands manually:" - $envVars.GetEnumerator() |% { - if ($_.Key -eq 'PATH') { - # Special case this one for readability - Write-Host "SET PATH=$DotNetInstallDir;%PATH%" - } else { - Write-Host "SET $($_.Key)=$($_.Value)" - } - } -} else { - Write-Host "Environment variables set:" -ForegroundColor Blue - $envVars + & "$PSScriptRoot/../azure-pipelines/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null } From ad12e4a7f4af5563a6132015340e888cd068a714 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Jan 2020 20:22:47 -0700 Subject: [PATCH 073/704] Simpler way to avoid shallow clone --- .github/workflows/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4e991873..4e178096 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -29,8 +29,8 @@ jobs: steps: - uses: actions/checkout@v2 - - name: Deep clone - run: git fetch --prune --unshallow origin HEAD + with: + fetch-depth: 0 # avoid shallow clone so nbgv can do its work. - name: Install prerequisites run: | ./init.ps1 -UpgradePrerequisites From 2e0c3eb6f0273c6f2350eb5d4a01016dccced6a8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 16 Jan 2020 13:49:59 -0700 Subject: [PATCH 074/704] Pin the compiler version Although we already pin the SDK which includes compilers, when we use msbuild.exe (including VS) to build we still get whatever compilers are on the box. Pinning the compilers has many of the same merits as pinning the SDK. --- src/Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ddd8ae60..03a6a1c3 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -27,6 +27,7 @@ + From 45818306689ea5709b30f398e86908cf02eb1ab9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 17 Jan 2020 07:29:10 -0700 Subject: [PATCH 075/704] Set NUGET_PACKAGES in CI workflow --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4e178096..2d71d97a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -14,7 +14,7 @@ env: BUILDCONFIGURATION: Release codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed. Learn more at https://github.com/AArnott/Library.Template/issues/28 -# NUGET_PACKAGES: ${{ env.GITHUB_WORKSPACE }}/.nuget/packages + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages jobs: build: From aa77109d0aaada2d6e53b3035a9a57e4249ea35e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 13 Feb 2020 13:45:54 -0700 Subject: [PATCH 076/704] Update coverlet.msbuild to 2.8.0 --- azure-pipelines/artifacts/coverageResults.ps1 | 4 ++-- azure-pipelines/publish-codecoverage.yml | 2 +- src/Library.Tests/Library.Tests.csproj | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 index 7d1e9a35..addbf85c 100644 --- a/azure-pipelines/artifacts/coverageResults.ps1 +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -3,7 +3,7 @@ $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") # Prepare code coverage reports for merging on another machine if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) { Write-Host "Substituting $env:SYSTEM_DEFAULTWORKINGDIRECTORY with `"{reporoot}`"" - $reports = Get-ChildItem "$RepoRoot/bin/coverage.cobertura.xml" -Recurse + $reports = Get-ChildItem "$RepoRoot/bin/coverage.*.cobertura.xml" -Recurse $reports |% { $content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape($env:SYSTEM_DEFAULTWORKINGDIRECTORY), "{reporoot}" } Set-Content -Path $_ -Value $content -Encoding UTF8 @@ -16,7 +16,7 @@ if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } @{ $RepoRoot = ( - @(Get-ChildItem "$RepoRoot\bin\coverage.cobertura.xml" -Recurse) + + @(Get-ChildItem "$RepoRoot\bin\coverage.*.cobertura.xml" -Recurse) + (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) ); } diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 6d367de9..976f0781 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -15,7 +15,7 @@ steps: dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" - $reports = Get-ChildItem -Recurse "$(Pipeline.Workspace)/coverage.cobertura.xml" + $reports = Get-ChildItem -Recurse "$(Pipeline.Workspace)/coverage.*.cobertura.xml" $reports |% { $content = Get-Content -Path $_ |% { $_.Replace("{reporoot}", "$(System.DefaultWorkingDirectory)") } Set-Content -Path $_ -Value $content -Encoding UTF8 diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj index 78ebcfd4..1cf1c1b0 100644 --- a/src/Library.Tests/Library.Tests.csproj +++ b/src/Library.Tests/Library.Tests.csproj @@ -14,7 +14,7 @@ - + From ca0811eb720026e8510a4f83813eb15019ac476c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 13 Feb 2020 13:48:09 -0700 Subject: [PATCH 077/704] Update SDK package references --- src/Directory.Build.props | 2 +- src/Library.Tests/Library.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 03a6a1c3..9b208727 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -26,7 +26,7 @@ - + diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj index 1cf1c1b0..8018f97d 100644 --- a/src/Library.Tests/Library.Tests.csproj +++ b/src/Library.Tests/Library.Tests.csproj @@ -15,7 +15,7 @@ - + From fc25f7a1665fccf4c1cc4d574f18e22894955387 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 30 Jan 2020 13:05:05 -0700 Subject: [PATCH 078/704] Remove unused ci_feed from GitHub workflow --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2d71d97a..86c35164 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,6 @@ env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BUILDCONFIGURATION: Release codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ - ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed. Learn more at https://github.com/AArnott/Library.Template/issues/28 NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages jobs: From 5fbad730e20884725a8930a733f2490ac919c07f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 3 Feb 2020 15:53:59 -0700 Subject: [PATCH 079/704] Always collect artifacts, even on build failures --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 86c35164..f3e10f53 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -50,6 +50,7 @@ jobs: - name: Collect artifacts run: azure-pipelines/artifacts/_stage_all.ps1 shell: pwsh + if: always() - name: Upload project.assets.json files if: always() uses: actions/upload-artifact@v1 From ba764031a80c365dbf0182c67fda295fd89aaa5b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 25 Feb 2020 13:33:55 -0700 Subject: [PATCH 080/704] Use macOS-10.15 macOS 10.13 is about to be decommissioned on Azure Pipelines --- azure-pipelines/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index e1a73d4d..186438a1 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -27,7 +27,7 @@ jobs: - job: macOS pool: - vmImage: macOS 10.13 + vmImage: macOS-10.15 steps: - checkout: self clean: true From d54e43ed8c74c7bc243eee86717fd1fdff9f9bfb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 27 Feb 2020 23:18:59 -0700 Subject: [PATCH 081/704] More assuredly pin the .NET Core SDK version There's talk that the .NET SDK may change the default value for rollForward from "patch" to "latestMajor", effectively turning our "version" property to a minimum instead of a 'pin'. Setting rollForward explicitly guards against this. --- global.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/global.json b/global.json index e9aac8c2..5c8032d3 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,7 @@ { "sdk": { - "version": "3.1.100" + "version": "3.1.100", + "rollForward": "latestPatch", + "allowPrerelease": false } } From e0365203f8562571e344bfeb54418ca65af08fb5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 29 Feb 2020 07:06:03 -0700 Subject: [PATCH 082/704] Generate msbuild properties for every restored package --- src/Directory.Build.props | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 9b208727..5e0395b5 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,4 +1,5 @@ - + Debug $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\')) @@ -34,4 +35,9 @@ + + + + + From c608bf061aaa56fd21b6c2af0b950f61e5132d05 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 3 Mar 2020 09:33:08 -0700 Subject: [PATCH 083/704] Only install .NET Core runtimes once per version --- tools/Install-DotNetSdk.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index f29cb0a6..0bd4082f 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -91,7 +91,7 @@ if ($InstallLocality -eq 'machine') { Install-DotNet -Version $sdkVersion } - $runtimeVersions |% { + $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { Install-DotNet -Version $_ -Runtime } From abf3830bc939537776c45be9d437cb4b89471baf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 3 Mar 2020 09:50:03 -0700 Subject: [PATCH 084/704] Add Directory.Build.rsp file --- .gitignore | 1 + Directory.Build.rsp | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) create mode 100644 Directory.Build.rsp diff --git a/.gitignore b/.gitignore index e353101d..d060a300 100644 --- a/.gitignore +++ b/.gitignore @@ -72,6 +72,7 @@ StyleCopReport.xml *.pgc *.pgd *.rsp +!Directory.Build.rsp *.sbr *.tlb *.tli diff --git a/Directory.Build.rsp b/Directory.Build.rsp new file mode 100644 index 00000000..9a833a03 --- /dev/null +++ b/Directory.Build.rsp @@ -0,0 +1,16 @@ +#------------------------------------------------------------------------------ +# This file contains command-line options that MSBuild will process as part of +# every build, unless the "/noautoresponse" switch is specified. +# +# MSBuild processes the options in this file first, before processing the +# options on the command line. As a result, options on the command line can +# override the options in this file. However, depending on the options being +# set, the overriding can also result in conflicts. +# +# NOTE: The "/noautoresponse" switch cannot be specified in this file, nor in +# any response file that is referenced by this file. +#------------------------------------------------------------------------------ +/nr:false +/m +/verbosity:minimal +/clp:Summary;ForceNoAlign From 3d164a2c0cfdd219930cd84db2db38051483da6d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 6 Mar 2020 13:07:24 -0700 Subject: [PATCH 085/704] Fix _pipelines.ps1 to check env vars in all caps --- azure-pipelines/variables/_pipelines.ps1 | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index 28230b81..14d6ffc2 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -5,15 +5,17 @@ # what the build would do. So only set them if they have not already been set. (& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { - if (Test-Path -Path "env:$($_.Key)") { - Write-Host "Skipping setting $($_.Key) because variable is already set." -ForegroundColor Cyan + # Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive. + $keyCaps = $_.Key.ToUpper() + if (Test-Path -Path "env:$keyCaps") { + Write-Host "Skipping setting $keyCaps because variable is already set." -ForegroundColor Cyan } else { - Write-Host "$($_.Key)=$($_.Value)" -ForegroundColor Yellow + Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow if ($env:TF_BUILD) { - Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" + Write-Host "##vso[task.setvariable variable=$keyCaps;]$($_.Value)" } elseif ($env:GITHUB_ACTIONS) { - Write-Host "::set-env name=$($_.Key)::$($_.Value)" + Write-Host "::set-env name=$keyCaps::$($_.Value)" } - Set-Item -Path "env:$($_.Key)" -Value $_.Value + Set-Item -Path "env:$keyCaps" -Value $_.Value } } From 43d492bdd13912fca8e600824e702b527ee7c2d1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 6 Mar 2020 13:12:28 -0700 Subject: [PATCH 086/704] Fix artifacts/variables.ps1 to check env vars in all caps --- azure-pipelines/artifacts/Variables.ps1 | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/artifacts/Variables.ps1 b/azure-pipelines/artifacts/Variables.ps1 index 2ee09d42..c6330cd3 100644 --- a/azure-pipelines/artifacts/Variables.ps1 +++ b/azure-pipelines/artifacts/Variables.ps1 @@ -12,8 +12,11 @@ Get-ChildItem -Path (Join-Path $PSScriptRoot (Join-Path .. variables)) |% { $value = $null if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts # First check the environment variables in case the variable was set in a queued build - if (Test-Path env:$($_.BaseName)) { - $value = Get-Content "env:$($_.BaseName)" + # Always use all caps for env var access because Azure Pipelines converts variables to upper-case for env vars, + # and on non-Windows env vars are case sensitive. + $envVarName = $_.BaseName.ToUpper() + if (Test-Path env:$envVarName) { + $value = Get-Content "env:$envVarName" } # If that didn't give us anything, try executing the script right now from its original position From 53448b3d6825a478d98c90af5b8fbf444ee8870a Mon Sep 17 00:00:00 2001 From: Tina Chen <43013310+xuachen@users.noreply.github.com> Date: Wed, 25 Mar 2020 15:36:12 -0700 Subject: [PATCH 087/704] Use agent jobname for for symbols folder --- azure-pipelines/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 9d910d2d..9b5a2e88 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -49,7 +49,7 @@ steps: - task: PublishSymbols@2 inputs: - SymbolsFolder: $(Build.ArtifactStagingDirectory)/symbols-Windows + SymbolsFolder: $(Build.ArtifactStagingDirectory)/symbols-$(Agent.JobName) SearchPattern: '**/*.pdb' IndexSources: false SymbolServerType: TeamServices From bdd6849d9956088b9163d771a926e1dc0a5f0b08 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Mar 2020 10:05:42 -0600 Subject: [PATCH 088/704] Update to global.json 3.1.201 --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 5c8032d3..0275fa5c 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "3.1.100", - "rollForward": "latestPatch", + "version": "3.1.201", + "rollForward": "patch", "allowPrerelease": false } } From 8c4c16154cf2df279e716f6921fe9cb6cd7edffb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Mar 2020 10:11:57 -0600 Subject: [PATCH 089/704] Consider test .runsettings files to be xml --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 03c2bcf3..3a833bdb 100644 --- a/.editorconfig +++ b/.editorconfig @@ -16,7 +16,7 @@ insert_final_newline = true trim_trailing_whitespace = true # Xml project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,runsettings}] indent_size = 2 # Xml config files From 917c0492532ac0669bad1696df2b151926562d9a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Mar 2020 10:12:41 -0600 Subject: [PATCH 090/704] Accommodate PathInfo as keys from artifact scripts --- azure-pipelines/artifacts/_all.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index 6f62be5c..171b55b8 100644 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -28,7 +28,7 @@ Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse |% { Write-Warning "No files found for the `"$ArtifactName`" artifact." } else { $fileGroups.GetEnumerator() | % { - $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key), [UriKind]::Absolute) + $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key.ToString()), [UriKind]::Absolute) $_.Value | % { if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { $_ = $_.FullName From 70a1f50d261b02bde5f121957c317a7cf8dbef3e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Mar 2020 10:29:44 -0600 Subject: [PATCH 091/704] Collect dumps and sequence.xml files on test hangs and crashes This makes diagnosing test runner crashes and hangs on Azure Pipelines possible. After such a failure, a testResults artifact is collected that includes the `Sequence_*.xml` and `testhost.*.dmp` files collected at the timeout or crash. These files can then be downloaded from the Azure Pipeline artifacts for study. --- azure-pipelines/Darwin.runsettings | 1 + azure-pipelines/Linux.runsettings | 1 + azure-pipelines/Windows_NT.runsettings | 14 ++++++++++++++ azure-pipelines/artifacts/testResults.ps1 | 12 ++++++++++++ azure-pipelines/dotnet.yml | 6 +++--- azure-pipelines/install-dependencies.yml | 7 +++++++ 6 files changed, 38 insertions(+), 3 deletions(-) create mode 100644 azure-pipelines/Darwin.runsettings create mode 100644 azure-pipelines/Linux.runsettings create mode 100644 azure-pipelines/Windows_NT.runsettings create mode 100644 azure-pipelines/artifacts/testResults.ps1 diff --git a/azure-pipelines/Darwin.runsettings b/azure-pipelines/Darwin.runsettings new file mode 100644 index 00000000..b444e819 --- /dev/null +++ b/azure-pipelines/Darwin.runsettings @@ -0,0 +1 @@ + diff --git a/azure-pipelines/Linux.runsettings b/azure-pipelines/Linux.runsettings new file mode 100644 index 00000000..b444e819 --- /dev/null +++ b/azure-pipelines/Linux.runsettings @@ -0,0 +1 @@ + diff --git a/azure-pipelines/Windows_NT.runsettings b/azure-pipelines/Windows_NT.runsettings new file mode 100644 index 00000000..0b43ecb0 --- /dev/null +++ b/azure-pipelines/Windows_NT.runsettings @@ -0,0 +1,14 @@ + + + + + + + + + %BUILD_ARTIFACTSTAGINGDIRECTORY% + + + + + diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 new file mode 100644 index 00000000..1c9d3572 --- /dev/null +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -0,0 +1,12 @@ +if ($env:AGENT_TEMPDIRECTORY) { + # The DotNetCoreCLI uses an alternate location to publish these files + $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' + @{ + $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\testhost.*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); + } +} else { + $srcRoot = Resolve-Path "$PSScriptRoot\..\..\src" + @{ + $srcRoot = (Get-ChildItem "$srcRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File); + } +} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 9b5a2e88..0d837acb 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -12,7 +12,7 @@ steps: displayName: dotnet test -f net472 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: net472-$(Agent.JobName) workingDirectory: src condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) @@ -21,7 +21,7 @@ steps: displayName: dotnet test -f netcoreapp2.1 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: netcoreapp2.1-$(Agent.JobName) workingDirectory: src @@ -29,7 +29,7 @@ steps: displayName: dotnet test -f netcoreapp3.1 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: netcoreapp3.1-$(Agent.JobName) workingDirectory: src diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 9257db85..a778022a 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -8,6 +8,13 @@ steps: dotnet --info displayName: Install prerequisites +# The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. +- powershell: | + choco install procdump + Write-Host "##vso[task.setvariable variable=PROCDUMP_PATH;]$env:ProgramData\chocolatey\bin\" + displayName: Install procdump + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + - task: PowerShell@2 inputs: filePath: azure-pipelines/variables/_pipelines.ps1 From 941448de1f90a8abebfd487fbcfb9230f5bcdbb7 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Mar 2020 14:51:27 -0600 Subject: [PATCH 092/704] Collect crash/hang dumps on GitHub Actions --- .github/workflows/Linux.runsettings | 1 + .github/workflows/Windows.runsettings | 14 ++++++++++++++ .github/workflows/build.yml | 13 ++++++++++++- .github/workflows/macOS.runsettings | 1 + 4 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 .github/workflows/Linux.runsettings create mode 100644 .github/workflows/Windows.runsettings create mode 100644 .github/workflows/macOS.runsettings diff --git a/.github/workflows/Linux.runsettings b/.github/workflows/Linux.runsettings new file mode 100644 index 00000000..b444e819 --- /dev/null +++ b/.github/workflows/Linux.runsettings @@ -0,0 +1 @@ + diff --git a/.github/workflows/Windows.runsettings b/.github/workflows/Windows.runsettings new file mode 100644 index 00000000..5e2244a0 --- /dev/null +++ b/.github/workflows/Windows.runsettings @@ -0,0 +1,14 @@ + + + + + + + + + %GITHUB_WORKSPACE% + + + + + diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3e10f53..b167b51f 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,6 +34,10 @@ jobs: run: | ./init.ps1 -UpgradePrerequisites dotnet --info + if ($env:RUNNER_OS -eq "Windows") { + choco install procdump + Write-Host "##[set-env name=PROCDUMP_PATH;]$env:PROGRAMDATA\chocolatey\bin\" + } shell: pwsh - name: Set pipeline variables based on source run: azure-pipelines/variables/_pipelines.ps1 @@ -43,7 +47,7 @@ jobs: - name: pack run: dotnet pack src --no-build -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/pack.binlog" - name: test - run: dotnet test src --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true + run: dotnet test src --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --settings "${{ github.workspace }}/.github/workflows/${{ runner.os }}.runsettings" - name: Update pipeline variables based on build outputs run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh @@ -72,6 +76,13 @@ jobs: name: build_logs-${{ runner.os }} path: obj/_artifacts/build_logs continue-on-error: true + - name: Upload testResults + if: always() + uses: actions/upload-artifact@v1 + with: + name: testResults-${{ runner.os }} + path: obj/_artifacts/testResults + continue-on-error: true - name: Upload coverageResults if: always() uses: actions/upload-artifact@v1 diff --git a/.github/workflows/macOS.runsettings b/.github/workflows/macOS.runsettings new file mode 100644 index 00000000..b444e819 --- /dev/null +++ b/.github/workflows/macOS.runsettings @@ -0,0 +1 @@ + From 8a3f6cd5d471bc588b5eb1cf54446a297e4cd3f5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Mar 2020 14:58:41 -0600 Subject: [PATCH 093/704] Collect deployables on GitHub Actions even for failing jobs --- .github/workflows/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f3e10f53..b50c5605 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -20,6 +20,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: os: - ubuntu-18.04 @@ -91,7 +92,7 @@ jobs: with: name: deployables path: obj/_artifacts/deployables - if: runner.os == 'Windows' + if: always() && runner.os == 'Windows' - name: Publish code coverage results to codecov.io run: bash <(curl -s https://codecov.io/bash) shell: bash From c5581d16fedaaaf95549f1f8105a8f6a7171534d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Mar 2020 15:39:20 -0600 Subject: [PATCH 094/704] Fix dmp collection on Azure Pipelines --- azure-pipelines/artifacts/testResults.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 index 1c9d3572..bc9e0467 100644 --- a/azure-pipelines/artifacts/testResults.ps1 +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -2,7 +2,7 @@ if ($env:AGENT_TEMPDIRECTORY) { # The DotNetCoreCLI uses an alternate location to publish these files $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' @{ - $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\testhost.*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); + $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); } } else { $srcRoot = Resolve-Path "$PSScriptRoot\..\..\src" From ce7cd13abbdfd6b7cd0fe95c196bc82e36e7bddb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 28 Mar 2020 13:03:09 -0600 Subject: [PATCH 095/704] Recommend C# extension in VS Code by its new name --- .vscode/extensions.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index c5b615df..ecda668e 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -4,7 +4,7 @@ // List of extensions which should be recommended for users of this workspace. "recommendations": [ "ms-azure-devops.azure-pipelines", - "ms-vscode.csharp", + "ms-dotnettools.csharp", "k--kato.docomment", "editorconfig.editorconfig", "pflannery.vscode-versionlens", From 426a7bd79f81f9c5dabf5e7f48fc24251e0e5577 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 28 Mar 2020 16:15:06 -0600 Subject: [PATCH 096/704] Update package references --- src/Directory.Build.props | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 5e0395b5..bdfdc2b2 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -27,9 +27,9 @@ - - - + + + From f0b174a54640be9482a14dea28cd19c9b1cd481b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 29 Mar 2020 07:35:13 -0600 Subject: [PATCH 097/704] Update NB.GV This gets Omnisharp on Linux to work. --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index bdfdc2b2..ce9c3194 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -27,7 +27,7 @@ - + From ae335995e9c2dd914b642a64084e4be0090901e6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 29 Mar 2020 19:35:18 -0600 Subject: [PATCH 098/704] Make ps1 scripts directly executable from linux --- azure-pipelines/artifacts/_all.ps1 | 2 ++ azure-pipelines/variables/_all.ps1 | 2 ++ init.ps1 | 2 ++ tools/Install-DotNetSdk.ps1 | 2 ++ tools/Install-NuGetCredProvider.ps1 | 2 ++ 5 files changed, 10 insertions(+) mode change 100644 => 100755 azure-pipelines/artifacts/_all.ps1 mode change 100644 => 100755 azure-pipelines/variables/_all.ps1 mode change 100644 => 100755 init.ps1 mode change 100644 => 100755 tools/Install-DotNetSdk.ps1 mode change 100644 => 100755 tools/Install-NuGetCredProvider.ps1 diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 old mode 100644 new mode 100755 index 171b55b8..4b544236 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -1,3 +1,5 @@ +#!/usr/bin/pwsh + # This script returns all the artifacts that should be collected after a build. # # Each powershell artifact is expressed as an object with these properties: diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1 old mode 100644 new mode 100755 index ed099792..269425b5 --- a/azure-pipelines/variables/_all.ps1 +++ b/azure-pipelines/variables/_all.ps1 @@ -1,3 +1,5 @@ +#!/usr/bin/pwsh + # This script returns a hashtable of build variables that should be set # at the start of a build or release definition's execution. diff --git a/init.ps1 b/init.ps1 old mode 100644 new mode 100755 index ae4ce9a6..ac980028 --- a/init.ps1 +++ b/init.ps1 @@ -1,3 +1,5 @@ +#!/usr/bin/pwsh + <# .SYNOPSIS Installs dependencies required to build and test the projects in this repository. diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 old mode 100644 new mode 100755 index 0bd4082f..a830dd40 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -1,3 +1,5 @@ +#!/usr/bin/pwsh + <# .SYNOPSIS Installs the .NET SDK specified in the global.json file at the root of this repository, diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 old mode 100644 new mode 100755 index 0a8d77f6..9e0e2fce --- a/tools/Install-NuGetCredProvider.ps1 +++ b/tools/Install-NuGetCredProvider.ps1 @@ -1,3 +1,5 @@ +#!/usr/bin/pwsh + <# .SYNOPSIS Downloads and installs the Microsoft Artifacts Credential Provider From c2c2ec18581074f1ab53333bc97e0b2d9e9e9d51 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 29 Mar 2020 20:26:44 -0600 Subject: [PATCH 099/704] Use more portable #! for ps1 --- azure-pipelines/artifacts/_all.ps1 | 2 +- azure-pipelines/variables/_all.ps1 | 2 +- init.ps1 | 2 +- tools/Install-DotNetSdk.ps1 | 2 +- tools/Install-NuGetCredProvider.ps1 | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index 4b544236..efd6bdb3 100755 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -1,4 +1,4 @@ -#!/usr/bin/pwsh +#!/usr/bin/env pwsh # This script returns all the artifacts that should be collected after a build. # diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1 index 269425b5..0407d307 100755 --- a/azure-pipelines/variables/_all.ps1 +++ b/azure-pipelines/variables/_all.ps1 @@ -1,4 +1,4 @@ -#!/usr/bin/pwsh +#!/usr/bin/env pwsh # This script returns a hashtable of build variables that should be set # at the start of a build or release definition's execution. diff --git a/init.ps1 b/init.ps1 index ac980028..6701e725 100755 --- a/init.ps1 +++ b/init.ps1 @@ -1,4 +1,4 @@ -#!/usr/bin/pwsh +#!/usr/bin/env pwsh <# .SYNOPSIS diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index a830dd40..2a444134 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -1,4 +1,4 @@ -#!/usr/bin/pwsh +#!/usr/bin/env pwsh <# .SYNOPSIS diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 index 9e0e2fce..496dcd96 100755 --- a/tools/Install-NuGetCredProvider.ps1 +++ b/tools/Install-NuGetCredProvider.ps1 @@ -1,4 +1,4 @@ -#!/usr/bin/pwsh +#!/usr/bin/env pwsh <# .SYNOPSIS From cbb60159af1bd4bbe336ba677e277152bd8b050b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 30 Mar 2020 10:16:19 -0600 Subject: [PATCH 100/704] Add machine-wide .NET install support off Windows --- tools/Install-DotNetSdk.ps1 | 37 +++++++++++++++++-------------------- 1 file changed, 17 insertions(+), 20 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 2a444134..101b68fe 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -83,25 +83,6 @@ Function Install-DotNet($Version, [switch]$Runtime) { } } -if ($InstallLocality -eq 'machine') { - if ($IsMacOS -or $IsLinux) { - Write-Error "Installing the .NET Core SDK or runtime at a machine-wide location is only supported by this script on Windows." - exit 1 - } - - if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - Install-DotNet -Version $sdkVersion - } - - $runtimeVersions | Get-Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - Install-DotNet -Version $_ -Runtime - } - } - - return -} - $switches = @( '-Architecture','x64' ) @@ -110,7 +91,23 @@ $envVars = @{ 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' = 'true'; } -if ($InstallLocality -eq 'repo') { +if ($InstallLocality -eq 'machine') { + if ($IsWindows) { + if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + Install-DotNet -Version $sdkVersion + } + + $runtimeVersions | Get-Unique |% { + if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + Install-DotNet -Version $_ -Runtime + } + } + + return + } else { + $DotNetInstallDir = '/usr/share/dotnet' + } +} elseif ($InstallLocality -eq 'repo') { $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet" } elseif ($env:AGENT_TOOLSDIRECTORY) { $DotNetInstallDir = "$env:AGENT_TOOLSDIRECTORY/dotnet" From ef30ea448e502db518bbe3d245dd6b185e084ad0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 7 Apr 2020 17:22:02 -0600 Subject: [PATCH 101/704] Use PowerShell Core in Azure Pipelines --- azure-pipelines/build.yml | 2 +- azure-pipelines/dotnet.yml | 12 ++++-------- azure-pipelines/expand-template.yml | 2 +- azure-pipelines/install-dependencies.yml | 10 ++++------ azure-pipelines/publish-codecoverage.yml | 2 +- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 186438a1..218e1c3d 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -9,7 +9,7 @@ jobs: clean: true - template: install-dependencies.yml - - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud' + - pwsh: '& (./azure-pipelines/Get-nbgv.ps1) cloud' displayName: Set build number - template: dotnet.yml diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 0d837acb..0b6e3cc5 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -33,17 +33,13 @@ steps: testRunTitle: netcoreapp3.1-$(Agent.JobName) workingDirectory: src -- task: PowerShell@2 - inputs: - filePath: azure-pipelines/variables/_pipelines.ps1 - failOnStderr: true +- pwsh: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true displayName: Update pipeline variables based on build outputs condition: succeededOrFailed() -- task: PowerShell@2 - inputs: - filePath: azure-pipelines/artifacts/_pipelines.ps1 - arguments: -ArtifactNameSuffix "-$(Agent.JobName)" +- pwsh: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" + failOnStderr: true displayName: Publish artifacts condition: succeededOrFailed() diff --git a/azure-pipelines/expand-template.yml b/azure-pipelines/expand-template.yml index 2d9ea7b3..a66a1157 100644 --- a/azure-pipelines/expand-template.yml +++ b/azure-pipelines/expand-template.yml @@ -3,7 +3,7 @@ steps: dotnet build-server shutdown git clean -fdx displayName: Cleaning repo for template expansion -- powershell: | +- pwsh: | git config user.name "test user" git config user.email "andrewarnott@gmail.com" ./Expand-Template.ps1 -LibraryName Calc -Author "Andrew Arnott" diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index a778022a..af97093b 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -3,20 +3,18 @@ parameters: steps: -- powershell: | +- pwsh: | .\init.ps1 -AccessToken '$(System.AccessToken)' ${{ parameters['initArgs'] }} -UpgradePrerequisites dotnet --info displayName: Install prerequisites # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. -- powershell: | +- pwsh: | choco install procdump Write-Host "##vso[task.setvariable variable=PROCDUMP_PATH;]$env:ProgramData\chocolatey\bin\" displayName: Install procdump condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) -- task: PowerShell@2 - inputs: - filePath: azure-pipelines/variables/_pipelines.ps1 - failOnStderr: true +- pwsh: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true displayName: Set pipeline variables based on source diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 976f0781..080a0f60 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -11,7 +11,7 @@ steps: artifact: coverageResults-macOS displayName: Download macOS code coverage results continueOnError: true -- powershell: | +- pwsh: | dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" From cae9277ee0851c093aac955ca82e6cb94bfe7408 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 7 Apr 2020 18:56:36 -0600 Subject: [PATCH 102/704] Revert "Use PowerShell Core in Azure Pipelines" This reverts commit ef30ea448e502db518bbe3d245dd6b185e084ad0. --- azure-pipelines/build.yml | 2 +- azure-pipelines/dotnet.yml | 12 ++++++++---- azure-pipelines/expand-template.yml | 2 +- azure-pipelines/install-dependencies.yml | 10 ++++++---- azure-pipelines/publish-codecoverage.yml | 2 +- 5 files changed, 17 insertions(+), 11 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 218e1c3d..186438a1 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -9,7 +9,7 @@ jobs: clean: true - template: install-dependencies.yml - - pwsh: '& (./azure-pipelines/Get-nbgv.ps1) cloud' + - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud' displayName: Set build number - template: dotnet.yml diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 0b6e3cc5..0d837acb 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -33,13 +33,17 @@ steps: testRunTitle: netcoreapp3.1-$(Agent.JobName) workingDirectory: src -- pwsh: azure-pipelines/variables/_pipelines.ps1 - failOnStderr: true +- task: PowerShell@2 + inputs: + filePath: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true displayName: Update pipeline variables based on build outputs condition: succeededOrFailed() -- pwsh: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" - failOnStderr: true +- task: PowerShell@2 + inputs: + filePath: azure-pipelines/artifacts/_pipelines.ps1 + arguments: -ArtifactNameSuffix "-$(Agent.JobName)" displayName: Publish artifacts condition: succeededOrFailed() diff --git a/azure-pipelines/expand-template.yml b/azure-pipelines/expand-template.yml index a66a1157..2d9ea7b3 100644 --- a/azure-pipelines/expand-template.yml +++ b/azure-pipelines/expand-template.yml @@ -3,7 +3,7 @@ steps: dotnet build-server shutdown git clean -fdx displayName: Cleaning repo for template expansion -- pwsh: | +- powershell: | git config user.name "test user" git config user.email "andrewarnott@gmail.com" ./Expand-Template.ps1 -LibraryName Calc -Author "Andrew Arnott" diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index af97093b..a778022a 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -3,18 +3,20 @@ parameters: steps: -- pwsh: | +- powershell: | .\init.ps1 -AccessToken '$(System.AccessToken)' ${{ parameters['initArgs'] }} -UpgradePrerequisites dotnet --info displayName: Install prerequisites # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. -- pwsh: | +- powershell: | choco install procdump Write-Host "##vso[task.setvariable variable=PROCDUMP_PATH;]$env:ProgramData\chocolatey\bin\" displayName: Install procdump condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) -- pwsh: azure-pipelines/variables/_pipelines.ps1 - failOnStderr: true +- task: PowerShell@2 + inputs: + filePath: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true displayName: Set pipeline variables based on source diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 080a0f60..976f0781 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -11,7 +11,7 @@ steps: artifact: coverageResults-macOS displayName: Download macOS code coverage results continueOnError: true -- pwsh: | +- powershell: | dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" From fbca91fdfbdbc4cced5d8a7eb2193710e3eb27e5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 7 Apr 2020 18:57:50 -0600 Subject: [PATCH 103/704] Simplify syntax of Powershell tasks --- azure-pipelines/dotnet.yml | 12 ++++-------- azure-pipelines/install-dependencies.yml | 6 ++---- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 0d837acb..71bd42e1 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -33,17 +33,13 @@ steps: testRunTitle: netcoreapp3.1-$(Agent.JobName) workingDirectory: src -- task: PowerShell@2 - inputs: - filePath: azure-pipelines/variables/_pipelines.ps1 - failOnStderr: true +- powershell: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true displayName: Update pipeline variables based on build outputs condition: succeededOrFailed() -- task: PowerShell@2 - inputs: - filePath: azure-pipelines/artifacts/_pipelines.ps1 - arguments: -ArtifactNameSuffix "-$(Agent.JobName)" +- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" + failOnStderr: true displayName: Publish artifacts condition: succeededOrFailed() diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index a778022a..ec9c3f56 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -15,8 +15,6 @@ steps: displayName: Install procdump condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) -- task: PowerShell@2 - inputs: - filePath: azure-pipelines/variables/_pipelines.ps1 - failOnStderr: true +- powershell: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true displayName: Set pipeline variables based on source From 8441b31c2d4509873d92a28896d12955e2917f7f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Apr 2020 07:27:52 -0600 Subject: [PATCH 104/704] Specify nuget version to use This shields us against default version changes and service outages such as the one we just experienced. --- azure-pipelines/publish-deployables.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index a89f389f..a4f8e593 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -3,6 +3,11 @@ steps: displayName: Download deployables artifact: deployables-Windows +- task: NuGetToolInstaller@1 + displayName: Use NuGet 5.x + inputs: + versionSpec: 5.x + - task: NuGetCommand@2 displayName: Push packages to CI feed inputs: From 606547170822ba211cb097dcdf5e8da44f4f90e6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Apr 2020 21:34:11 -0600 Subject: [PATCH 105/704] Move sln file to repo root --- .github/workflows/build.yml | 6 +++--- Expand-Template.ps1 | 29 +++++++++++++---------------- src/Library.sln => Library.sln | 22 +++++++++++----------- azure-pipelines/dotnet.yml | 5 ----- azure-pipelines/expand-template.yml | 1 - init.ps1 | 2 +- 6 files changed, 28 insertions(+), 37 deletions(-) rename src/Library.sln => Library.sln (75%) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8d8d7655..55575add 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -44,11 +44,11 @@ jobs: run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh - name: build - run: dotnet build src --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/build.binlog" + run: dotnet build --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/build.binlog" - name: pack - run: dotnet pack src --no-build -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/pack.binlog" + run: dotnet pack --no-build -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/pack.binlog" - name: test - run: dotnet test src --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --settings "${{ github.workspace }}/.github/workflows/${{ runner.os }}.runsettings" + run: dotnet test --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --settings "${{ github.workspace }}/.github/workflows/${{ runner.os }}.runsettings" - name: Update pipeline variables based on build outputs run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index aa4f5ec2..6a030fc1 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -80,30 +80,27 @@ try { } # Rename project directories and solution - Set-Location src git mv Library.sln "$LibraryName.sln" - git mv Library/Library.csproj "Library/$LibraryName.csproj" - git mv Library "$LibraryName" - git mv Library.Tests/Library.Tests.csproj "Library.Tests/$LibraryName.Tests.csproj" - git mv Library.Tests "$LibraryName.Tests" + git mv src/Library/Library.csproj "src/Library/$LibraryName.csproj" + git mv src/Library "src/$LibraryName" + git mv src/Library.Tests/Library.Tests.csproj "src/Library.Tests/$LibraryName.Tests.csproj" + git mv src/Library.Tests "src/$LibraryName.Tests" # Refresh solution file both to update paths and give the projects unique GUIDs - dotnet sln remove Library/Library.csproj - dotnet sln remove Library.Tests/Library.Tests.csproj - dotnet sln add "$LibraryName" - dotnet sln add "$LibraryName.Tests" + dotnet sln remove src/Library/Library.csproj + dotnet sln remove src/Library.Tests/Library.Tests.csproj + dotnet sln add "src/$LibraryName" + dotnet sln add "src/$LibraryName.Tests" git add "$LibraryName.sln" # Update project reference in test project. Add before removal to keep the same ItemGroup in place. - dotnet add "$LibraryName.Tests" reference "$LibraryName" - dotnet remove "$LibraryName.Tests" reference Library/Library.csproj - git add "$LibraryName.Tests/$LibraryName.Tests.csproj" + dotnet add "src/$LibraryName.Tests" reference "src/$LibraryName" + dotnet remove "src/$LibraryName.Tests" reference src/Library/Library.csproj + git add "src/$LibraryName.Tests/$LibraryName.Tests.csproj" # Establish a new strong-name key - & $sn.Path -k 2048 strongname.snk - git add strongname.snk - - Set-Location .. + & $sn.Path -k 2048 src/strongname.snk + git add src/strongname.snk # Replace placeholders in source files Replace-Placeholders -Path "src/$LibraryName/Calculator.cs" -Replacements @{ diff --git a/src/Library.sln b/Library.sln similarity index 75% rename from src/Library.sln rename to Library.sln index 09dfb1fe..d034f5b2 100644 --- a/src/Library.sln +++ b/Library.sln @@ -3,21 +3,21 @@ Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio Version 16 VisualStudioVersion = 16.0.29322.22 MinimumVisualStudioVersion = 15.0.26124.0 -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library", "Library\Library.csproj", "{C06D702E-6FC7-453B-BDDF-608F825EC003}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library", "src\Library\Library.csproj", "{C06D702E-6FC7-453B-BDDF-608F825EC003}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library.Tests", "Library.Tests\Library.Tests.csproj", "{DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library.Tests", "src\Library.Tests\Library.Tests.csproj", "{DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1CE9670B-D5FF-46A7-9D00-24E70E6ED48B}" ProjectSection(SolutionItems) = preProject - ..\.editorconfig = ..\.editorconfig - Directory.Build.props = Directory.Build.props - Directory.Build.targets = Directory.Build.targets - ..\global.json = ..\global.json - ..\nuget.config = ..\nuget.config - shipping.ruleset = shipping.ruleset - stylecop.json = stylecop.json - tests.ruleset = tests.ruleset - ..\version.json = ..\version.json + .editorconfig = .editorconfig + src\Directory.Build.props = src\Directory.Build.props + src\Directory.Build.targets = src\Directory.Build.targets + global.json = global.json + nuget.config = nuget.config + src\shipping.ruleset = src\shipping.ruleset + src\stylecop.json = src\stylecop.json + src\tests.ruleset = src\tests.ruleset + version.json = version.json EndProjectSection EndProject Global diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 71bd42e1..6764e6ec 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -2,11 +2,9 @@ steps: - script: dotnet build --no-restore -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" displayName: dotnet build - workingDirectory: src - script: dotnet pack --no-build -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/pack.binlog" displayName: dotnet pack - workingDirectory: src - task: DotNetCoreCLI@2 displayName: dotnet test -f net472 @@ -14,7 +12,6 @@ steps: command: test arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: net472-$(Agent.JobName) - workingDirectory: src condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - task: DotNetCoreCLI@2 @@ -23,7 +20,6 @@ steps: command: test arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: netcoreapp2.1-$(Agent.JobName) - workingDirectory: src - task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp3.1 @@ -31,7 +27,6 @@ steps: command: test arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: netcoreapp3.1-$(Agent.JobName) - workingDirectory: src - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true diff --git a/azure-pipelines/expand-template.yml b/azure-pipelines/expand-template.yml index 2d9ea7b3..ed510de3 100644 --- a/azure-pipelines/expand-template.yml +++ b/azure-pipelines/expand-template.yml @@ -11,5 +11,4 @@ steps: failOnStderr: true # TODO: Verify that all changes are staged to the git index - script: dotnet build - workingDirectory: src displayName: dotnet build (expanded template) diff --git a/init.ps1 b/init.ps1 index 6701e725..a0c9961f 100755 --- a/init.ps1 +++ b/init.ps1 @@ -54,7 +54,7 @@ try { if (!$NoRestore -and $PSCmdlet.ShouldProcess("NuGet packages", "Restore")) { Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor - dotnet restore src + dotnet restore if ($lastexitcode -ne 0) { throw "Failure while restoring packages." } From 234e1da8eb8a1b077214b6e4d8dfc64edcab21b1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Apr 2020 23:06:03 -0600 Subject: [PATCH 106/704] Fix Install-DotNetSdk script under -WhatIf --- tools/Install-DotNetSdk.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 101b68fe..8d77a9fe 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -23,7 +23,7 @@ Param ( ) $DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools" -if (!(Test-Path $DotNetInstallScriptRoot)) { New-Item -ItemType Directory -Path $DotNetInstallScriptRoot | Out-Null } +if (!(Test-Path $DotNetInstallScriptRoot)) { New-Item -ItemType Directory -Path $DotNetInstallScriptRoot -WhatIf:$false | Out-Null } $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot # Look up actual required .NET Core SDK version from global.json From e9107462f142ba4c25289ef1d609378e0c2bb270 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Apr 2020 23:23:30 -0600 Subject: [PATCH 107/704] Avoid building on Azure Pipelines for .github folder changes --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c6eeb7b6..fc1b06e3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -8,6 +8,7 @@ trigger: - doc/ - '*.md' - .vscode/ + - .github/ variables: TreatWarningsAsErrors: true From 18676a3d915d6be387f2b76e19a492c623b9930c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Apr 2020 23:14:23 -0600 Subject: [PATCH 108/704] Lose guid in favor of feed name Closes #28 --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fc1b06e3..22f8b553 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -15,7 +15,7 @@ variables: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BuildConfiguration: Release codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ - ci_feed: /a5a3bad0-e566-4c53-be83-6458be8d1653 # find guid used by Azure DevOps Artifacts for the feed. Learn more at https://github.com/AArnott/Library.Template/issues/28 + ci_feed: CI # Azure Artifacts feed name NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages jobs: From 9c3b3fe1534bf2b05aa1b7163699590d5027b06b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Apr 2020 23:30:24 -0600 Subject: [PATCH 109/704] Fix build of WPF projects Fixes #22 --- src/Directory.Build.targets | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 1ddcba6f..8f529fae 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,4 +1,8 @@ + + + false + cobertura [xunit.*]* From 3c0c7dae0fe407097af6455adbfb4d6e8b8ba600 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Apr 2020 22:36:49 -0600 Subject: [PATCH 110/704] Use top-level test folder --- .editorconfig | 8 ++ Directory.Build.props | 43 ++++++++++ Directory.Build.targets | 8 ++ Expand-Template.ps1 | 22 +++--- Library.sln | 28 +++++-- azure-pipelines/artifacts/testResults.ps1 | 4 +- src/.editorconfig | 0 src/Directory.Build.props | 44 +---------- src/Directory.Build.targets | 8 +- src/Library.Tests/Library.Tests.csproj | 23 ------ src/Library/Library.csproj | 5 -- src/shipping.ruleset | 74 ------------------ src/tests.ruleset | 18 ----- src/strongname.snk => strongname.snk | Bin src/stylecop.json => stylecop.json | 0 test/.editorconfig | 28 +++++++ test/Directory.Build.props | 11 +++ test/Directory.Build.targets | 3 + .../Library.Tests/CalculatorTests.cs | 0 test/Library.Tests/Library.Tests.csproj | 14 ++++ {src => test}/Library.Tests/app.config | 0 tools/Install-DotNetSdk.ps1 | 2 +- 22 files changed, 157 insertions(+), 186 deletions(-) create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets create mode 100644 src/.editorconfig delete mode 100644 src/Library.Tests/Library.Tests.csproj delete mode 100644 src/shipping.ruleset delete mode 100644 src/tests.ruleset rename src/strongname.snk => strongname.snk (100%) rename src/stylecop.json => stylecop.json (100%) create mode 100644 test/.editorconfig create mode 100644 test/Directory.Build.props create mode 100644 test/Directory.Build.targets rename {src => test}/Library.Tests/CalculatorTests.cs (100%) create mode 100644 test/Library.Tests/Library.Tests.csproj rename {src => test}/Library.Tests/app.config (100%) diff --git a/.editorconfig b/.editorconfig index 3a833bdb..979d170a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -155,3 +155,11 @@ csharp_new_line_before_members_in_anonymous_types = true # Blocks are allowed csharp_prefer_braces = true:silent + +[*.cs] + +# SA1130: Use lambda syntax +dotnet_diagnostic.SA1130.severity = silent + +[*.sln] +indent_style = tab diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..7a97368f --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,43 @@ + + + Debug + $(MSBuildThisFileDirectory) + $(RepoRootPath)obj\$(MSBuildProjectName)\ + $(RepoRootPath)bin\$(MSBuildProjectName)\ + $(RepoRootPath)bin\Packages\$(Configuration)\ + 8.0 + enable + true + + true + $(MSBuildThisFileDirectory)\strongname.snk + + COMPANY-PLACEHOLDER + COMPANY-PLACEHOLDER + © COMPANY-PLACEHOLDER. All rights reserved. + MIT + true + true + true + snupkg + + + + + + + + + + + + + + + + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 00000000..1ddcba6f --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,8 @@ + + + cobertura + [xunit.*]* + + $(OutputPath)/ + + diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index 6a030fc1..9a05ecec 100644 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -83,20 +83,20 @@ try { git mv Library.sln "$LibraryName.sln" git mv src/Library/Library.csproj "src/Library/$LibraryName.csproj" git mv src/Library "src/$LibraryName" - git mv src/Library.Tests/Library.Tests.csproj "src/Library.Tests/$LibraryName.Tests.csproj" - git mv src/Library.Tests "src/$LibraryName.Tests" + git mv test/Library.Tests/Library.Tests.csproj "test/Library.Tests/$LibraryName.Tests.csproj" + git mv test/Library.Tests "test/$LibraryName.Tests" # Refresh solution file both to update paths and give the projects unique GUIDs dotnet sln remove src/Library/Library.csproj - dotnet sln remove src/Library.Tests/Library.Tests.csproj + dotnet sln remove test/Library.Tests/Library.Tests.csproj dotnet sln add "src/$LibraryName" - dotnet sln add "src/$LibraryName.Tests" + dotnet sln add "test/$LibraryName.Tests" git add "$LibraryName.sln" # Update project reference in test project. Add before removal to keep the same ItemGroup in place. - dotnet add "src/$LibraryName.Tests" reference "src/$LibraryName" - dotnet remove "src/$LibraryName.Tests" reference src/Library/Library.csproj - git add "src/$LibraryName.Tests/$LibraryName.Tests.csproj" + dotnet add "test/$LibraryName.Tests" reference "src/$LibraryName" + dotnet remove "test/$LibraryName.Tests" reference src/Library/Library.csproj + git add "test/$LibraryName.Tests/$LibraryName.Tests.csproj" # Establish a new strong-name key & $sn.Path -k 2048 src/strongname.snk @@ -107,17 +107,17 @@ try { 'Library'=$LibraryName 'COMPANY-PLACEHOLDER'=$Author } - Replace-Placeholders -Path "src/$LibraryName.Tests/CalculatorTests.cs" -Replacements @{ + Replace-Placeholders -Path "test/$LibraryName.Tests/CalculatorTests.cs" -Replacements @{ 'Library'=$LibraryName 'COMPANY-PLACEHOLDER'=$Author } Replace-Placeholders -Path "LICENSE" -Replacements @{ 'COMPANY-PLACEHOLDER'=$Author } - Replace-Placeholders -Path "src/stylecop.json" -Replacements @{ + Replace-Placeholders -Path "stylecop.json" -Replacements @{ 'COMPANY-PLACEHOLDER'=$Author } - Replace-Placeholders -Path "src/Directory.Build.props" -Replacements @{ + Replace-Placeholders -Path "Directory.Build.props" -Replacements @{ 'COMPANY-PLACEHOLDER'=$Author } Replace-Placeholders -Path "README.md" -Replacements @{ @@ -174,4 +174,4 @@ try { } # When testing this script, all the changes can be quickly reverted with this command: -# git reset HEAD :/README.md :/LICENSE :/azure-pipelines.yml :/src :/azure-pipelines; git co -- :/README.md :/LICENSE :/azure-pipelines.yml :/src :/azure-pipelines; git clean -fd :/src +# git reset HEAD :/README.md :/LICENSE :/azure-pipelines.yml :/src :/test :/azure-pipelines; git co -- :/README.md :/LICENSE :/azure-pipelines.yml :/src :/azure-pipelines; git clean -fd :/src :/test diff --git a/Library.sln b/Library.sln index d034f5b2..85b8939d 100644 --- a/Library.sln +++ b/Library.sln @@ -5,21 +5,33 @@ VisualStudioVersion = 16.0.29322.22 MinimumVisualStudioVersion = 15.0.26124.0 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library", "src\Library\Library.csproj", "{C06D702E-6FC7-453B-BDDF-608F825EC003}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library.Tests", "src\Library.Tests\Library.Tests.csproj", "{DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Library.Tests", "test\Library.Tests\Library.Tests.csproj", "{DC5F3D1C-A9A3-44B7-A3C0-82C1FF4C3336}" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{1CE9670B-D5FF-46A7-9D00-24E70E6ED48B}" ProjectSection(SolutionItems) = preProject .editorconfig = .editorconfig - src\Directory.Build.props = src\Directory.Build.props - src\Directory.Build.targets = src\Directory.Build.targets + Directory.Build.props = Directory.Build.props + Directory.Build.targets = Directory.Build.targets global.json = global.json nuget.config = nuget.config - src\shipping.ruleset = src\shipping.ruleset - src\stylecop.json = src\stylecop.json - src\tests.ruleset = src\tests.ruleset + stylecop.json = stylecop.json version.json = version.json EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{9E154A29-1796-4B85-BD81-B6A385D8FF71}" + ProjectSection(SolutionItems) = preProject + src\.editorconfig = src\.editorconfig + src\Directory.Build.props = src\Directory.Build.props + src\Directory.Build.targets = src\Directory.Build.targets + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A}" + ProjectSection(SolutionItems) = preProject + test\.editorconfig = test\.editorconfig + test\Directory.Build.props = test\Directory.Build.props + test\Directory.Build.targets = test\Directory.Build.targets + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -38,6 +50,10 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {9E154A29-1796-4B85-BD81-B6A385D8FF71} = {1CE9670B-D5FF-46A7-9D00-24E70E6ED48B} + {36CCE840-6FE5-4DB9-A8D5-8CF3CB6D342A} = {1CE9670B-D5FF-46A7-9D00-24E70E6ED48B} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {E3944F6A-384B-4B0F-B93F-3BD513DC57BD} EndGlobalSection diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 index bc9e0467..1e4c4c4e 100644 --- a/azure-pipelines/artifacts/testResults.ps1 +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -5,8 +5,8 @@ if ($env:AGENT_TEMPDIRECTORY) { $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); } } else { - $srcRoot = Resolve-Path "$PSScriptRoot\..\..\src" + $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" @{ - $srcRoot = (Get-ChildItem "$srcRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File); + $testRoot = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File); } } diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 00000000..e69de29b diff --git a/src/Directory.Build.props b/src/Directory.Build.props index ce9c3194..50b6409e 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,43 +1,7 @@ - - - Debug - $([System.IO.Path]::GetFullPath('$(MSBuildThisFileDirectory)..\')) - $(RepoRootPath)obj\$(MSBuildProjectName)\ - $(RepoRootPath)bin\$(MSBuildProjectName)\ - $(RepoRootPath)bin\Packages\$(Configuration)\ - 8.0 - enable - true - - true - $(MSBuildThisFileDirectory)\strongname.snk + + - COMPANY-PLACEHOLDER - COMPANY-PLACEHOLDER - © COMPANY-PLACEHOLDER. All rights reserved. - MIT - true - true - true - snupkg + + netstandard2.0 - - - - - - - - - - - - - - - - - - diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 8f529fae..ada76655 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -3,10 +3,6 @@ false - - cobertura - [xunit.*]* - - $(OutputPath)/ - + + diff --git a/src/Library.Tests/Library.Tests.csproj b/src/Library.Tests/Library.Tests.csproj deleted file mode 100644 index 8018f97d..00000000 --- a/src/Library.Tests/Library.Tests.csproj +++ /dev/null @@ -1,23 +0,0 @@ - - - - net472;netcoreapp2.1;netcoreapp3.1 - false - $(NoWarn);CS1591 - true - ..\tests.ruleset - - - - - - - - - - - - - - - diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index ae6eca97..61718a1f 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -1,8 +1,3 @@ - - netstandard2.0 - ..\shipping.ruleset - - diff --git a/src/shipping.ruleset b/src/shipping.ruleset deleted file mode 100644 index 72903546..00000000 --- a/src/shipping.ruleset +++ /dev/null @@ -1,74 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/tests.ruleset b/src/tests.ruleset deleted file mode 100644 index a1365976..00000000 --- a/src/tests.ruleset +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - - - diff --git a/src/strongname.snk b/strongname.snk similarity index 100% rename from src/strongname.snk rename to strongname.snk diff --git a/src/stylecop.json b/stylecop.json similarity index 100% rename from src/stylecop.json rename to stylecop.json diff --git a/test/.editorconfig b/test/.editorconfig new file mode 100644 index 00000000..eac6d8ae --- /dev/null +++ b/test/.editorconfig @@ -0,0 +1,28 @@ +[*.cs] + +# SA1600: Elements should be documented +dotnet_diagnostic.SA1600.severity = silent + +# SA1601: Partial elements should be documented +dotnet_diagnostic.SA1601.severity = silent + +# SA1602: Enumeration items should be documented +dotnet_diagnostic.SA1602.severity = silent + +# SA1615: Element return value should be documented +dotnet_diagnostic.SA1615.severity = silent + +# VSTHRD103: Call async methods when in an async method +dotnet_diagnostic.VSTHRD103.severity = silent + +# VSTHRD111: Use .ConfigureAwait(bool) +dotnet_diagnostic.VSTHRD111.severity = none + +# VSTHRD200: Use Async suffix for async methods +dotnet_diagnostic.VSTHRD200.severity = silent + +# CA1303: Do not pass literals as localized parameters +dotnet_diagnostic.CA1303.severity = none + +# CS1591: Missing XML comment for publicly visible type or member +dotnet_diagnostic.CS1591.severity = silent diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 00000000..66b41d56 --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,11 @@ + + + + + net472;netcoreapp2.1;netcoreapp3.1 + false + true + + + + diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets new file mode 100644 index 00000000..6a5a72c2 --- /dev/null +++ b/test/Directory.Build.targets @@ -0,0 +1,3 @@ + + + diff --git a/src/Library.Tests/CalculatorTests.cs b/test/Library.Tests/CalculatorTests.cs similarity index 100% rename from src/Library.Tests/CalculatorTests.cs rename to test/Library.Tests/CalculatorTests.cs diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj new file mode 100644 index 00000000..6113925a --- /dev/null +++ b/test/Library.Tests/Library.Tests.csproj @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/src/Library.Tests/app.config b/test/Library.Tests/app.config similarity index 100% rename from src/Library.Tests/app.config rename to test/Library.Tests/app.config diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 8d77a9fe..7f9bf6cd 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -31,7 +31,7 @@ $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1 # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() -Get-ChildItem "$PSScriptRoot\..\src\*.*proj" -Recurse |% { +Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { $projXml = [xml](Get-Content -Path $_) $targetFrameworks = $projXml.Project.PropertyGroup.TargetFramework if (!$targetFrameworks) { From acda37b47951338b6c06a579a49e6215ce5bc586 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 10 Apr 2020 09:14:13 -0600 Subject: [PATCH 111/704] Add -y switch to choco install Fixes #47 --- .github/workflows/build.yml | 2 +- azure-pipelines/install-dependencies.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 55575add..4ea0df36 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -36,7 +36,7 @@ jobs: ./init.ps1 -UpgradePrerequisites dotnet --info if ($env:RUNNER_OS -eq "Windows") { - choco install procdump + choco install procdump -y Write-Host "##[set-env name=PROCDUMP_PATH;]$env:PROGRAMDATA\chocolatey\bin\" } shell: pwsh diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index ec9c3f56..d4804866 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -10,7 +10,7 @@ steps: # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. - powershell: | - choco install procdump + choco install procdump -y Write-Host "##vso[task.setvariable variable=PROCDUMP_PATH;]$env:ProgramData\chocolatey\bin\" displayName: Install procdump condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) From fd029d44e16358417a3e30cacc159f2efb9f5da0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Apr 2020 07:50:02 -0600 Subject: [PATCH 112/704] Stop passing $(System.AccessToken) as an arg in AzP Fixes #49 --- azure-pipelines/install-dependencies.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index d4804866..96917c4f 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -4,7 +4,7 @@ parameters: steps: - powershell: | - .\init.ps1 -AccessToken '$(System.AccessToken)' ${{ parameters['initArgs'] }} -UpgradePrerequisites + .\init.ps1 ${{ parameters['initArgs'] }} -UpgradePrerequisites dotnet --info displayName: Install prerequisites From f45370dbf3dc173e09d8738e462a81431bd7c70b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Apr 2020 09:42:24 -0600 Subject: [PATCH 113/704] Fix Set-EnvVars to print vars to console When run in the context of init.ps1, they were just swallowed up. Also we should only return a boolean. Outputing more than that will cause callers to malfunction. --- azure-pipelines/Set-EnvVars.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Set-EnvVars.ps1 b/azure-pipelines/Set-EnvVars.ps1 index 907659a7..9d14d9aa 100644 --- a/azure-pipelines/Set-EnvVars.ps1 +++ b/azure-pipelines/Set-EnvVars.ps1 @@ -24,7 +24,7 @@ if ($cmdInstructions) { Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue } else { Write-Host "Environment variables set:" -ForegroundColor Blue - $envVars + Write-Host ($Variables | Out-String) if ($PrependPath) { Write-Host "Paths prepended to PATH: $PrependPath" } From e9dcc410b3a0cc01d48927253a66e9e3e8eb0a21 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Apr 2020 09:44:37 -0600 Subject: [PATCH 114/704] Acquire procdump via nuget Just using nuget instead of choco makes it take less than 1 second instead of nearly a minute. It also removes the requirement for chocolatey to be installed on AzP agents, which helps compatibility with custom/private agents. Also move it to init.ps1 so it doesn't require a special AzP or GitHub Actions task and it canl run on local dev boxes. --- .github/workflows/build.yml | 4 ---- azure-pipelines/Get-ProcDump.ps1 | 14 ++++++++++++++ azure-pipelines/install-dependencies.yml | 7 ------- init.ps1 | 10 ++++++++++ 4 files changed, 24 insertions(+), 11 deletions(-) create mode 100644 azure-pipelines/Get-ProcDump.ps1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4ea0df36..91040d81 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -35,10 +35,6 @@ jobs: run: | ./init.ps1 -UpgradePrerequisites dotnet --info - if ($env:RUNNER_OS -eq "Windows") { - choco install procdump -y - Write-Host "##[set-env name=PROCDUMP_PATH;]$env:PROGRAMDATA\chocolatey\bin\" - } shell: pwsh - name: Set pipeline variables based on source run: azure-pipelines/variables/_pipelines.ps1 diff --git a/azure-pipelines/Get-ProcDump.ps1 b/azure-pipelines/Get-ProcDump.ps1 new file mode 100644 index 00000000..1493fe4b --- /dev/null +++ b/azure-pipelines/Get-ProcDump.ps1 @@ -0,0 +1,14 @@ +<# +.SYNOPSIS +Downloads 32-bit and 64-bit procdump executables and returns the path to where they were installed. +#> +$version = '0.0.1' +$baseDir = "$PSScriptRoot\..\obj\tools" +$procDumpToolPath = "$baseDir\procdump.$version\bin" +if (-not (Test-Path $procDumpToolPath)) { + if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } + $baseDir = (Resolve-Path $baseDir).Path # Normalize it + & (& $PSScriptRoot\Get-NuGetTool.ps1) install procdump -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://api.nuget.org/v3/index.json | Out-Null +} + +(Resolve-Path $procDumpToolPath).Path diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 96917c4f..51cf839d 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -8,13 +8,6 @@ steps: dotnet --info displayName: Install prerequisites -# The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. -- powershell: | - choco install procdump -y - Write-Host "##vso[task.setvariable variable=PROCDUMP_PATH;]$env:ProgramData\chocolatey\bin\" - displayName: Install procdump - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true displayName: Set pipeline variables based on source diff --git a/init.ps1 b/init.ps1 index a0c9961f..ca0d718a 100755 --- a/init.ps1 +++ b/init.ps1 @@ -39,9 +39,17 @@ Param ( [string]$AccessToken ) +$EnvVars = @{} + if (!$NoPrerequisites) { & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality + + # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. + # But it only works on Windows. + if ($env:OS -eq 'Windows_NT') { + $EnvVars['PROCDUMP_PATH'] = & "$PSScriptRoot\azure-pipelines\Get-ProcDump.ps1" + } } # Workaround nuget credential provider bug that causes very unreliable package restores on Azure Pipelines @@ -59,6 +67,8 @@ try { throw "Failure while restoring packages." } } + + & "$PSScriptRoot\azure-pipelines\Set-EnvVars.ps1" -Variables $EnvVars | Out-Null } catch { Write-Error $error[0] From e5347ab78aada5c9401f35fe6d16b3b5569b0cc6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Apr 2020 11:54:51 -0600 Subject: [PATCH 115/704] Update README file --- README.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 0c3bcf59..32a67820 100644 --- a/README.md +++ b/README.md @@ -11,14 +11,22 @@ ## Features * Follow the best and simplest patterns of build, pack and test with dotnet CLI. +* Init script that installs prerequisites and auth helpers, supporting both non-elevation and elevation modes. * Static analyzers: [FxCop](https://docs.microsoft.com/en-us/visualstudio/code-quality/fxcop-analyzers?view=vs-2019) and [StyleCop](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) * Read-only source tree (builds to top-level bin/obj folders) * Auto-versioning (via [Nerdbank.GitVersioning](https://github.com/aarnott/nerdbank.gitversioning)) -* Azure Pipeline via YAML with all dependencies declared for long-term serviceability. -* Testing on .NET Framework, multiple .NET Core versions -* Testing on Windows, Linux and OSX -* Code coverage published to Azure Pipelines -* Code coverage published to codecov.io so GitHub PRs get code coverage results added as a PR comment +* Builds with a "pinned" .NET Core SDK to ensure reproducible builds across machines and across time. +* Automatically pack the library and publish it as an artifact, and even push it to some NuGet feed for consumption. +* Testing + * Testing on .NET Framework, multiple .NET Core versions + * Testing on Windows, Linux and OSX + * Tests that crash or hang in Azure Pipelines automatically collect dumps and publish as a pipeline artifact for later investigation. +* Cloud build support: + * YAML based build for long-term serviceability, and PR review opportunities for any changes. + * Azure Pipelines and GitHub Action support + * Emphasis on PowerShell scripts over reliance on tasks for a more locally reproducible build. + * Code coverage published to Azure Pipelines + * Code coverage published to codecov.io so GitHub PRs get code coverage results added as a PR comment ## Consumption From b38ffc731de6cd80b20e1f5f612bb5c2b8ce1055 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Apr 2020 11:56:47 -0600 Subject: [PATCH 116/704] touchup readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 32a67820..e235ca64 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ * Testing on .NET Framework, multiple .NET Core versions * Testing on Windows, Linux and OSX * Tests that crash or hang in Azure Pipelines automatically collect dumps and publish as a pipeline artifact for later investigation. -* Cloud build support: +* Cloud build support * YAML based build for long-term serviceability, and PR review opportunities for any changes. * Azure Pipelines and GitHub Action support * Emphasis on PowerShell scripts over reliance on tasks for a more locally reproducible build. From 091601252d2dfefb66e63da77295dbc853013e79 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 16 Apr 2020 12:02:32 -0600 Subject: [PATCH 117/704] Bring back access tokens for AzP feed access Fixes #49 (properly) --- azure-pipelines/install-dependencies.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 51cf839d..5b1ac4af 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -4,7 +4,8 @@ parameters: steps: - powershell: | - .\init.ps1 ${{ parameters['initArgs'] }} -UpgradePrerequisites + $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors + .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites dotnet --info displayName: Install prerequisites From ce6f1d1170dfff88bc1f6f44095442f75bd94e2d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 17 Apr 2020 12:10:46 -0600 Subject: [PATCH 118/704] Update link to NB.GV --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index e235ca64..5424ff0a 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ * Init script that installs prerequisites and auth helpers, supporting both non-elevation and elevation modes. * Static analyzers: [FxCop](https://docs.microsoft.com/en-us/visualstudio/code-quality/fxcop-analyzers?view=vs-2019) and [StyleCop](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) * Read-only source tree (builds to top-level bin/obj folders) -* Auto-versioning (via [Nerdbank.GitVersioning](https://github.com/aarnott/nerdbank.gitversioning)) +* Auto-versioning (via [Nerdbank.GitVersioning](https://github.com/dotnet/nerdbank.gitversioning)) * Builds with a "pinned" .NET Core SDK to ensure reproducible builds across machines and across time. * Automatically pack the library and publish it as an artifact, and even push it to some NuGet feed for consumption. * Testing From ebb0cb39f8ba823761693db82e7e0e509e080df2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 19 Apr 2020 10:10:43 -0600 Subject: [PATCH 119/704] Make Expand-Template.ps1 executable on linux --- Expand-Template.ps1 | 2 ++ 1 file changed, 2 insertions(+) mode change 100644 => 100755 Expand-Template.ps1 diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 old mode 100644 new mode 100755 index 9a05ecec..84b96680 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -1,3 +1,5 @@ +#!/usr/bin/env pwsh + <# .SYNOPSIS Expands this template into an actual project, taking values for placeholders From 7688576a6aa2badce32e092a66708b0a4f452875 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 19 Apr 2020 10:13:23 -0600 Subject: [PATCH 120/704] Remove line that doesn't work on pwsh --- Expand-Template.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index 84b96680..dc53d1c1 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -148,7 +148,6 @@ try { Replace-Placeholders -Path "azure-pipelines.yml" -Replacements $YmlReplacements # Self destruct - $Invocation = (Get-Variable MyInvocation -Scope 1).Value git rm Expand-Template.* git rm :/azure-pipelines/expand-template.yml From 35cd5a2502d02cf0ba3e0141b7156403bf0b49e0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 19 Apr 2020 10:34:22 -0600 Subject: [PATCH 121/704] Move test project authoring into test folder --- Directory.Build.targets | 6 ------ test/Directory.Build.targets | 7 +++++++ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Directory.Build.targets b/Directory.Build.targets index 1ddcba6f..8c119d54 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,8 +1,2 @@ - - cobertura - [xunit.*]* - - $(OutputPath)/ - diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index 6a5a72c2..c48559e7 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -1,3 +1,10 @@ + + cobertura + [xunit.*]* + + $(OutputPath)/ + + From 498b5e6a34037dca15b629a07ef0d05908fc6782 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 20 Apr 2020 12:19:03 -0600 Subject: [PATCH 122/704] Authorize feeds in all nuget.config files throughout the repo --- tools/Install-NuGetCredProvider.ps1 | 20 +++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 index 496dcd96..2b3fb6fb 100755 --- a/tools/Install-NuGetCredProvider.ps1 +++ b/tools/Install-NuGetCredProvider.ps1 @@ -46,14 +46,20 @@ if ($IsMacOS -or $IsLinux) { if ($AccessToken) { $endpoints = @() - $nugetConfig = [xml](Get-Content -Path "$PSScriptRoot\..\nuget.config") + $endpointURIs = @() + Get-ChildItem "$PSScriptRoot\..\nuget.config" -Recurse |% { + $nugetConfig = [xml](Get-Content -Path $_) - $nugetConfig.configuration.packageSources.add |? { ($_.value -match '^https://pkgs\.dev\.azure\.com/') -or ($_.value -match '^https://[\w\-]+\.pkgs\.visualstudio\.com/') } |% { - $endpoint = New-Object -TypeName PSObject - Add-Member -InputObject $endpoint -MemberType NoteProperty -Name endpoint -Value $_.value - Add-Member -InputObject $endpoint -MemberType NoteProperty -Name username -Value ado - Add-Member -InputObject $endpoint -MemberType NoteProperty -Name password -Value $AccessToken - $endpoints += $endpoint + $nugetConfig.configuration.packageSources.add |? { ($_.value -match '^https://pkgs\.dev\.azure\.com/') -or ($_.value -match '^https://[\w\-]+\.pkgs\.visualstudio\.com/') } |% { + if ($endpointURIs -notcontains $_.Value) { + $endpointURIs += $_.Value + $endpoint = New-Object -TypeName PSObject + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name endpoint -Value $_.value + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name username -Value ado + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name password -Value $AccessToken + $endpoints += $endpoint + } + } } $auth = New-Object -TypeName PSObject From ddccc9105d88680362b8d59de699dfec0ce94bce Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Apr 2020 09:36:52 -0600 Subject: [PATCH 123/704] Fix conditional imports so they skip import on linux --- src/Directory.Build.props | 2 +- src/Directory.Build.targets | 2 +- test/Directory.Build.props | 2 +- test/Directory.Build.targets | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 50b6409e..165d2ddd 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,5 +1,5 @@ - + netstandard2.0 diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index ada76655..c1ce3634 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -4,5 +4,5 @@ false - + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 66b41d56..b48b5d81 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,5 +1,5 @@ - + net472;netcoreapp2.1;netcoreapp3.1 diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index c48559e7..2faab375 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -6,5 +6,5 @@ $(OutputPath)/ - + From a67e84559d64cf88a38e01c95e7f59a41104787d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Apr 2020 09:38:05 -0600 Subject: [PATCH 124/704] Reorder the docs to make more sense --- CONTRIBUTING.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 0893b308..2102ba9b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -14,6 +14,9 @@ with any additional questions or comments. ## Prerequisites +All dependencies can be installed by running the `init.ps1` script at the root of the repository +using Windows PowerShell or [PowerShell Core][pwsh] (on any OS). + The only prerequisite for building, testing, and deploying from this repository is the [.NET SDK](https://get.dot.net/). You should install the version specified in `global.json` or a later version within @@ -22,11 +25,6 @@ For example if 2.2.300 is specified, you may install 2.2.300, 2.2.301, or 2.2.31 while the 2.2.400 version would not be considered compatible by .NET SDK. See [.NET Core Versioning](https://docs.microsoft.com/en-us/dotnet/core/versions/) for more information. -All dependencies can be installed by running the `init.ps1` script at the root of the repository -using Windows PowerShell or [PowerShell Core][pwsh] (on any OS). - -This repository can be built on Windows, Linux, and OSX. - ## Package restore The easiest way to restore packages may be to run `init.ps1` which automatically authenticates @@ -35,6 +33,8 @@ to the feeds that packages for this repo come from, if any. ## Building +This repository can be built on Windows, Linux, and OSX. + Building, testing, and packing this repository can be done by using the standard dotnet CLI commands (e.g. `dotnet build`, `dotnet test`, `dotnet pack`, etc.). [pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-6 From e649d82e01088d680a1182a49697e5dfa892a553 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Apr 2020 09:38:25 -0600 Subject: [PATCH 125/704] Update dependencies --- test/Library.Tests/Library.Tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 6113925a..28433bf5 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -5,8 +5,8 @@ - - + + From 8c54c69baede3744b4e8f8ed3d72b7115bdffc3b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 11 May 2020 09:40:52 -0600 Subject: [PATCH 126/704] Reduce certain rule severities in test projects --- test/.editorconfig | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/test/.editorconfig b/test/.editorconfig index eac6d8ae..89195dda 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -26,3 +26,15 @@ dotnet_diagnostic.CA1303.severity = none # CS1591: Missing XML comment for publicly visible type or member dotnet_diagnostic.CS1591.severity = silent + +# CA1707: Identifiers should not contain underscores +dotnet_diagnostic.CA1707.severity = silent + +# CA1062: Validate arguments of public methods +dotnet_diagnostic.CA1062.severity = suggestion + +# CA1063: Implement IDisposable Correctly +dotnet_diagnostic.CA1063.severity = silent + +# CA1816: Dispose methods should call SuppressFinalize +dotnet_diagnostic.CA1816.severity = silent From 76eadc7926fc96ebc71e61988d2ee4516b34d73a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 11 May 2020 09:40:59 -0600 Subject: [PATCH 127/704] Add README as solution item --- Library.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/Library.sln b/Library.sln index 85b8939d..606811aa 100644 --- a/Library.sln +++ b/Library.sln @@ -14,6 +14,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Directory.Build.targets = Directory.Build.targets global.json = global.json nuget.config = nuget.config + README.md = README.md stylecop.json = stylecop.json version.json = version.json EndProjectSection From 160569a53024729c70b014fcad3c005e05a11ad2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 22 May 2020 09:35:59 -0600 Subject: [PATCH 128/704] Update package references --- Directory.Build.props | 6 +++--- test/Library.Tests/Library.Tests.csproj | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 7a97368f..9c119f37 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,11 +24,11 @@ - + - - + + diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 28433bf5..29ac7bf8 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -6,7 +6,7 @@ - + From 6d120a6a222577b239671d0f14f89bd5c63dbb59 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 22 May 2020 09:56:20 -0600 Subject: [PATCH 129/704] Update SDK to 3.1.300 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 0275fa5c..0200a660 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.201", + "version": "3.1.300", "rollForward": "patch", "allowPrerelease": false } From ecbb92cd2f3022bb408014c8394869c8f9ed20a2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 22 May 2020 10:20:17 -0600 Subject: [PATCH 130/704] Quote arguments to mklink This prevents breaks when the linked paths contain spaces, commas or other characters. --- azure-pipelines/artifacts/_stage_all.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index a05db529..4e6a6dbe 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -33,7 +33,7 @@ function Create-SymbolicLink { if ($IsMacOS -or $IsLinux) { ln $Target $Link | Out-Null } else { - cmd /c mklink $Link $Target | Out-Null + cmd /c "mklink `"$Link`" `"$Target`"" | Out-Null } } From 860402b0b5cd59f44ca392c4ae42d38013eb637f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 8 Jun 2020 15:23:03 -0600 Subject: [PATCH 131/704] Fix Install-DotNetSdk.ps1 script on Windows PowerShell It misinterpreted it as a Mac/Linux environment under Windows Powershell. It only worked as-is under PowerShell Core, where `$IsWindows` is defined. --- tools/Install-DotNetSdk.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 7f9bf6cd..a13638ae 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -92,7 +92,9 @@ $envVars = @{ } if ($InstallLocality -eq 'machine') { - if ($IsWindows) { + if ($IsMacOS -or $IsLinux) { + $DotNetInstallDir = '/usr/share/dotnet' + } else { if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { Install-DotNet -Version $sdkVersion } @@ -104,8 +106,6 @@ if ($InstallLocality -eq 'machine') { } return - } else { - $DotNetInstallDir = '/usr/share/dotnet' } } elseif ($InstallLocality -eq 'repo') { $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet" From 3c97ead14af585787a0cc41040dbb8e7077c5f9a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 15 Jun 2020 07:17:00 -0600 Subject: [PATCH 132/704] Update .NET Core SDK version to 3.1.301 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 0200a660..11833de0 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.300", + "version": "3.1.301", "rollForward": "patch", "allowPrerelease": false } From bc3f88d11b10f7f34769ad7af884a3eb9cb66fe9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 15 Jun 2020 07:09:02 -0600 Subject: [PATCH 133/704] Avoid unannounced system restart When installing the .NET SDK or runtime, if the installer wants a system restart, it would do so quietly. This avoids the restart but adds a prompt at the end of the script to inform the user of a restart being required when necessary. Fixes #57 --- init.ps1 | 3 +++ tools/Install-DotNetSdk.ps1 | 14 ++++++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/init.ps1 b/init.ps1 index ca0d718a..72d68b5f 100755 --- a/init.ps1 +++ b/init.ps1 @@ -44,6 +44,9 @@ $EnvVars = @{} if (!$NoPrerequisites) { & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality + if ($LASTEXITCODE -eq 3010) { + Exit 3010 + } # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. # But it only works on Windows. diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index a13638ae..be5f6a27 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -77,8 +77,10 @@ Function Install-DotNet($Version, [switch]$Runtime) { Write-Host "Downloading .NET Core $sdkSubstring$Version..." $Installer = Get-InstallerExe -Version $Version -Runtime:$Runtime Write-Host "Installing .NET Core $sdkSubstring$Version..." - cmd /c start /wait $Installer /install /quiet - if ($LASTEXITCODE -ne 0) { + cmd /c start /wait $Installer /install /passive /norestart + if ($LASTEXITCODE -eq 3010) { + Write-Verbose "Restart required" + } elseif ($LASTEXITCODE -ne 0) { throw "Failure to install .NET Core SDK" } } @@ -95,16 +97,24 @@ if ($InstallLocality -eq 'machine') { if ($IsMacOS -or $IsLinux) { $DotNetInstallDir = '/usr/share/dotnet' } else { + $restartRequired = $false if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { Install-DotNet -Version $sdkVersion + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) } $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { Install-DotNet -Version $_ -Runtime + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) } } + if ($restartRequired) { + Write-Host -ForegroundColor Yellow "System restart required" + Exit 3010 + } + return } } elseif ($InstallLocality -eq 'repo') { From 4a0dface5e4967814178cdf2ebf67f38b01744a7 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Jul 2020 15:08:50 -0600 Subject: [PATCH 134/704] Remove strongname.snk This is generated by expanding the template. It was mistakenly checked in at some point. --- strongname.snk | Bin 596 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 strongname.snk diff --git a/strongname.snk b/strongname.snk deleted file mode 100644 index a4d0a2ce39df5f7c284340b4a2c4690385c44208..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097Td7B6KsP|cl#<{bONo_!&t)QUG9wW^j zM1zvNAOI=XF}potSO>54lS%MGl8tv)xYTSw?~K<1McvNlJ;DITeY__C?><|;F`bgX zj;&2ME}KBWPb0zVSK+iW?{2`tzZR-#x0K_|t&0FhD+3urA!lNmCH;&b|?g|_AC39ox-0 zcV%KJis3}%`RVWSXN58fc}#LF$A#kcB2VWh=MH0zs+k7{ zQT<5V>NGhWzC7Jnt4A?n%Kk`fPt&FR4k~q{TSW%@D{plIpotzop}i+x`~C))*Vr-i zrW2)aE17f*=wCRa_#bHkYlQko_Jh)wN@;?yML9mYk)XZ`l6IQ*D7xZmmL=m(T|zMG i={(T>StYQl!YSPV From 2095a96269bc9bcf6c2eb9e21e3bbd2ccc33cc97 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 24 Jul 2020 07:57:24 -0600 Subject: [PATCH 135/704] Print existing variable in Azure Pipelines --- azure-pipelines/variables/_pipelines.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index 14d6ffc2..3de19d7a 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -8,7 +8,7 @@ # Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive. $keyCaps = $_.Key.ToUpper() if (Test-Path -Path "env:$keyCaps") { - Write-Host "Skipping setting $keyCaps because variable is already set." -ForegroundColor Cyan + Write-Host "Skipping setting $keyCaps because variable is already set to '$(Get-Content env:$keyCaps)'." -ForegroundColor Cyan } else { Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow if ($env:TF_BUILD) { From ecf6c16025a3905e673cdd542ad80185a9587e9e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 24 Jul 2020 08:46:23 -0600 Subject: [PATCH 136/704] Fix build and snk updates during template expansion We inappropriately removed the required snk file for our own build in 4a0dface5e496. This brings it back. It also updates Expand-Template.ps1 to overwrite the existing one rather than creating a new one in an ignored location. --- Expand-Template.ps1 | 4 ++-- strongname.snk | Bin 0 -> 596 bytes 2 files changed, 2 insertions(+), 2 deletions(-) create mode 100644 strongname.snk diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index dc53d1c1..5ed211d0 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -101,8 +101,8 @@ try { git add "test/$LibraryName.Tests/$LibraryName.Tests.csproj" # Establish a new strong-name key - & $sn.Path -k 2048 src/strongname.snk - git add src/strongname.snk + & $sn.Path -k 2048 strongname.snk + git add strongname.snk # Replace placeholders in source files Replace-Placeholders -Path "src/$LibraryName/Calculator.cs" -Replacements @{ diff --git a/strongname.snk b/strongname.snk new file mode 100644 index 0000000000000000000000000000000000000000..a4d0a2ce39df5f7c284340b4a2c4690385c44208 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50097Td7B6KsP|cl#<{bONo_!&t)QUG9wW^j zM1zvNAOI=XF}potSO>54lS%MGl8tv)xYTSw?~K<1McvNlJ;DITeY__C?><|;F`bgX zj;&2ME}KBWPb0zVSK+iW?{2`tzZR-#x0K_|t&0FhD+3urA!lNmCH;&b|?g|_AC39ox-0 zcV%KJis3}%`RVWSXN58fc}#LF$A#kcB2VWh=MH0zs+k7{ zQT<5V>NGhWzC7Jnt4A?n%Kk`fPt&FR4k~q{TSW%@D{plIpotzop}i+x`~C))*Vr-i zrW2)aE17f*=wCRa_#bHkYlQko_Jh)wN@;?yML9mYk)XZ`l6IQ*D7xZmmL=m(T|zMG i={(T>StYQl!YSPV literal 0 HcmV?d00001 From c03b185de7c83b21f1f84ac01656e2d3226625ac Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 25 Jul 2020 09:59:36 -0600 Subject: [PATCH 137/704] Set output variables as well This allows them to be referenced by subsequent jobs and stages. --- azure-pipelines/install-dependencies.yml | 1 + azure-pipelines/variables/_pipelines.ps1 | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 5b1ac4af..f773f385 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -12,3 +12,4 @@ steps: - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true displayName: Set pipeline variables based on source + name: SetPipelineVariables diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index 3de19d7a..55299550 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -12,7 +12,10 @@ } else { Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow if ($env:TF_BUILD) { - Write-Host "##vso[task.setvariable variable=$keyCaps;]$($_.Value)" + # Create two variables: the first that can be used by its simple name and accessible only within this job. + Write-Host "##vso[task.setvariable variable=$keyCaps]$($_.Value)" + # and the second that works across jobs and stages but must be fully qualified when referenced. + Write-Host "##vso[task.setvariable variable=$keyCaps;isOutput=true]$($_.Value)" } elseif ($env:GITHUB_ACTIONS) { Write-Host "::set-env name=$keyCaps::$($_.Value)" } From 171534d501b52b18a1d8bba53f93ec0149ad016a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 27 Jul 2020 16:13:01 -0600 Subject: [PATCH 138/704] Remove microbuild from CI list --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 91040d81..b9f17c23 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,6 @@ on: push: branches: - master - - microbuild - validate/* pull_request: From 285bd4f1a116799fe42bbb454710fec90155e9f8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 4 Aug 2020 10:01:41 -0600 Subject: [PATCH 139/704] Enable GitHub Dependabot --- .editorconfig | 4 ++++ .github/dependabot.yml | 9 +++++++++ 2 files changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.editorconfig b/.editorconfig index 979d170a..15f0b0e6 100644 --- a/.editorconfig +++ b/.editorconfig @@ -9,6 +9,10 @@ indent_style = space # (Please don't specify an indent_size here; that has too many unintended consequences.) +[*.yml] +indent_size = 2 +indent_style = space + # Code files [*.{cs,csx,vb,vbx,h,cpp,idl}] indent_size = 4 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..aa48b0fe --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: +- package-ecosystem: nuget + directory: / + schedule: + interval: weekly From cc969eccc71582c459b528fbd6f2a7752a302e4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2020 16:03:35 +0000 Subject: [PATCH 140/704] Bump xunit.runner.visualstudio from 2.4.1 to 2.4.3 Bumps [xunit.runner.visualstudio](https://github.com/xunit/visualstudio.xunit) from 2.4.1 to 2.4.3. - [Release notes](https://github.com/xunit/visualstudio.xunit/releases) - [Commits](https://github.com/xunit/visualstudio.xunit/commits/v2.4.3) Signed-off-by: dependabot[bot] --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 29ac7bf8..a491f369 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -8,7 +8,7 @@ - + From 116a8b074c2cc91e2ee2105e29b6bbaf9010c793 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2020 16:03:38 +0000 Subject: [PATCH 141/704] Bump Nerdbank.GitVersioning from 3.1.91 to 3.2.31 Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.1.91 to 3.2.31. - [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases) - [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/compare/v3.1.91...v3.2.31) Signed-off-by: dependabot[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9c119f37..7a6a46ae 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -27,7 +27,7 @@ - + From a6010319f64a75446a3f0c513388e736e0c98c0f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 4 Aug 2020 16:16:14 +0000 Subject: [PATCH 142/704] Bump coverlet.msbuild from 2.8.1 to 2.9.0 Bumps [coverlet.msbuild](https://github.com/coverlet-coverage/coverlet) from 2.8.1 to 2.9.0. - [Release notes](https://github.com/coverlet-coverage/coverlet/releases) - [Commits](https://github.com/coverlet-coverage/coverlet/commits) Signed-off-by: dependabot[bot] --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index a491f369..4b76c54b 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -5,7 +5,7 @@ - + From a8c59c572c872c495b467e1a1a1f81d174592bd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2020 06:21:04 +0000 Subject: [PATCH 143/704] Bump Microsoft.Net.Compilers.Toolset from 3.6.0 to 3.7.0 Bumps [Microsoft.Net.Compilers.Toolset](https://github.com/dotnet/roslyn) from 3.6.0 to 3.7.0. - [Release notes](https://github.com/dotnet/roslyn/releases) - [Changelog](https://github.com/dotnet/roslyn/blob/master/docs/Breaking%20API%20Changes.md) - [Commits](https://github.com/dotnet/roslyn/commits) Signed-off-by: dependabot[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 7a6a46ae..8ffdea80 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -28,7 +28,7 @@ - + From c73b9220f6b0131fc5ac67af91b71c96df51d782 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 10 Aug 2020 06:21:04 +0000 Subject: [PATCH 144/704] Bump Microsoft.NET.Test.Sdk from 16.6.1 to 16.7.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.6.1 to 16.7.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.6.1...v16.7.0) Signed-off-by: dependabot[bot] --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 4b76c54b..6e1c8293 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -6,7 +6,7 @@ - + From 29cf0a517da6adf751a11d2558361d5240f831a2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 10 Aug 2020 08:02:17 -0600 Subject: [PATCH 145/704] Update .NET Core SDK to 3.1.302 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 11833de0..cc9e47f2 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.301", + "version": "3.1.302", "rollForward": "patch", "allowPrerelease": false } From fe64abe20bc74fc6aecedcbc54176b76298e4302 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 10 Aug 2020 09:13:44 -0600 Subject: [PATCH 146/704] Get WPF inner-builds to import NuGet packages' imports Workaround for https://github.com/dotnet/wpf/issues/810 --- Directory.Build.props | 27 +++++++++++++++++++++++++++ Directory.Build.targets | 6 ++++++ src/Directory.Build.targets | 5 ----- 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 7a6a46ae..23d033f6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,4 +40,31 @@ + + + false + true + + + + + <_WpfTempProjectNuGetFilePathNoExt>$(RepoRootPath)obj\$(_TargetAssemblyProjectName)\$(_TargetAssemblyProjectName)$(MSBuildProjectExtension).nuget.g + + false + false + false + false + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets index 8c119d54..65a15bfc 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -1,2 +1,8 @@ + + + false + + + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index c1ce3634..e7edee55 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,8 +1,3 @@ - - - false - - From 225c8e7b9ea43c30640323f8ba4b89c5783b386c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 15 Aug 2020 09:00:24 -0600 Subject: [PATCH 147/704] Ignore CA2007 in tests --- test/.editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/.editorconfig b/test/.editorconfig index 89195dda..2abae62d 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -38,3 +38,6 @@ dotnet_diagnostic.CA1063.severity = silent # CA1816: Dispose methods should call SuppressFinalize dotnet_diagnostic.CA1816.severity = silent + +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = none From eef30466f115466841d4107cfc7cd6affec91e08 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 17 Aug 2020 06:30:20 +0000 Subject: [PATCH 148/704] Bump Microsoft.CodeAnalysis.FxCopAnalyzers from 3.0.0 to 3.3.0 Bumps [Microsoft.CodeAnalysis.FxCopAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 3.0.0 to 3.3.0. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/v3.0.0...v3.3.0) Signed-off-by: dependabot[bot] --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index ce0d2a55..b9f89e5a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,7 +24,7 @@ - + From d5f3e774f5b345b578742607edc91513fcf66d0f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 19 Aug 2020 10:57:24 -0600 Subject: [PATCH 149/704] Add YAML based release pipeline --- azure-pipelines/release.yml | 72 +++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 azure-pipelines/release.yml diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml new file mode 100644 index 00000000..bfe5987c --- /dev/null +++ b/azure-pipelines/release.yml @@ -0,0 +1,72 @@ +trigger: none # We only want to trigger manually or based on resources +pr: none + +resources: + pipelines: + - pipeline: CI + source: Library # TODO: This should match the name of your CI pipeline + trigger: + tags: + - auto-release + +stages: +- stage: GitHubRelease + displayName: GitHub Release + jobs: + - deployment: create + pool: + vmImage: ubuntu-latest + environment: No-Approval + strategy: + runOnce: + deploy: + steps: + - download: none + - powershell: | + Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" + displayName: Set pipeline name + - task: GitHubRelease@1 + displayName: GitHub release (create) + inputs: + gitHubConnection: # TODO: fill in service connection here + repositoryName: $(Build.Repository.Name) + target: $(resources.pipeline.CI.sourceCommit) + tagSource: userSpecifiedTag + tag: v$(resources.pipeline.CI.runName) + title: v$(resources.pipeline.CI.runName) + isDraft: true # After running this step, visit the new draft release, edit, and publish. + changeLogCompareToRelease: lastNonDraftRelease + changeLogType: issueBased + changeLogLabels: | + [ + { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, + { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } + ] + +- stage: nuget_org + displayName: nuget.org + dependsOn: GitHubRelease + jobs: + - deployment: push + pool: + vmImage: ubuntu-latest + environment: No-Approval + strategy: + runOnce: + deploy: + steps: + - download: CI + artifact: deployables-Windows + displayName: Download deployables-Windows artifact + patterns: 'deployables-Windows/*' + - task: NuGetToolInstaller@1 + displayName: Use NuGet 5.x + inputs: + versionSpec: 5.x + - task: NuGetCommand@2 + displayName: NuGet push + inputs: + command: push + packagesToPush: $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg + nuGetFeedType: external + publishFeedCredentials: # TODO: fill in service connection here From 9469bdf8c4e70ac8a8d5d7b8eacbf94ad2b1c5e0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 19 Aug 2020 12:13:49 -0600 Subject: [PATCH 150/704] Fix up init.cmd to set env vars from .ps1 child process --- azure-pipelines/Set-EnvVars.ps1 | 20 ++++++++++++++++++- init.cmd | 16 +++++++++++++++ init.ps1 | 35 ++++++++++++++++++--------------- tools/Install-DotNetSdk.ps1 | 22 ++++++++++----------- 4 files changed, 65 insertions(+), 28 deletions(-) diff --git a/azure-pipelines/Set-EnvVars.ps1 b/azure-pipelines/Set-EnvVars.ps1 index 9d14d9aa..bde2e343 100644 --- a/azure-pipelines/Set-EnvVars.ps1 +++ b/azure-pipelines/Set-EnvVars.ps1 @@ -4,8 +4,13 @@ Azure Pipeline and CMD environments are considered. .PARAMETER Variables A hashtable of variables to be set. +.PARAMETER PrependPath + A set of paths to prepend to the PATH environment variable. .OUTPUTS A boolean indicating whether the environment variables can be expected to propagate to the caller's environment. +.DESCRIPTION + The CmdEnvScriptPath environment variable may be optionally set to a path to a cmd shell script to be created (or appended to if it already exists) that will set the environment variables in cmd.exe that are set within the PowerShell environment. + This is used by init.cmd in order to reapply any new environment variables to the parent cmd.exe process that were set in the powershell child process. #> [CmdletBinding(SupportsShouldProcess=$true)] Param( @@ -18,7 +23,7 @@ if ($Variables.Count -eq 0) { return $true } -$cmdInstructions = !$env:TF_BUILD -and !$env:GITHUB_ACTIONS -and $env:PS1UnderCmd -eq '1' +$cmdInstructions = !$env:TF_BUILD -and !$env:GITHUB_ACTIONS -and !$env:CmdEnvScriptPath -and ($env:PS1UnderCmd -eq '1') if ($cmdInstructions) { Write-Warning "Environment variables have been set that will be lost because you're running under cmd.exe" Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue @@ -38,6 +43,7 @@ if ($env:GITHUB_ACTIONS) { Write-Host "GitHub Actions detected. Logging commands will be used to propagate environment variables and prepend path." } +$CmdEnvScript = '' $Variables.GetEnumerator() |% { Set-Item -Path env:$($_.Key) -Value $_.Value @@ -52,6 +58,8 @@ $Variables.GetEnumerator() |% { if ($cmdInstructions) { Write-Host "SET $($_.Key)=$($_.Value)" } + + $CmdEnvScript += "SET $($_.Key)=$($_.Value)`r`n" } $pathDelimiter = ';' @@ -73,7 +81,17 @@ if ($PrependPath) { if ($env:GITHUB_ACTIONS) { Write-Host "::add-path::$_" } + + $CmdEnvScript += "SET PATH=$_$pathDelimiter%PATH%" + } +} + +if ($env:CmdEnvScriptPath) { + if (Test-Path $env:CmdEnvScriptPath) { + $CmdEnvScript = (Get-Content -Path $env:CmdEnvScriptPath) + $CmdEnvScript } + + Set-Content -Path $env:CmdEnvScriptPath -Value $CmdEnvScript } return !$cmdInstructions diff --git a/init.cmd b/init.cmd index 970285c2..667efabb 100644 --- a/init.cmd +++ b/init.cmd @@ -1,4 +1,20 @@ @echo off SETLOCAL set PS1UnderCmd=1 + +:: Get the datetime in a format that can go in a filename. +set _my_datetime=%date%_%time% +set _my_datetime=%_my_datetime: =_% +set _my_datetime=%_my_datetime::=% +set _my_datetime=%_my_datetime:/=_% +set _my_datetime=%_my_datetime:.=_% +set CmdEnvScriptPath=%temp%\envvarscript_%_my_datetime%.cmd + powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }" + +:: Set environment variables in the parent cmd.exe process. +IF EXIST "%CmdEnvScriptPath%" ( + ENDLOCAL + CALL "%CmdEnvScriptPath%" + DEL "%CmdEnvScriptPath%" +) diff --git a/init.ps1 b/init.ps1 index 72d68b5f..a6978b6f 100755 --- a/init.ps1 +++ b/init.ps1 @@ -2,28 +2,31 @@ <# .SYNOPSIS -Installs dependencies required to build and test the projects in this repository. + Installs dependencies required to build and test the projects in this repository. .DESCRIPTION -This MAY not require elevation, as the SDK and runtimes are installed to a per-user location, -unless the `-InstallLocality` switch is specified directing to a per-repo or per-machine location. -See detailed help on that switch for more information. + This MAY not require elevation, as the SDK and runtimes are installed to a per-user location, + unless the `-InstallLocality` switch is specified directing to a per-repo or per-machine location. + See detailed help on that switch for more information. + + The CmdEnvScriptPath environment variable may be optionally set to a path to a cmd shell script to be created (or appended to if it already exists) that will set the environment variables in cmd.exe that are set within the PowerShell environment. + This is used by init.cmd in order to reapply any new environment variables to the parent cmd.exe process that were set in the powershell child process. .PARAMETER InstallLocality -A value indicating whether dependencies should be installed locally to the repo or at a per-user location. -Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. -Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. -Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. -When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. -Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. -Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. + A value indicating whether dependencies should be installed locally to the repo or at a per-user location. + Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. + Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. + Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. + When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. + Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. + Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. .PARAMETER NoPrerequisites -Skips the installation of prerequisite software (e.g. SDKs, tools). + Skips the installation of prerequisite software (e.g. SDKs, tools). .PARAMETER UpgradePrerequisites -Takes time to install prerequisites even if they are already present in case they need to be upgraded. -No effect if -NoPrerequisites is specified. + Takes time to install prerequisites even if they are already present in case they need to be upgraded. + No effect if -NoPrerequisites is specified. .PARAMETER NoRestore -Skips the package restore step. + Skips the package restore step. .PARAMETER AccessToken -An optional access token for authenticating to Azure Artifacts authenticated feeds. + An optional access token for authenticating to Azure Artifacts authenticated feeds. #> [CmdletBinding(SupportsShouldProcess=$true)] Param ( diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index be5f6a27..a02b5cdc 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -2,19 +2,19 @@ <# .SYNOPSIS -Installs the .NET SDK specified in the global.json file at the root of this repository, -along with supporting .NET Core runtimes used for testing. + Installs the .NET SDK specified in the global.json file at the root of this repository, + along with supporting .NET Core runtimes used for testing. .DESCRIPTION -This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, -unless `-InstallLocality machine` is specified. + This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, + unless `-InstallLocality machine` is specified. .PARAMETER InstallLocality -A value indicating whether dependencies should be installed locally to the repo or at a per-user location. -Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. -Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. -Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. -When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. -Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. -Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. + A value indicating whether dependencies should be installed locally to the repo or at a per-user location. + Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. + Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. + Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. + When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. + Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. + Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( From 5439be7fde0ebed774cffc561bf2390cea1a87b3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 19 Aug 2020 12:14:19 -0600 Subject: [PATCH 151/704] Move Set-EnvVars.ps1 to tools --- init.ps1 | 2 +- tools/Install-DotNetSdk.ps1 | 2 +- tools/Install-NuGetCredProvider.ps1 | 8 +++++--- {azure-pipelines => tools}/Set-EnvVars.ps1 | 0 4 files changed, 7 insertions(+), 5 deletions(-) rename {azure-pipelines => tools}/Set-EnvVars.ps1 (100%) diff --git a/init.ps1 b/init.ps1 index a6978b6f..e5aad5bf 100755 --- a/init.ps1 +++ b/init.ps1 @@ -74,7 +74,7 @@ try { } } - & "$PSScriptRoot\azure-pipelines\Set-EnvVars.ps1" -Variables $EnvVars | Out-Null + & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars | Out-Null } catch { Write-Error $error[0] diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index a02b5cdc..2da4a73d 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -165,5 +165,5 @@ $runtimeVersions | Get-Unique |% { } if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) { - & "$PSScriptRoot/../azure-pipelines/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null + & "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null } diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 index 2b3fb6fb..6d310034 100755 --- a/tools/Install-NuGetCredProvider.ps1 +++ b/tools/Install-NuGetCredProvider.ps1 @@ -19,6 +19,8 @@ Param ( [string]$AccessToken ) +$envVars = @{} + $toolsPath = & "$PSScriptRoot\..\azure-pipelines\Get-TempToolsPath.ps1" if ($IsMacOS -or $IsLinux) { @@ -66,9 +68,9 @@ if ($AccessToken) { Add-Member -InputObject $auth -MemberType NoteProperty -Name endpointCredentials -Value $endpoints $authJson = ConvertTo-Json -InputObject $auth - $envVars = @{ + $envVars += @{ 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'=$authJson; } - - & "$PSScriptRoot\..\azure-pipelines\Set-EnvVars.ps1" -Variables $envVars | Out-Null } + +& "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars | Out-Null diff --git a/azure-pipelines/Set-EnvVars.ps1 b/tools/Set-EnvVars.ps1 similarity index 100% rename from azure-pipelines/Set-EnvVars.ps1 rename to tools/Set-EnvVars.ps1 From 7d217d1f1658b5348bd9739b1e742c9ad7e21402 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 21 Aug 2020 21:54:00 -0600 Subject: [PATCH 152/704] Run net472 tests on mac/linux (which means on Mono) --- azure-pipelines/dotnet.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 6764e6ec..8f4e950f 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -12,7 +12,7 @@ steps: command: test arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: net472-$(Agent.JobName) - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) + condition: succeededOrFailed() - task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp2.1 @@ -20,6 +20,7 @@ steps: command: test arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: netcoreapp2.1-$(Agent.JobName) + condition: succeededOrFailed() - task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp3.1 @@ -27,6 +28,7 @@ steps: command: test arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" testRunTitle: netcoreapp3.1-$(Agent.JobName) + condition: succeededOrFailed() - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true From 461288dfc334ecacc78d797ab9ceba504bbac25b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 23 Aug 2020 12:58:47 -0600 Subject: [PATCH 153/704] Beef up contrib doc explanation of init.ps1 --- CONTRIBUTING.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2102ba9b..36424c42 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,6 +16,8 @@ with any additional questions or comments. All dependencies can be installed by running the `init.ps1` script at the root of the repository using Windows PowerShell or [PowerShell Core][pwsh] (on any OS). +Some dependencies installed by `init.ps1` may only be discoverable from the same command line environment the init script was run from due to environment variables, so be sure to launch Visual Studio or build the repo from that same environment. +Alternatively, run `init.ps1 -InstallLocality Machine` (which may require elevation) in order to install dependencies at machine-wide locations so Visual Studio and builds work everywhere. The only prerequisite for building, testing, and deploying from this repository is the [.NET SDK](https://get.dot.net/). From b79b08af1a6da50c9bee63c8b5e932992be53fa2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 23 Aug 2020 13:15:57 -0600 Subject: [PATCH 154/704] Add warning that non-machine installs must run within same environment --- tools/Install-DotNetSdk.ps1 | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 2da4a73d..ec66c949 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -148,7 +148,10 @@ if (-not (Test-Path $DotNetInstallScriptPath)) { } } +$anythingInstalled = $false + if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" } else { Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" @@ -158,6 +161,7 @@ $switches += '-Runtime','dotnet' $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" } else { Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" @@ -167,3 +171,7 @@ $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) { & "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null } + +if ($anythingInstalled -and ($InstallLocality -ne 'machine') -and !$env:TF_BUILD -and !$env:GITHUB_ACTIONS) { + Write-Warning ".NET Core runtimes or SDKs were installed to a non-machine location. Perform your builds or open Visual Studio from this same environment in order for tools to discover the location of these dependencies." +} From 3d1c43c3d3222adfec73c0981fc799308a6a94e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 24 Aug 2020 06:48:20 -0600 Subject: [PATCH 155/704] Bump Microsoft.NET.Test.Sdk from 16.7.0 to 16.7.1 (#72) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.7.0 to 16.7.1. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.7.0...v16.7.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 6e1c8293..ea4220b9 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -6,7 +6,7 @@ - + From 641eaa17cdf690aacad122a78b3f32b13cf36d8a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Sep 2020 03:40:22 -0600 Subject: [PATCH 156/704] Provide better error when sn is not on the PATH Since the .NET Core SDK does not include the sn tool, on mac/linux the only way to create strong name keys is with mono. The expand-template.ps1 script didn't explain this to the user, but instead searched a Windows directory. This commit improves the error they see. Fixes #73 --- Expand-Template.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index 5ed211d0..e0708bd4 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -56,6 +56,10 @@ function Replace-Placeholders { # Try to find sn.exe if it isn't on the PATH $sn = Get-Command sn -ErrorAction SilentlyContinue if (-not $sn) { + if ($IsMacOS -or $IsLinux) { + Write-Error "sn command not found on PATH. Install mono and/or vote up this issue: https://github.com/dotnet/sdk/issues/13560" + exit(1) + } $snExes = Get-ChildItem -Recurse "${env:ProgramFiles(x86)}\Microsoft SDKs\Windows\sn.exe" if ($snExes) { $sn = Get-Command $snExes[0].FullName From e3449f0b073df5ec14886be35a8f01e76f4c50f1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Sep 2020 03:44:08 -0600 Subject: [PATCH 157/704] Fail fast when dotnet returns an exit code --- Expand-Template.ps1 | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index e0708bd4..adc4fb11 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -82,31 +82,48 @@ try { if ($Squash) { $originalCommitId = git rev-parse HEAD git reset --soft $(git rev-list --max-parents=0 HEAD) + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git commit --amend -qm "Initial template from https://github.com/AArnott/Library.Template" -m "Original commit from template $originalCommitId" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } # Rename project directories and solution git mv Library.sln "$LibraryName.sln" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git mv src/Library/Library.csproj "src/Library/$LibraryName.csproj" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git mv src/Library "src/$LibraryName" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git mv test/Library.Tests/Library.Tests.csproj "test/Library.Tests/$LibraryName.Tests.csproj" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git mv test/Library.Tests "test/$LibraryName.Tests" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Refresh solution file both to update paths and give the projects unique GUIDs dotnet sln remove src/Library/Library.csproj + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet sln remove test/Library.Tests/Library.Tests.csproj + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet sln add "src/$LibraryName" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet sln add "test/$LibraryName.Tests" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git add "$LibraryName.sln" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Update project reference in test project. Add before removal to keep the same ItemGroup in place. dotnet add "test/$LibraryName.Tests" reference "src/$LibraryName" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } dotnet remove "test/$LibraryName.Tests" reference src/Library/Library.csproj + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git add "test/$LibraryName.Tests/$LibraryName.Tests.csproj" + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Establish a new strong-name key & $sn.Path -k 2048 strongname.snk + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git add strongname.snk + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Replace placeholders in source files Replace-Placeholders -Path "src/$LibraryName/Calculator.cs" -Replacements @{ @@ -153,7 +170,9 @@ try { # Self destruct git rm Expand-Template.* + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git rm :/azure-pipelines/expand-template.yml + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Self-integrity check Get-ChildItem -Recurse -File -Exclude bin,obj,README.md,Expand-Template.* |? { -not $_.FullName.Contains("obj") } |% { @@ -165,6 +184,7 @@ try { # Commit the changes git commit -qm "Expanded template for $LibraryName" -m "This expansion done by the (now removed) Expand-Template.ps1 script." + if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } Write-Host -ForegroundColor Green "Template successfully expanded." From 0c212b6459c470633a941c7854eb6f73f258f488 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Sep 2020 05:59:22 -0600 Subject: [PATCH 158/704] Skip .NET SDK and runtime install when unneeded --- tools/Check-DotNetRuntime.ps1 | 41 +++++++++++++++++++++++++++++ tools/Check-DotNetSdk.ps1 | 31 ++++++++++++++++++++++ tools/Install-DotNetSdk.ps1 | 49 ++++++++++++++++++++++++----------- 3 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 tools/Check-DotNetRuntime.ps1 create mode 100644 tools/Check-DotNetSdk.ps1 diff --git a/tools/Check-DotNetRuntime.ps1 b/tools/Check-DotNetRuntime.ps1 new file mode 100644 index 00000000..9d012109 --- /dev/null +++ b/tools/Check-DotNetRuntime.ps1 @@ -0,0 +1,41 @@ +<# +.SYNOPSIS + Checks whether a given .NET Core runtime is installed. +#> +[CmdletBinding()] +Param ( + [Parameter()] + [ValidateSet('Microsoft.AspNetCore.App','Microsoft.NETCore.App')] + [string]$Runtime='Microsoft.NETCore.App', + [Parameter(Mandatory=$true)] + [Version]$Version +) + +$dotnet = Get-Command dotnet -ErrorAction SilentlyContinue +if (!$dotnet) { + # Nothing is installed. + Write-Output $false + exit 1 +} + +Function IsVersionMatch { + Param( + [Parameter()] + $actualVersion + ) + return $actualVersion -and + $Version.Major -eq $actualVersion.Major -and + $Version.Minor -eq $actualVersion.Minor -and + (($Version.Build -eq -1) -or ($Version.Build -eq $actualVersion.Build)) -and + (($Version.Revision -eq -1) -or ($Version.Revision -eq $actualVersion.Revision)) +} + +$installedRuntimes = dotnet --list-runtimes |? { $_.Split()[0] -ieq $Runtime } |% { $v = $null; [Version]::tryparse($_.Split()[1], [ref] $v); $v } +$matchingRuntimes = $installedRuntimes |? { IsVersionMatch -actualVersion $_ } +if (!$matchingRuntimes) { + Write-Output $false + exit 1 +} + +Write-Output $true +exit 0 diff --git a/tools/Check-DotNetSdk.ps1 b/tools/Check-DotNetSdk.ps1 new file mode 100644 index 00000000..9d080f75 --- /dev/null +++ b/tools/Check-DotNetSdk.ps1 @@ -0,0 +1,31 @@ +<# +.SYNOPSIS + Checks whether the .NET Core SDK required by this repo is installed. +#> +[CmdletBinding()] +Param ( +) + +$dotnet = Get-Command dotnet -ErrorAction SilentlyContinue +if (!$dotnet) { + # Nothing is installed. + Write-Output $false + exit 1 +} + +# We need to set the current directory so dotnet considers the SDK required by our global.json file. +Push-Location "$PSScriptRoot\.." +try { + dotnet -h 2>&1 | Out-Null + if ($LASTEXITCODE -eq 129) { + # This error code indicates no matching SDK exists. + Write-Output $false + exit 2 + } + + # The required SDK is already installed! + Write-Output $true + exit 0 +} finally { + Pop-Location +} diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index ec66c949..f7c023e6 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -15,11 +15,14 @@ When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. +.PARAMETER Force + Installs the preferred .NET SDK and runtime versions even if compatible versions are found to already be installed. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( [ValidateSet('repo','user','machine')] - [string]$InstallLocality='user' + [string]$InstallLocality='user', + [switch]$Force ) $DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools" @@ -98,15 +101,23 @@ if ($InstallLocality -eq 'machine') { $DotNetInstallDir = '/usr/share/dotnet' } else { $restartRequired = $false - if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - Install-DotNet -Version $sdkVersion - $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetSdk.ps1"))) { + if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + Install-DotNet -Version $sdkVersion + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } + } else { + Write-Verbose "A .NET SDK version compatible with $sdkVersion is already installed." } $runtimeVersions | Get-Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - Install-DotNet -Version $_ -Runtime - $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetRuntime.ps1" -Version $_))) { + if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + Install-DotNet -Version $_ -Runtime + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } + } else { + Write-Verbose ".NET runtime $_ is already installed." } } @@ -150,21 +161,29 @@ if (-not (Test-Path $DotNetInstallScriptPath)) { $anythingInstalled = $false -if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" +if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetSdk.ps1"))) { + if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" + } else { + Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" + } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" + Write-Verbose "A .NET SDK version compatible with $sdkVersion is already installed." } $switches += '-Runtime','dotnet' $runtimeVersions | Get-Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" + if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetRuntime.ps1" -Version $_))) { + if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" + } else { + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" + } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" + Write-Verbose ".NET runtime $_ is already installed." } } From 1c2cb37ea5e403f058c045559bc1788d416c2bf7 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Sep 2020 05:59:35 -0600 Subject: [PATCH 159/704] Install SDK to expand-template when necessary --- Expand-Template.ps1 | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index adc4fb11..c6ae8cba 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -15,7 +15,7 @@ The `/{guid}` path to the Azure Pipelines artifact feed to push your nuget packa .PARAMETER Squash A switch that causes all of git history to be squashed to just one initial commit for the template, and one for its expansion. #> -[CmdletBinding()] +[CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] Param( [Parameter(Mandatory=$true)] [string]$LibraryName, @@ -69,6 +69,15 @@ if (-not $sn) { } } +if (-not (& "$PSScriptRoot\tools\Check-DotNetSdk.ps1")) { + if ($PSCmdlet.ShouldProcess('Install .NET Core SDK?')) { + & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" + } else { + Write-Error "Matching .NET Core SDK version not found. Install now?" + exit 1 + } +} + # Verify all commands we use are on the PATH ('git','dotnet') |% { if (-not (Get-Command $_ -ErrorAction SilentlyContinue)) { From 8377c641a87333da635846e2b4511900407ac1bd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 13 Sep 2020 07:40:35 -0600 Subject: [PATCH 160/704] Catch exception thrown on some machines --- tools/Check-DotNetSdk.ps1 | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/tools/Check-DotNetSdk.ps1 b/tools/Check-DotNetSdk.ps1 index 9d080f75..6c9fa772 100644 --- a/tools/Check-DotNetSdk.ps1 +++ b/tools/Check-DotNetSdk.ps1 @@ -17,8 +17,10 @@ if (!$dotnet) { Push-Location "$PSScriptRoot\.." try { dotnet -h 2>&1 | Out-Null - if ($LASTEXITCODE -eq 129) { - # This error code indicates no matching SDK exists. + if (($LASTEXITCODE -eq 129) -or # On Linux + ($LASTEXITCODE -eq -2147450751) # On Windows + ) { + # These exit codes indicate no matching SDK exists. Write-Output $false exit 2 } @@ -26,6 +28,10 @@ try { # The required SDK is already installed! Write-Output $true exit 0 +} catch { + # I don't know why, but on some build agents (e.g. MicroBuild), an exception is thrown from the `dotnet` invocation when a match is not found. + Write-Output $false + exit 3 } finally { Pop-Location } From 69a74f8c05201c01d1771f9ea2fa528283275e0d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Sep 2020 11:46:12 -0600 Subject: [PATCH 161/704] Revert incremental install of SDKs/Runtimes The 0c212b6459c4 commit brought this optimization in, but it is buggy because an SDK or runtime might not be installed because it's at the machine level, but if another runtime is missing and installed, it sets env vars which hide the machine level ones already found, so now they need to also be installed. But they weren't, so the build would just fail. Similarly, if the script is supposed to install to the machine location and the SDK is already installed at the user location, the recent optimization would skip installing it at the machine location. --- tools/Install-DotNetSdk.ps1 | 49 ++++++++++++------------------------- 1 file changed, 15 insertions(+), 34 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index f7c023e6..ec66c949 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -15,14 +15,11 @@ When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. -.PARAMETER Force - Installs the preferred .NET SDK and runtime versions even if compatible versions are found to already be installed. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( [ValidateSet('repo','user','machine')] - [string]$InstallLocality='user', - [switch]$Force + [string]$InstallLocality='user' ) $DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools" @@ -101,23 +98,15 @@ if ($InstallLocality -eq 'machine') { $DotNetInstallDir = '/usr/share/dotnet' } else { $restartRequired = $false - if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetSdk.ps1"))) { - if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - Install-DotNet -Version $sdkVersion - $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) - } - } else { - Write-Verbose "A .NET SDK version compatible with $sdkVersion is already installed." + if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + Install-DotNet -Version $sdkVersion + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) } $runtimeVersions | Get-Unique |% { - if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetRuntime.ps1" -Version $_))) { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - Install-DotNet -Version $_ -Runtime - $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) - } - } else { - Write-Verbose ".NET runtime $_ is already installed." + if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + Install-DotNet -Version $_ -Runtime + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) } } @@ -161,29 +150,21 @@ if (-not (Test-Path $DotNetInstallScriptPath)) { $anythingInstalled = $false -if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetSdk.ps1"))) { - if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" - } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" - } +if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" } else { - Write-Verbose "A .NET SDK version compatible with $sdkVersion is already installed." + Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" } $switches += '-Runtime','dotnet' $runtimeVersions | Get-Unique |% { - if ($Force -or (-not (& "$PSScriptRoot/Check-DotNetRuntime.ps1" -Version $_))) { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" - } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" - } + if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" } else { - Write-Verbose ".NET runtime $_ is already installed." + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" } } From 6c9781abbfcdcf0bd3001583cae8be38ab4c4903 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Sep 2020 11:34:03 -0600 Subject: [PATCH 162/704] Bump SDK to 3.1.402 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index cc9e47f2..a2e8ff9e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.302", + "version": "3.1.402", "rollForward": "patch", "allowPrerelease": false } From 1304c04d58a501d47ce335515b8aa61404a8126e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Sep 2020 14:52:20 -0600 Subject: [PATCH 163/704] Use lowercase for privateassets --- Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index b9f89e5a..c6652de4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -25,8 +25,8 @@ - - + + From 35ce94a23526a98dd3b827c1c609f6a4cf9968e9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Sep 2020 14:50:01 -0600 Subject: [PATCH 164/704] Simplify Project tag --- Directory.Build.props | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index c6652de4..8bb360bf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,5 +1,4 @@ - + Debug $(MSBuildThisFileDirectory) From c406cb86fdc100dd8ace0902562701f6a0110b1f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Sep 2020 14:50:11 -0600 Subject: [PATCH 165/704] Update URL for NB.GV schema --- version.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/version.json b/version.json index 38da1662..a13f567b 100644 --- a/version.json +++ b/version.json @@ -1,8 +1,8 @@ { - "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", "version": "0.1-beta", "publicReleaseRefSpec": [ "^refs/heads/master$", "^refs/heads/v\\d+(?:\\.\\d+)?$" ] -} \ No newline at end of file +} From 19da325b6bb3aa7d61195098c546e6d0ed58cf31 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 25 Sep 2020 09:24:48 -0600 Subject: [PATCH 166/704] Add `Nullable` package --- Directory.Build.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8bb360bf..4e95413b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,10 +24,11 @@ + - + From e00b38d09ce88c091325e6c572b397827b146683 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 25 Sep 2020 12:26:36 -0600 Subject: [PATCH 167/704] Checkout ps1 with LF endings --- .gitattributes | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.gitattributes b/.gitattributes index 9b6ea624..c22a129e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -3,8 +3,9 @@ ############################################################################### * text=auto -# Ensure bash shell scripts use LF line endings +# Ensure shell scripts use LF line endings (linux only accepts LF) *.sh eol=lf +*.ps1 eol=lf ############################################################################### # Set default behavior for command prompt diff. @@ -20,7 +21,7 @@ # # Merging from the command prompt will add diff markers to the files if there # are conflicts (Merging from VS is not affected by the settings below, in VS -# the diff markers are never inserted). Diff markers may cause the following +# the diff markers are never inserted). Diff markers may cause the following # file extensions to fail to load in VS. An alternative would be to treat # these files as binary and thus will always conflict and require user # intervention with every merge. To do so, just uncomment the entries below @@ -49,9 +50,9 @@ ############################################################################### # diff behavior for common document formats -# +# # Convert binary document formats to text before diffing them. This feature -# is only available from the command line. Turn it on by uncommenting the +# is only available from the command line. Turn it on by uncommenting the # entries below. ############################################################################### #*.doc diff=astextplain From 4765380c9ee5f82d2622728cfb4397d93e23a265 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 30 Mar 2020 10:00:18 -0600 Subject: [PATCH 168/704] Reorder TFMs in test project This gets the default run (and only run from VS Code) to work on Linux. --- test/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Directory.Build.props b/test/Directory.Build.props index b48b5d81..2b780029 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,7 +2,7 @@ - net472;netcoreapp2.1;netcoreapp3.1 + netcoreapp3.1;netcoreapp2.1;net472 false true From 68153893f540a33cd449500c5ca742888928e54e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 25 Sep 2020 13:50:58 -0600 Subject: [PATCH 169/704] Add devcontainer.json Also add other supporting files so that the VS Code 'dev container' scenario and GitHub Codespaces works nicely. --- .devcontainer/Dockerfile | 8 ++++++++ .devcontainer/devcontainer.json | 16 ++++++++++++++++ .vscode/extensions.json | 4 +++- .vscode/launch.json | 14 ++++++++++++++ .vscode/tasks.json | 17 +++++++++++++++++ 5 files changed, 58 insertions(+), 1 deletion(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/tasks.json diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..c551ecf2 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,8 @@ +FROM mcr.microsoft.com/dotnet/core/sdk:3.1-bionic + +# Installing mono makes `dotnet test` work without errors even for net472. +# But installing it takes a long time, so it's excluded by default. +#RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF +#RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | tee /etc/apt/sources.list.d/mono-official-stable.list +#RUN apt-get update +#RUN DEBIAN_FRONTEND=noninteractive apt-get install -y mono-devel diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..9a86e07d --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,16 @@ +{ + "name": "Dev space", + "dockerFile": "Dockerfile", + "postCreateCommand": "./init.ps1 -InstallLocality machine", + "extensions": [ + "ms-azure-devops.azure-pipelines", + "ms-dotnettools.csharp", + "k--kato.docomment", + "editorconfig.editorconfig", + "pflannery.vscode-versionlens", + "davidanson.vscode-markdownlint", + "dotjoshjohnson.xml", + "ms-vscode-remote.remote-containers", + "ms-azuretools.vscode-docker" + ] +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json index ecda668e..4ca01616 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -9,7 +9,9 @@ "editorconfig.editorconfig", "pflannery.vscode-versionlens", "davidanson.vscode-markdownlint", - "dotjoshjohnson.xml" + "dotjoshjohnson.xml", + "ms-vscode-remote.remote-containers", + "ms-azuretools.vscode-docker" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [] diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 00000000..a6e4859c --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,14 @@ +{ + // Use IntelliSense to find out which attributes exist for C# debugging + // Use hover for the description of the existing attributes + // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md + "version": "0.2.0", + "configurations": [ + { + "name": ".NET Core Attach", + "type": "coreclr", + "request": "attach", + "processId": "${command:pickProcess}" + } + ] +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 00000000..67b06180 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,17 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "build", + "command": "dotnet", + "type": "process", + "args": [ + "build", + "${workspaceFolder}", + "/property:GenerateFullPaths=true", + "/consoleloggerparameters:NoSummary" + ], + "problemMatcher": "$msCompile" + } + ] +} From e1294286706d94b02029da23aa48ab177fa8d494 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 25 Sep 2020 17:59:29 -0600 Subject: [PATCH 170/704] Honor .editorconfig in Omnisharp --- .vscode/settings.json | 5 ++++- test/Library.Tests/CalculatorTests.cs | 7 +------ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index f0cafc05..00aaed88 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,8 @@ { "files.trimTrailingWhitespace": true, "files.insertFinalNewline": true, - "files.trimFinalNewlines": true + "files.trimFinalNewlines": true, + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableImportCompletion": true, + "omnisharp.enableRoslynAnalyzers": true } diff --git a/test/Library.Tests/CalculatorTests.cs b/test/Library.Tests/CalculatorTests.cs index 84fe9a97..44e89aaa 100644 --- a/test/Library.Tests/CalculatorTests.cs +++ b/test/Library.Tests/CalculatorTests.cs @@ -1,18 +1,13 @@ // Copyright (c) COMPANY-PLACEHOLDER. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; using Library; using Xunit; -using Xunit.Abstractions; public class CalculatorTests { - private readonly ITestOutputHelper logger; - - public CalculatorTests(ITestOutputHelper logger) + public CalculatorTests() { - this.logger = logger; } [Fact] From aed5ff61d26dc1aa77f1eeeb73ddc47a640b1c39 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 26 Sep 2020 21:07:19 -0600 Subject: [PATCH 171/704] Fix RootNamespace property to actually take effect --- test/Directory.Build.props | 1 - test/Library.Tests/Library.Tests.csproj | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 2b780029..2371a7ef 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -5,7 +5,6 @@ netcoreapp3.1;netcoreapp2.1;net472 false true - diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index ea4220b9..3565372a 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -1,5 +1,9 @@ + + + + From 41d2e5533ffdacbb6abf9555860bead64cbcd1ea Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 30 Sep 2020 17:19:25 +0000 Subject: [PATCH 172/704] Use PowerShell as the preferred terminal --- .devcontainer/devcontainer.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9a86e07d..99630282 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,6 +1,9 @@ { "name": "Dev space", "dockerFile": "Dockerfile", + "settings": { + "terminal.integrated.shell.linux": "/usr/bin/pwsh" + }, "postCreateCommand": "./init.ps1 -InstallLocality machine", "extensions": [ "ms-azure-devops.azure-pipelines", From fa5d1e6eacf9de4a29fdf9d429541e33d0ddc8d2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 13 Oct 2020 16:05:42 -0500 Subject: [PATCH 173/704] Bump Nerdbank.GitVersioning from 3.2.31 to 3.3.37 (#75) Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.2.31 to 3.3.37. - [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases) - [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/compare/v3.2.31...v3.3.37) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 4e95413b..7fb8d826 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -27,7 +27,7 @@ - + From bfd65cceb1895c72d04008ee5bcb9abed1f4d6dc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 20 Oct 2020 08:23:21 -0600 Subject: [PATCH 174/704] Print mono version in Azure Pipelines --- azure-pipelines/install-dependencies.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index f773f385..7563bc1f 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -7,6 +7,11 @@ steps: $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites dotnet --info + + # Print mono version if it is present. + if (Get-Command mono -ErrorAction SilentlyContinue) { + mono --version + } displayName: Install prerequisites - powershell: azure-pipelines/variables/_pipelines.ps1 From 5fdb2443f20647acb95316eaa1c39f94422a8f39 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 21 Oct 2020 07:42:32 -0600 Subject: [PATCH 175/704] Update dependencies monthly instead of weekly --- .github/dependabot.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index aa48b0fe..b9b0f54a 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -6,4 +6,4 @@ updates: - package-ecosystem: nuget directory: / schedule: - interval: weekly + interval: monthly From 4f2a03546774ba1f8312a2c3c8d4838aff43ca13 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 22 Oct 2020 09:05:58 -0600 Subject: [PATCH 176/704] Add release notes link to built package --- Directory.Build.props | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 7fb8d826..7ced2673 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -41,6 +41,13 @@ + + + + + + + false true From 958ffedb97ea213d52b76e04af515e31b1342eba Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 25 Oct 2020 21:36:40 -0600 Subject: [PATCH 177/704] Avoid warnings in Expand-Template due to line endings --- Expand-Template.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index c6ae8cba..d665e56a 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -96,6 +96,8 @@ try { if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } } + git config core.safecrlf false # Avoid warnings when adding files with mangled line endings + # Rename project directories and solution git mv Library.sln "$LibraryName.sln" if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } @@ -204,6 +206,7 @@ try { } } finally { + git config --local --unset core.safecrlf Pop-Location } From 05b332401c7545ac7c669f59defdcf796d4925e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Nov 2020 06:14:20 -0700 Subject: [PATCH 178/704] Bump Microsoft.CodeAnalysis.FxCopAnalyzers from 3.3.0 to 3.3.1 (#76) Bumps [Microsoft.CodeAnalysis.FxCopAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 3.3.0 to 3.3.1. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/v3.3.0...v3.3.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 7ced2673..642fb1d7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,7 +23,7 @@ - + From 9c16ae2061cf5dc70b79c9cfa94bac9e95a978c8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 2 Nov 2020 09:48:52 -0700 Subject: [PATCH 179/704] Publish test symbols on failures When investigating test run failures from Azure Pipelines, symbols from test binaries may be just as important as symbols from product binaries. So publish them as pipeline artifacts as well. Also index all these symbols even in PR builds, since PR builds may fail and investigations may be required. --- azure-pipelines/Get-SymbolFiles.ps1 | 67 ++++++++++++++++++++++ azure-pipelines/artifacts/symbols.ps1 | 54 +---------------- azure-pipelines/artifacts/test_symbols.ps1 | 12 ++++ azure-pipelines/dotnet.yml | 11 +++- 4 files changed, 90 insertions(+), 54 deletions(-) create mode 100644 azure-pipelines/Get-SymbolFiles.ps1 create mode 100644 azure-pipelines/artifacts/test_symbols.ps1 diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1 new file mode 100644 index 00000000..bba177f1 --- /dev/null +++ b/azure-pipelines/Get-SymbolFiles.ps1 @@ -0,0 +1,67 @@ +<# +.SYNOPSIS + Collect the list of PDBs built in this repo, after converting them from portable to Windows PDBs. +.PARAMETER Path + The root path to recursively search for PDBs. +.PARAMETER Tests + A switch indicating to find test-related PDBs instead of product-only PDBs. +#> +[CmdletBinding()] +param ( + [parameter(Mandatory=$true)] + [string]$Path, + [switch]$Tests +) + +$WindowsPdbSubDirName = "symstore" + +$ActivityName = "Collecting symbols from $Path" +Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" +$PDBs = Get-ChildItem -rec "$Path\*.pdb" |? { $_.FullName -notmatch "\W$WindowsPdbSubDirName\W" } + +# Filter PDBs to product OR test related. +$testregex = "unittest|tests" +if ($Tests) { + $PDBs = $PDBs |? { $_.FullName -match $testregex } +} else { + $PDBs = $PDBs |? { $_.FullName -notmatch $testregex } +} + +Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" +$PDBsByHash = @{} +$i = 0 +$PDBs |% { + Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length) + $hash = Get-FileHash $_ + $i++ + Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash + Write-Output $_ +} | Sort-Object CreationTime |% { + # De-dupe based on hash. Prefer the first match so we take the first built copy. + if (-not $PDBsByHash.ContainsKey($_.Hash)) { + $PDBsByHash.Add($_.Hash, $_.FullName) + Write-Output $_ + } +} |% { + # Collect the DLLs/EXEs as well. + $dllPath = "$($_.Directory)\$($_.BaseName).dll" + $exePath = "$($_.Directory)\$($_.BaseName).exe" + if (Test-Path $dllPath) { + $BinaryImagePath = $dllPath + } elseif (Test-Path $exePath) { + $BinaryImagePath = $exePath + } + + Write-Output $BinaryImagePath + + # Convert the PDB to legacy Windows PDBs + Write-Host "Converting PDB for $_" -ForegroundColor DarkGray + $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" + if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } + & "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb" + if ($LASTEXITCODE -ne 0) { + Write-Warning "PDB conversion of `"$_`" failed." + } + + Write-Output "$WindowsPdbDir\$($_.BaseName).pdb" +} diff --git a/azure-pipelines/artifacts/symbols.ps1 b/azure-pipelines/artifacts/symbols.ps1 index 50491368..b3451ce1 100644 --- a/azure-pipelines/artifacts/symbols.ps1 +++ b/azure-pipelines/artifacts/symbols.ps1 @@ -1,55 +1,3 @@ -Function Get-SymbolFiles { - [CmdletBinding()] - param ( - [parameter(Mandatory=$true)] - [string]$Path - ) - - $WindowsPdbSubDirName = "symstore" - - $ActivityName = "Collecting symbols from $Path" - Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" - $PDBs = Get-ChildItem -rec "$Path\*.pdb" |? { $_.FullName -notmatch "unittest|tests|\W$WindowsPdbSubDirName\W" } - Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" - $PDBsByHash = @{} - $i = 0 - $PDBs |% { - Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length) - $hash = Get-FileHash $_ - $i++ - Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash - Write-Output $_ - } | Sort-Object CreationTime |% { - # De-dupe based on hash. Prefer the first match so we take the first built copy. - if (-not $PDBsByHash.ContainsKey($_.Hash)) { - $PDBsByHash.Add($_.Hash, $_.FullName) - Write-Output $_ - } - } |% { - # Collect the DLLs/EXEs as well. - $dllPath = "$($_.Directory)\$($_.BaseName).dll" - $exePath = "$($_.Directory)\$($_.BaseName).exe" - if (Test-Path $dllPath) { - $BinaryImagePath = $dllPath - } elseif (Test-Path $exePath) { - $BinaryImagePath = $exePath - } - - Write-Output $BinaryImagePath - - # Convert the PDB to legacy Windows PDBs - Write-Host "Converting PDB for $_" -ForegroundColor DarkGray - $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" - if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } - & "$PSScriptRoot\..\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb" - if ($LASTEXITCODE -ne 0) { - Write-Warning "PDB conversion of `"$_`" failed." - } - - Write-Output "$WindowsPdbDir\$($_.BaseName).pdb" - } -} - # This doesn't work off Windows, nor do we need to convert symbols on multiple OS agents if ($IsMacOS -or $IsLinux) { return; @@ -57,7 +5,7 @@ if ($IsMacOS -or $IsLinux) { $BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin") if (!(Test-Path $BinPath)) { return } -$symbolfiles = Get-SymbolFiles -Path $BinPath | Get-Unique +$symbolfiles = & "$PSScriptRoot\..\Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique @{ "$BinPath" = $SymbolFiles; diff --git a/azure-pipelines/artifacts/test_symbols.ps1 b/azure-pipelines/artifacts/test_symbols.ps1 new file mode 100644 index 00000000..d65ad0ae --- /dev/null +++ b/azure-pipelines/artifacts/test_symbols.ps1 @@ -0,0 +1,12 @@ +# This doesn't work off Windows, nor do we need to convert symbols on multiple OS agents +if ($IsMacOS -or $IsLinux) { + return; +} + +$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin") +if (!(Test-Path $BinPath)) { return } +$symbolfiles = & "$PSScriptRoot\..\Get-SymbolFiles.ps1" -Path $BinPath -Tests | Get-Unique + +@{ + "$BinPath" = $SymbolFiles; +} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 8f4e950f..e664ecd3 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -47,7 +47,16 @@ steps: IndexSources: false SymbolServerType: TeamServices displayName: Publish symbols to symbol server - condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Agent.OS'], 'Windows_NT')) + condition: eq(variables['Agent.OS'], 'Windows_NT') # Execute on failed test runs too. Windows-only till https://github.com/microsoft/azure-pipelines-tasks/issues/13821 is fixed. + +- task: PublishSymbols@2 + inputs: + SymbolsFolder: $(Build.ArtifactStagingDirectory)/test_symbols-$(Agent.JobName) + SearchPattern: '**/*.pdb' + IndexSources: false + SymbolServerType: TeamServices + displayName: Publish test symbols to symbol server + condition: and(failed(), eq(variables['Agent.OS'], 'Windows_NT')) # Execute on failed test runs only. - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io From 1ba201241f4ab86578fd26e6f0489aaa620268cc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 2 Nov 2020 11:17:29 -0700 Subject: [PATCH 180/704] Remove macOS from Azure Pipeline runs --- azure-pipelines.yml | 8 ++++++++ azure-pipelines/build.yml | 4 ++++ azure-pipelines/publish-codecoverage.yml | 4 ++++ 3 files changed, 16 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 22f8b553..bba62459 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,6 +10,12 @@ trigger: - .vscode/ - .github/ +parameters: +- name: includeMacOS + displayName: Build on macOS + type: boolean + default: false # macOS is often bogged down in Azure Pipelines + variables: TreatWarningsAsErrors: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true @@ -20,3 +26,5 @@ variables: jobs: - template: azure-pipelines/build.yml + parameters: + includeMacOS: ${{ parameters.includeMacOS }} diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 186438a1..b4561394 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -1,5 +1,6 @@ parameters: windowsPool: Hosted Windows 2019 with VS2019 + includeMacOS: jobs: - job: Windows @@ -26,6 +27,7 @@ jobs: - template: expand-template.yml - job: macOS + condition: ${{ parameters.includeMacOS }} pool: vmImage: macOS-10.15 steps: @@ -50,4 +52,6 @@ jobs: parameters: initArgs: -NoRestore - template: publish-codecoverage.yml + parameters: + includeMacOS: ${{ parameters.includeMacOS }} - template: publish-deployables.yml diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 976f0781..0112aacf 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -1,3 +1,6 @@ +parameters: + includeMacOS: + steps: - download: current artifact: coverageResults-Windows @@ -11,6 +14,7 @@ steps: artifact: coverageResults-macOS displayName: Download macOS code coverage results continueOnError: true + condition: ${{ parameters.includeMacOS }} - powershell: | dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj From d4b9a6afcd2fd37fe66be60a2ad9888a194cf53f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 3 Nov 2020 10:05:53 -0700 Subject: [PATCH 181/704] Capture binlog for test runs --- azure-pipelines/dotnet.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index e664ecd3..5c498fc9 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -10,7 +10,7 @@ steps: displayName: dotnet test -f net472 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" + arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net472.binlog" testRunTitle: net472-$(Agent.JobName) condition: succeededOrFailed() @@ -18,7 +18,7 @@ steps: displayName: dotnet test -f netcoreapp2.1 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp2.1.binlog" testRunTitle: netcoreapp2.1-$(Agent.JobName) condition: succeededOrFailed() @@ -26,7 +26,7 @@ steps: displayName: dotnet test -f netcoreapp3.1 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp3.1.binlog" testRunTitle: netcoreapp3.1-$(Agent.JobName) condition: succeededOrFailed() From c234c68d0b45e5cc621db26063c199b51b4a45fd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 11 Nov 2020 08:51:22 -0700 Subject: [PATCH 182/704] Update to .NET 5.0.100 SDK --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index a2e8ff9e..e6e7ee5c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.402", + "version": "5.0.100", "rollForward": "patch", "allowPrerelease": false } From d8b3fc060bc43cc9e0371a62720e2b828c72f308 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 16 Nov 2020 09:48:54 -0700 Subject: [PATCH 183/704] Adapt to GitHub's new env and path operations Fixes #79 --- azure-pipelines/variables/_pipelines.ps1 | 2 +- tools/Set-EnvVars.ps1 | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index 55299550..867b7fc8 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -17,7 +17,7 @@ # and the second that works across jobs and stages but must be fully qualified when referenced. Write-Host "##vso[task.setvariable variable=$keyCaps;isOutput=true]$($_.Value)" } elseif ($env:GITHUB_ACTIONS) { - Write-Host "::set-env name=$keyCaps::$($_.Value)" + Add-Content -Path $env:GITHUB_ENV -Value "$keyCaps=$($_.Value)" } Set-Item -Path "env:$keyCaps" -Value $_.Value } diff --git a/tools/Set-EnvVars.ps1 b/tools/Set-EnvVars.ps1 index bde2e343..3f6f86ba 100644 --- a/tools/Set-EnvVars.ps1 +++ b/tools/Set-EnvVars.ps1 @@ -52,7 +52,7 @@ $Variables.GetEnumerator() |% { Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" } if ($env:GITHUB_ACTIONS) { - Write-Host "::set-env name=$($_.Key)::$($_.Value)" + Add-Content -Path $env:GITHUB_ENV -Value "$($_.Key)=$($_.Value)" } if ($cmdInstructions) { @@ -79,7 +79,7 @@ if ($PrependPath) { Write-Host "##vso[task.prependpath]$_" } if ($env:GITHUB_ACTIONS) { - Write-Host "::add-path::$_" + Add-Content -Path $env:GITHUB_PATH -Value $_ } $CmdEnvScript += "SET PATH=$_$pathDelimiter%PATH%" From 759f9645c2ff5385c00f7c7e7a1613fba9628f8a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 17 Nov 2020 08:45:06 -0700 Subject: [PATCH 184/704] Add .NET 5.0 as a tested runtime --- Directory.Build.props | 2 +- azure-pipelines/dotnet.yml | 8 ++++++++ test/Directory.Build.props | 2 +- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 642fb1d7..ae6f905b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,7 +24,7 @@ - + diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 5c498fc9..34db9a40 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -30,6 +30,14 @@ steps: testRunTitle: netcoreapp3.1-$(Agent.JobName) condition: succeededOrFailed() +- task: DotNetCoreCLI@2 + displayName: dotnet test -f net5.0 + inputs: + command: test + arguments: --no-build -c $(BuildConfiguration) -f net5.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net5.0.binlog" + testRunTitle: net5.0-$(Agent.JobName) + condition: succeededOrFailed() + - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true displayName: Update pipeline variables based on build outputs diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 2371a7ef..4803641a 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,7 +2,7 @@ - netcoreapp3.1;netcoreapp2.1;net472 + net5.0;netcoreapp3.1;netcoreapp2.1;net472 false true From 80928a35fc7d1499cadfd62f3e656ccb713a3c2f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 17 Nov 2020 08:46:15 -0700 Subject: [PATCH 185/704] Update package dependencies --- Directory.Build.props | 4 ++-- test/Library.Tests/Library.Tests.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 642fb1d7..db63a189 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,12 +24,12 @@ - + - + diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 3565372a..ee3b3ae6 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From 1aaddcfd2d397004c01aacd549136e06b80350bf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Dec 2020 16:16:48 -0700 Subject: [PATCH 186/704] Update code analysis --- .editorconfig | 3 +++ Directory.Build.props | 3 ++- test/.editorconfig | 6 ++++++ 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 15f0b0e6..3be52e30 100644 --- a/.editorconfig +++ b/.editorconfig @@ -165,5 +165,8 @@ csharp_prefer_braces = true:silent # SA1130: Use lambda syntax dotnet_diagnostic.SA1130.severity = silent +# CA1508: Avoid dead conditional code +dotnet_diagnostic.CA1508.severity = warning + [*.sln] indent_style = tab diff --git a/Directory.Build.props b/Directory.Build.props index ae6f905b..dedb50b8 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,6 +7,7 @@ $(RepoRootPath)bin\Packages\$(Configuration)\ 8.0 enable + latest true true @@ -23,7 +24,7 @@ - + diff --git a/test/.editorconfig b/test/.editorconfig index 2abae62d..19b19171 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -21,6 +21,12 @@ dotnet_diagnostic.VSTHRD111.severity = none # VSTHRD200: Use Async suffix for async methods dotnet_diagnostic.VSTHRD200.severity = silent +# CA1014: Mark assemblies with CLSCompliant +dotnet_diagnostic.CA1014.severity = none + +# CA1050: Declare types in namespaces +dotnet_diagnostic.CA1050.severity = none + # CA1303: Do not pass literals as localized parameters dotnet_diagnostic.CA1303.severity = none From 3ecde23ecfbd8983ee613dee60ed2c0bfe140608 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Dec 2020 16:17:45 -0700 Subject: [PATCH 187/704] Update compiler toolset This applies the fix to https://github.com/dotnet/roslyn/issues/49882 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index dedb50b8..2253d3e5 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -25,7 +25,7 @@ - + From 20e22606dc0c5bd2349b1c847ea619809bbe3946 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Dec 2020 16:34:12 -0700 Subject: [PATCH 188/704] Download pdb2pdb from pkgs.dev.azure.com instead of dotnet.myget.org --- azure-pipelines/Convert-PDB.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1 index a3212213..cfdb2369 100644 --- a/azure-pipelines/Convert-PDB.ps1 +++ b/azure-pipelines/Convert-PDB.ps1 @@ -24,7 +24,7 @@ if (-not (Test-Path $pdb2pdbpath)) { if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } $baseDir = (Resolve-Path $baseDir).Path # Normalize it - & (& $PSScriptRoot\Get-NuGetTool.ps1) install pdb2pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://dotnet.myget.org/F/symreader-converter/api/v3/index.json | Out-Null + & (& $PSScriptRoot\Get-NuGetTool.ps1) install pdb2pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/myget-legacy/nuget/v3/index.json | Out-Null } $args = $DllPath,'/out',$OutputPath,'/nowarn','0021' From 1e98c8f2c174806de3a82ca08b3834429a641bfc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Dec 2020 17:19:13 -0700 Subject: [PATCH 189/704] Update source and pkg id for pdb2pdb tool --- azure-pipelines/Convert-PDB.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1 index cfdb2369..e9ecebcd 100644 --- a/azure-pipelines/Convert-PDB.ps1 +++ b/azure-pipelines/Convert-PDB.ps1 @@ -18,13 +18,13 @@ [string]$OutputPath ) - $version = '1.1.0-beta1-64128-01' + $version = '1.1.0-beta2-20115-01' $baseDir = "$PSScriptRoot\..\obj\tools" - $pdb2pdbpath = "$baseDir\pdb2pdb.$version\tools\Pdb2Pdb.exe" + $pdb2pdbpath = "$baseDir\Microsoft.DiaSymReader.Pdb2Pdb.$version\tools\Pdb2Pdb.exe" if (-not (Test-Path $pdb2pdbpath)) { if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } $baseDir = (Resolve-Path $baseDir).Path # Normalize it - & (& $PSScriptRoot\Get-NuGetTool.ps1) install pdb2pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/myget-legacy/nuget/v3/index.json | Out-Null + & (& $PSScriptRoot\Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null } $args = $DllPath,'/out',$OutputPath,'/nowarn','0021' From e48583cdb8b5fec1e8debd747952ac6275ff6285 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 17 Dec 2020 10:45:30 -0700 Subject: [PATCH 190/704] Update to .NET Core SDK 3.1.404 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index a2e8ff9e..daed8e94 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "3.1.402", + "version": "3.1.404", "rollForward": "patch", "allowPrerelease": false } From e36ce89e39e21d9adf14ca5e7aa4a9a684ee2701 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jan 2021 07:27:43 -0700 Subject: [PATCH 191/704] Bump Microsoft.NET.Test.Sdk from 16.8.0 to 16.8.3 (#85) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.8.0 to 16.8.3. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.8.0...v16.8.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index ee3b3ae6..aef334c2 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From c8c97da661b70635c42b56d5c3e6111f62abc448 Mon Sep 17 00:00:00 2001 From: Julien Chomarat Date: Thu, 7 Jan 2021 11:06:16 +0100 Subject: [PATCH 192/704] Remove [*.cs] Remove the second [*.cs] because it is already declared at line 122 --- .editorconfig | 2 -- 1 file changed, 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 15f0b0e6..4937e153 100644 --- a/.editorconfig +++ b/.editorconfig @@ -160,8 +160,6 @@ csharp_new_line_before_members_in_anonymous_types = true # Blocks are allowed csharp_prefer_braces = true:silent -[*.cs] - # SA1130: Use lambda syntax dotnet_diagnostic.SA1130.severity = silent From e47af99c1a8ba0dd97b6370d5f1b214c39e2ef67 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 15 Jan 2021 10:36:00 -0700 Subject: [PATCH 193/704] Remove protocolVersion attribute from nuget.config This isn't necessary so long as the URL ends in `/index.json`. --- nuget.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget.config b/nuget.config index c0173d1b..68f36551 100644 --- a/nuget.config +++ b/nuget.config @@ -6,6 +6,6 @@ - + From e7e6de897b7ec8f6a442fd5ab9008d1d8993f271 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Feb 2021 20:17:53 -0700 Subject: [PATCH 194/704] Bump coverlet.msbuild from 2.9.0 to 3.0.2 (#88) Bumps [coverlet.msbuild](https://github.com/coverlet-coverage/coverlet) from 2.9.0 to 3.0.2. - [Release notes](https://github.com/coverlet-coverage/coverlet/releases) - [Commits](https://github.com/coverlet-coverage/coverlet/commits) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index aef334c2..72782f19 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -9,7 +9,7 @@ - + From 17ccfd1c617c6a3eaf6c95bedc5031404fb425a0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 11 Nov 2020 08:51:22 -0700 Subject: [PATCH 195/704] Update to .NET 5.0.102 SDK --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index e6e7ee5c..b95ee4da 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.100", + "version": "5.0.102", "rollForward": "patch", "allowPrerelease": false } From 72d343729e63bc2cb098aab63e63f3a6e96d5e4d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Feb 2021 17:11:22 -0700 Subject: [PATCH 196/704] Update compilers --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2253d3e5..c67b24ac 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -25,7 +25,7 @@ - + From fba5eed179f121b5db92185215b15af7caa73266 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Feb 2021 17:33:40 -0700 Subject: [PATCH 197/704] Rename master branch to main --- .github/workflows/build.yml | 2 +- README.md | 4 ++-- azure-pipelines.yml | 2 +- version.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b9f17c23..8567b4c9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,7 +3,7 @@ name: CI on: push: branches: - - master + - main - validate/* pull_request: diff --git a/README.md b/README.md index 5424ff0a..22d1091e 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ ![NuGet package](https://img.shields.io/badge/nuget-your--package--here-yellow.svg) -[![Azure Pipelines status](https://dev.azure.com/andrewarnott/OSS/_apis/build/status/AArnott.Library.Template?branchName=master)](https://dev.azure.com/andrewarnott/OSS/_build/latest?definitionId=29&branchName=master) +[![Azure Pipelines status](https://dev.azure.com/andrewarnott/OSS/_apis/build/status/AArnott.Library.Template?branchName=main)](https://dev.azure.com/andrewarnott/OSS/_build/latest?definitionId=29&branchName=main) ![GitHub Actions status](https://github.com/aarnott/Library.Template/workflows/CI/badge.svg) -[![codecov](https://codecov.io/gh/aarnott/library.template/branch/master/graph/badge.svg)](https://codecov.io/gh/aarnott/library.template) +[![codecov](https://codecov.io/gh/aarnott/library.template/branch/main/graph/badge.svg)](https://codecov.io/gh/aarnott/library.template) ## Features diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bba62459..2e4b2c15 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,7 +1,7 @@ trigger: branches: include: - - master + - main - 'validate/*' paths: exclude: diff --git a/version.json b/version.json index a13f567b..f0da4f6a 100644 --- a/version.json +++ b/version.json @@ -2,7 +2,7 @@ "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", "version": "0.1-beta", "publicReleaseRefSpec": [ - "^refs/heads/master$", + "^refs/heads/main$", "^refs/heads/v\\d+(?:\\.\\d+)?$" ] } From 7d993369c0977f77c28754360781ec67b3eeedf2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 4 Feb 2021 18:25:04 -0700 Subject: [PATCH 198/704] Bump Microsoft.CodeAnalysis.NetAnalyzers from 5.0.1 to 5.0.3 (#89) Bumps [Microsoft.CodeAnalysis.NetAnalyzers](https://github.com/dotnet/roslyn-analyzers) from 5.0.1 to 5.0.3. - [Release notes](https://github.com/dotnet/roslyn-analyzers/releases) - [Changelog](https://github.com/dotnet/roslyn-analyzers/blob/master/PostReleaseActivities.md) - [Commits](https://github.com/dotnet/roslyn-analyzers/compare/5.0.1...5.0.3) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index ecc06606..bedac7bb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -24,7 +24,7 @@ - + From 28f1b256e7915a8889c3868cc965907fbb508dc9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Feb 2021 18:17:22 -0700 Subject: [PATCH 199/704] Consume newer PDB conversion package that is signed --- azure-pipelines/Convert-PDB.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1 index e9ecebcd..7a20305d 100644 --- a/azure-pipelines/Convert-PDB.ps1 +++ b/azure-pipelines/Convert-PDB.ps1 @@ -18,7 +18,7 @@ [string]$OutputPath ) - $version = '1.1.0-beta2-20115-01' + $version = '1.1.0-beta2-21101-01' $baseDir = "$PSScriptRoot\..\obj\tools" $pdb2pdbpath = "$baseDir\Microsoft.DiaSymReader.Pdb2Pdb.$version\tools\Pdb2Pdb.exe" if (-not (Test-Path $pdb2pdbpath)) { From b3f2ca32e4b9139125b5075a556965731ff5bf1a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Feb 2021 18:28:51 -0700 Subject: [PATCH 200/704] Update dotnet-reportgenerator-globaltool to 4.8.5 --- azure-pipelines/publish-codecoverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 0112aacf..d83eb64a 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -16,7 +16,7 @@ steps: continueOnError: true condition: ${{ parameters.includeMacOS }} - powershell: | - dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.2.2 --configfile azure-pipelines/justnugetorg.nuget.config + dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.8.5 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" $reports = Get-ChildItem -Recurse "$(Pipeline.Workspace)/coverage.*.cobertura.xml" From 18b5902d5ea27b3d71aed9f231e79e142ea57c8c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Feb 2021 20:58:50 -0700 Subject: [PATCH 201/704] Propagate failure to install .NET SDK --- tools/Install-DotNetSdk.ps1 | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index ec66c949..06710ee3 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -149,10 +149,16 @@ if (-not (Test-Path $DotNetInstallScriptPath)) { } $anythingInstalled = $false +$global:LASTEXITCODE = 0 if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } } else { Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" } @@ -163,6 +169,11 @@ $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } } else { Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" } From 5355f205cefddc0b46291cd02ca7e96f9df072d2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Feb 2021 21:06:04 -0700 Subject: [PATCH 202/704] Use pinned dotnet installer script This unblocks builds by working around https://github.com/dotnet/install-scripts/issues/136 --- tools/Install-DotNetSdk.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 06710ee3..83ddec87 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -134,10 +134,10 @@ if ($DotNetInstallDir) { } if ($IsMacOS -or $IsLinux) { - $DownloadUri = "https://dot.net/v1/dotnet-install.sh" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/1ebb108764c092e7a314ff3fe1388f582cbcf89a/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { - $DownloadUri = "https://dot.net/v1/dotnet-install.ps1" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/1ebb108764c092e7a314ff3fe1388f582cbcf89a/src/dotnet-install.ps1" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } From 2152fb59ab19d37691ff3fe9ac0df58cf433d921 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 5 Feb 2021 19:53:57 -0700 Subject: [PATCH 203/704] Update LangVersion to 9 Also update StyleCop. --- Directory.Build.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index bedac7bb..0281d8ab 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ $(RepoRootPath)obj\$(MSBuildProjectName)\ $(RepoRootPath)bin\$(MSBuildProjectName)\ $(RepoRootPath)bin\Packages\$(Configuration)\ - 8.0 + 9.0 enable latest true @@ -30,7 +30,7 @@ - + From a64ebcc0e9965c8b5119c79807f5b47bcfd8e96e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 8 Feb 2021 08:29:48 -0700 Subject: [PATCH 204/704] Update .NET installer script This may help with curl failures, as described in https://github.com/dotnet/install-scripts/issues/139 --- tools/Install-DotNetSdk.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 83ddec87..132c374e 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -134,10 +134,10 @@ if ($DotNetInstallDir) { } if ($IsMacOS -or $IsLinux) { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/1ebb108764c092e7a314ff3fe1388f582cbcf89a/src/dotnet-install.sh" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/7a9d5dcab92cf131fc2d8977052f8c2c2d540e22/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/1ebb108764c092e7a314ff3fe1388f582cbcf89a/src/dotnet-install.ps1" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/7a9d5dcab92cf131fc2d8977052f8c2c2d540e22/src/dotnet-install.ps1" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } From 791accaddbc87f2a06675d7620c849bc0a15a605 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 18 Feb 2021 15:55:28 -0700 Subject: [PATCH 205/704] Embed PDBs for all local builds --- Directory.Build.props | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 0281d8ab..836dd521 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -10,6 +10,9 @@ latest true + + embedded + true $(MSBuildThisFileDirectory)\strongname.snk From c463b89ca7a0edd3c8024420f3559b024126f8c7 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 19 Feb 2021 10:20:37 -0700 Subject: [PATCH 206/704] Produce ref assembly for better incremental build Referencing projects don't need to recompile if the public API of a referenced project does not change. --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index 836dd521..081e4cfa 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -9,6 +9,7 @@ enable latest true + true embedded From c24318f044150c84e25c12d3240dddcfb9b509d8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 24 Feb 2021 09:52:16 -0700 Subject: [PATCH 207/704] Update to .NET SDK 5.0.103 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index b95ee4da..24c50bd3 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.102", + "version": "5.0.103", "rollForward": "patch", "allowPrerelease": false } From fb488e6cd9acbf391f24db08cdbb51f2d0826113 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 24 Feb 2021 09:52:51 -0700 Subject: [PATCH 208/704] Sort PackageReference items --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 72782f19..8da18927 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -11,8 +11,8 @@ - + From a568829bc239d746133f05200936a1074627a9ce Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Mar 2021 09:19:46 -0700 Subject: [PATCH 209/704] Bump Microsoft.NET.Test.Sdk from 16.8.3 to 16.9.1 (#95) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.8.3 to 16.9.1. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.8.3...v16.9.1) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 8da18927..b1728e23 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From bf34bea3b0d8cb04c617fa82a2b4bbd487e6ebaa Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Mar 2021 16:42:18 +0000 Subject: [PATCH 210/704] Bump coverlet.msbuild from 3.0.2 to 3.0.3 (#94) --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index b1728e23..5a37213f 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -9,7 +9,7 @@ - + From 1c04816f75df76aefb8cfdb9f61865de2104ff92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 2 Apr 2021 10:09:48 -0600 Subject: [PATCH 211/704] Bump Microsoft.Net.Compilers.Toolset from 3.9.0-3.final to 3.9.0 (#96) Bumps [Microsoft.Net.Compilers.Toolset](https://github.com/dotnet/roslyn) from 3.9.0-3.final to 3.9.0. - [Release notes](https://github.com/dotnet/roslyn/releases) - [Changelog](https://github.com/dotnet/roslyn/blob/main/docs/Breaking%20API%20Changes.md) - [Commits](https://github.com/dotnet/roslyn/commits/v3.9.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 081e4cfa..df9e2a69 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -29,7 +29,7 @@ - + From ae45375f669733596bd8f904264b37797f20ae91 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 7 Apr 2021 10:16:33 -0600 Subject: [PATCH 212/704] Avoid writing garbage bytes to read blobs in managed git engine In the case of this bug, the `Stream.Read` method read fewer bytes than was requested. This is totally allowed, but the caller did not expect it and assumed the entire buffer was initialized rather than a subset of it. Fixes #580 --- .../ManagedGit/GitPackMemoryCacheStream.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs index ea746f17..9f1b38be 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs @@ -49,9 +49,9 @@ public override int Read(Span buffer) { var currentPosition = this.cacheStream.Position; var toRead = (int)(buffer.Length - this.cacheStream.Length + this.cacheStream.Position); - this.stream.Read(buffer.Slice(0, toRead)); + int actualRead = this.stream.Read(buffer.Slice(0, toRead)); this.cacheStream.Seek(0, SeekOrigin.End); - this.cacheStream.Write(buffer.Slice(0, toRead)); + this.cacheStream.Write(buffer.Slice(0, actualRead)); this.cacheStream.Seek(currentPosition, SeekOrigin.Begin); this.DisposeStreamIfRead(); } From b321efd0948312413aaca0d22df1b2991c8671ca Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 7 Apr 2021 11:47:56 -0600 Subject: [PATCH 213/704] Fix discovery of git directories within submodules Fixes #578 --- src/NerdBank.GitVersioning/GitContext.cs | 10 ++++- .../ManagedGit/GitRepository.cs | 37 ++----------------- 2 files changed, 13 insertions(+), 34 deletions(-) diff --git a/src/NerdBank.GitVersioning/GitContext.cs b/src/NerdBank.GitVersioning/GitContext.cs index 7b632214..e9d9114b 100644 --- a/src/NerdBank.GitVersioning/GitContext.cs +++ b/src/NerdBank.GitVersioning/GitContext.cs @@ -214,8 +214,16 @@ protected static bool IsVersionFileChangedInWorkingTree(VersionOptions? committe return committedVersion is object; } - private protected static bool TryFindGitPaths(string path, [NotNullWhen(true)] out string? gitDirectory, [NotNullWhen(true)] out string? workingTreeDirectory, [NotNullWhen(true)] out string? workingTreeRelativePath) + internal static bool TryFindGitPaths(string? path, [NotNullWhen(true)] out string? gitDirectory, [NotNullWhen(true)] out string? workingTreeDirectory, [NotNullWhen(true)] out string? workingTreeRelativePath) { + if (path is null || path.Length == 0) + { + gitDirectory = null; + workingTreeDirectory = null; + workingTreeRelativePath = null; + return false; + } + path = Path.GetFullPath(path); var gitDirs = FindGitDir(path); if (gitDirs is null) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 26a1ef84..227e2b89 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -40,42 +40,13 @@ public class GitRepository : IDisposable /// public static GitRepository? Create(string? workingDirectory) { - // Search for the top-level directory of the current git repository. This is the directory - // which contains a directory of file named .git. - // Loop until Path.GetDirectoryName returns null; in this case, we've reached the root of - // the file system (and we're not in a git repository). - while (!string.IsNullOrEmpty(workingDirectory) - && !File.Exists(Path.Combine(workingDirectory, GitDirectoryName)) - && !Directory.Exists(Path.Combine(workingDirectory, GitDirectoryName))) - { - workingDirectory = Path.GetDirectoryName(workingDirectory); - } - - if (string.IsNullOrEmpty(workingDirectory)) - { - return null; - } - - var gitDirectory = Path.Combine(workingDirectory, GitDirectoryName); - - if (File.Exists(gitDirectory)) - { - // This is a worktree, and the path to the git directory is stored in the .git file - var worktreeConfig = File.ReadAllText(gitDirectory); - - var gitDirStart = worktreeConfig.IndexOf("gitdir: "); - var gitDirEnd = worktreeConfig.IndexOf("\n", gitDirStart); - - gitDirectory = worktreeConfig.Substring(gitDirStart + 8, gitDirEnd - gitDirStart - 8); - } - - if (!Directory.Exists(gitDirectory)) + if (!GitContext.TryFindGitPaths(workingDirectory, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath)) { return null; } - var commonDirectory = gitDirectory; - var commonDirFile = Path.Combine(gitDirectory, "commondir"); + string commonDirectory = gitDirectory; + string commonDirFile = Path.Combine(gitDirectory, "commondir"); if (File.Exists(commonDirFile)) { @@ -83,7 +54,7 @@ public class GitRepository : IDisposable commonDirectory = Path.Combine(gitDirectory, commonDirectoryRelativePath); } - var objectDirectory = Path.Combine(commonDirectory, "objects"); + string objectDirectory = Path.Combine(commonDirectory, "objects"); return new GitRepository(workingDirectory!, gitDirectory, commonDirectory, objectDirectory); } From 1685f22a5954a7ffd5b83ab4a85769551a27dc5c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 10 Apr 2021 06:51:29 -0600 Subject: [PATCH 214/704] Bump .NET SDK to 5.0.201 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 24c50bd3..e8e7c67e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.103", + "version": "5.0.201", "rollForward": "patch", "allowPrerelease": false } From 460ed85ac95c78c5d7abf850be1097f566356371 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 12 Apr 2021 10:37:37 -0600 Subject: [PATCH 215/704] Add path filter test with two-deep folder path This repros #587 --- .../VersionOracleTests.cs | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 2f433859..af4d1e05 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -731,6 +731,28 @@ public void GetVersionHeight_IncludeRootExcludeSome() Assert.Equal(2, this.GetVersionHeight(relativeDirectory)); } + [Fact] + public void GetVersion_PathFilterInTwoDeepSubDirAndVersionBump() + { + this.InitializeSourceControl(); + + const string relativeDirectory = "src\\lib"; + var versionOptions = new VersionOptions + { + Version = new SemanticVersion("1.1"), + PathFilters = new FilterPath[] + { + new FilterPath(".", relativeDirectory), + }, + }; + this.WriteVersionFile(versionOptions, relativeDirectory); + Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); + + versionOptions.Version = new SemanticVersion("1.2"); + this.WriteVersionFile(versionOptions, relativeDirectory); + Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); + } + [Fact] public void GetVersionHeight_ProjectDirectoryDifferentToVersionJsonDirectory() { From 9e74f1e35cebd630783461d272df111c4024aa1f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 15 Apr 2021 08:21:44 -0600 Subject: [PATCH 216/704] Include BCL assemblies required for VS 2017 build tools Several assemblies are required by this msbuild task but are not included in MSBuild 2017. Adding the assemblies to the package alone is not enough, since binding redirects are also missing in msbuild.exe.config. We make up for this with a custom assembly resolver. Fixes #589 --- azure-pipelines.yml | 8 ++-- global.json | 2 +- src/Directory.Build.props | 2 +- .../AssemblyLoader.cs | 48 +++++++++++++++++++ .../Nerdbank.GitVersioning.nuspec | 7 ++- 5 files changed, 59 insertions(+), 8 deletions(-) create mode 100644 src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c3a113fd..46dee667 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -58,10 +58,10 @@ stages: displayName: Configure git commit author for testing - task: UseDotNet@2 - displayName: Install .NET Core SDK 5.0.100 + displayName: Install .NET Core SDK 5.0.202 inputs: packageType: sdk - version: 5.0.100 + version: 5.0.202 - task: UseDotNet@2 displayName: Install .NET Core 3.1 @@ -306,10 +306,10 @@ stages: packageType: sdk version: 3.1.100 - task: UseDotNet@2 - displayName: Install .NET Core SDK 5.0.100 + displayName: Install .NET Core SDK 5.0.202 inputs: packageType: sdk - version: 5.0.100 + version: 5.0.202 - script: dotnet --info displayName: Show dotnet SDK info - bash: | diff --git a/global.json b/global.json index ee8f712f..66a8a8b2 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,5 @@ { "sdk": { - "version": "5.0.100" + "version": "5.0.202" } } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 4921af4e..0757e8d2 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -4,7 +4,7 @@ $(MSBuildThisFileDirectory)..\obj\$(MSBuildProjectName)\ $(MSBuildThisFileDirectory)..\bin\$(MSBuildProjectName)\$(Configuration)\ $(MSBuildThisFileDirectory)..\wiki\api - 8.0 + 9.0 true $(MSBuildThisFileDirectory)strongname.snk diff --git a/src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs b/src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs new file mode 100644 index 00000000..55da8b8b --- /dev/null +++ b/src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs @@ -0,0 +1,48 @@ +#if NETFRAMEWORK + +using System; +using System.IO; +using System.Reflection; +using System.Runtime.CompilerServices; + +namespace System.Runtime.CompilerServices +{ + [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] + public sealed class ModuleInitializerAttribute : Attribute { } +} + +namespace Nerdbank.GitVersioning.Tasks +{ + internal static class AssemblyLoader + { + [ModuleInitializer] + internal static void LoaderInitializer() + { + AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; + } + + private static Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args) + { + try + { + var required = new AssemblyName(args.Name); + string path = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), required.Name + ".dll"); + if (File.Exists(path)) + { + AssemblyName actual = AssemblyName.GetAssemblyName(path); + if (actual.Version >= required.Version) + { + return Assembly.LoadFile(path); + } + } + } + catch + { + } + + return null; + } + } +} + +#endif diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index b260a210..30e035fc 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -23,10 +23,13 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj + + + + + - - From 98156ca3cad1a3095df9b061df4adaa4fe8bbc62 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 27 Apr 2021 08:35:25 -0600 Subject: [PATCH 217/704] Fix local pack builds Local dev boxes were failing to build the `pack` target because symbols are now embedded into the assembly in that configuration and thus there were no pdb files to include in the snupkg file. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index df9e2a69..ad5589bf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,7 +23,7 @@ MIT true true - true + true snupkg From 00cc0d4cdc0cade1e1ef311b63ed36c5f9293fb0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 27 Apr 2021 08:35:42 -0600 Subject: [PATCH 218/704] Bump .NET SDK to 5.0.202 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index e8e7c67e..728ab674 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.201", + "version": "5.0.202", "rollForward": "patch", "allowPrerelease": false } From 675a2fb4ba16988a79082c4770aea9afb7dc4100 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 27 Apr 2021 10:05:04 +0200 Subject: [PATCH 219/704] Don't load git packs if the .pack file is missing --- .../ManagedGit/GitPack.cs | 17 ----------------- .../ManagedGit/GitRepository.cs | 15 ++++++++++++--- 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs index 4a5d25ba..27c45c69 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs @@ -51,23 +51,6 @@ public class GitPack : IDisposable // are closed by the caller). private readonly Queue pooledStreams = new Queue(); - /// - /// Initializes a new instance of the class. - /// - /// - /// The repository to which this pack file belongs. - /// - /// - /// The name of the pack file. - /// - internal GitPack(GitRepository repository, string name) - : this( - repository.GetObjectBySha, - indexPath: Path.Combine(repository.ObjectDirectory, "pack", $"{name}.idx"), - packPath: Path.Combine(repository.ObjectDirectory, "pack", $"{name}.pack")) - { - } - /// /// Initializes a new instance of the class. /// diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 227e2b89..16fe4fb6 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -648,15 +648,24 @@ private GitPack[] LoadPacks() } var indexFiles = Directory.GetFiles(packDirectory, "*.idx"); - GitPack[] packs = new GitPack[indexFiles.Length]; + List packs = new List(indexFiles.Length); for (int i = 0; i < indexFiles.Length; i++) { + var name = Path.GetFileNameWithoutExtension(indexFiles[i]); - packs[i] = new GitPack(this, name); + var indexPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.idx"); + var packPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.pack"); + + // Only proceed if both the packfile and index file exist. + if (!File.Exists(packPath)) + { + packs.Add(new GitPack(this.GetObjectBySha, indexPath, packPath)); + } + } - return packs; + return packs.ToArray(); } private static string TrimEndingDirectorySeparator(string path) From 8dab6c3a58fafe68e9ab352e080b9123dce3af4c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 29 Apr 2021 08:38:36 -0600 Subject: [PATCH 220/704] Fix inverted logic error --- src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 16fe4fb6..e12f46fe 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -658,7 +658,7 @@ private GitPack[] LoadPacks() var packPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.pack"); // Only proceed if both the packfile and index file exist. - if (!File.Exists(packPath)) + if (File.Exists(packPath)) { packs.Add(new GitPack(this.GetObjectBySha, indexPath, packPath)); } From 0303d9682a52fb62791f8e60e09489e48c5d5f65 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 29 Apr 2021 08:38:57 -0600 Subject: [PATCH 221/704] Avoid an array copy and `List` allocation --- .../ManagedGit/GitRepository.cs | 23 +++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index e12f46fe..741ec25c 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -17,7 +17,7 @@ public class GitRepository : IDisposable { private const string HeadFileName = "HEAD"; private const string GitDirectoryName = ".git"; - private readonly Lazy packs; + private readonly Lazy> packs; /// /// UTF-16 encoded string. @@ -137,7 +137,7 @@ public GitRepository(string workingDirectory, string gitDirectory, string common this.objectPathBuffer[this.ObjectDirectory.Length + 3] = '/'; this.objectPathBuffer[pathLengthInChars - 1] = '\0'; // Make sure to initialize with zeros - this.packs = new Lazy(this.LoadPacks); + this.packs = new Lazy>(this.LoadPacks); } // TODO: read from Git settings @@ -375,7 +375,7 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) var hex = ConvertHexStringToByteArray(objectish); - foreach (var pack in this.packs.Value) + foreach (var pack in this.packs.Value.Span) { var objectId = pack.Lookup(hex, endsWithHalfByte); @@ -514,7 +514,7 @@ public bool TryGetObjectBySha(GitObjectId sha, string objectType, out Stream? va } #endif - foreach (var pack in this.packs.Value) + foreach (var pack in this.packs.Value.Span) { if (pack.TryGetObject(sha, objectType, out value)) { @@ -563,7 +563,7 @@ public string GetCacheStatistics() builder.AppendLine(); #endif - foreach (var pack in this.packs.Value) + foreach (var pack in this.packs.Value.Span) { pack.GetCacheStatistics(builder); } @@ -582,7 +582,7 @@ public void Dispose() { if (this.packs.IsValueCreated) { - foreach (var pack in this.packs.Value) + foreach (var pack in this.packs.Value.Span) { pack.Dispose(); } @@ -638,7 +638,7 @@ private GitObjectId ResolveReference(object reference) } } - private GitPack[] LoadPacks() + private ReadOnlyMemory LoadPacks() { var packDirectory = Path.Combine(this.ObjectDirectory, "pack/"); @@ -648,11 +648,11 @@ private GitPack[] LoadPacks() } var indexFiles = Directory.GetFiles(packDirectory, "*.idx"); - List packs = new List(indexFiles.Length); + var packs = new GitPack[indexFiles.Length]; + int addCount = 0; for (int i = 0; i < indexFiles.Length; i++) { - var name = Path.GetFileNameWithoutExtension(indexFiles[i]); var indexPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.idx"); var packPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.pack"); @@ -660,12 +660,11 @@ private GitPack[] LoadPacks() // Only proceed if both the packfile and index file exist. if (File.Exists(packPath)) { - packs.Add(new GitPack(this.GetObjectBySha, indexPath, packPath)); + packs[addCount++] = new GitPack(this.GetObjectBySha, indexPath, packPath); } - } - return packs.ToArray(); + return packs.AsMemory(0, addCount); } private static string TrimEndingDirectorySeparator(string path) From 775a2b03b3f6d01cd94f24b665a8c4f774ef0605 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 27 Apr 2021 09:55:57 +0200 Subject: [PATCH 222/704] Improve alternate parsing --- .../ManagedGit/GitRepositoryTests.cs | 19 ++++++++ .../ManagedGit/GitRepository.cs | 45 +++++++++++++++---- 2 files changed, 55 insertions(+), 9 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs index fb8a3ba0..c7a70c65 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs @@ -286,6 +286,25 @@ public void GetMissingObjectByShaTest() } } + [Fact] + public void ParseAlternates_SingleValue_Test() + { + var alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("/home/git/nbgv/.git/objects\n")); + Assert.Collection( + alternates, + a => Assert.Equal("/home/git/nbgv/.git/objects", a)); + } + + [Fact] + public void ParseAlternates_TwoValues_Test() + { + var alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("/home/git/nbgv/.git/objects:../../clone/.git/objects\n")); + Assert.Collection( + alternates, + a => Assert.Equal("/home/git/nbgv/.git/objects", a), + a => Assert.Equal("../../clone/.git/objects", a)); + } + private static void AssertPath(string expected, string actual) { Assert.Equal( diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 227e2b89..ab8428be 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Runtime.InteropServices; using System.Text; namespace Nerdbank.GitVersioning.ManagedGit @@ -110,16 +111,14 @@ public GitRepository(string workingDirectory, string gitDirectory, string common var length = alternateStream!.Read(alternates); alternates = alternates.Slice(0, length); - int index = 0; - - while ((index = alternates.IndexOf((byte)':')) > 0) + foreach(var alternate in ParseAlternates(alternates)) { - var alternate = GetString(alternates.Slice(0, index)); - alternate = Path.GetFullPath(Path.Combine(this.ObjectDirectory, alternate)); - - this.alternates.Add(GitRepository.Create(workingDirectory, gitDirectory, commonDirectory, alternate)); - - alternates = alternates.Slice(index + 1); + this.alternates.Add( + GitRepository.Create( + workingDirectory, + gitDirectory, + commonDirectory, + objectDirectory: Path.GetFullPath(Path.Combine(this.ObjectDirectory, alternate)))); } } @@ -714,5 +713,33 @@ public static unsafe string GetString(ReadOnlySpan bytes) return Encoding.GetString(pBytes, bytes.Length); } } + + /// + /// Parses the contents of the alternates file, and returns a list of (relative) paths to the alternate object directories. + /// + /// + /// The contents of the alternates files. + /// + /// + /// A list of (relative) paths to the alternate object directories. + public static List ParseAlternates(ReadOnlySpan alternates) + { + List values = new List(); + + int index = 0; + + // The alternates path is colon (:)-separated. On Windows, there may be full paths, such as + // C:/Users/username/source/repos/nbgv/.git, which also contain a colon. Because the colon + // can only appear at the second position, we skip the first two characters (e.g. C:) on Windows. + int skipCount = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 2 : 0; + + while (alternates.Length > skipCount && (index = alternates.Slice(skipCount).IndexOfAny((byte)':', (byte)'\n')) > 0) + { + values.Add(GetString(alternates.Slice(0, skipCount + index))); + alternates = alternates.Slice(skipCount + index + 1); + } + + return values; + } } } From cb37baab2b7c93c6ae6d15bf7b12c63e165e67b7 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Fri, 30 Apr 2021 11:19:36 +0200 Subject: [PATCH 223/704] Update src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs Co-authored-by: Andrew Arnott --- src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index ab8428be..6b7452a1 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -721,7 +721,8 @@ public static unsafe string GetString(ReadOnlySpan bytes) /// The contents of the alternates files. /// /// - /// A list of (relative) paths to the alternate object directories. + /// A list of (relative) paths to the alternate object directories. + /// public static List ParseAlternates(ReadOnlySpan alternates) { List values = new List(); From c311a3f5b8b93dbd72c62090820a1da0527191f1 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Fri, 30 Apr 2021 11:25:58 +0200 Subject: [PATCH 224/704] Add unit tests for alternates with colons in their path (e.g. C:/Users/) --- .../ManagedGit/GitRepositoryTests.cs | 13 ++++++++++++ .../ManagedGit/GitRepository.cs | 21 +++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs index c7a70c65..82174ee9 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs @@ -305,6 +305,19 @@ public void ParseAlternates_TwoValues_Test() a => Assert.Equal("../../clone/.git/objects", a)); } + [Fact] + public void ParseAlternates_PathWithColon_Test() + { + var alternates = GitRepository.ParseAlternates( + Encoding.UTF8.GetBytes("C:/Users/nbgv/objects:C:/Users/nbgv2/objects/:../../clone/.git/objects\n"), + 2); + Assert.Collection( + alternates, + a => Assert.Equal("C:/Users/nbgv/objects", a), + a => Assert.Equal("C:/Users/nbgv2/objects/", a), + a => Assert.Equal("../../clone/.git/objects", a)); + } + private static void AssertPath(string expected, string actual) { Assert.Equal( diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 6b7452a1..d6d829d2 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -111,7 +111,7 @@ public GitRepository(string workingDirectory, string gitDirectory, string common var length = alternateStream!.Read(alternates); alternates = alternates.Slice(0, length); - foreach(var alternate in ParseAlternates(alternates)) + foreach (var alternate in ParseAlternates(alternates)) { this.alternates.Add( GitRepository.Create( @@ -724,16 +724,29 @@ public static unsafe string GetString(ReadOnlySpan bytes) /// A list of (relative) paths to the alternate object directories. /// public static List ParseAlternates(ReadOnlySpan alternates) + => ParseAlternates(alternates, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 2 : 0); + + /// + /// Parses the contents of the alternates file, and returns a list of (relative) paths to the alternate object directories. + /// + /// + /// The contents of the alternates files. + /// + /// + /// The number of bytes to skip in the span when looking for a delimiter. + /// + /// + /// A list of (relative) paths to the alternate object directories. + /// + public static List ParseAlternates(ReadOnlySpan alternates, int skipCount) { List values = new List(); - int index = 0; + int index; // The alternates path is colon (:)-separated. On Windows, there may be full paths, such as // C:/Users/username/source/repos/nbgv/.git, which also contain a colon. Because the colon // can only appear at the second position, we skip the first two characters (e.g. C:) on Windows. - int skipCount = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 2 : 0; - while (alternates.Length > skipCount && (index = alternates.Slice(skipCount).IndexOfAny((byte)':', (byte)'\n')) > 0) { values.Add(GetString(alternates.Slice(0, skipCount + index))); From 6faef508d3156e370688931d734b35c0c55fcba4 Mon Sep 17 00:00:00 2001 From: Matthias Koch Date: Fri, 30 Apr 2021 16:57:39 +0200 Subject: [PATCH 225/704] Update TeamCity documentation --- src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs b/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs index e4df2b69..da5367e9 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs @@ -8,8 +8,8 @@ /// TeamCity CI build support. /// /// - /// The TeamCIty-specific properties referenced here are documented here: - /// https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters + /// The TeamCity-specific properties referenced here are documented here: + /// https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html /// internal class TeamCity : ICloudBuild { From 50c71756772ac72b77ae4534e53d3a17bb732dc5 Mon Sep 17 00:00:00 2001 From: Matthias Koch Date: Fri, 30 Apr 2021 17:03:21 +0200 Subject: [PATCH 226/704] Add SpaceAutomation support --- src/NerdBank.GitVersioning/CloudBuild.cs | 1 + .../CloudBuildServices/SpaceAutomation.cs | 38 +++++++++++++++++++ 2 files changed, 39 insertions(+) create mode 100644 src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs diff --git a/src/NerdBank.GitVersioning/CloudBuild.cs b/src/NerdBank.GitVersioning/CloudBuild.cs index c1025aac..e5417145 100644 --- a/src/NerdBank.GitVersioning/CloudBuild.cs +++ b/src/NerdBank.GitVersioning/CloudBuild.cs @@ -21,6 +21,7 @@ public static class CloudBuild new Jenkins(), new GitLab(), new Travis(), + new SpaceAutomation(), }; /// diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs b/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs new file mode 100644 index 00000000..cf1930ab --- /dev/null +++ b/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs @@ -0,0 +1,38 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace Nerdbank.GitVersioning.CloudBuildServices +{ + /// + /// SpaceAutomation CI build support. + /// + /// + /// The SpaceAutomation-specific properties referenced here are documented here: + /// https://www.jetbrains.com/help/space/automation-environment-variables.html + /// + internal class SpaceAutomation : ICloudBuild + { + public string BuildingBranch => CloudBuild.IfStartsWith(BuildingRef, "refs/heads/"); + + public string BuildingTag => CloudBuild.IfStartsWith(BuildingRef, "refs/tags/"); + + public string GitCommitId => Environment.GetEnvironmentVariable("JB_SPACE_GIT_REVISION"); + + public bool IsApplicable => this.GitCommitId != null; + + public bool IsPullRequest => false; + + private static string BuildingRef => Environment.GetEnvironmentVariable("JB_SPACE_GIT_BRANCH"); + + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } + + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } + } +} \ No newline at end of file From f76724d450717da3aaff3204b964d71a37e2980b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sat, 1 May 2021 18:58:45 +0200 Subject: [PATCH 227/704] Abort prepare-release command when version on current branch is not incremented Ensure version on current branch is updated by prepare-release command When the next version for the current branch is set by the user using the '--nextVersion' command line parameter, the next version might be equal to the current version. In that case no commit is created (no changes on the branch), which in turn causes the current branch to be fast-forwarded to the commit on the newly-created release branch when the branches are merged. To prevent this error, abort command if both versions match (there is already a check in place that prevents the version from being decremented). The check only applies to the current branch because the version on the release branch not being incremented is a valid use case. --- .../ReleaseManagerTests.cs | 20 ++++++++++++++++++- src/NerdBank.GitVersioning/ReleaseManager.cs | 13 ++++++++++++ src/nbgv/Program.cs | 1 + 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs b/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs index c69f5120..9ad8c96c 100644 --- a/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs @@ -392,12 +392,30 @@ public void PrepareRelease_MasterWithVersionDecrement(string initialVersion, str this.WriteVersionFile(versionOptions); // running PrepareRelease should result in an error - // because we're trying to add a prerelease tag to a version without prerelease tag + // because we're setting the version on master to a lower version this.AssertError( () => new ReleaseManager().PrepareRelease(this.RepoPath, releaseUnstableTag, (nextVersion == null ? null : Version.Parse(nextVersion))), ReleasePreparationError.VersionDecrement); } + [Theory] + [InlineData("1.2", "1.2")] + public void PrepareRelease_MasterWithoutVersionIncrement(string initialVersion, string nextVersion) + { + // create and configure repository + this.InitializeSourceControl(); + + // create version.json + var versionOptions = new VersionOptions() { Version = SemanticVersion.Parse(initialVersion) }; + this.WriteVersionFile(versionOptions); + + // running PrepareRelease should result in an error + // because we're trying to set master to the version it already has + this.AssertError( + () => new ReleaseManager().PrepareRelease(this.RepoPath, null, (nextVersion == null ? null : Version.Parse(nextVersion))), + ReleasePreparationError.NoVersionIncrement); + } + [Fact] public void PrepareRelease_DetachedHead() { diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index e30efa6a..8ac24c9d 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -47,6 +47,11 @@ public enum ReleasePreparationError /// VersionDecrement, + /// + /// Branch cannot be set to the specified version because the new version is not higher than the current version + /// + NoVersionIncrement, + /// /// Cannot create a branch because it already exists /// @@ -273,6 +278,14 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag = var nextDevVersion = this.GetNextDevVersion(versionOptions, nextVersion, versionIncrement); + // check if the current version on the main branch is different from the next version + // otherwise, both the release branch and the dev branch would have the same version + if (versionOptions.Version.Version == nextDevVersion.Version) + { + this.stderr.WriteLine($"Version on '{originalBranchName}' is already set to next version {nextDevVersion.Version}."); + throw new ReleasePreparationException(ReleasePreparationError.NoVersionIncrement); + } + // check if the release branch already exists if (repository.Branches[releaseBranchName] != null) { diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 7df6b7bf..e23b2d42 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -736,6 +736,7 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s case ReleaseManager.ReleasePreparationError.NoVersionFile: return (int)ExitCodes.NoVersionJsonFound; case ReleaseManager.ReleasePreparationError.VersionDecrement: + case ReleaseManager.ReleasePreparationError.NoVersionIncrement: return (int)ExitCodes.InvalidVersionSpec; case ReleaseManager.ReleasePreparationError.BranchAlreadyExists: return (int)ExitCodes.BranchAlreadyExists; From 48ef902eb6be3cd5e09a77e2a317619338ef9f64 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 1 May 2021 17:47:49 -0600 Subject: [PATCH 228/704] Remove assumption of current branch name in code comment --- src/NerdBank.GitVersioning/ReleaseManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index 8ac24c9d..42324946 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -278,7 +278,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag = var nextDevVersion = this.GetNextDevVersion(versionOptions, nextVersion, versionIncrement); - // check if the current version on the main branch is different from the next version + // check if the current version on the current branch is different from the next version // otherwise, both the release branch and the dev branch would have the same version if (versionOptions.Version.Version == nextDevVersion.Version) { From ca33a6cabf6125d561f8e80466840181d8494592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 May 2021 18:28:42 -0600 Subject: [PATCH 229/704] Bump Microsoft.NET.Test.Sdk from 16.9.1 to 16.9.4 (#98) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.9.1 to 16.9.4. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.9.1...v16.9.4) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 5a37213f..2b8eff73 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From aba19025767fed9e84f867e3a1efc1e6a3051e92 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 May 2021 18:28:55 -0600 Subject: [PATCH 230/704] Bump Nerdbank.GitVersioning from 3.3.37 to 3.4.194 (#97) Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.3.37 to 3.4.194. - [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases) - [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/compare/v3.3.37...v3.4.194) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index ad5589bf..1dc06021 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -32,7 +32,7 @@ - + From 62aadee1bc2847f48ef95a0c044705a0fc82441f Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 4 May 2021 17:45:01 +0200 Subject: [PATCH 231/704] Don't require a trailing `\n` character at the end of the alternates file --- .../ManagedGit/GitRepositoryTests.cs | 9 +++++++++ src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs | 10 +++++++--- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs index 82174ee9..edbbbb80 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs @@ -295,6 +295,15 @@ public void ParseAlternates_SingleValue_Test() a => Assert.Equal("/home/git/nbgv/.git/objects", a)); } + [Fact] + public void ParseAlternates_SingleValue_NoTrailingNewline_Test() + { + var alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("../repo/.git/objects")); + Assert.Collection( + alternates, + a => Assert.Equal("../repo/.git/objects", a)); + } + [Fact] public void ParseAlternates_TwoValues_Test() { diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index a2346b8c..40cfc644 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -751,14 +751,18 @@ public static List ParseAlternates(ReadOnlySpan alternates, int sk List values = new List(); int index; + int length; // The alternates path is colon (:)-separated. On Windows, there may be full paths, such as // C:/Users/username/source/repos/nbgv/.git, which also contain a colon. Because the colon // can only appear at the second position, we skip the first two characters (e.g. C:) on Windows. - while (alternates.Length > skipCount && (index = alternates.Slice(skipCount).IndexOfAny((byte)':', (byte)'\n')) > 0) + while (alternates.Length > skipCount) { - values.Add(GetString(alternates.Slice(0, skipCount + index))); - alternates = alternates.Slice(skipCount + index + 1); + index = alternates.Slice(skipCount).IndexOfAny((byte)':', (byte)'\n'); + length = index > 0 ? skipCount + index : alternates.Length; + + values.Add(GetString(alternates.Slice(0, length))); + alternates = index > 0 ? alternates.Slice(length + 1) : Span.Empty; } return values; From dae20a6d15f04d8161fd092c36fdf1f57c021ba1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 11 May 2021 12:00:32 -0600 Subject: [PATCH 232/704] Bump hosted-git-info in /src/nerdbank-gitversioning.npm (#601) Bumps [hosted-git-info](https://github.com/npm/hosted-git-info) from 2.8.8 to 2.8.9. - [Release notes](https://github.com/npm/hosted-git-info/releases) - [Changelog](https://github.com/npm/hosted-git-info/blob/v2.8.9/CHANGELOG.md) - [Commits](https://github.com/npm/hosted-git-info/compare/v2.8.8...v2.8.9) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index 58378eda..5d2beb75 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -1222,9 +1222,9 @@ homedir-polyfill@^1.0.1: parse-passwd "^1.0.0" hosted-git-info@^2.1.4: - version "2.8.8" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.8.tgz#7539bd4bc1e0e0a895815a2e0262420b12858488" - integrity sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg== + version "2.8.9" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" + integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== ignore@^5.1.1: version "5.1.4" From d3d35b668d08a2852bdd224c4f695d8b8e677605 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 15 May 2021 17:45:08 -0600 Subject: [PATCH 233/704] Add support for windowsdesktop runtimes to Install-DotNetSdk.ps1 script --- tools/Install-DotNetSdk.ps1 | 44 ++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 132c374e..3afca0ee 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -31,17 +31,25 @@ $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1 # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() +$windowsDesktopRuntimeVersions = @() Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { $projXml = [xml](Get-Content -Path $_) - $targetFrameworks = $projXml.Project.PropertyGroup.TargetFramework - if (!$targetFrameworks) { - $targetFrameworks = $projXml.Project.PropertyGroup.TargetFrameworks - if ($targetFrameworks) { - $targetFrameworks = $targetFrameworks -Split ';' + $pg = $projXml.Project.PropertyGroup + if ($pg) { + $targetFrameworks = $pg.TargetFramework + if (!$targetFrameworks) { + $targetFrameworks = $pg.TargetFrameworks + if ($targetFrameworks) { + $targetFrameworks = $targetFrameworks -Split ';' + } } } $targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% { - $runtimeVersions += $Matches[1] + $v = $Matches[1] + $runtimeVersions += $v + if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) { + $windowsDesktopRuntimeVersions += $v + } } } @@ -163,19 +171,35 @@ if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" } -$switches += '-Runtime','dotnet' +$dotnetRuntimeSwitches = $switches + '-Runtime','dotnet' -$runtimeVersions | Get-Unique |% { +$runtimeVersions | Sort-Object -Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $dotnetRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $dotnetRuntimeSwitches -DryRun" + } +} + +$windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop' + +$windowsDesktopRuntimeVersions | Sort-Object -Unique |% { + if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $windowsDesktopRuntimeSwitches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $windowsDesktopRuntimeSwitches -DryRun" } } From 192d62eee1a6143e49f6e76a81a1082277f93c25 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 25 May 2021 21:05:19 -0600 Subject: [PATCH 234/704] Improve msbuild documentation --- doc/msbuild.md | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/doc/msbuild.md b/doc/msbuild.md index 5ae13032..10b23e8a 100644 --- a/doc/msbuild.md +++ b/doc/msbuild.md @@ -2,6 +2,23 @@ Installing the `Nerdbank.GitVersioning` package from NuGet into your MSBuild-based projects is the recommended way to add version information to your MSBuild project outputs including assemblies, native dll's, and packages. +If you want the package to affect all the projects in your repo, and you use `PackageReference` (rather than `packages.config`), +you can add this to a repo-level `Directory.Build.props` file: + +```xml + + + +``` + +The condition prevents the `PackageReference` from impacting any `packages.config`-based projects +such as vcxproj that may be in your repo. +Such projects will require individual installation of the Nerdbank.GitVersioning nuget package +using the NuGet Package Manager in Visual Studio. + ## Public releases By default, each build of a Nuget package will include the git commit ID. @@ -21,6 +38,64 @@ You should only build with this property set from one release branch per major.minor version to avoid the risk of producing multiple unique NuGet packages with a colliding version spec. +## Custom build authoring + +If you are writing your own MSBuild targets or properties and need to consume version information, +Nerdbank.GitVersioning is there to help. +The version information created by this package is expressed as MSBuild properties. +These properties are set by the `GetBuildVersion` target defined in this package. +This means any dependency you have on these properties must ensure this target has already executed. +This can be done by defining your own msbuild target like so: + +```xml + + + My assembly version is: $(AssemblyVersion) + + +``` + +In the above example, the `AssemblyVersion` property, which is set by the +`GetBuildVersion` target defined by Nerdbank.GitVersioning, is used to define +another property. +It could also be used to define msbuild items or anything else you want. + +### MSBuild properties defined in `GetBuildVersion` + +Many MSBuild properties are set by `GetBuildVersion` allowing you to define or redefine +properties in virtually any format you like. +The authoritative list is [here](https://github.com/dotnet/Nerdbank.GitVersioning/blob/dae20a6d15f04d8161fd092c36fdf1f57c021ba1/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs#L300-L323) (switch to the default branch to see the current set). + +Below is a snapshot of the properties with example values. +Note that the values and formats can vary depending on your `version.json` settings and version height. + +Property | Example value +--|-- +AssemblyFileVersion | 2.7.74.11627 +AssemblyInformationalVersion | 2.7.74-alpha+6b2d14ba68 +AssemblyVersion | 2.7.0.0 +BuildingRef | refs/heads/fix299 +BuildNumber | 74 +BuildVersion | 2.7.74.11627 +BuildVersion3Components | 2.7.74 +BuildVersionNumberComponent | 74 +BuildVersionSimple | 2.7.74 +ChocolateyPackageVersion | 2.7.74-alpha-g6b2d14ba68 +CloudBuildNumber | (empty except in cloud build) +FileVersion | 2.7.74.11627 +GitCommitDateTicks | 637547960670000000 +GitCommitId | 6b2d14ba6844d2152c48268a8d2c1933759e7229 +GitCommitIdShort | 6b2d14ba68 +GitVersionHeight | 74 +MajorMinorVersion | 2.7 +NPMPackageVersion | 2.7.74-alpha.g6b2d14ba68 +NuGetPackageVersion | 2.7.74-alpha-g6b2d14ba68 +PackageVersion | 2.7.74-alpha-g6b2d14ba68 +PrereleaseVersion | -alpha +PublicRelease | False +SemVerBuildSuffix | +6b2d14ba68 +Version | 2.7.74-alpha-g6b2d14ba68 + ## Build performance Repos with many projects or many commits between major/minor version bumps can suffer from compromised build performance due to the MSBuild task that computes the version information for each project. From f62b3815de957cae7e1f99376215fbec4fab84f0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 29 May 2021 09:21:55 -0600 Subject: [PATCH 235/704] Unpack xml doc files with nupkg for better Intellisense When using devcontainer for development, the xml files were not getting unpacked due to an environment variable being set in the docker container. This reverts that. Workaround for https://github.com/dotnet/dotnet-docker/issues/2790 --- .devcontainer/Dockerfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c551ecf2..40e736b3 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -6,3 +6,8 @@ FROM mcr.microsoft.com/dotnet/core/sdk:3.1-bionic #RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | tee /etc/apt/sources.list.d/mono-official-stable.list #RUN apt-get update #RUN DEBIAN_FRONTEND=noninteractive apt-get install -y mono-devel + +# Clear the NUGET_XMLDOC_MODE env var so xml api doc files get unpacked, allowing a rich experience in Intellisense. +# See https://github.com/dotnet/dotnet-docker/issues/2790 for a discussion on this, where the prioritized use case +# was *not* devcontainers, sadly. +ENV NUGET_XMLDOC_MODE= From 8644f535701be9be5f1f6b92fb5f10c566272394 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 29 May 2021 09:28:27 -0600 Subject: [PATCH 236/704] Update devcontainer base image to match global.json This leads to faster devcontainer creation times because init.ps1 can skip the SDK installation step. --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 40e736b3..4e770766 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/core/sdk:3.1-bionic +FROM mcr.microsoft.com/dotnet/sdk:5.0.202-focal # Installing mono makes `dotnet test` work without errors even for net472. # But installing it takes a long time, so it's excluded by default. From ee7f2ebc84a391f77229dce0d76878940b0b4c59 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 29 May 2021 09:48:29 -0600 Subject: [PATCH 237/704] Add powershell extension to devcontainer.json --- .devcontainer/devcontainer.json | 3 ++- .editorconfig | 1 + 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 99630282..f4e3b31a 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -14,6 +14,7 @@ "davidanson.vscode-markdownlint", "dotjoshjohnson.xml", "ms-vscode-remote.remote-containers", - "ms-azuretools.vscode-docker" + "ms-azuretools.vscode-docker", + "ms-vscode.powershell" ] } diff --git a/.editorconfig b/.editorconfig index 01feb97f..3f5b80ac 100644 --- a/.editorconfig +++ b/.editorconfig @@ -30,6 +30,7 @@ indent_size = 2 # JSON files [*.json] indent_size = 2 +indent_style = space # Dotnet code style settings: [*.{cs,vb}] From e987a7e27523af7ed65a3b5e5a14c317d607a3ec Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 25 May 2021 12:34:35 +0200 Subject: [PATCH 238/704] FilterPath: Recurse into child directories. --- src/NerdBank.GitVersioning/FilterPath.cs | 25 ++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/NerdBank.GitVersioning/FilterPath.cs b/src/NerdBank.GitVersioning/FilterPath.cs index 52edad43..72322045 100644 --- a/src/NerdBank.GitVersioning/FilterPath.cs +++ b/src/NerdBank.GitVersioning/FilterPath.cs @@ -199,6 +199,31 @@ public bool Includes(string repoRelativePath, bool ignoreCase) stringComparison); } + /// + /// Determines if children of may be included + /// by this . + /// + /// Forward-slash delimited path (repo relative). + /// + /// Whether paths should be compared case insensitively. + /// Should be the 'core.ignorecase' config value for the repository. + /// + /// + /// if this is an including filter that may match + /// children of , otherwise . + /// + public bool IncludesChildren(string repoRelativePath, bool ignoreCase) + { + if (repoRelativePath is null) + throw new ArgumentNullException(nameof(repoRelativePath)); + + if (!this.IsInclude) return false; + if (this.IsRoot) return true; + + var stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + return this.RepoRelativePath.StartsWith(repoRelativePath + "/", stringComparison); + } + private static (int dirsToAscend, StringBuilder result) GetRelativePath(string path, string relativeTo) { var pathParts = path.Split('/'); From 4f46d95c2b8ae6a135d1b54ff23cf1ab5f2d6c4f Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 25 May 2021 12:33:32 +0200 Subject: [PATCH 239/704] Remove dead code --- .../Managed/ManagedGitExtensions.cs | 32 ++----------------- 1 file changed, 2 insertions(+), 30 deletions(-) diff --git a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs b/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs index a2f1fefc..58b8206e 100644 --- a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs +++ b/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs @@ -165,15 +165,6 @@ bool TryCalculateHeight(GitCommit commit) var ignoreCase = repository.IgnoreCase; - /* - bool ContainsRelevantChanges(IEnumerable changes) => - excludePaths.Count == 0 - ? changes.Any() - // If there is a single change that isn't excluded, - // then this commit is relevant. - : changes.Any(change => !excludePaths.Any(exclude => exclude.Excludes(change.Path, ignoreCase))); - */ - int height = 1; if (pathFilters != null) @@ -194,26 +185,6 @@ bool ContainsRelevantChanges(IEnumerable changes) => } } - /* - // If there are no include paths, or any of the include - // paths refer to the root of the repository, then do not - // filter the diff at all. - var diffInclude = - includePaths.Count == 0 || pathFilters.Any(filter => filter.IsRoot) - ? null - : includePaths; - - // If the diff between this commit and any of its parents - // does not touch a path that we care about, don't bump the - // height. - var relevantCommit = - commit.Parents.Any() - ? commit.Parents.Any(parent => ContainsRelevantChanges(commit.GetRepository().Diff - .Compare(parent.Tree, commit.Tree, diffInclude, DiffOptions))) - : ContainsRelevantChanges(commit.GetRepository().Diff - .Compare(null, commit.Tree, diffInclude, DiffOptions)); - */ - if (!relevantCommit) { height = 0; @@ -268,7 +239,8 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git bool isRelevant = // Either there are no include filters at all (i.e. everything is included), or there's an explicit include filter - (!filters.Any(f => f.IsInclude) || filters.Any(f => f.Includes(fullPath, repository.IgnoreCase))) + (!filters.Any(f => f.IsInclude) || filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)) + || (!entry.IsFile && filters.Any(f => f.IncludesChildren(fullPath, repository.IgnoreCase)))) // The path is not excluded by any filters && !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase)); From 0066fa0d5c9a7c80ae9f2dd0e249ee4b66466499 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 29 May 2021 15:14:36 -0600 Subject: [PATCH 240/704] Fix directory separator to be linux compatible --- src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index af4d1e05..937b0575 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -444,7 +444,7 @@ public void Worktree_Support(bool detachedHead) var context = this.CreateGitContext(workTreePath); var oracleWorkTree = new VersionOracle(context); Assert.Equal(oracleOriginal.Version, oracleWorkTree.Version); - + Assert.True(context.TrySelectCommit("HEAD")); Assert.True(context.TrySelectCommit(this.LibGit2Repository.Head.Tip.Sha)); } @@ -736,7 +736,7 @@ public void GetVersion_PathFilterInTwoDeepSubDirAndVersionBump() { this.InitializeSourceControl(); - const string relativeDirectory = "src\\lib"; + const string relativeDirectory = "src/lib"; var versionOptions = new VersionOptions { Version = new SemanticVersion("1.1"), From 7a23e0daa9c0179205aed56bab82e5dd5df75d24 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 29 May 2021 19:05:50 -0600 Subject: [PATCH 241/704] Fixes the Install-DotNetSdk.ps1 script when the path to the repo contains spaces (#100) --- tools/Install-DotNetSdk.ps1 | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) mode change 100755 => 100644 tools/Install-DotNetSdk.ps1 diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 old mode 100755 new mode 100644 index 3afca0ee..91399997 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -136,16 +136,16 @@ if ($InstallLocality -eq 'machine') { Write-Host "Installing .NET Core SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue if ($DotNetInstallDir) { - $switches += '-InstallDir',$DotNetInstallDir + $switches += '-InstallDir',"`"$DotNetInstallDir`"" $envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0' $envVars['DOTNET_ROOT'] = $DotNetInstallDir } if ($IsMacOS -or $IsLinux) { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/7a9d5dcab92cf131fc2d8977052f8c2c2d540e22/src/dotnet-install.sh" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/49d5da7f7d313aa65d24fe95cc29767faef553fd/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/7a9d5dcab92cf131fc2d8977052f8c2c2d540e22/src/dotnet-install.ps1" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/49d5da7f7d313aa65d24fe95cc29767faef553fd/src/dotnet-install.ps1" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } @@ -156,19 +156,24 @@ if (-not (Test-Path $DotNetInstallScriptPath)) { } } +# In case the script we invoke is in a directory with spaces, wrap it with single quotes. +# In case the path includes single quotes, escape them. +$DotNetInstallScriptPathExpression = $DotNetInstallScriptPath.Replace("'", "''") +$DotNetInstallScriptPathExpression = "& '$DotNetInstallScriptPathExpression'" + $anythingInstalled = $false $global:LASTEXITCODE = 0 if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches -DryRun" } $dotnetRuntimeSwitches = $switches + '-Runtime','dotnet' @@ -176,14 +181,14 @@ $dotnetRuntimeSwitches = $switches + '-Runtime','dotnet' $runtimeVersions | Sort-Object -Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $dotnetRuntimeSwitches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $dotnetRuntimeSwitches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches -DryRun" } } @@ -192,14 +197,14 @@ $windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop' $windowsDesktopRuntimeVersions | Sort-Object -Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop runtime $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $windowsDesktopRuntimeSwitches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $windowsDesktopRuntimeSwitches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches -DryRun" } } From c6bc22403965b6336a4afe52d244d796cbc94536 Mon Sep 17 00:00:00 2001 From: "C. Augusto Proiete" Date: Sun, 30 May 2021 15:17:10 -0300 Subject: [PATCH 242/704] Add cake-addin tag to Cake.GitVersioning NuGet package --- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 62f6dc01..87c9fdc4 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -8,7 +8,7 @@ andarno Cake wrapper for Nerdbank.GitVersioning. Stamps your assemblies with semver 2.0 compliant git commit specific version information and provides NuGet versioning information as well. Copyright (c) .NET Foundation and Contributors - git commit versioning version assemblyinfo + git commit versioning version assemblyinfo cake-addin https://cdn.jsdelivr.net/gh/cake-contrib/graphics/png/cake-contrib-medium.png cake-contrib-medium.png http://github.com/dotnet/Nerdbank.GitVersioning From cfcbc7e434c2fe1d5499a31cd7bcc548bad9ad8b Mon Sep 17 00:00:00 2001 From: "C. Augusto Proiete" Date: Sun, 30 May 2021 15:22:25 -0300 Subject: [PATCH 243/704] Update Cake.GitVersioning NuGet package icon to the new icon for Cake addins --- .../Cake.GitVersioning.csproj | 6 +++--- .../cake-contrib-addin-medium.png | Bin 0 -> 15893 bytes src/Cake.GitVersioning/cake-contrib-medium.png | Bin 15580 -> 0 bytes 3 files changed, 3 insertions(+), 3 deletions(-) create mode 100644 src/Cake.GitVersioning/cake-contrib-addin-medium.png delete mode 100644 src/Cake.GitVersioning/cake-contrib-medium.png diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 62f6dc01..0ae5bc75 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -9,8 +9,8 @@ Cake wrapper for Nerdbank.GitVersioning. Stamps your assemblies with semver 2.0 compliant git commit specific version information and provides NuGet versioning information as well. Copyright (c) .NET Foundation and Contributors git commit versioning version assemblyinfo - https://cdn.jsdelivr.net/gh/cake-contrib/graphics/png/cake-contrib-medium.png - cake-contrib-medium.png + https://cdn.jsdelivr.net/gh/cake-contrib/graphics/png/addin/cake-contrib-addin-medium.png + cake-contrib-addin-medium.png http://github.com/dotnet/Nerdbank.GitVersioning false @@ -36,7 +36,7 @@ - + diff --git a/src/Cake.GitVersioning/cake-contrib-addin-medium.png b/src/Cake.GitVersioning/cake-contrib-addin-medium.png new file mode 100644 index 0000000000000000000000000000000000000000..84c2a823c7b1757c9f61013337351de45a309ccc GIT binary patch literal 15893 zcmY*gWl$W?)80EcoWKz*xCZy&b~wQu65I(Pxa(oTU4py2BuH=w0YZS_?(XjP^80^# zuWDineYX94ltyNqIP&A(jqM=K3IKgb)QHS8gDEbt zZC$g3_mnmr+^=T2S7`WLr(kt&V})Lk8?9s3dIO)=-GjdnqF~1|Gxs8qqR=>#vv43g zm278;T>CuhPpa#yYwAzBIJ;awpBspN^0fF_?sfNk@Aup>o}g45*0ZYd*5Ju)+n$lY z7U0W3`$`PFDh^mhg7=gfJ#3zgwFvg42S3{$hDna#-8%AR#OD^|1B;ofmy+LuL#N&! z`67LV6C=E$6Q%tO1nEB;Q=xr+Aml|NiAJKe1bzzkM0Iy}46IZ;ns%=C(=#AYFh6OV z$9G^iaja+vX~-eL_>N6SSsQM0n_nI<(;5Roz0cNJ=k0j*rk$nqdUn7C^HW1`rt{$9 z_2`XNqN~U=^Wj6IWu?2dEe4-?OgSbztG8n-9@BYxU0Ll*&q0hrr1Y*E+r!uYc*3gU z1_FBQs;5$)(}+bB4Lwf0(qej|Kq2|jOqg&oyXUAzza$Z-zGXsBy%%yBdJEP-gH`YC zvHOYYT|Xvon&+#R$0P(q@T1|AFOnCrbJrd2)1v>1*dCe-M+Txm#cB>oAnXiZuZi~R z?Z0;TFK;IW&0};L{BU|MByWpuKfOtaHo)RV%5d!CM#^d7^5%su7G4Pdx+V8n{gI)P zJ^nIH1{po$|5i$0(pmiQK1Qe`FuC0>s-B<_6xkIa>K9<(eTORGyTZamc7_dYlaR!^ zkj(4&vHz2wgx{6}K)Kb=y$}}6@YNdg+j@8C{lu$96o>*{l#x_+H1DiU&m;bi`6S7U z@UiRI&FdItU8+V>v3E!vb7u&9!i9`hk)1K9B)SfPAeF_(#kY@_XIsOh&fCRR>W`oN zH1P@(7|w256H`)+uRVmw{+u_i{DzzIOC6%pA3TLe_>FIOZ1k`7c|6U`-+wZ>Ai4h* z1X);W?jMWIpWe7YVBnI3AhBJi|uH$M>2=tvfxY>?O z`j8edI-@{+*uC$7^rWNKi@9eL-EJ(Ruc1c9njt+J^9u@<^50a|x2g8@{3ta;h@J3B zyS=32?pcL&`hU3m)PT#*pW%JCXW`5j-nb;#C|msvPxzKc_}^x}{qdGO`=*tP!;fz+ z*}(ISi_Zy8!;F34#Zi-y%kW6s#YF;ht7UQ-M4moLc25mNb$NLBeM90KdvWea^}TEk z;){Aph2ueH3Y@pcCXd~i4?=2)Gi>?XB8LTUWeTW4Xae2$%b6=`66P= z`QpucuRa{pybcTuA9-5_?9R?xNv=?5r*T`5Rfm`aK7PPscRzC%tF9~jjLP!!2H`Io zg*57~-VVn_DFv}4%Ke}%_BE&ln`pO=42L&hsPgkQo}aX<4pRytnVJu72@t;_OLz&9 z-6t3uprMtKndwjgaha~CjZ{J&a0hwyl%7=R`(UI?jp>i~I}shGm#@vOF=W|M*pcW) z`Q=dPoX~!8Aiyg`DNnbx3XlD6L^wUP6Vhff#r& zUh%+3^TmDbCrjzPg*dakuC87-GBGx3E(h`6P|qHI63q-%_b$nP6y>vnDoW);$^qyN zWUGU%zNz;g?ZYcs*SWiq7*1+LS~bvb*gHhG^L&2}8%4+zf7iEF$<-0VWqVTjBj_n& zz(l*v8$sQ2hqLPzD{JR>`#!vL$p^|>ZWfvT8>ebRb>|;U{#^|8;9}fZ4TP|AKmNoX z;yb<9XReEj?5n?C|H#2Em8ETLj#}TRE!F-NZ{xGhz!SHGBb9h*SfsyVI+cTv+$XwEh1 zdzacmuGiY1_SfG8f^Lt??F#;N(@5e_>1))D*98G_+@D}PrG3tB% zy{=qpP+j<&;vcMQc%Q!M#1vPr!~nDOo3nS~+M^)7$O%y|)rdt@pwiK9nB*~!57az* z6A5;5X2-$VHC_7CuNj2GVjvdQKK^~Lteo3#BoeI?Jny|*QP-8)W-%#XfnlLUUYN5y z7#~-Wcf0~3iq0r?Q1wW*3-%gHz}_!!B?TrQq?tC$ zXi+KCc~SWuWw+6rDqRNG-x+b&ylvTgthcP(`W-RWQ#*3{aIjC(J!GQxFOZVDqANS_ zg)-;2sJy@si4$42=rK4*Ql>k0V%?U8DrXDh0x58#yt3HIa^&NkK-{NLTob<?Y(fq1(|l!7sWjE_@>jIIre{|i%o%N0w*Xtc5e9W<=g`MB`i%0cN9$M7{fSkUk$ zYPHWfp97u^vIf#4krq(sjs5^Ac3WDNy@qZB)CUVl#j!+Pu&(BVul@XBBf6|Cvp9I_ zDTh9msWfE645`S13qdUB3#c6D`$tG9eG+~T+liZDQ=Ak7TCd`7AiLWBnx|pbsz&Li z)e-S8BfRqCdQ0t1dGgbTtIt8s;bB6!NXq=)zzH%%auyaBqfs>1zx5#jgtlDkv+0T1 zJh0@1Tm&>v()ky&qbYoMNcNaDh{W`ydJt0>%#$u8y@FR=)S#+)(L5NMOUm8|Y5t{D*2`gszyU7Fyz`}U5e36D9! zg1BfrF@w<57w(Ys2ga`g+BsrUYp@EZzB9>Kw`xO(Y^J|KI2NW^$JP7+dThYOcJ$=&ApfxU^HKGlFKO_~cMdod z<$L+p6bI+Zn|!!20>$@pwZtd)`tnO!E8M8UW8L)giQSoZx7PbQWz|c;mXZ)7vD{jE zSM8~2Ad1M%K<4+BQr518wFKUO z#9L=50m&g|CyJr^9qm{6sjmzMiNsLLDNTAr)adNr%~!}Hw!$=E-|=^MpFc3;X?>Nk z{Du0IZ1h4*PPwh?sc?ekM-KEH?3IN*3i4)^F}!P(W4X8X9WfZK7Q`nC@XFSP zsa`#&P;}9Sgkb)_WWtq%oTSA?(zL&t0P9R;v2Zgm-%N9%i{y?>o9uqJX^Aw)C=0@~ z6W7R5yT>BZ1j5@MC?6HQ9!!f#IRF|GgkOtqER8g_Zi&0!(Z;QNS{;7u4!66Y7)JQT z$9`I(x;WE6=CYcJrKMfpOIT)SZ?^p{KnV1y(S$@(;SIoiGcX-y@yg<# zMxyf94bP7e*XI0rz)JC~c5NX$O9YlhbXljz)cJvg3vd`*J2fM6Z5S#(tuNMLs9b`C zLelZm9E`4iO_#b;30|m+VAZ5V=%F{G!Pz=v(Lyu-BwexwO=4C241RmPT&xPe3= z8g4*TU?^^qYVo@r>lK<&EJ8J61R{#Z?Nix5lHDjo%D;Q*gk%$abDy&5o@)MCrwl`%dERkJ4zpZ_Cdm=q4O!q4!>OCru01WF1OyKgQ3oUb z8hm~C(+mwGGg3LPr+H8o`4h6k={M@7pRGtnwg2|24jc+Wa5UNM`eBp}=gr=nVTN2l zRt2QhO%fqK^c;FJ6Uyi8b0T5WWlGm4E)9AWje7IJ8%r99xIcK}t)HH7c-qTg>Nz#u zN%UdZ=gV8U4LrY15&rS3(Xj^)$;d>FlEwAFV~`3gYY{h$D6{&i|HnJM4Dta9qZ z*{|B64Rr_srJxMAadE%jjqCmskrbQUB&P|hDNTxQztWWtaWcv^Jqtil-NGndQ}ucXSJ&RGC-Nv^0Z#o_WL5CNna?qa znJ*YBWbnm_YqD`<(4$pcRrg__)~dnWBUt^)l2Y9mR-TeJv4awn-|2-FSG;a89xSc` zDshy^MSrgWyNuV|kP1Ip!%K{O#la1)=l!`U>-L$tvos`_QQ+cNq=c+{slPvGrxm+H zuBm^5y%0)}_=Lx*R6_w%Im?rzGaudSng&*w;e(@b+tVPNDL9wcJR%>dQ@b$~2cdeX zSu}wp-+>_%?c&+)?E7=&Cu#uiWQ8=9lGH}v-v#ddim4fI%Wr#h&1r76if4>-%+61J zW2We^IV%KoC7ZTjDKZoD9)FwLngn66y`sHB_bMH$?{`{LCp5G1yyNHLkWag4_v3{z zS^jh^8S|J#TGV%wq} z75cFiyiurwdel6iZ8QK`o7OuVsp*H^*j8% zeRyaqGf;%K9Ts*lp^R@|V9c1Qn-BLqiH5T$r95^7*cyn)4l)%hsfvrIMmShl_$LxG z;Kh5euzd~1xH5l4_&a}`_v9;QbQ%*AStE;VfIi!F zgM3$HwQc9cGQa6_DX$=kBtxoA2%Lmu242W~YuI~+NFsZ7DB(Vtb#3+#D)}2HpP&kz z{_~l=AMehSRf-&+7;R+uClCW>IsA)a1oGHsduw>^;anw}z>CFAVR6%pDv3kowUm>( z`=;z;D<|=Mqvz={j;s5@h1T&InO|jLOy58+H`}fyGhqzX^RlU_&gr$AWF@b<9M8M5 zZa6vhi|eww)gu4-W||OS=IiML_*D?-smeNdOi_MaOb<9CPf4x1{nXWe}3 z;a`?7j^D_Q^y}2tm*~2J@JDy=*~`C;+lk`UDag_J3a2IV;L25qQ-~iyA(m&A`f{rK zW6;#n4%5>0HaZ#m{-++cS}<{NvWMJVyPG{DdW8lvfPY zE!#dUF#arRNg%twnzy-r4Shr?O=UV@J`A)89!}HLKzTZdNcc zf0qo(>GIE7o6N-0LNke}{7mJiutT8;hU&zNhY{k8j8-Gp)y@2Vzk#Pr#&vBbB~QfBo(2_Nc=WV(kpq*ut@ z*9>2Acrf>^W7RN7{8gow#E>*%UVDUwV`7c9p0nB0n82;Y3dq(43W9}mt;zL0J&;Lf zL~X3Ug(QX)5V(2NkCBN0v~(16!`yo3pVebn=tNG^roJ07>3wor0eT|$))n;+|ljqyUGv&xo^x{tV7dRybi0z(7ZvVp|i<~S!D4LSL)&W z1T7kqw|_1);tg&axgadQe22*_CAsCS*17wvU-Bcgc+7-v%)?)Q%22^`gO0w(cU*sY|mYVFbHV86GL#ObOe;PIYGoyIx;W=Mti>57kX48y*aS&`HoA^Zh3N z;6J4mUh*$_MVqrr{9Ampv~NZZ)_$UOAQP^6CaE-7KXSDB^vh^}M7du)#Kig(=taI~ z`0mahLD-3c*gaIS)bWo|q74S2Q0JJNPB%sQ9{YRCfl1~;aceMLxXXUnNbfc>a^mKb zoMJ}NhGbAY^*sYeo#C;BDdKY03u-B>6v^OJ$?#m<;T70^o$xG~8{4v3NXRjBQCi6O zm7?oAZ@is#a!1VK_UBKLbT*Din|BMjd};$gYj6~6@RJeV!m z5dS!{u3+-~pYrYUiqpq0BiSfdHUJIOeu1qU-WzKZ!W-V2mxhtz4Tu#6S)sJw_e41l zY@XL?N7GQ5;e^W|1fho5?42+n%Td#&%5I!{?&KvIH|&3_MHqRPLYeZRV)@6$3uZJXOx*K-HC^k(>_=1x%ANIWl+3IdFk-c7Q&Bcc>DA3`<+wvZHh34 zUz0ziR6(bbY0;UJRy|rYia-E$Q&aN@_N7_HwQQjd!fcIii=OEregzh?*ObkuLDAZ~!+6u^EMc@bS zS7q=jTK;x`5H!r3TK~i||8g$cGsCOJ)@5s|TDWXJZRM1o0rnW3%^IjQD8kNmpNRYi ztFv6LYAQOrW^=Pslr|(yuo+6=lNN>HNRurh(>}4oxk#4ON52XZH|fDTybxocfhZ@;>0Wv zb+(O-)oK@|VHzOnxbfKoSP8I!sDWdD_J+m6iAc|MC{6GKG!s0XuU1Qk!@Wu9{ACL{ z8g!#_BvR3uZc%pjmb8+@+wPyd-wZVOkS&{Y@dW1*tcJHzYUii`sqv?cKj@Ux1Qo(A zU+7%r$T6NSS`-tu2wciLqm;b?-5_>W`guShfegLb91=pS`GIy(qk|))4HcE#jAwOH z{5W`U;=Suk6;RHXUb#I{?~*)CSgDHBX`A)tpmvHTsA}YK!W5BRdnFyqP|TR?kO;A6 z@c33j^zq(FhWXQHmg;mFaP*FQLOEcDEKmqOA$dv1BusCc#(}E93+QOk*o7(lPX%M# zOBQcMb7r@J;lZ zYVo1)hjUNVT#xwIuLw3KL+857bvBYoIwBGJ2A>InsdRWcq%|Rk^8z{@z_vywR9u_B z1aRK$s?4~%NkW%Z69380h>F*g6#7&a`|YFJrr~WQaI<>7RPco@v!LZ^mr6sAn{%#GSXuw_s)BLzP(6s1wcrt`gFXE+Jo$#5y^Tum}Dz#E_- zhKF!MfM*QIvV&KD0*CHSIvmRIAnGo~^sHQEA6M?SbFB{Zme!`3p{b!kO+eK%8Vy#F zRSrbs20`LT3jWDcOf0@>ucpI!EF0zho5a#}=HKf!8O-8AusY)B*g3J*Cm!4d-QRK$ zX(+QLV}u3$AX28CO{B#67|~~Xs^I5`3`aY0w?MDW0rMS6=3AdA-GCzvoZk}x@igeA zldo{YXKrvJ^liL9$t<>7>D3jC zH6yg8)T%>**Wm?W9#~lTi%;bviOt=Np`u3Cq@!p6U!!C-JO6IbXoE6HyyJ=4 z2tc>X9+J^y-bVpHhs=EE@`rYb1KG&Hx!z&Hg37j~?I+F-)y^f1>4 zuZi;onVSP(k;}z}A%-ePyx5Gizp5bhS7pF==r<+oSwEYnp{rC1~8X}K|Woukn@ z6OBuN8-$FPaH)wcXG5ogmq^7x2Ix2&WC&imc5))xE(7S&LU6P}RWf}VlsV<9(o%e& zo*!4y%XJV49{b#K-)~<*kT&Q@YCEIr4;Nsacyy88%xDC^2Qw1=C7eLz1*m8R&y~a= zIdcCP@Ys(ZCiNgq7zpZLU0g7$2ay7U|vJ{T0SeDVjSs9Z!yz=}(+p ztG4Ub^=klgU-?VHbGY6hYx5bBd$B+jrd6~YnitbR$YL<*on^{Mp`t&e0q1+Mq&e}( z5%>uclE3<)u>a&-uDv;Uf#9FOhyz}1tb*mxuEj40jHE1h(F$6QS!^jhnMXzwD1+R( zpRRHGJTMGqcN}2Ag*F?_r~$_ua1k8?-r&Kn_GH&0a0VfZk{$#%Gj&~A)q3sw<~LPe zBv|rUc`~U^c#Z}^8^ZfMaK@ik8;m*b6j#-pWD4l|`QHbhP;xY>^sJ4(yPG)E$Ut&D z=(RzcLl=U}OlH@j#oHl&mH?|Hly6jyc-Sbsf@NTK{giTGTQ;&)v;Rohvlx=p2BL3N z)po>N`C{d$0m+f3NRl<{U^U0<9J5wG`r`F z+^x~soLhkgbInO$1o{A;K^TCb^tL!5TBuQzqA0rV)vVTmGWtVgR& zv_A%*4e#3@R0TbyeYDhsO~+TT!4audleJV9x* z3@{uN>eB?I!@_c8OAtPtHqyFGa?4)?;o7{PCFnmR|wR;73w< zQvz^fyTx4TiJkgS+xW2_+^OFm7h8=;Gokt93CHc=Q+KFL$p9XbIV5rAfHHf(CX8%s z;GzCi4PhUF-FCaCn&qGT?O8AozzMAWDg5 zX5{MCaE&yzQXGk(>IqkuDm@Vbln`>;#QKmC6`?=OB^+0B^e;QH&VXf;3=&JF3Gy$} zN+UXOQGmp<>wJIyCzu#&uJ+lDoU9P@bNbc;2`6&x&P$O8J<@K_4_`FqtES$zI}H0j zJCa5W=3f9tPO2BM%M3ZsIJBN|1%;UHRW_W@K=0u9FW0-=HzGC@o;9mJELcz)He#xbAvv)LOaE2ehYqpA<(h#xA;!XPn|hESJ!UYt2p* zG?9$%{+TkDQf3lPKQvGL4Lv&^DWFfSV+|3GQ>fRvqBb4g=+zbD{G_VrBcQlDgJC`t zHZ7kpN)JJMiTc)0kx~g3*Q>iWUdt(7)~06`B+v>k{Hp6!w!j2j@4`gAgK;EU6!j&; zF|%r>jJHcko|pB6$h0^k-;0w~e^VPkWLoZh&IFo4sJOI+nvrSK%4B{l33p_6o08TF zICvz!KLs9ldJ{qHKW~KFbGiv_E=S(y8lCQQ1IisY9Fxbwrz0U&`yD)R(PMEM)^DL*ZX3| z*!)}>?=PqPT0Wlg-+2}9MDRY^4nJNmxKUQNl<;r2E0X*0-}^=4oYUYWCO;Yr`+GKw zo1Qvh)DBfN8e*#J2ApOZ-tNXTd}e`9uN&(-osBN3=HI?PB%MswA0NXrp1UX>+-VVQ zkGFm3W*m=c^wvzVZF1m$92}`GO7C#)S|G>PfWJApL-)aY*de63C3g3wJo`G#^rQDV z65Emuf9BHeI83toyXk4dxGE51_}G)!(2x8!Pv&ro3;5#EZb;9LXxMuAm@G_&(e-?@ z|D)Lrjj@w?pVfwS2Wr0%OSJ0jICq9ff;=<-I?Pq<0wv-F7M7CKf6=2=FgZ0JIny~~ zwg9sxNMKXc)tqI@V8VKld!T9Sregnf|k+OUQGTXo_w` zT-qB>AK_jYeVspL)2xLQHeTdVe3tA5Pm8M$Lo_iEqx=D)^9i_U08dlfotGkV+1%O5 zv-q?Ui_{BUze3MoB43&@I5`%F)MNmo*o8P{lqQXVy(q^mIVe?BdE_6=F!H)p*Ix_A zSy4wSD%0%gs3Z4{Z(?7m-s#{=fOg_;*ny8qg0vgM5<(&d$*%+zt`yl|K?(&(;QW~~P6e%Lo`lS4PLH{_kY$&wt#iYeu zw*$v7E#L@27kUaN0#qRdCw=CA8? z5+GWTUaq_KBR##bCQrtzjTX^T<}q=ClJZk`Oc$)=zK19^rFOVuzARFX(y6Zv4r<76 z1qK$I!ut03TzVJIS^xK%cyL4thCK34j2B-hVT}+l#B)Mogu2N>`U~5dZZ@|a3iHMJ z0qUG0@SSJz79mJp1HL?>2_K~YIK+$wOO!1fo5K5TMWGGkfmF`=zvZJ*RL5Z6YN&(m zuQ0Z~^{vEXai#ELSs!`U3KdQFbz0Rwcl%D0Hs{ZyA(ATtih520b5mT5m#aCb$W& z3kYR|h5156;U8ouUXl zCuP80i2%apU7bH?@jKq3NdX_t$NQo;j{a(qfI`awZPkb2R5Egp@(J22g@qec3d8tx zy|F=pHg}R(6J7J1`h8z~(ns*sVM8Al>}8XXw7(CVALeQhaj$W8N5YjPdvjbcU|o^8 z%?H|yMH~s}KuD3fqG+YKOb7h*^j8KEP#z7Mc{E0BLZfG`+RZ#f%`D!-mJGKSvb8Cn z_~Y_z8|cS_t0}@qO#uvSd|@Q>Za9DHRz*5k1Fne%+&sKEn#9+HfF10d9$sHZ<_B*& zFDETcQiCU%JUjW0bk@l0?N2Ch&S%d2fI$kr6J#u4!DZokVtA1x zCg@-HDy5C|WaDUO{OMMo8`!M%qa}w^LR9+m+&;PKdCeJVcWE}BH1xwq5eg#84`@M4D`WYE9-F+2BD#S z6Go3ChfMq>{mn|z_0O3dZoo>{xp$%E@YJTK#9iVrF-^@jFV`ILi~*pvYhOxxh9y<6 z1d(dpt56v&(!D*2>SP;Es6JRjA*V_#c)1BuZH zYIM1CufDv^sxF>adSxK$WWyO|C|td=?LrbmXDRa=3Q&p(8bd(?>s)w7-`FTr$MU2vc|Ia z=X|hk8xXy$9Zx~x{bSl(^Oe$_$6S7(Ij;$JYJT>Upt{zjpXp4t~|904baJx6C^ewj-BEG;2k(t=*x?~bhi`% z9UP4B`5f2odkK9y^Au*riBh3^jg+@f|b1a3Xvxm_fkE?8dc2xY}x2d zBFrhZzJ9B2$nl`=0F-odZC(&}hQp#gLJJz-je{#o4m-lpB;rO*T=5Y4aPqU|EGJ~=5E zrCjhVtE*51woyIkG=oRbF|C|s^csEf@^U1KV0x;Y_aA%rxiIyC1)gw+K(DP<+#$ir zWnBWU23#$jy`{etYLw046exxM@ED(YlTVPp)WRa?RyR8Gf*If>1X~L@)6LKyK7F`7 zKD9`Kh`XJQS%s!z{n~;+0V2y5 z5=Fpv(Cl!;c5-k$6FY2TOpiwxi17kg&nMP_9ayg?nZFBD#UiAIX^fcqhI;20C&jx* zlV+Jk_bP;}H4A$ARR@4{au*sY$oY!lkNUhuastV5WX}drNtvjTGrVlZdZ*VT*^lw?w;HH5P9x}4SE~VGpMkT~9zmxu(E7K$nfXDU%6{boWk7b!8-&JE zfPQ#lqeaU`;3ZHU4d(!g1i+}tj!K?2xHpL2UF@1Ji?FPf1sx$e3C9CIMe-+6k7Z0g zHcO}V%zeH;Up+LYKMei1RV^K7BfYPNi>2FrxG5xI&YO zQ_Jjdr!IvLP2s2`TRQ85GFRWE@~aGtza9()0xezN0`z&gxugcdI9xGM8XCsEWMcR{ zG1+-0SM3{2*g0CK|MV)0JD2CNe*wOqffHZkqv%w>aqNUG`QNXjYIT#1N;$6)%`WHw zHH{jFO!BEQstrtn10I9g8`+Oqgt8B%q5raR$7O&&BnUr)x={la z&pF*c6R6gl3!r`1mwqbZuD~wF@ps7Z+`fP3^zdG;Z;_t@p~cT?)bVU`O5LR9o45!T zi%$L2=x4r`XGNmJIrA?8SMPH74|jT}AH?{-G7lu8Jh{25b3o^aJ6rD35=OKqI$p#N&luyma? z3qvN6a#Z_s4Yc{~j9FiDS@nk~2qDvd!-~U?B$LWs9LcY5v5t$AwDmSi&{D`q3lln) zlg8Uy0pE$&VYaRZdHSJ+KU%uqpiKtc|JlUk45&W!X}Dv{;oM{O2uge2K%6wVP(0&p zTW;7M14I2cCTJp1+yganZEOocA=Kd9uSo4TES+a-k8<4L-182}sA)#6_qwmVsomS{ zuU-Fx0Llveq_f~pyS-EF#L$yQ*MH6RmNT;p@5L`69Tx335N2VpY-!>;fN%PehWhAx z#fx^vEZIlNxlYoxUbt6<_m=?M?;2NATbq9mo$qE1J(v&NG5I=7ORv=sbAIkxHW7YA z;;)7fhn8_0(RTBmT~bqCR1tIfAuX+HSw2^@kuL|0#sgG&o}xZn+6vqNXfv(0TM?oJ z^SJQDqha=?ix3+>D&(%UJ`*PcPvV{{`#ecV!S9jLi`0bg8-d?yxPE35MuKy6_lmM) zzaOM~6ZJw7U~i~v4Cu)iZ>hyfnSB`=f?o@hooP%Yb(}is#y=1oM?hA6LPcszPsQ3`{ZMD>Qz?u>1;+YbvCg%0|(!? zcj6*FmmUcgo`b@(&%nUSGjqGRa#Bx355l!d1!V>V9G)}$i)XrzW5PZb?ZFV2pT;Rd zi+qbg*%~T@kZ~)4-qNo-EnDmF#vt-8_KSwNWJu^vd6LdQ)315N05mtpD#6|5V$<_S$iWD2%WNHcr^1UR~6a z1ePW9oc;J-|BHHpLV;|K?pV&5((UZcOV<@Fn%&Q+&3+%pHX_1-W%KQ065P~&;|=;l zJsI0=kK$kK919pKVc^9CU*X$61`ZCfQZtJiD@}djp~x8XOs}r5>>m3;y7mqE=NG&A zi6ng!D+jfOYeXJ8!JjeV<0xp7qvaa)Tf^ZyX7Aef*>nR1)aeDWM0rE2EbcBKWLu{7Eias&Fiuu{mvoc>zEv*<{q{K4Qzu1+NLm(SKHc zN!cvX+}Ko&T)S5!RF8~A!aHiET#WZYWyW`ZQF$`yGt(dY#yu5RRwzWL^ZAg_W?hnM zZo;@NcFn4_{b6pFHx7Ty+->osEm*`DDpy>zgSd|)`{+d;$jS*bgzk8pmW(;}{iSfE zk!Ft-Glj$x75WLD+vRN5&1v;Of4|b=6)Wbf6zOQX^#X4KU-}91FaD-nIJS>+6jPtw)qzIQ>&>Nn!hy^S5Fsd! zmSK2YCjI`GFl1d#_}Z!J@3}$v@0A2eGnp^%JPQ{!2NZ=Wg2+Lf^u8skeuiOItw&6V zrln}&4)jegZ5ITneL=@YID%<6Y2Hk^up|HOm5615zps!O2yi82+tI!#g`3euWx!h| zF^Wi5n@&W7i6^@HLU%q=-BCbUsPldcWsCLS^M>spzu?EO-x}h}fNTLydLqCtm=PfH zd1u6!6I-LJOcNe2*;^<1o=V5=rSpXAygDEs`K2e)>165?5r8v%ll*%T@}sk`t;e1m zjwEuJSre~{k?JUiWedD3nE=rWprE6QW#EJm1DH26oQh2#dW0s>KMK;ApI38wop*A6 z2!HBv~#i0q*FI7tjiQ*g-rUDFQXa$6sNNoWclyNiMO#cKs?@FC-=7PI7 z^oqDwcTHgWm-kZ!7vRj#dP(0Kc%MRYO`tvuv@&f06QY6AlW12z+(vuO28@<@9xg}sv|U-6-E1vpVw#S z-e#Nk!`@%7>m<|#!0H^JxN1;YOTSKaz(;cm2|G8J?@AwA+OT^L6%_fy$8k?5^8}6qJ!l=C;#lWf@1q*wq|5FK7irrd#rX5zjQ+iMvm|udA?G|N>aBdgpip-1JY@xYl;-O<95J}SeFVbX048CchvSL}fc~WW6RtHox?m z8;^);v_N729ZH3$g20>9Pis28{MYm$>4goRmr|v6HF_#e4bc_$>rS0h{f@d-q)ur) zE0nx$j!omNsXGWMffrzvU`L}N43ds27i3tvG1h|Gto*C+f zVWcGg0^I-i$!N@t0YKuL;)`eRU8i>SFkN-k%g>r>Z0BK2-Hmy*9gXeW)y7>aG+otS zxhLbfCfXHKLrr{BL0|H{Pp|9KI;p&}-Jl&8k_@E7T@M%Am~Ii`e_AvH!uY!ZIX z?1&-uETy5^u~(ZMRj;n(!{0ea%CUMWXUBTCu^((47qOEZZEk*x3aGVMC2k~PrdRcm z8O&f)cuw5fntDaW3jt1AMX?`DBEDYPx<|9HEcMt<#dbXw%8wS?Q<2gwh)v7U_*=Zb zaRp1^PunGhz4=3R8CEYWNGBHhE;E;d9>e@~5PH!FJftkiYv4#wU^?9=02ZyKLq|;f zR>iU#+P^TjhPRs$I&$$QM&i-f$b=l9y=RfAvU=&KXS^lFv|B+<-=8;~&-*r^>2MPh zGlmQ+%8aNQlt*{tVP(UN@ zXQ=r{wJyS7M_7VI2MPP2(SNQZJ0+F?5Ot%4FfR?_`SseYET%0Vi&F&!PYkf>BZsF{ z@D;n4mlG~r8PQ-rDv*b95xU$Vf$A3arv#6jTsY+O4eCG{@kMz-FM7iZiAz* z^rrZB-BlyO`-4Cc19pflC>8ChQOyP+DueMgbE_5HAIBj@k7kCCX`0$lLys@p%}& zONnhsTDyK%6sLLTE*X|x-5?*#(bD(^8eBV}_li^Txlx=$R@R+TK~!;dN>p_H7>>4! z(z{{%Jpj^!z4NsNgV6IvB9!f?A7sQzSzlk%j7T-W!LwuAjG1j4>VLVF*!p+heMn!nota{Nr3uK6!um zv5DE<_5G`Mqd6cG*&}nK(49KWxxcW@h z^R*4~3%P>ms=-eTA&(bTR$k7m-FGBA>UQlHQSCUkLIr3%A^1B)~bI79sm*j8mJ#lr=je`@HnL-B6dj)-HX4$Xar zdsq+mJp0Mq3O|lg=2eQo>UF4Oj7=e3E>Ar0p`2IvgWpOJZ{?TYnyRxw8oz`z&xbsE4ibqt?>|9gG!=iU z$%@bYTe>)&cljYNUylwr6zg~Qw?2~&=2)T?30Ky%k1mm5Wf0`&mIplQ8a4`lH>_A6 z#KMKPUp>-6*d$@U*Lh8x=C@hfALgU%L2`4jt52coE$T?9?|EZL!1ZWa z?dpBcX2_v)ZbVK0PyV;)70H&rBl=}z6$y+XRGhe4AIEW^&;m0j8gB0DQ{2a_sx>Ui z3P1E-5P$D1iRN)KyD=wlZpnmQw~)APtWobk82Y~dEJ)oNMuxq#JZsL4rYkRv#+I{& ztrZIr%KAQXf>HcE{?}Ya_6!S9uyfNTigjb4u`s8f8}H4>RVFJuf2Fe$trLIs*Z9Ut z{QDwuK-xd|C_TZT)Pr`m{l(dQ)0Uron{EFsR{1TnqWr&;5n6KwV~ECCSz)d^AE8WY z$uc*$RED}@kcH;AfB-FrE$MZ^+PEV8()-+WB=zL^@`IU8n;3-{vOX0hS(T&OpfT;l ztq8S4HWgc0wizrziWo`@CycG0&mYW~ud;gTE|o$>GwPympe&4b`w2Ix1IV@UhxJbD zF02&=N3_L|_1LOV_s}gy(dy zCK*2u)Ct^qH)Y7u;&J8h{`)}2NfLJHZqY=Grl@gs_Z<~nlAXL##l;^zui>>wG|iF& z#+DK{SB6Up=a+MDU%EtfO|k0fZ|}^qQssyphre@#EQ8ygs{f{ZEO0@ zGz37^z;{uL7??c<>M0pSsYkU&pN#38g<|RU=(e{T=QXMuZ-ewkRP;0iEJlnc^*sAN zj9i3^P3>qSWnS_~cy8m{-7P(%DC9xY`&g+92ETI$_t(9$DB&=QQ0U!o*m=WJshSaY zn<~$VeVIkZ!s7e;TD<$%=g79kKkBpH{oN2+29Zu-#gkdPn)fx5s*B6Qh-OCixrq)F zNJVa(=!&3%N=B+YvFn!YW{yh$@5)mN3B2b$QU1oSrMrhQ@H`HGj};f#)J=4jC`B5E zKdWO~FFmIo9xeY4<5#^O3Tv56&FC1+B}G)?Y?2ofCn+f0Fj+G_h%9TkEHOvpzi2e@ zCMfyjM!eU&s8f4&;xxEDc$l00_g#)TmrBKX)_`Ee3)&yI{(>AyHFRp9bOo0_j9j0H zY;e7y75;qsUTbCuj}sFwi~7>_t6mhXCuGz(ip9=P_{@{ihs}8tP5kg_vEJ4&96x6= zLou$*Lqu%3l=2Is_)ry_0jqy?uPa}i30ms6dJ~9$s&kT`PLAVK4c%cC7VN=UgF3$f zWNG1q0a%#%lbvZ}#N_gQ`9rfr;`Dobr8=QPRRccMs8a^I*7r3WEDjcI(P(RTC9zE_ z7OuzJJ!p;B;^<)SVOOlSL`Oa6=geGz2W!2B0XaX(;7!ZzgSvQmU`w+SS@QrxJ{P&nP$&!E#t~ ztjen0d7jdQe#Zj=6c#pWFDLh4289QZcg zah2AH-DPaLbF*M(Le;1U^9ff=rEQAe>mBCLoATTYf#b!ms`$FJt#) zG?1nD2SnG5{U4TfeV^TO(D4gQKr_xLge!xYDJ32w~#W{@_6__>XXr zv@=}C_z`MzurZt^zbPe0d2o$ISUrI-oz*c*-2Kh&oKE7S;))3$ddq8m3Z`j+u`9NM|8R%{=EKTJ3WEaySRZ{ueergr^K#t zT0hYWI{WuIWi*e!!x!mcG-$Rlf)*xOk!{L{(ZxLkReA03t57XalI(J{#y%sLL?Cmc7B|3Jy!j*HPv1Llgq3<2| zBS^QhWJYhMFQE{V-xLpb0WY(niP(`czUc}h!kc&V-L;9uvChX`TDO_a0Wn-vF)=GU z4X=D*<`Rn&4~vwIMC#1-Gd4S}!tcf>Ll;GCJ{kh%HzOI@KYR1rhV_J3J6c$AaTWq~ zzb_>0&iO;O*aoWF@N;ARe=~gYe3B8>Bp>t5|3f8?Ho0@}sfnzl`?Ycw6v;MS!!PZx z$N0vEGI_e|yQ2<%Rt?Ae=HQ@x8zO~h`aesP(YIO5ds~e$x?k8#Ld9Uy<X<^WC?7I>FHGaLlWOVh$f+3oNB!wRp9ZshVo^%_( z>xRM}+x#_t_|Im1lIeD}T|lI~BAt6<+sAhCHc3_5vx67dtxOnnv0zSCV~wc(HF2c$ z1rS3PbD%olTc_BI^c%a-B&ZZLe^mdG^ru7NPhY`14*lik`x2j{t;<`~!RER$PQ6&! zbjEM}clT$WHh-x`GQ^a#q{OG2i2|balN_dDAe-h8Qa_)Yz^|cC) zU9#gz>PvYWuclkKgWQG9i6k}`Ji+kly-y_^W)sjg`aEv>aIytGI$SruA`=Qun(1<` zbfQUIZ)an#)eQ;(-Ny9+P3$AQA@c=XLDy}m@afkJ6STLbhJVy={dRaw!XboJ@9O?e zX3aRdcO(WnVgLi{d$tSRrc0v-DdNrZZV#mKNXM1U7!X5H*_U?~^0ZzWOiD*Y^%h;T z{EK4SmezTXOA%z}ziDZ`^IY_+-o~15;#0UnL0)jpdE0NV-^IhhRVLr=PA+ogbC>^E zH=%1wi<3v}P}xy~rn$ohSg{hP=i(XDk2Itoeg2k?)7d$dedk-AGW3&bmnM{=d;LK` zR?IsqTEX$R!XaLr5&5JM%F-0O&F6JiH%Ah)=rC0XI9|4{{WXtLAjCT3q_ipqJo4nrc?#)n|DeQwb7~f4tAYX&W;8Oc^nZ_F+!#*D@O|g=VhRM=qL(Yf*S$R;)rS-7D$y@b8#v>Y+;>^=h`7ou zH>^A`?U(0JJ=$_R{myBLa%8Y`+7ex_XL~!{p-H0P#cWE8G+LX%rv*H3x@K|%G$7Lf zW%jOq^c%tTzIR0Ww$`M{c@Ac(Sn6X{q6zF=Ck|)4#R%Us9BePPap?>iEB{(FMWeJI zjBv5FY6l~s@&Y*D(w5uPt7K=H&aQZAVJf}0EqbPD9vj|^^nVv^Yp;jNDDJK}DDF%` zJPaki0r)u?tUzPMZP&I+`|Z6_Jjc|mfiup$-(0i(R&D6oLm;JtR(j8kCHL$e8BX0F zs1oe%)%68Zz>WL@!Nl05p`Fma#n#i>WqVf%v_XM=DZlqk${%=u=!)nYsRIH$9}i5t zebF{fSyEi^hX41M{VLtq@|Pz0OQQGs3q2=P`zJ1afXpFz=LweC@Zw_7=Aq*MCThRw?(0iDJd)J){N=&7y|ltt5d1=ZWGG(VRQm%;XXhXZ!!7X`mPZr-)v&&>n7X*c!$ zBWRPgLgbZnxejCFJ3(4}M=f zGYZEA>BZFn3D4g++jx-&ZP8v`8NMaxf}X^1sfF0H)M{}7tA{&Vd_0L(ja>tW1ufUq zpmZO>DA-AfwUe_WV@Qh_5SLovOd!9;1I;@+Pp$-8sPOIN^*zq=%lxG{a55?~gI3p; zA2RS$A;M0sZF^o*gkw=S7%c|Z)WbgB+yU^uSITKl=}mPMm*!&(u*S&u{M z5>8wXfSiQ!P>1|tVT(G&fPfpT3J*L)8G@evfi@5+wWU{Ly&LG^Elu%#DflY|Ce!r% zASffgg_(>DK~P>|z%M5R?5@w)%jXyXVq#C@m>jlCfeYH|gP(Ko!e{Ij_w)*@7k1nv zGX`FZY_asl;qKugE&O+n8{Jobe8B)IJTJzn(ZIo+w2m9O#r>J-P4jVwyOR4yia!Sj ze4a;(J_|+M$&0)4no~gL>tk7&GU)|{uuhg`!&cR<94p^bY1sz?o$b6CGc>agbvZqJORA3bI=4{P9rZSKYxeKRp_L$#QJnnkFk(#{<@IQJe4Q4 zF>+AP*9!w|5fL^3yI1DL9wlWS1TM4}HPYO3nNs?R4eq)C9{ygLI}3t*-iB9yUT3G0 z#^BSI`2cevPF#2=HeEgK@zw_bMet#Qwss1Uqao|32IgeQ^YgC>j|0vx=;;F&d3ggD zBiBQpf1`zDp!mi-u8a!4u^{_DAD(=2%1M`+$9GASMpv=!u^W%*vAMmNbcUjymwmNr zMMp(#p0Pu)cPx1)9-%IQ*=Attx2PI_y&7Tt0FcS*d>sFZ0YayDNlN*g#*6ADT>dsY z=0?0EY!F@5&Qg1H|6)V(evbt(0FhrVwiZX8htm3g>Ly*=F`yslr7=L^a((aWWL7yy z(X$(6<_SEfw_Lro_L$!YmM{KJV18~^@nk=ZN}|cxR-db|SlKu9gz_~uzyh7>;uh>W=nd(&tkiEV(EdByCpRDt;PJJn_{vIeJS zqGBzL-f?8I+FTSJ{&5fS!igN~2g`mxtLt+4IDi01ZXk2J)A3u%IzYQnPZ;KBAho=A z7-^3@z#Q5;^n)O9*sisxLL625iQ>=`ALUF-?#K0Ul&H9!X*(DhzEl=Sng5QF>|U`O zCN&Cxe3)@oln&$e+KH=*sv0LNxqY)kxemKt#C(^bh?(gqKN?_yB3W^j{Q9*zFai5E z)sMDMZ5&B?F@biTNi{0<TYMf4S9HVv;^;aFDf{rtWV)t3Ps4VPqSq#MpCNwZ+eNvSqnfA zkpRI3-={uqr2+&t+th-NqoWeEV!xFBHG34`zBGkU*q3_UH~EQ(<9;aY&cyRQa0~Gc!T_ z^eMLW#T^=gT7{du9Z_cO{={Wf`wxG{s-QYw4F{!rC`p4`QR9XP3pgMKZ{{23X{y1& zcE5Mp&@%sEAXmo6=+*bd?8I^C@b;Fo+kv;aL0qUX>yWL9(QNn2Pr0gf{{F;(*3MP@ z-ZM0Pe%to}os~Z(Z-KFOTRY@u^1i*g7Cr|GOk9+A)P*iBBC9jMKtLyy;`S-HWd-Rg}2D@73}8x~N& z1`gzxUko0PeyiB3%EfGJJvg_aMQHAiqxLjzYFELCkto?92>J^>+eg)B{;#bClixF9 z0^a$_-t>l89{=QlUjfYG*SF4{GFsIIxUVzV8KkZ=$lWwnx;36=e34K zAV%cQcYK4UY6|_|Jy;1`k53-2l68eFy4u^g(@=}mxeq?30`N*mHUTqpM_suwT+LQP z0fL-9w{qRTDw&%lMmW(Uq>DJ6nwoGn$IyTZ08aMkKF|KjSTecz^*{KSeQ&xBy*SuJ zKgcE7rm%3Mj(AQ6UjoQChK4BSG9mOYly3=seTUVai3Y^)^XVPn852@b9*aLmI6u69 z{ns4}qyXfYq;@ZJ-?;k z#MrR!LyQGLcw^wnM!Y}^BQai}^3_5}1Ni;5WH$aQvjn!52sZyV+khbqw(V;hg-5uT zF!1K7vzcEDwrQF{w%_e^#DfKPX?kag3W`r6+1S14_Dd$Q`BCWYWme!3*5dh^kjB@) zP>iidlQouBZ-VeZhLLn@=sG#_u1K=Q0e@z4U+8&;hN3MKutTM0gRj zZ60?}U+shC@zsN++2e(Tkl6LbX=~*r*o-ILvZIlPjmyV!?bvl~xMhtURva zd8pMw1ist`uj1jR&{MMxWce=>5!IL{TOaB(gl8oUWa{G3W3|iAP=qJSL3@AkR(RaU z{N%&}XoKsYK03b3eC!nkkm#tTB~Y5XSe+EwdcC7~bZ}gqbMUtjcQFfHT}rrN)NuCZ z2bxGy_8@gQiQD}n7YGVK{bk}4Ry9uYMU`Yq&Gc(rn-HR8WEr%5gJHe}9#|k?P_WLm z&A&~@&5;sL z19I9jA%W<$=}Co^3D(3@}>rs6;yJM3YGw*)5&7+Q@~lZs&A} zZv>D*Waa3ZiCJk@`vPPiejpo-Y4-*{=O=9^0a%(9T5rU0EJRBS z$->uPXsrC=bTXvWxyiK&ggsg4Z6*5qOEn>U^GpdWyu@;or!V-tx~=h}?`s?}sLj`O zR1SDHhq;-&6tvG97VPANQ*B>Dny(nNjyg*i(#jCkit)swms4VIwSgRswKVMP5*3Q{ z_%&O)t3ESB5SU+!^6b?UAt6ca7+QD!Pom} zU0Q7v`nJzD^$`bd;nl>+_w1uOgeA2hPu(+tOoF8;BrtwL>)$v7YV?VBR_Av;1!`Ep^L+yIzlYJHXdsP4 zemV6LdPjlA))WQcsM-)b(~-ItP0FP>rX@vK}NYD1U(+F^JS3S+h=eEUGsCwcnww(aFJo<#4~YkHyDKGPYEtQ z!@_3H{rWBf;i$!p#`@XUbtq0~CvtG0qCuwQxy9RuW+r!;f-wN8q&E~RHg~m!TGo4O z3(=pUZ=QLg=pbWANEmwMTEV|_GM6VII8a>2ksYZvqdhv*=1A=?`4;)~k0T6%2%Z`k zNijCmHu@(3G>SCUFgh*A$g0&+9*N<~`1t2?Ay6y%{@J(-f?(h#Aut2Tp|OaP`tnDj zg%A)NB0v^p&fm-0Y4-LRU?!;EZ_Z;10Z7@~HQ^ZQn6RAb|K`-Y=HNLSLmg{~|KCdD zWzD^Ea-1`TWIvE0E#-ZOd7Q3>?Z+bkQol^CjC$KWQLtv75V&T9x)~KDvQkuo3_CbP zRD%ruE))lZ;tB3}2t_#bF@e$vYSjWeE3ebfmt|;xZsY4#Sy4UD6O#Z*82l|_N?@a~ zBKF{WPx%XTNb1XcXM%2go-{!SqOsUo#cAK2JS@B2j}mC8(r#;?YTB!2Kx7j7P*In; z3(7SB*RIh(S@etl?)3ntA`7sSwTG6~7cJ|qlyRW8@WbPqUGv5szu}8OOb~(!p@OC; z`tdVrpiV`~Y8B4$4iq4`He@vR6mJoc=Szej?F%WW9Vv+bUn?}4n~Q;SGP+_un}ig^ zC+?(bJFu}5f?6v5@+xw7i4DUcLef*+|3;D5oo-sAVWSrK@LxpDC*^vIh?CG<``QnE z&3e|^_ZJoST~GT@)jkM_VBUUhMbL3n@0NS@vBoJ9VS>7phn-M90Yu>Qp6in=DDqv! z_}*>V%6F7C_q=9TBrfG!t{d0?Gf#v6RMXn`{G%^06t3EOR3QersjI1zaU>g5H#7L! zsGpz$7Bbc!thrA?_r(5l;9-L6aObPn>L|C8gYxmp1n)N7v_c)vjHhvyVHlu!Z|8y7 zvd_g=_sEGiMX_8A;NT7KemQ-sYZDJQ69m}`<5Ylt zo)|z>S6bBG#eN=lVxtK2*=`f#dmVP@daE;RLWwdlhx2WjS6_H%?-z8SS4{JoDgxbv z1))KT&xtwp5*=aMSQKUxR!Okk7wWI2HBT`Kya%ZX zm*+24CGlce-6k&786_i8Zr4FJ&zxQ4KX!484zw7*IG{Nu9cCzn`^Hs>zd%Qjdb!tM zhBvyEh5ZLfoh5SCy&_3;1W}k>&s+G8+|~+e9B~e_bi`34fFKgSX4i6u%PcX`0j)@2 z0*QOMv#srvlU0F0RqX1|yJqlw08;lnKUK=VNipPLYWCw0{{3KZqus3H>ZjbRpbyf> zHvsIM@2dpr`~Wh##l){^aFN(;B4-|BJ1TD>zzcuFp|r2FAy3&8xL!uA*|SO6Q2aHo zx-g=+=X9wGn_lgbyyCS&f%s?Uq&g`)oIigMg0KtdPjx@Ta#NbIolR5JWSZDt68OI) z&4M9uYo7d`kpE`eDrKtST?E(XM8374HWdscTI>}*7*T=0QyQk zsw&V5H8MP306e(US0N1-UxdD}__mnB)qC|9!Kk1r|03Kg?>FGC( zf1Yb5iMmN#D`L05;^Y&Ez(pQz56P~?AR5ph<7=eCBaOelgv$nQaAh=CyUq--uz(p4 z#c6k-jFv7c-Ahjm=7M}*=v4+d9H?IzI2>{gGAL~@uNX7s(KHb~!QGPDo? zrJ}rsXX(!Xya#&p4gEEyjSk+%uqYW{jnaFdC7f&wu^h^FgBZaO>-p8sa&)Ot$~HoP z1=kX3AT}6CX0Kkv17Tm8aUWMu{7vcP7(!M2^+M(;WHz7(>t+?V5BBf#6iQ*pIx+NQ z!iT+`^pAl>k1D#_vCyC$n}d}c&3~0cQlRmGO0=4&O}rd`f5D)^B+LQs6x~)OG!)e++B6s_V%@7p6TkVKWS< zR$v>;;#0gT=kAlx{fG*K71TS|3$tEBu?nd4@|onFt~HR^{X<7h-s$cAoPtasMA+#w z6lii~@Y%$oZ&VOZUf90Ea4W7C zcJ5OSY|wd(F7z65%c682z^Gib!3DRI%bC5Nzq{U&0mw{*q(j^Z#O5d0>y_&* zHuxCln54n3+wOH+C9UdJ^jwUBl!pmL*M-Xo7)Dfspuj^Pm-TUZ0aOg(%f^`cD#+cT zR_Bhge#%b{l+#)uq#+=j{`}x|Ad5;ttbV80J|fT2fL+g2Lyne&R0Z`Y_*d3>*=dUt zNjGy;R`up76q^ND(3T%feHB3d6Nz&=vK&w}Ty93?c(N#emI@pn@D)CmZkXM50Te_u z4VmiQ@pkw7rkO{VqF!Mm+Eayj_u)A5sP`r1R-Aec!EhiMI4}kRW*425Rd`qj9=JNW zq5aUc>VNAy_ot&r2neF+KZWM!_g+;fqT2s@GE&ktp5DGrJ3G49MuV0!62}GguoO`! zIffg)Ppuw=0(YSpP>`8$F{m<%{fED$I4xt*;V%@vL`XKF*sToy?5?zW4!ni^{J7{C zKKtP7If?Mker2rc8bkt@*DY9JqL40`ErPv4)5#p=&jW&9vFHzVf_`xc2z}{?292ui zN_C}A#G%uIs4sZnUslLD)!+{%fb|d;N%C8UT?{bb@~yB$nqg827%yyVhM|FPXdsd3 zOD03t#CLTHc|Zu(GxF^@ILTUlct54Hi(&Onj8A$6S!u)(f)~UfMzk-w(D-}o9yu9G zjaO<9m2Wd2a3TJ07I01VrjGA=4^;snp#kWEe&&{QYsi1;NT`)(TY8O$;zn7(7Zy}n z^jk8kZsLWu=H5v!V@9nm5~&a~|k$gaw$e zQQ2>A&$?daOVTvqb1gyj{>}i*m?2{uXnB$wD|U99lD~GDw!->*rIz^L64Sg~NUd12 z30}MF7x znlrmpf#{$;%Wf={mxjooK>&w}L9l^zW9>`mhfER=yW9hX^Q%9ROBq6yo_iQ(5$eJuwI{a=c zjf=qXogt6>VHMpwPe=FEsU&Pw>+cxp&4bwIA3ngkRMjvV-VthpYWxwyMS}CE-1}A} zwBUa>y{jya1q>GeZk_)lN|~dvcY*Y%Cp8S$)v2i#0)<;f{RHxx;-yk@!wO4EXHCmS4! z3W=w$1u@|kqx%vWPS@Hy9wotjxw-{P=hCH@s_n)69E!d~$a`QZA}HjG=?_olrx6*}TyWb^Nhj)4$tC|} z>DM-W?dAT6-i9A}nj2eIT<2{JF%=z@>UdW%q^q}a&ctZ)d`}`dt}h=A+z}Q%zq&}w zmy*5ogMlr2GBPo}*FWZx-FNXxQ*AHqb<|9y)}inX0yaG3ig&ipT?)o54;DDverg7|xOtd*W>DM#?rlrb1c;D^J0407gD(=!Km@Sx0mtT}F3kGE zx9m75cRO>qPMP23EB3AmSB2Ym4Dra$twBHZzP%w8?jBrxx$!B3D@0vn=|+}6Ex6)f zGj%)nz*&np0)6Fq*XZXnVQ2hSOX<5mn0DkKB|MoK5W+z0FsbpAKkXD6^SqrH^UYNW zsXzP4oT9SZnDqiMa3bC<<4XKNzsP1M86WG(oDLnN72D*|egjJGmGR}B&#wCpx>EdR zJd9&VPlCjc(_K@^5nLH=QyVl8u7#Gv`POx4FU|4X9zeEfj-v9teH;d>6^~lm`4S=< zhx?Osx&(&74oV)ebv`H86%X^U7~BP=4T5|=vDHCQwvzyA#)sm&OXlLS>~H`IjVvl-qc)BKhPh@$oxQwbF5E(RSEIq2tEGrPNN z)Ss{@i7s!+SliL6hh+L}{4rU8AGKl){tn2jcag-JMb9=8A&LnfwBK;bfxpFof%iLf z?a=|T@ts+T++Q{u(q2>O2$oQzn5iWS_1?UaX9=k$mKqmAx^OnIP4z*)$hAcGl0!p4q7~y!Suha8cG{G{=;lWg za_)+@wb9|~5k$rsH|WFjhR*Jd9oxp%n?H8240t~M-2J{>fAO84E$%~HinopuX9+A< zCMSBAY3A#J*-LuV$D${nuH^Ux;CX*A)p{Jo8DyN{Df+P8u?{>!9nsRk)gN}9segu0 zg03EQza}ASF{_@;f}EDmsfpTMcj>#^=MOvDRQJUOGXGtb_AkR^coW)VR&mxb6I;)t z$W`LnS{~fUCpUX#_gKm^=CWzI3#H7)^hH~?;}`_}^1hExB4yz&)~v-x6Vc3Y&{^FW zL)xsOh+b_Zzi(Mn(tn)dCSm8cZ!r9xQoCq@OUC)Zd|PL}^xaIQMf=lKeg5L7uIfru zGtKtD;4pS(Us49~t=|e*Z(GpXQv% zSQXhM(O0y7rTyFbYh(uO6>TDA`2)>#Q&jo7(Z;ndic148IOCnWsO=I~&08pu*tMw# zy#t+|L^HyPhQP#GUxZ_L-~4_G%iP7>-!RLLGT2JU^5BlSh-aRfwo`x#sD~{nB+DseoBzyDTcf<9p#2P&1k8Ah+GxnS~ zDxP17X#e_>rJ+z_e|EqR+r88^i!OVCSh~HrmDgQF>68{5d_OqTCTphlN?fhAifr(F zS-wk!=2Ee>%4&|66$Fak(WX$W;MTt>VA(avVfxC0k{Nmo%BL_lKD=}P__st?cHc88uR*By5T#_+b0je z`>YDn2K1Jd@SgaGZREU^mK8Bak6el@UXlL&eSuRW>?1qA*-Yg-Eom9&)ZO~rb)S*e z<_1fXi^*g2%uJ+=TlUZBUYqOVZ|YZqEQybL7U*tN(|E>js6;>bd=_nRO2MHvkaQ7jq=Nbt54DM$(zzo8E)39cu@87+*xz^*~T1Nx@I$XnY2}}gz?s*b&axZ zda<*aKAw|z1_I=Aw-JT>UugX@i(Nk&y8fN59y8+5;7yz0b&S{lvz7K_l^>_PRi+$K zsFg3r?jcV6gl0{2fiFe|iX@p(VQZ_|kV<{0qfADDcL&@GzruV~+q_1qOyy7>g;CAB zP$GVfh7Zbw$? zkd!@yD5Vq8s^s2LbAMLk)_#{Kj)iLF`t;1;L7;N* zto1!@D{G(XZ4M(16I!~}`{A7TljJCYT*P0>+77Q?by52ar{km;S*g<}?`i%2Q*66z z@jgYhela>=A4g^Cuu8_rUQYN~!qNu6GhVeb`>f81pDE!Pb+|_->%KGXTYvHLmRwu@ z$4mT&Wv>dC$KlP-;!X^70#8C^tY4gDVaon0iPH0~%6~>qNm0G_RpM{av76XffaS^z zGbOY8?;EW(nOOOROcDj|1Yzu-IGePd$t3mI!Mdb#ogFv3RimF#8s_wTPIbjClr4xq zsAiq9KuCWidb0P37%vngwAsF((7;~WX)8;0V3`<3b@NEf!(6CDdrojCbZ#83KVNDg zGlNd@?z3s15o?2tsN!`PV&eWMfi6In>8jv-EdK8Y!y(K`LE|;bm5#vEUYSC}g&xB9 z%K(4xlS;iG%e$4QT8e8HSnFqN0bWWxxiEG0VKxihs22f31rc$_ln{byEEjOmgKb)j zVL3Xo$AIlI^q58169Zw~)HZ|_(Ptmdv+1)36yue!s_Yg9C07Q!W)T?OA znWq?87W+VKbU%Nx0i!9U!y*CrCuxy_*BDnRtH2ZudC^)*Oq04t1z1!^2pB^Y=#eNc zC_oa$FdH{KO8zgK%+Y&J+yodBR*r1$x}GTiCzyFgyBxp7@k7lbAu6Cq2xX-B=?zTU zr&8nn!Qw!K6Q}$U!2@spm>p3*LlG&S z$2uG5813wxYkndFVrLvI!j*ywOd;qJ?dDkjBw(8kfBMn>4Pm0-EZxBTe}x4L&8Qb) zLYz61s9mZl~vTL)f?4+)SrLV2LxI$OX8G6NlB`r_0s* zvMl{jq>K4g{kmXLILt~TA)ws}bS3GP75)qM%_G6FcpCNM7w-a*W@nkVGtbS9zUm;= zedNAl+oa@VQ`ok9yfZ|x9fu%?W%Z6mCgGr_Z z{{8vP7(Ul@9a$KvksJ`P&yf+E#{8o!^O#Wbl+)}Ng-FU!T*rxtEXMWR&e03T6t}&C zS9RYsk^g{Ja#ovdiyDm2$r{v|`XR$tFv}eRG^e^2>ixPJ9_KJ1CkBM@H zLOC|W7Y%Qs>-z%VHfO7|G9F%tG5r2R-UTPzP+vp+@n;ST63n%FR`H{{Oy+JCE*LzOiQO59j{Z#|#u-s=O$E4)^;%%!L}; From 443d4223166e1f5575be4ce9609a6051779c98e0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 30 May 2021 17:12:05 -0600 Subject: [PATCH 244/704] Add 3rd party notices to repo and deployed packages Closes #593 --- 3rdPartyNotices.txt | 243 ++++++++++++++++++++++++++++++++++++++ src/Directory.Build.props | 3 + 2 files changed, 246 insertions(+) create mode 100644 3rdPartyNotices.txt diff --git a/3rdPartyNotices.txt b/3rdPartyNotices.txt new file mode 100644 index 00000000..f96a675c --- /dev/null +++ b/3rdPartyNotices.txt @@ -0,0 +1,243 @@ +This repo consumes and redistributes elements created by others. +Due attribution and their associated licenses follow: + +LibGit2Sharp (https://github.com/libgit2/libgit2sharp) +============ + +The MIT License + +Copyright (c) LibGit2Sharp contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + +Newtonsoft.Json (https://github.com/JamesNK/Newtonsoft.Json/) +=============== + +The MIT License (MIT) + +Copyright (c) 2007 James Newton-King + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software is furnished to do so, +subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +Nullable (https://github.com/manuelroemer/Nullable) +======== + +MIT License + +Copyright (c) Manuel Römer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Validation (https://github.com/AArnott/Validation) +========== + +Microsoft Public License (MS-PL) +This license governs use of the accompanying software. If you use the software, you +accept this license. If you do not accept the license, do not use the software. + +1. Definitions +The terms "reproduce," "reproduction," "derivative works," and "distribution" have the +same meaning here as under U.S. copyright law. +A "contribution" is the original software, or any additions or changes to the software. +A "contributor" is any person that distributes its contribution under this license. +"Licensed patents" are a contributor's patent claims that read directly on its contribution. + +2. Grant of Rights +(A) Copyright Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free copyright license to reproduce its contribution, prepare derivative works of its contribution, and distribute its contribution or any derivative works that you create. +(B) Patent Grant- Subject to the terms of this license, including the license conditions and limitations in section 3, each contributor grants you a non-exclusive, worldwide, royalty-free license under its licensed patents to make, have made, use, sell, offer for sale, import, and/or otherwise dispose of its contribution in the software or derivative works of the contribution in the software. + +3. Conditions and Limitations +(A) No Trademark License- This license does not grant you rights to use any contributors' name, logo, or trademarks. +(B) If you bring a patent claim against any contributor over patents that you claim are infringed by the software, your patent license from such contributor to the software ends automatically. +(C) If you distribute any portion of the software, you must retain all copyright, patent, trademark, and attribution notices that are present in the software. +(D) If you distribute any portion of the software in source code form, you may do so only under this license by including a complete copy of this license with your distribution. If you distribute any portion of the software in compiled or object code form, you may only do so under a license that complies with this license. +(E) The software is licensed "as-is." You bear the risk of using it. The contributors give no express warranties, guarantees or conditions. You may have additional consumer rights under your local laws which this license cannot change. To the extent permitted under your local laws, the contributors exclude the implied warranties of merchantability, fitness for a particular purpose and non-infringement. + +System.Text.Json, et. al (https://github.com/dotnet/runtime) +================ + +The MIT License (MIT) + +Copyright (c) .NET Foundation and Contributors + +All rights reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +dotnet/PInvoke (https://github.com/dotnet/pinvoke) +============== + +MIT License + +Copyright (c) .NET Foundation and Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +Cake Contrib (https://github.com/cake-contrib/graphics) +============ + +Creative Commons Attribution 4.0 International Public License +By exercising the Licensed Rights (defined below), You accept and agree to be bound by the terms and conditions of this Creative Commons Attribution 4.0 International Public License ("Public License"). To the extent this Public License may be interpreted as a contract, You are granted the Licensed Rights in consideration of Your acceptance of these terms and conditions, and the Licensor grants You such rights in consideration of benefits the Licensor receives from making the Licensed Material available under these terms and conditions. + +Section 1 – Definitions. + +Adapted Material means material subject to Copyright and Similar Rights that is derived from or based upon the Licensed Material and in which the Licensed Material is translated, altered, arranged, transformed, or otherwise modified in a manner requiring permission under the Copyright and Similar Rights held by the Licensor. For purposes of this Public License, where the Licensed Material is a musical work, performance, or sound recording, Adapted Material is always produced where the Licensed Material is synched in timed relation with a moving image. +Adapter's License means the license You apply to Your Copyright and Similar Rights in Your contributions to Adapted Material in accordance with the terms and conditions of this Public License. +Copyright and Similar Rights means copyright and/or similar rights closely related to copyright including, without limitation, performance, broadcast, sound recording, and Sui Generis Database Rights, without regard to how the rights are labeled or categorized. For purposes of this Public License, the rights specified in Section 2(b)(1)-(2) are not Copyright and Similar Rights. +Effective Technological Measures means those measures that, in the absence of proper authority, may not be circumvented under laws fulfilling obligations under Article 11 of the WIPO Copyright Treaty adopted on December 20, 1996, and/or similar international agreements. +Exceptions and Limitations means fair use, fair dealing, and/or any other exception or limitation to Copyright and Similar Rights that applies to Your use of the Licensed Material. +Licensed Material means the artistic or literary work, database, or other material to which the Licensor applied this Public License. +Licensed Rights means the rights granted to You subject to the terms and conditions of this Public License, which are limited to all Copyright and Similar Rights that apply to Your use of the Licensed Material and that the Licensor has authority to license. +Licensor means the individual(s) or entity(ies) granting rights under this Public License. +Share means to provide material to the public by any means or process that requires permission under the Licensed Rights, such as reproduction, public display, public performance, distribution, dissemination, communication, or importation, and to make material available to the public including in ways that members of the public may access the material from a place and at a time individually chosen by them. +Sui Generis Database Rights means rights other than copyright resulting from Directive 96/9/EC of the European Parliament and of the Council of 11 March 1996 on the legal protection of databases, as amended and/or succeeded, as well as other essentially equivalent rights anywhere in the world. +You means the individual or entity exercising the Licensed Rights under this Public License. Your has a corresponding meaning. +Section 2 – Scope. + +License grant. +Subject to the terms and conditions of this Public License, the Licensor hereby grants You a worldwide, royalty-free, non-sublicensable, non-exclusive, irrevocable license to exercise the Licensed Rights in the Licensed Material to: +reproduce and Share the Licensed Material, in whole or in part; and +produce, reproduce, and Share Adapted Material. +Exceptions and Limitations. For the avoidance of doubt, where Exceptions and Limitations apply to Your use, this Public License does not apply, and You do not need to comply with its terms and conditions. +Term. The term of this Public License is specified in Section 6(a). +Media and formats; technical modifications allowed. The Licensor authorizes You to exercise the Licensed Rights in all media and formats whether now known or hereafter created, and to make technical modifications necessary to do so. The Licensor waives and/or agrees not to assert any right or authority to forbid You from making technical modifications necessary to exercise the Licensed Rights, including technical modifications necessary to circumvent Effective Technological Measures. For purposes of this Public License, simply making modifications authorized by this Section 2(a)(4) never produces Adapted Material. +Downstream recipients. +Offer from the Licensor – Licensed Material. Every recipient of the Licensed Material automatically receives an offer from the Licensor to exercise the Licensed Rights under the terms and conditions of this Public License. +No downstream restrictions. You may not offer or impose any additional or different terms or conditions on, or apply any Effective Technological Measures to, the Licensed Material if doing so restricts exercise of the Licensed Rights by any recipient of the Licensed Material. +No endorsement. Nothing in this Public License constitutes or may be construed as permission to assert or imply that You are, or that Your use of the Licensed Material is, connected with, or sponsored, endorsed, or granted official status by, the Licensor or others designated to receive attribution as provided in Section 3(a)(1)(A)(i). +Other rights. + +Moral rights, such as the right of integrity, are not licensed under this Public License, nor are publicity, privacy, and/or other similar personality rights; however, to the extent possible, the Licensor waives and/or agrees not to assert any such rights held by the Licensor to the limited extent necessary to allow You to exercise the Licensed Rights, but not otherwise. +Patent and trademark rights are not licensed under this Public License. +To the extent possible, the Licensor waives any right to collect royalties from You for the exercise of the Licensed Rights, whether directly or through a collecting society under any voluntary or waivable statutory or compulsory licensing scheme. In all other cases the Licensor expressly reserves any right to collect such royalties. +Section 3 – License Conditions. + +Your exercise of the Licensed Rights is expressly made subject to the following conditions. + +Attribution. + +If You Share the Licensed Material (including in modified form), You must: + +retain the following if it is supplied by the Licensor with the Licensed Material: +identification of the creator(s) of the Licensed Material and any others designated to receive attribution, in any reasonable manner requested by the Licensor (including by pseudonym if designated); +a copyright notice; +a notice that refers to this Public License; +a notice that refers to the disclaimer of warranties; +a URI or hyperlink to the Licensed Material to the extent reasonably practicable; +indicate if You modified the Licensed Material and retain an indication of any previous modifications; and +indicate the Licensed Material is licensed under this Public License, and include the text of, or the URI or hyperlink to, this Public License. +You may satisfy the conditions in Section 3(a)(1) in any reasonable manner based on the medium, means, and context in which You Share the Licensed Material. For example, it may be reasonable to satisfy the conditions by providing a URI or hyperlink to a resource that includes the required information. +If requested by the Licensor, You must remove any of the information required by Section 3(a)(1)(A) to the extent reasonably practicable. +If You Share Adapted Material You produce, the Adapter's License You apply must not prevent recipients of the Adapted Material from complying with this Public License. +Section 4 – Sui Generis Database Rights. + +Where the Licensed Rights include Sui Generis Database Rights that apply to Your use of the Licensed Material: + +for the avoidance of doubt, Section 2(a)(1) grants You the right to extract, reuse, reproduce, and Share all or a substantial portion of the contents of the database; +if You include all or a substantial portion of the database contents in a database in which You have Sui Generis Database Rights, then the database in which You have Sui Generis Database Rights (but not its individual contents) is Adapted Material; and +You must comply with the conditions in Section 3(a) if You Share all or a substantial portion of the contents of the database. +For the avoidance of doubt, this Section 4 supplements and does not replace Your obligations under this Public License where the Licensed Rights include other Copyright and Similar Rights. +Section 5 – Disclaimer of Warranties and Limitation of Liability. + +Unless otherwise separately undertaken by the Licensor, to the extent possible, the Licensor offers the Licensed Material as-is and as-available, and makes no representations or warranties of any kind concerning the Licensed Material, whether express, implied, statutory, or other. This includes, without limitation, warranties of title, merchantability, fitness for a particular purpose, non-infringement, absence of latent or other defects, accuracy, or the presence or absence of errors, whether or not known or discoverable. Where disclaimers of warranties are not allowed in full or in part, this disclaimer may not apply to You. +To the extent possible, in no event will the Licensor be liable to You on any legal theory (including, without limitation, negligence) or otherwise for any direct, special, indirect, incidental, consequential, punitive, exemplary, or other losses, costs, expenses, or damages arising out of this Public License or use of the Licensed Material, even if the Licensor has been advised of the possibility of such losses, costs, expenses, or damages. Where a limitation of liability is not allowed in full or in part, this limitation may not apply to You. +The disclaimer of warranties and limitation of liability provided above shall be interpreted in a manner that, to the extent possible, most closely approximates an absolute disclaimer and waiver of all liability. +Section 6 – Term and Termination. + +This Public License applies for the term of the Copyright and Similar Rights licensed here. However, if You fail to comply with this Public License, then Your rights under this Public License terminate automatically. +Where Your right to use the Licensed Material has terminated under Section 6(a), it reinstates: + +automatically as of the date the violation is cured, provided it is cured within 30 days of Your discovery of the violation; or +upon express reinstatement by the Licensor. +For the avoidance of doubt, this Section 6(b) does not affect any right the Licensor may have to seek remedies for Your violations of this Public License. +For the avoidance of doubt, the Licensor may also offer the Licensed Material under separate terms or conditions or stop distributing the Licensed Material at any time; however, doing so will not terminate this Public License. +Sections 1, 5, 6, 7, and 8 survive termination of this Public License. +Section 7 – Other Terms and Conditions. + +The Licensor shall not be bound by any additional or different terms or conditions communicated by You unless expressly agreed. +Any arrangements, understandings, or agreements regarding the Licensed Material not stated herein are separate from and independent of the terms and conditions of this Public License. +Section 8 – Interpretation. + +For the avoidance of doubt, this Public License does not, and shall not be interpreted to, reduce, limit, restrict, or impose conditions on any use of the Licensed Material that could lawfully be made without permission under this Public License. +To the extent possible, if any provision of this Public License is deemed unenforceable, it shall be automatically reformed to the minimum extent necessary to make it enforceable. If the provision cannot be reformed, it shall be severed from this Public License without affecting the enforceability of the remaining terms and conditions. +No term or condition of this Public License will be waived and no failure to comply consented to unless expressly agreed to by the Licensor. +Nothing in this Public License constitutes or may be interpreted as a limitation upon, or waiver of, any privileges and immunities that apply to the Licensor or You, including from the legal processes of any jurisdiction or authority. diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 0757e8d2..7f82c288 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -28,6 +28,9 @@ + + + From 30c95ce6bfce68ed827ec86eace746cca6f3af8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 07:05:02 -0600 Subject: [PATCH 245/704] Bump Microsoft.NET.Test.Sdk from 16.9.4 to 16.10.0 (#101) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.9.4 to 16.10.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.9.4...v16.10.0) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 2b8eff73..38e325ac 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From 7c90eadbe31ccbf681c4f61a8002d93cef712ba5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 13:20:30 +0000 Subject: [PATCH 246/704] Bump Nerdbank.GitVersioning from 3.4.194 to 3.4.205 (#103) --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 1dc06021..3282b795 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -32,7 +32,7 @@ - + From fc1faae5f71bb2f7e4fa9cafef565617756b78d6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Jun 2021 13:31:36 +0000 Subject: [PATCH 247/704] Bump Microsoft.NETFramework.ReferenceAssemblies from 1.0.0 to 1.0.2 (#102) --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3282b795..d375bb2b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -30,7 +30,7 @@ - + From e9fbae8d46b9b8e28038cb9378682e24e54958a1 Mon Sep 17 00:00:00 2001 From: TrymPet Date: Thu, 3 Jun 2021 15:03:18 +0200 Subject: [PATCH 248/704] Fix spelling error Remove a duplicate word --- doc/public_vs_stable.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/public_vs_stable.md b/doc/public_vs_stable.md index 3c121400..058790e0 100644 --- a/doc/public_vs_stable.md +++ b/doc/public_vs_stable.md @@ -25,7 +25,7 @@ When a branch becomes stable, the `-prerelease` tag can be removed by adding a c To remove the `-prerelease`, the version.json file must be changed to remove it. Committing this change communicates to everyone looking at the repo that this software is stable. -The natural evolution of a product includes usually includes entering and exiting a `-prerelease` stage many times, but within a branded release (usually recognized by an intentional version number like "1.2") the progression usually transitions only one direction: from `-prerelease` to stable quality. +The natural evolution of a product usually includes entering and exiting a `-prerelease` stage many times, but within a branded release (usually recognized by an intentional version number like "1.2") the progression usually transitions only one direction: from `-prerelease` to stable quality. For example, an anticipated version 1.2 might first be released to the public as 1.2-beta before releasing as 1.2 (without the `-beta` suffix). If the product is undergoing significant changes that warrant downgrading the stability rating to pre-release quality, the version number tends to be incremented at the same time. So a 1.2 product's subsequent release might appear as 1.3-beta or 2.0-beta. From 49fd15d3c60f1a092e7beb4293a4478f2812323a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 12 Jun 2021 12:11:13 -0600 Subject: [PATCH 249/704] Build `v*.*` branches in CI --- azure-pipelines.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 46dee667..10d8b58c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -3,7 +3,7 @@ trigger: branches: include: - master - - 'v*' + - 'v*.*' paths: exclude: - doc From b7707b3d5544146176974418ea19c8390fa1ab3f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 12 Jun 2021 12:14:10 -0600 Subject: [PATCH 250/704] Remove references to empty folder --- .../NerdBank.GitVersioning.Tests.csproj | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 00c2a561..5819c885 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -51,7 +51,4 @@ - - - From ed2759eb6ae0362d607c70a167081d696c9968c0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 12 Jun 2021 12:38:33 -0600 Subject: [PATCH 251/704] Switch from 7z to zip for test archive This not only gets us able to address #125, but allows the test to run on .NET Core runtimes as well, since the 7z library we were using only ran on net461. The test from #125 is still broken though, on account of not regularly running. --- .../NerdBank.GitVersioning.Tests.csproj | 3 +- .../TestUtilities.cs | 30 +++--------------- .../repos/submodules.7z | Bin 9322 -> 0 bytes .../repos/submodules.zip | Bin 0 -> 36757 bytes 4 files changed, 6 insertions(+), 27 deletions(-) delete mode 100644 src/NerdBank.GitVersioning.Tests/repos/submodules.7z create mode 100644 src/NerdBank.GitVersioning.Tests/repos/submodules.zip diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 5819c885..9e4bd7ef 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -25,14 +25,13 @@ - + - diff --git a/src/NerdBank.GitVersioning.Tests/TestUtilities.cs b/src/NerdBank.GitVersioning.Tests/TestUtilities.cs index dac1daec..a67edbd1 100644 --- a/src/NerdBank.GitVersioning.Tests/TestUtilities.cs +++ b/src/NerdBank.GitVersioning.Tests/TestUtilities.cs @@ -1,7 +1,4 @@ -#if NET461 -using SevenZipNET; -#endif -using Validation; +using Validation; using System; using System.Collections.Generic; @@ -67,36 +64,19 @@ internal static void ExtractEmbeddedResource(string resourcePath, string extract internal static ExpandedRepo ExtractRepoArchive(string repoArchiveName) { -#if NET461 string archiveFilePath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); string expandedFolderPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); - ExtractEmbeddedResource($"repos.{repoArchiveName}.7z", archiveFilePath); + ExtractEmbeddedResource($"repos.{repoArchiveName}.zip", archiveFilePath); try { - for (int retryCount = 0; ; retryCount++) - { - try - { - var extractor = new SevenZipExtractor(archiveFilePath); - extractor.ExtractAll(expandedFolderPath); - return new ExpandedRepo(expandedFolderPath); - } - catch (System.ComponentModel.Win32Exception) when (retryCount < 2) - { - } - } + System.IO.Compression.ZipFile.ExtractToDirectory(archiveFilePath, expandedFolderPath); + return new ExpandedRepo(expandedFolderPath); } finally { - if (File.Exists(archiveFilePath)) - { - File.Delete(archiveFilePath); - } + File.Delete(archiveFilePath); } -#else - throw new PlatformNotSupportedException(); -#endif } internal class ExpandedRepo : IDisposable diff --git a/src/NerdBank.GitVersioning.Tests/repos/submodules.7z b/src/NerdBank.GitVersioning.Tests/repos/submodules.7z deleted file mode 100644 index be5ac1721c128b6140ae84689d82a5a81d7c4da5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9322 zcmV-wB$eAYdc3bE8~_9n&+DNlBme*a0000Z000000001T_^Z6&i&h;6T>v1NEI@NQ zmkF}|Z@ah*QRq~N zEVdq0hDtRdbkwWq8#&w)RnAw?nzKUbx?Hc|H-!}aR~nwLmO?9UnBvzsF6E_&Vja^sh%%{_v(X|lg|4%juH&AZQru@^QgxhQj>$np}|I5bdU`INAzLZ$#Xa4k%%wyY$cG&SvExls2DMI8sRTL&oLTNcOn=pg`&(>!3Hy_z z`tE45NjKV`jb zWZZ7+VEw4)U3sK+Gl2@~8L{-yzxIGvza!>ui`hz&0es4{El8CHsFgu1RPE&jwLad8 z78Xtolj&$5_w$v9(;(fqb+=&+d~od#hxbtiv%_%yg8*s^8O#`vT9$r`c8}n69>~PFUq(+xs3^<24r*;{GYKNEKpWJ+8@3mPW>s}h8SX-Ir;*~{Bk6j%NjK8k?O={dC zRzOI^iLm05MRGn4v@EX;-PYI%Wi z{xaIvh1KENm|BZh%BBWZNx=CUus7gB&KQiv8Y6oyYY!^r-1su_D<03{-*x-OqL#%; z4u9?x(3ACea|A+rbxcv-(#c}K|L{{5%;}F#_Lth>XLyYCQh!I3A-7*eLvwR|Tco89 zA-uI<0qANNCG=9urbnMmq6FREn!?`EF3VT4{PIc`OTSbTMKUBR)+&AKw72fjC`mEB z@-jSeWpD1^1l5 zGadk9Ze2_c^d~uc-684|Z;%rC=RnMv9<_#HrNc~9EMHiv5?nROiRlIEe8aIc)rP%n z@tZxbA@SlQ;(3cdV*hF0A8P;H&atcXhjE#&TRTybX@tYqqrn40LYn(k>Q#7=p_xyU zg0U(_UCI@5^MNYAE0{7>x}$1;536m_D9KXJGa0@W@0~oKyG~bbONBiDJ~R+qjtNMD zXq9bKb*1B!TUt&r!Bcr2_9C^oWJ{izbq`eOrsV`9;?f3!0e^UZ_ii84H!&;{N0$|B z9ppk+fR2y@UEQ%k;_bBk>RSXXY#d7yUWZh;O+)ayjd4V* z;P&u*u5puco6h}g@rR+#7KBiyP>Upgm^LB!8%^<>liEuc_F@I^72sA9d!PL+<@D6i zmEHo<1BEnZj`U)YCaQ0{CjZrN0pDz_#X=Swy+hVO54q*1oPDrsB*ttTyjJ-vR&sr1 zM_Rvrk1%c78_jF`fh0;X{jm${1Dg+0;%yQ>D^kbe>pM}I^LYJv%9+GsYfiQQcP)ZGHNia36%UCS(?*k8;hS1Q!Al5GlP-VGB zmwj{kVG0A%)NBt8Nen`-RZ45(45PugEK3VM4kjm35{JqZYt3C##K==Db6P5_bpY~I z^8gCS(0=9@PeNX`V{dZVnyMMlkEJJOY}Bi0H49Us&egL^RcE`Jf7~ZgIIj>=vfu z4E2uWKB6V5Dg_0fm73RWae?Vaq2Vw5F<-G6*UN`s9`HG5_#c4+>3JwAW5Dd1c|l?I zttmGVnQ)0kjO!@p$f3}7;5UM>SZEnbd0=fL zP}2Nj^)W0w8d5itm^4U%Z7&jn8o={1T!Y2HBZ`XkO?hePtQVR;HzLZFe+=#Bn;k+a zyv~bhYTVgp<@vRHSFUkzVwh>YeiCS%oPE8xcho2{d`3q0%SLoqPpbLlfR{C2xNw<_ z2lqDqo!yd;C%GQkz;j^6^S)5)N&ra<824(nCaG~@lt)w78v^N#{n?R z>sD6^HSbsSiQgs4OMwie*GGJ5Q&!1VvjZ28^TivV$0E5l^pIrjpacvENOivid^3!g zln;Xepi5Uv&+C~9NuJc@=FgPE-qKZ*P@!IB;ErH`V;=z%<(|ip$2{&YKtc3CJZSxg4A*pG5t9!?cgNx93W#Ozd zsHCh1&XM@8lTiru40b39N$t^C@rW8Ap;T>KWe=2GijL+KU>FrF;^Y#|D(qMvK?p1%CA~&g%z$L>KROV(j_Nm zmcpf0oS6u|TMK~eq!k^O)LCqf7A1GgafyC%@Adz3#w9S|AxcL(R_r7aN(&s*veVAK zE5QIn^k&_HdRj{4T!ez+oadH|dIN67nY|IMW|hJf3&YM<0F@Kt65gm zc+!OucCA*Zm5Em6MhnhEP6*M{@nx|nt#iOua2=HC@)OT6^Hqe5fV zEjJ3FCI5z<_@C@A0aGJRKNRTh)*tn(-FD*>$ljDzC50{_Zh@oq2KHh{d?E>}}_ zfOE{4V2Nu&W#ZF0TZ^yPTso5@Yf%bgPDtcN{Mu~T`+qJ1N%`~?Q=Q1WI<AEj6-7~8VWbAKlTKbp8h{rUu-FgQrNizM}bFz z3J!&38$R|PiS*xGu7vo1AzdmDT2#jiS#*vzw-y>$XT`Y2+58koH|yuEiJvurUvgLt znCKo8JpiG2ONRPkU&wYtjDH$2@|zwIQFwG&h>lc46xMw;_sD9M2$e3Pmuv ztvhop+VyKcNv8Y_j_#Y0G!5@keYoAUO`Oj_rrg2rH&&8=0aM3PRyxby7=u4k5ZdI+ zCwK?I{BoleEP0GfZ zfCYsKN1R)hP842;maM3OfFRE2e4YG+*dYhk%p78NwZLHjySIvEeHb+($UC3(Zq1eMJ{AJq`$-g37)5H-G-k1)ODAU`xe27dqiLgltEq zHUvayyNSffW9=|3v^2VCI<)&Y2$atNsYk=9k}&3vZNYtcjonz#>~KQnJ*fS2KU^Rx zK$3Uc@|pqtscWSg-+yb+_Q-5Sz#pk~cjjl|w6!mJH&$W2$m|XEwf3*90$%4r6WR}b zfnMUvlDxV*Iq#rV8h@#?jf-u%t>bQ&GnlV*>JW9Uhguv-i;uOS1B-gPV$wq0GGgd& z(09CWh!!v*-tY(RB0_K(+uFshG-VA4@=6XK3T+eQ{qna^I!u6njV`3sEDmH53AL%R z5a-HP*r2J^a1uJsY=0kbuOg?sp|`4KfQzP^{nhm6`@Ev(8vGP~R$wQ|@S!Y|IzNuW z?ZxHof?-(SsqE|zrBn)UqSct)t(O;cax`)RB!bSsF?)U^nr3BzZ>f-8zE7p5l zg=U3St-=jJwo3dy=4hY+{S%@IC)o9J!E5z=$<(Kh%tg&s?FWL6S8pcs(H8Zgft`-* zkXksV#S)Oe&_zRbFFsIa2-gfq%9<2YC`^1qCKc30ze}|JgZ@?qFg@&Sw>ox#&=3@x z73nyX4%w)gBe9WG=!$-oYM{HRler|y)cT-SP8nzfq6ey!-n>0zkHV@H`+h4ItK<`T zLF}$KmcmcD0CS^bVR>`lm#)A1kTq!rT(_b$6oV>=6aAuac_7;L(K@gQ-h&6HTxs`f zb@TB|^a@Vi9CHyl!(}<`F9aU4NJKYn`{d77NZ<~iHQEbh@(_S^9+TE|lL(vhFO;5agfTxk zLh|^QW5uR;$47ls>WVHEJfYbu@P&}LM-QY}+-P`91CK}hmBpIy*?ytF3Y$}(o*F6F zdH`{+&PT&BJ}s)+RxZmuX=T%Ri$O-`;xg#rN3Yw;-p>9C z4Z1*b4q#^(ofn^Sh}4p@HIn<4j1I%V0QyE93y9gZj)v}Y2?33yReamAeYX)2|%z~wQm+#x1< z>}PaPK~7$!hUk-f;z*h>31<9CZtkQ;`v&|fM*6x;Lb8AO3efoLu~%S| zB*_8$IrI8`6}icSJtx9z8)Kq#OtHUKw}+a$i~&Nhs}!${%N=?E1-+>FwOmV#G%ZW( zUaHGC1c$05m?goO=0CO}59+K*?HkwbpbNsU$+lY@d<1mGHQynic$xgtvou?|Cn+s} zxKRh0=z}zP0@08-IdTpb>j1iN5pW?E6HOhOyDsXCmaw>;_x$ZD7@9pXg7`TG=Dr36 zYD9N2S(P3jwT}UAha%^8sN$ezkGXe9vr|KP(Uk9L7HClbH7$|Kt=XjbC4>T_;P*CJ za4@Dmf?y&yN0CM55W;pf@fw4PXU{8l;XAkLj0JAFxHYE49Fd!+!UZ@%Hy{V%#t#u} zZ1aGa_3su1&swG74S_lDr8dY(f2wR4FXz1-qwO@t6sA?)j^Gxy>`2#C7> zRvssy_T%^V4vhT59@`#~_1K9|kAd+Z>Xn@GD(oM!^fNrzi!f)*2>h&kZLyIwFbG-n z1ZZ3^#g^~1G>Y(n){i!x7Tp5}KzhZ|bE8Uzrrvj;Eqv@Nku5WU=~mkFWIDv2g$HfP zQJ$611Uia=DNyPas?8I|m44j@q=yeVLi1&GsoQdzS_72o)BYN*YJ z#(_#zSCHyLy1`Wo*LG@YSpY77@Ia&br6>TW_0_*f3~mCRXb3I@lW;4jWaQ6tEG>u} z6<9URGhYmj;g8VPU1M7@d+gj1vOp)6i(LE-t$0M`jE!MV`Wj!VAwcRXL1 z&0FHhA+dnP-vph*c?+9xj1A{n{_01(K@;r=gsqZy((++C^D;bEMrRp ztJlYLBO!_nmE}@Hs}YS;r1sl2V3c&}j+hE4{*+#t_C%1wd|J7N z1C&0)eOm`YnTQs4F*KZ#$pl#t&DcWL={MW(B9o0_DCo8zr~mWx@35PWLT3KPAinuN zy+DtZL=){dlv0~!={c68ZQl}%X}xGDV<(lmT;S4IKjB*9d2}83PF4Y1Vf-?e$-wSr zrdQSc#xd>yHtMGNnpSv7BCAh$h&*s zYDnxnGz3Il4MQ6~E;&sNK^ym~pV}VoaLUh}`tGF-t4HsxdxhY2oH?JFu*kIM< z6*4X~C3t*lr$Mo(gOdHe_u9AK$t%S2ZyE=-oGws?ogQL3URmQ-=;UDr;HSPemnBFz z=vUS6c!o!aT|mi#n%}aG+la=dw%5Ciaca36u|gRImQ;wnyYlL`krBHmnw>d*AV_3^ zO`^M7G@Km~Y=A?=#jvZHw!7#xI(N^5YJfC`39{m3uF0CKm^d!6x@v$!2xxVhQ-zga8SQGHA)8JSQfMYE4jQi^T(KrM5lq{p>SLU`bk+1*ri02!(=t@Di1N4;RhqU1^w+t6v=Uk-!r@d#-mR^iUYO16_ri*Os z5#VsLt64dezp4>%)$x>wG3LC+XuD1l1VeEhfhS~w z$&&LSf@dtxa4EeoyZBCE&3)k5j4^!g_+~4q$H3#X6`D*KK3F&m_`@T+p6fZKppC`Y zcwy(+(Q?$*GS2RDOoTC0*wI+O^jvI>V1A|keM7a{CqS>Ql_9%=fY35s|1!D>=7A~5 zd=;^B_Q^8Wu|@9Je!S|@3t@u3DOn#^|GVvXv&~a-+vjU__P7lxz3A%)oIlDVW=&!_ z)!(>Ik<(3&;!$M6`};Fkxck7>PN6imYG^+fXG!$?I^AC~$$X02ALl57w635lA3LB9 zgSP_@F;wGRj@|QmU^r*LfUNfMfSXoSnIv71Ev!LzCJd{A_R;aN_xmu%-t7T<`s?R&j2yIXBoMV1%q zbXZpofA7u~smR}_Q+CGTGhESFfMnA7r(Ka7CW@pomT>t&#G9-w00000finlL57uln z==sKG+Kuz=(3*V;yCaGDcWi&`b4d<8flT(3G|BMZ@cp{7#T?bd%YcB4(MhHH9EZeq z-{NTxIpo}|?_xQ!Tjfuj@*~R@Fvl&y<&0x}uhx@&$nDU1q0`9UYR~~XTr39R>2?Qz z_FAo>4tX17rCh9jNZlT8IAWd+752yW0)MRabcbn!OZ-yOd1}HDL5YvOy zpPIS46j0)@Ce5`-4X^#;+Ah03Q2on5g)KQAG~x3Ask4K5%^~Z-RZ_OmMVk5T#P>9P zwiy*@S%T%jbDB}{Bpv7Sd^p0K*0FTrC(cClnA8S4E{C9^p|7o>&L)cu4M?s;TQQ$V zuH3U3rXkL28R3jhjDWqGJLQLrTnMAUGm2~0b0%E6?o0F=cSd&9al3@j_^sR+8(BgQ zTtmuYt<&=#Vj_>y1C-z zy;LtZaq6IU1We9072wlBBh`Lz6_mWZUZac|kNfttt5^lQN!WiHscFGpWFXjNH&BL- zzknX*Sb3sR!xq#WfXOC-`k){N`(v2%(wS?DWimeHdw9KT(SMO0Pxu28IyLXcSW@Kh zL`Ye4FQpMEO5QnJG?BLC$+g@2QdW(?ukF6cR#8$2IhTx%Xr^M^C!7L$mAeN*< zr6ZQzq8NJIx@X6jnLYv8wo;*_1FH{K|6uoyG0qCg? z=2oO=6FAur_L?>}cPWu5AtkDnNg8JI&YRix+M)y*v648fJ6bEYVloL~_Iu{cB&6L) zn#}w)kkny=GBC(;y&Rs4%Y5u5^Ha&q*|%)8>v9Lqm1ZtZTxpN~3AUX0KUbO&|8SHA z5Nw~7w^Fmz>66p&Xq`dT-d=AU&Z($o5wuA}@RcQwJjg5Wtm!Ar_og|8iT?o%tKgK@ z!=MY__hW}}smhF)1H)fH%wZZeAOu}A14l$iVt%!{}%I)qI?%My84uprQdLF`tc z!^Vm*2Rn}g3$WrRDs*Q{sijDvr)MIq{;EHA15xzO#jkEkY6?r|afyoc?ZP5c^~08$ zqJ=gPqDoiR%4u81StWAkzOxSSEBInD<^TeH(yZq`m7D9qIc0=_a655lkx2`X_d4su z$uVW(nL`bt2G_4VfrOx#QO-gN=iyz}_r_7V;dwr8%sJF=bwbFdx7`%ha>n}~S)p;g zhbH}ms`ky8MNW|M{b)PHe(Mur@fTRLsQ=TseHQj&AdlG*Ru8cQYX#ek$G3Rp682En zZUW4V>nK36B={0E%zkvu!wU)i4gLxFcx7y$zA}RrNX9V1tuEA=@pJilZUk}yTy+8J&01Nh%k?AA6D>GuB}|sNn(86P0fGJJ+peClXV*ORkHIRAfBE>ue_rNp1(eJND6ILYw?Vs`4JGyojWU{v^e>FS$tT#ywp zeqCjE^d>(QCLY>w3)N%_w=oVoq`B|f2Mpt}O3l@H4*-8_w1@(0i|Yt-mvmY;rtDj& zu(t4*szSb*d|S2%`iK7-`NUA_zwju6>>IU8T(nIkctNt?egGE+oeu#ChZq0{3jqKD YBLe{e1zi9z000c2ZVCaYPLpu}07>pN761SM diff --git a/src/NerdBank.GitVersioning.Tests/repos/submodules.zip b/src/NerdBank.GitVersioning.Tests/repos/submodules.zip new file mode 100644 index 0000000000000000000000000000000000000000..04488cb74cd4d3d35697205b16b2c96346408695 GIT binary patch literal 36757 zcmeIb2|QG98$UdDNp?w+HI;RYbu48qI|*4z&6pWkLbmK#%UVngeFXmGNdbeg|6@){)7a2Z z*X*#imaduM{=J9Js_RopvqZFgy6#hY+SYSmW6m9gebnmhVJG?TrhmFDoRpYeF+F&p zUJ$EEneJP+u=T661m=@w`OWQ{ZYkzf7N{2&)u(M2qDJRaXV7ahKG;babuOVaW?g~e zcE+TkguDl*?bssE=fyWTANN#3nP30X;6F{R;BJ6%ZM*tIZ793ogbf;KyCH-(63_rshg(Y?kOBkeYDjt8glZxlm&JbHReG1%Tm3UsI^GVn0 zLNZdW)J$AAb=XxIGGuIhOjwF9_PEi_!`x3=GiUQn4x4_5cqnmKS5F~^j!zx%P8T>> zfCHZ|7_5h#yMvpjgR6_-)3Oc0fSdO-ciz))plp5sqvx4o>rI$AH4!2?^WNg-goXOi zS&XmBdNa$yq^Pj8OHpsPj%(jO<^E&DgZG(A%~I}xaAFP~1zZ3Oc&sDB>1eBKxnprk z{J<|BQb(~UjEB@Ql!qtQeKFNwFz{;Ng2kW3a2|Dab@ITcI3Xv&h7rc!*Kq>*_zF1q zflKhL2n|tgZqB|yTH76!IObt5>47@t=8QEzJ75HKM#SV-4v}IJmOS>`Iy#@3s@1xy z49kD)^zNe_9yo4O5@xgT^@P!lsuvT1{R#VdDne$deQuReQ>T4pEiAqVcRSUJIzjDC ze<;2~CR{~LOHi4=R23ciQ=9QtvfIv7WxBu?)~lNg%Xb|d@@ATM>!D6-a64WYKm=aLc8AkQlLkFbn5)MpI_Sd(3s-ijdo9mLwP+@USj? zSe?oBo#S|5Wh&>6zCg7HDlMto3lY&zF?+VB+^cz|wb`@SY<-x$W-H4V%dSL$y9Wkd zKHVdmb-7oMzTO~j%UxuM_j={1t>tK8S`XTRs|*`nlmu+?{(ZV-_G_-otLZa-`)Zd` z84T(B?@w5!fp7*>!C+fRLu%)G?3jZmB%Fb!hg>`19Dy!Dj|EC}Y~>m50$QEIIY*q9!D2+#D@PXL>`{RJ)IMt6RUR` zx6tKjId=`SK5|n0;m`0Zn&C<2k#!Ww<_Dj{ZLTjIe{J(Nmie|Ed%SC*_N$7DH_U#Q zB%X3A-(W&T%3MzW7TxiSPqTw>=m>Rj+{l)U#1oM>?F2QF$9LOJWAA-w6F!5hY0G+0 zc>7M!9K(gNz}WePy9_}zwG^b;a-MPaeiV=;HNe43nk{aw9-b0jZWxp&_Mg!w(W1^2 zs>T>G^z-8IPMZ)JA37*sD^g2EG7i3VXtL2rYmkm^x1g9a1`94a*l(kLV^}*o9Ei?C%yUU#Hx_h;c zZ`qP$@c7-s^dIO8${9OwlhM}=++1FDp)DD!(@|ri{!ZbRuj5Nwq#h1`vtU*m_+2{Z z=U3WN{8PT|EgfkTx4{b!UI69{M_RIZ1B@bJ?)WEy$IKSzjeJcW9m5yq*v)*}MNe3g zM9v;zV-7ycJ}7%Rir2Z|5bN-5kMX?XQ$CT&k7h?+dbG|o#m`17_j}r zWwdBq-`S@njw-&IHn)m;JFjtMCJQB`%l~RS=f1z^iGQk{nPpTFTDLFrl+)&8ylL(niTK^m{N<#h-q2FxWS4l~3&q3O=4# z7z$?gdxwmb?oXqH)CE(?k>4@y)N&#%ij1vg&!7{&lBu|vqz7! zC7l&Ic&%%AD#^&=P@&wW#@H)@5iURYKRLYnm5_fU*!Z(v=e!YXQ+GW3y^)KphqGEW zUOw48R(K^`Dz;?ZL-f0BekX2}Yh2>*u%B#Y)e#vc)B!zamiy}xJA_Q#8=2@>N~Dc^ z?Pl%fn?GCa=N=u|C-CL7;4s&R`}_O%(q3(MVxld-&(=2eJaUV-XoU9WEjxo*b{rbB zzAoA{@;X^cHsD9_Spik+b~s!q&(+g!bHL|UKKEP=OTu2#U<<2<+B?o~d`^RTm!r1T zS-&ZD@3hvO3|Dmcob+JZMzg1^A?l8?kEx4HgZSvbV?CI5yAYfWqH$Fs=GG*K7ruBV-;)H}0heO!9K0~VB2a|g?x?rh1T z-CXd~ee}qu=f&3#@Vyc_(7kyfH1(C8uhMmWx7jleJNO@n4$>BkX^c>OeBjo8*E?_P zwWqDUhTEO%L|#ViNm6(6pET!+j?gb1+ag_bmv7XfD(Fmn+WNg5jqhjOb6X^BuS|)Z zmD*6vb5Bskw~%!z^`h%*HtK2}wo4;hf4NeOd=UvbuU>85c1A(tT(G7>xkaY3z6XDM zoYI1juuoa=&5jA3jF=#)@S^z*y9zTzCFYpE>^VEzKNu6UyXi3Lpr-CUQIaZMfYlPh|KVuK#J-~u=bq8&e=zc{+1I6XLNjOj&KVBg z0nzIp{rk%iiA=&hE;`>TE(Ot-6m8TRd$!5EV?Hx_&))lG1^iZfM|Jl)VzY0Uk8TJ> z7dIBSYHJHTQ4H6#W@dG(_!^y8bEf3hhJyQ-#qWD#B^^U$V&AA)HmLFN+9YB!GIsBn z++#A%&h)Z={5a=+SP+$t3;S>EaOM%V+x^@l@)!H{rIaH!K6KE#AmOm9K)<)~`9h!; zov&xpTosGkz9eZ;d(MJPw-3*I+J2wWp4QG#Dcxo*{+*?CM1EgQe|LnK8e)(!cZ87B2TrZUnv$cq|Wqt^IBIu5@EM*b4faM#$#OoL*EB^mAnmN-Tq!NOzgY6 zedT4UU*Mr$%h5elVQJ zGCVXe_2GL2p8$W(&?$`emCnI;#}4L{9XEB}lIF~r!p?rElUWpZw>{KCR`b~WPLX$w z(M=e=EPlDyVpumO6q1u2OKI_9nsMIs7yW(uG)GM*sbhUxFZ0A(u^Iia&|nI^y{|Y> zwA4L4*6sNL1h4x&H-X`cDpch=zA(CFy+luO)N~8ZoM=5mnZ^4sc@Mqf7qr*F>xujC z#%R49T%x4-FZXmlkb1eKn$;u#Rw zz2(J=19{ELkHlr{e_gf_O`Ng(K|`9*;)9ZD)pRh}0pJdHS#=ApQtntZ%7a+0x8oey4-u1OerBNF-=iM&vKzxoswGPs>_G+Q^HKQGv zQ+eMZ^fmwLTU^o>!}uE?i(WZYy|R>V6>&a3Ki#+U=kA72@+oHHN_SiIZFg>8@D%DT z?G}8FZi?GTMmHfuOJSaBdyot%30njAL>v5ieWcYoqjf#$xx zi7|*R1-r3Z#yr(?cTbUUF{fv*d&47phxeXh6SVT8=J|)iEif6>{wtze*nWPVq|*O}~o1 z;K%jObZ9tVm1V~sJK=nnHKjIgY}cJVPFkBewzJBA-fY`VQ|;2#4gXb>^IC9Y0TT%>fZ=b`#}j?DpOS9~5#Bhbl_ z+Qj7JS@!{FrE@cc4|Yp$5~s`d>5$;{b?LM5QXBT#pNeWu=Y0Lh&C|0{vP>JDa2E6W zVU=u`pu*P;;uq$QN*idQv;w}x_u6@nnsOra1sYujtNliJ7rsewv#|C$c(Vr6?4S{0 zu@*0IaeNVCyY8vX5wG*Ql1ai;N@~Zqo-)z(gIznAo^??;EQX6c;OBz~4UYcii{)?? z{j+yZJFd5~=1_dAEi5`R(LcdX<5+ZQ%wY8D8`^L7u>;bKt$YJ@Vf>LF#ommZa(9xd z)>V1*rRomcCq5kcsS=aVcUQ4C(C#qnzFYgozf95a?9ytI?Gq7XKnuK;X*%IUdFr*0 z>+4HG2h@DGscXD?@}Z=5x|pWuGEH{2tmB4<6Ovc-_*p}1rqB|3CnThvNmcsZ?{43h zSI3iL(oqZZVAZYoP8)0*cnQ(PRrTYTZQ%~Pmg0ce=+A11JrT**Nq{)`~2>V z#nA`RJWZ0x?KP5Xyd|^#yIT8{(Zj@|=m8s3AOE*U-0vK$j`}Dwzgh2{@&avV|Gke_ zq=Ir@1%7+(Z{AZEGOz4r$1217Y_fgJm+p{hm%(jeStSQCXK&Bm%y&}O*< zb*A!N*h%Zs5LfP;gGm${&whGz?qK#wVf(cETh-~l)*rpSw_AftoO7J|NAg`0$;Q!l zA4Y82Y%_xbrC&<5oJRy8^qeb?+oYEtn&wS!#J=E^tS&nBp!vHc^E@@JzU}@wCfctG zBWVSlUsYNTXPqyd)4ron-|F=qp)8YAJlWh8Q9d$P?6_;g=hkZPGw#kh;rlo)VMdO) zx4rf8c1L_UMJH7=+7UXuP&M)RW7DHP0i)P6COjI2xm$l-Z$L>K*8_I0fuWiFMr=~Y4;pdodVzq~QTF+9Qdwis4wml@osZwZ;v%4$$d91a>jFs9~xtq?IvJc({kt2+! z8 ze0XZYU{l>pt6U+Ax^CuiN?Fn zD2-O>2TG=o5zYaL)i7Z$<$)Hnl&4;~b8O=cbr{c&t(~_OKB;6bY`?Eprn8^2$76SP zooU`o^1}_C?@|wRkCvL+wEG9(9^!6tC(Q|5t_sq3@YLo&ZtPUk|4vC$emR-9Xty85 z)Tq7l{-@^pSz8%eqJ9}6#i-w0=&v0szoN10=f~LmPTPI#*Z|bcu;-%{v7`IP zha=y4>y9=(_Q?!;59c#;$|?1xpV+)nGiUx`bUANcnhrwE1g&u;H#>BoJTaE5wyB8f zq|dhxj&uPQ^6BnjLMOyy3*!+PBzS=N5wC`eiNsB zwfulsf%-t@aQcyn&$gq78{VMd z?AzE~6SKdNc`r9G87ifYe=v@CJN4@NhQ~MEFs0pF$NTTSsaBoOIuQ6kwJJZ%rzUCq z&D)c3r4=An`{9E&s;GI?Ue@<;;`Dlrs~0bS z@=NTg+M{&#x=C43&rM*$c<&uaAFc34-uRC2sd={JHAr#leXz;1rZZ`di};0uo*$-tukmv-j%J5i5z2WI$=+|+do z5*XTT`>-~G|Kq#$W_|l>H=U+RPGM&r;-$RVOT|8T-@et-ZTNQJZzrRpl(h~KyJ4iO ze&VC=sk-3ZJy6One@cO0_3f|@KxIgHM(Abo6uiAxX*gU~$r-3-{UkwDCz5LVnT24D zfVs<^gftOvj=Rj^-%oV!6xEJ=YJFE(CbO^mv70vTUHQ?djVhb&hlv(bs@vS9NPBMP z`+1{Yg?g_N^##oeug%V*O`8>tSQJfZc|2-UK5|(?$wYf<{RUex=GNl=y3FcRMzCvU zw{(@n^O`q12GlkGHnGB9?|`$bZ%zAhkiC)Su#-I7RZF#83mQZwm%t;rE)~(*?Z~P4 zuZ>0ZmGz7cr``FfM_+gNMs8^Q)+v0bl}oDaX`f0)^W~=vedzOgLw%6?aKW$I+8X9w!hV^!ll#Q8*j0TC>ydhM z$8ntix`{J;EeHTTkh`1er5V8Ud#5^ku)X9SSvi(dN;UAy2cs!4~Xg~e|1T?l_zVlI{vn$0EJ zF?!4KqoGLD6}y71r%lUuXO?A5oDM$9+;{xd1%=7Dn?0k}9}@2f>mwAO2iI!t-Vxq< z&L;cGlLsL(aLX;>+HSlW*m+welgklXqqJgZ?ApRjE$ikfo~0U(?A`fNzlSDyqiU$b zLw})^0yZWk^?MJ$)Au4Iv!(UY7w&I@%k7bS_AUw+3iqaLS=ShQ>mlWlzQ^2^^0D6V zaQ-IaP`MLxbV`L^8a<46aktZ7+0n|c#*^`Tk5lkPHzA2l^N&XQ9`{?G_F}C*=q@JF zjWXHw)pLF6!4G!Z%D;v_YkHx=HmX|Tkl=Glf+_D>S0gRFUC>45lA;K^RrIM`Z)%)p zQvUn&j=02>+&YfRh_ChQGJ9^>^r<@?5x5$AE$g<1v0Us{PMH#Hr&{I$>z8*FZ{!UT zw8#+(f+54F?|ckyt@3GYkCcXv)qMwuJs37s7uCFR7PB+ zX}(e|Dzk&@z7#hGYZ2<4UG2wsJ^T_(l5a`^Q!w`O4Sz(gP_0l*oMxtp;^6iL*Q}6* z&t)eC*X4<2XizA$xtC}?#{J^_Y?xRR9c|fnK>@yg;Z`kkL&N89x{StEw?7^}t2LT` z$TmPRbHe9W*29NmUq@%&&yJ?Wxb}?k?G8NjkhW2w^Fi=)qp}k>`X#>MMq^@`P+lfX z9=old-lqPd96Ie--{s(3-3PPaJ$%Vh8M$us4KrzCZx+zn<_IM9W+oVH6KP_TJpC*= zU;{oZ55hkzx3HFbPwRUBR3-f*Dz?z6a2EId1=9KxY|3IoUk2x#x9dNPFNriy`p`G_ zC1Ygr;t11Z3ztT#*G9%L0o9~OwKr!(#*%k>sVnV#RDX6~d84_zdOpTfw2tv`B1+8A zA*cIM{!ql(;!PWEOH~?%E?sil#>lBMG@Q7XC-q=>Ij4w_#nmTrX466!FDI5D-^XTX zi5{MhcwGj8pA(gIqhm(9+g-QD^AZ^ELP7CH!FeaFO~7y%MS` zoqnfjP@U85-~K}WsMPZ%-*b7YKPi=T_IV}_)E`&6<7#6wY$R~>%9pgQGV8we28Dgg z92Y)H?-%SX)Gs=Fw;2^LK>zrb%$97QZHnr{Dswx`X>@6>DVz4aWpQShN!ecS^5D{* zfjt-Nw-44!XpZsDxv>cwcx>_J(Bv>@2}(|-duoJ@*gvl=VD>>Q%cx+wwb)DgdsKq- z!~*QZ=s@ky2O|v>J>pfv!Rs5$c&?REA-ctHrufGiZ)y1Ebjns?kHpBlySueczx?$sCc^teAdN~-^@;X_yfO*vRS_G0MU7Uqx!G9B zC_1Mcx7nfVwlkfX$!aU3G+*wk;76BR%~1DbH#kk-wB2yJByNzUSo1|m%Gpl> zdi#^B+23S)gb)%w_`48w%dVnmkYQutM+JrKo)4)%7ataA_B_dU~2b zXDimvj=3XFF5@L(Q_RT9nIeSG%OM}tfeVb~R0SpVk*KN{z5;F|KWmQKGGG1Xru;** zV^ZdrRAkN0uTlYb#j1a8tGM90|Fylw!qxr*mAf8^)!dD%DD&e|H&%URe0apf~{kj?}>ggZ1%>H{PL1v8CbUxi0zq z(Nf+w9h*&EZ8s{MK6YK4ZKPBnUHruj)rpBRELYu=#^$VcaV8BbvCGL9cN}a)_iG7A z==G^PF!@N~Bp14`w~a0=Os9w?BVdhrXY#-7lo-8cET$TRux`_^(SS^L;#oJEClsD9Ig~~O_?uwk-TKytN%xb{L>PWVn`)9?D zaf(}e4A}M@%Swj}`!`FzO3zNpDSh-j6Y=uF@2;y2UzrN1oo>#Wq5V7#c&110Qs2Y% zb@xHeImbMtMc#$kg1)+1$#J)hc6@EuE2l5=BoFHC8$q}&RNzdF&zVr^o(qbW(A!e5 zZyg)8U9mZmCrADCF{9W?E@uI6N6fQp6pUAn49ZqdrW=2$3mA*GIl<~Y{Q0{+>T#ju z>|_0wt_A0qs2!;ZUPZrXiK_znD{M&AajwhWV4qNJ5hwwArWih8}JD%lSDQXOY~ktLt_Chg7X{y2Mugioi2YSI~US$lhr+U>mL zU@5||t-av3L-rmz?=<=S8B^!)mb@~roYNEEW4Gq@GMSs_-WUd)fBdN{g{F>_TV#_+}!qCAR*_ zx)@O!A?^9u(;lg3Cc>WI44?e8n0YXmB9M6ioyDKU7&yDyL*L?q$`S(#$ASW&r6Z7` zz#>Y>P<%U3F_0490tA31yltMtzbovr*2i%$#|haRd-s9 zDw9$alWUWhnt@2P(iKLd^V^fg`w(oN$k-pJT$=MODtl=rG;aIfIIcLKc+HLNJjaub zoLfwUT;9q*X1IIKF3!6*D`!20ZIb>r1FE_J>b5eK-ku3ZZWrr`(u@W`2{OSm;U{F+ znRK?^|Dz6FN8`y7Yju;QrMU{nZme^h99ZK=nl1SIe9K31tz;2C6Jtb&C0`G5RBo z5g1RX#%R@9<*(Z4uiEIZ+US2xZ3GT)sM=`p6~XeN0UX|cbw_`7NB=vzBQUk0x}!B$ zuD=STzY3(k3Z%aZq`wNJzY3(k3Z(yED3HMQAF4oF{kg_pEz90QN|22Kmc3`GzF)6}=-xc`{9N?E7 zmc1$@DwU3^gG!|r@3Bs4e{ zct?XPE5)>v!(x>8x%)j9x)|{B#hCy1Zxdq4uYbebTCB|YqEoJ3 zi^xG#&RD<9i*x%jEHsAW?0LxU)t8yX8zbsH>WX)tqA6!_S1iBc*(0qC9MAu5M*A zjXJ`Z(@@yqXKh;Eaj|`KP3)!&udVDGM0_4)f0j6L4W3f!t5(2mmrGSG=!|h~{aA_n;9x02JR*(bI0f9oJ6%g_mSsW6B#3}*_5wFh# z=<>&F-?KVPeUaqP+upG?!@1LvGS+k0+a7r%++xy9`)&0mL2CM{^5W%OuwF|!5g zNBvh(lSe|L1`Z=>ib1|V$PwT=q$~;zMt!?lK@-My>yA-8#3@% zBS(PivSA|Ry z&}=7sU6mT{ib>>CdchPpnT!6bXkz3c(FB<=WPB_Gt3dErg9&h*JVIU?A%n1!mQ_%c zmz9x~!(wF67_ zktLKQ2RI8JYdLHuC5y!=piv4y{H0|va?*;5@+i0>PF@jkTL$nIEsc;?MB1$$dLQ}O zj&Vb->q!3-PS?cF+&TVE*Z8v*40E4-arY>B#jwWQj)lg49-va5op%mY8H2|fRDkP{ z7%T#bMk6rN7%=p}bdErxus|xIfb>CNfr(#E1_@*lA(M{)pVTX*_`G_&7e8#VRNfNT zXngtqUtQ^jvU9@s6oCP2*f)zf_O z1DM372z}BZb$1f)X?ZJc0YoN89B3uEbh>=!6DhQ z2CE4q48;%59@5^fbxp5a;$2&1HS(;D4mv)E+Y%A=z-5juq>f!U&Cu6!-s9Pa3C9CL zuL3CKYQ-xG6=ilCOBE~bJ~NaWaPUIn(Dk&*Lm85voxQ6*=A|j~!KmnwhnAwUe8UV` zR1~ElOA6RJ*TAyT9Eb>bkVOS(EiEgHRgjZYL;?382(+vn4uJp`KD3Ms3MY?70!um? zE(ez-E+jXP{IiDtYfu$ynfP#XWQ%mi+wJ5sHD9H(+aMc|-2!|3gI$ zxaST?n#CWoA%unA$%C!W8eDLW2ik)NncF~X8AUW)2FNcQ91E0>;B6`nDThShdTu*Z2WQFf$y`ZAtlK23 z?9lw0b}S*Z?ffMLS;p3vS7UU?3OASvj+NN!iF*2W(T*hYoIK*J&l%#;3wQRcNrShX zHhW4_KC@lpgjT4kpH@ZxjM$G8>Mstf$06(PHkf*3ad*p9TL-$c&Cnd*q|vq1jsKc% zB&8kL8d}BMqqBhhO}Yr^7>Mf_R9K#HK{6c@MetyCH;Un7_nJ#m+?L)jfAJeL3qLm13$*cz^B0_9X(uK{5LT0^9%m-H-bw1f(S`D!3_+7OE#ncaCV3H zR74w$fQ>aRNK48PEKpGH#=rR?-=s-{|5OZM2nG%T@CP3u27ECJgHZs^vZS5LI}-Mc z!W!rQ{r2G=ifcaZ__K*VXm*Jn>DTZ6h}MAVO!W?LZKfO#}u{Y5gD!2q0k3l73_!3KCE84+vpX zD%AMG4L>}Cm=~)X2geq42Pn&8)WPt;flS6Tfb0T=BH;WxIcx#AyU91T^TDJ6;mB)4&`B;YYsh4hnZ$l>pbCOMs)z zT^SC#Cyq3n`gEjlfEteM+uKmY4h#X2s`nJ0;A)7_U1Ox-OaP`)D8a>VQ2p~MFeutg z3;}H?eJmc0>&eRepqp4WlY|oo%!td-ARAerSi2~mGX-FM zT!uxmvjB=V{g{B}a5QyIG^mD=G*KjgS4m`O&~K_i;Y`K}aE^Kx@NmRw4?3rU;|?m) z6DA2{8L-5V!mTXSgQ5~gd)0wVJgW9?!hE+ws4uzubuwpS|dh_=BAFbp=^JEWS zR1u1^L%Rq;%P%4XjR;EMM5qmx-(+l92&>p>9S ze{z78K1BlU3p6mk5!+xgi}Y%)pcEWrWBp zL|+plJPZRzAfC&_1bKxBa)DNeq9j~2R)bk8Y#^Vzgy!DtUP2si#TMbQi+3)kNa!SA#LC#vN|H3#Gk^$a#bA?tjR4xo51R^9T`_cwUYVtvv-v z@cGqN!C$ostv^9JcM<0>C?>i37P_=N(IUent4D8g@aTa>7nd?&h9sVsP{=1@jzwnR z0z9U@0?M+=R4|Lcg=l@Xc^F!m@+_k811Q{kRz_K&MkRttqW@b;zsbSKs@3=%cK9(! zL|KgzRA)$fJ0iW8j1nGY`C8d)Oo~KAT&s(?7lQ|O(eqW1@K0W$)0yK50@RGM2Y!Hm z;2@mWg5o2AV$@lg6yyo=N`Tf;guWsNB+O*cC~jK>1QSE|-vP<1T0|*sui#OLIIv8pNJu=?J_xMnnho=wY1AHym2cNs-G|6YOr5YIo za$X$>P`E;|rr-oDBB@Pw&~ZYjk;(P5#JL%`$%f^viS=h{TBt|HVqdm^^ElBX;(4tw zld?afziOBP@hTLH-jcxnP!FL?S7J{CRMn)?SSb63HL?CoC=2ySZGcr6WKZ;nc>Z(t zfd;Fx2gIyUEFyciUu&}`mC8cdSFDNkhw388J-RZC1J9o55%K)z>~9*b${rA`2%XS3DxdO6f!y(?D5)p~#wPHw`i<7G$67MviJw}Wrkr(m27Mc)Ak-yVyOD{JM2(h6A zq6$;+v(!swg6@VCVX2cy<=Vtf0`HU#uYmAp;%%rONg>7m)DW@>CfeU z01|5`g7?OJ{EON#c|xDA#FSjN4P`2JU>Vat7I8!UF!`KE;s?>6KWEyt+z&u?4Mli4 zS%^pYb!cs-q)KimQ%cKaO#fKd4fUg^k<<^OKTxLR8d#zqVD=6z_XChrLlJ6AjE;b{ z3(@k?Erc0?fIt|h?Kuw zLzxDxfbgH+0leuZ^@HdSl<9K0BO6H_G_>3gvbz8M-afpvjL4CA{&Ni0gUg~xR_zlp zh;;$+ycPxn2@iE523g%LAWqOw5^WOCP}^(gy#tAD@@ku?Ss`kDNf8Kh8HhkCbth&6 zKQNc2t$;vYW6%3F;>Q;ehj@lES>D^E>XK;^9J1=~PeQePDPK}Vfz!Ugp?|vCov53K zP7qO#2#Txt1j2A3o}mQD)%CZnF81*Rq#ludEyIHqNJBpfwWYhk}Cg+{sMwCSOwlD zSYtzd4c=1?L#PeFd(v$f56>pcI{fAmM*z{)}lkOuRdJIOG+m?J+!CDB!*bsbQ ziV5k411N$i9s#;}0BV1E%vZ8cz8L{(KNYaQnsuRssr_J<*y|8P+QhSoJ`F8E9(Ek~ OuK*5%^#V3vu>T8(dc`yV literal 0 HcmV?d00001 From daa03038aca727597a9f0b0b99c4c20cd6c9c5f9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 12 Jun 2021 13:12:34 -0600 Subject: [PATCH 252/704] Fix up submodule handling in managed git Fixes #125 by enabling the test that now passes. --- src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 937b0575..4f10abf1 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -49,19 +49,17 @@ public void NotRepo() Assert.Equal(0, oracle.VersionHeight); } - [Fact(Skip = "Unstable test. See issue #125")] + [Fact] public void Submodule_RecognizedWithCorrectVersion() { using (var expandedRepo = TestUtilities.ExtractRepoArchive("submodules")) { - this.Context = this.CreateGitContext(expandedRepo.RepoPath); - - this.Context.RepoRelativeProjectDirectory = "a"; + this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath, "a")); var oracleA = new VersionOracle(this.Context); Assert.Equal("1.3.1", oracleA.SimpleVersion.ToString()); Assert.Equal("e238b03e75", oracleA.GitCommitIdShort); - this.Context.RepoRelativeProjectDirectory = Path.Combine("b", "projB"); + this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath, "b", "projB")); var oracleB = new VersionOracle(this.Context); Assert.Equal("2.5.2", oracleB.SimpleVersion.ToString()); Assert.Equal("3ea7f010c3", oracleB.GitCommitIdShort); From e9b28de1c02aa76a442fbe44440e35803532d1e9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 12 Jun 2021 12:53:48 -0600 Subject: [PATCH 253/704] Add repro test for #602 --- .../GitContextTests.cs | 13 ++++++++++++- .../repos/PackedHeadRef.zip | Bin 0 -> 18594 bytes 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 src/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip diff --git a/src/NerdBank.GitVersioning.Tests/GitContextTests.cs b/src/NerdBank.GitVersioning.Tests/GitContextTests.cs index 05c4e8d9..81cf1a83 100644 --- a/src/NerdBank.GitVersioning.Tests/GitContextTests.cs +++ b/src/NerdBank.GitVersioning.Tests/GitContextTests.cs @@ -162,4 +162,15 @@ public void SelectDirectory_SubDir() Assert.Equal("sub", this.Context.RepoRelativeProjectDirectory); Assert.Equal(absolutePath, this.Context.AbsoluteProjectDirectory); } -} + + [Fact] + public void GetVersion_PackedHead() + { + using var expandedRepo = TestUtilities.ExtractRepoArchive("PackedHeadRef"); + this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath)); + var oracle = new VersionOracle(this.Context); + Assert.Equal("1.0.1", oracle.SimpleVersion.ToString()); + this.Context.TrySelectCommit("HEAD"); + Assert.Equal("1.0.1", oracle.SimpleVersion.ToString()); + } +} \ No newline at end of file diff --git a/src/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip b/src/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip new file mode 100644 index 0000000000000000000000000000000000000000..e1712d22aaa5d81cbf866af909977a2cabec8753 GIT binary patch literal 18594 zcmc(Hby$^66E`T`oq~XLcSxs5cXxM#AYD=t(jXxvNJ@7%64KpDH%O!30Uq>#&-;Gw z_t$s4_AGm@z2`SGyF0V@?5r~4kHOGDu0Pb~y>d5y{PP74sA-K&9q42LU0`m0Bm#6< zn&KEn1hlRT>RlH>X-UbK3fjU#FBK%^U%a$3buiVnAkeqAv@~^qxqki{0ty5U@cg;M z_K7y2s(5?dq%m*lBdc3Uv{*6 z)Jm{U}&#zXKLeMYHcO?r5OI2nWhwq2Jy~Ez0Dv{ zxcev*@3!A;d(-|{S1R3B;x{=laN&YgP|1l3@{LOmTEX8Eu6$#6xonRv-CZP*Vq zd#$<~&58&s2#RWp3iAv7>3prDa(x43bU>%;0)5x{x|^M$(Q^X8mpz?{p{{{Fou#g+ z)o=ZR+~^n3{rBg$eod^c&Fyan^3Oo{OP@lcgMxs}0SW=&ksFR~JL=llSh(2eI_R6w zSlS!Y+Ur`{SQsis%u2P=!};$XqLJp2B4wghii++b)bWi~OO{`E>2O71iF0eK$>u{3gi5RAdysv zK^kn9xDA?RwdNCgYzw_dDPi_!!xjE4vI4?p3kqR7N5RYn5kbzKAfVew+}4>X68MQp@4(1j`wO zU#3S4VGl8z4+B44;P%AnS3uv%VTRS*QTS`w#`|+>{j>+^2%t`{#~>h2?yK~6EdZ(0 zT~5<_m>$jD%A=jIKvbP2wCC9nC48_BorK;jYF1R#4DlEWXDMFCi?dw~G6yR9Z4xo7 zes1mKQ{hOlmLy>Ir z!8ISBtiSRj`Gv4It*%5LhDMkGu?f^rNDm!#JUqpk zJbS0^MpwHm#Y^9}MlhRxo76&!U3_ZOFBJvI11nf+SmfBB%L!oY!3l6Ejnw6;7xhy6 z9tV-idk?R>_HakrX7e5iH? z{fVD|1mg$$yH%vB$gFg(F=1r;zH)_>*2mHVx)~ftABZ^4^g%L-0(xJby1Wd2n}aD@ z%b&|K0wcJeLAdgKhjj|6N|FtYU>50c0`oi@Zis;?+MgY&aMo4mYYFNNvuktnoO5dB5uZ_WYt2#sj<&^!{v-sgBoQga84dLjeIH zzCT-x>@BSUM%3Dl=GFBowA8iwXAu^ttQVp%p#6lGw#{b)h3l=lWLUs?r9VZ8;UtuPx|K2v4yKXOF#~J7`Re#Mg(rq>?3?_j1GV_vS*v`I&9~GuU7lLD8JUUG zd)sr%xUGvBYB`4)P8ZA?$^<<7hMLeSCRg|tx(3@#rV%|s)r(S1;yc0ZkyL2Av`Kl} z^aI9qNb(9@D?>DirlgJy!Fn!;N}^!jBJk8H9vBeO^MVu8~RLJWV5HKz?yguH*j!} z04-I?p|Ffc#+_bN4FZP$7_t~Klzx-H2PUKgS}s6N-h?H}{?bs0wN$(ya~Og=l>@u{ ztic0PTDvgK6@_Uq05$lM*qLWPwepqd_0mZa9@m}<-$ECcMD~AzRQ=*wX z?oNkeQDjY0{Q`{VkKgOJ*OlYK%GPBEy2QCV;!w6IU|Vubd$&f*xwu(XicxrRD_49n zw{Vp*~5-{rT@aX+1oR%M(X-S2HS3yQl;#+X6&zKu=P6Ub8=Gc>Ub0 zvO+GW3niIw`AG^QnvQ$^+39|oQ97y_SHn^$B}P=V0pcL5Jo|?zLxJ2up>#<%;+Gl1 zX>m@gu3u3NPlQg~Fx1kvNkt|;+KJ+8oM|Z3I5)1hmJj^Q+b!#R(`z~P-b+uKN^dR2 zSy(mwRCs~5fG%OKqFdNGjdZcU{kCQ<>$$|J6kspp<_v{;gD zF}au{3pY(GI49AACsI7tBd6htjb7sY)rY$|&EUcvjY$L`!#Fu+f z)85cpL@OybujN%&#EY+!uX&syeZ7Z#aR{p%v&XG;`<%0Vz43eN4h7jc(A_V#i9aaJ z%X>(G>nx!rR(e!P2xlpOM!~a?wlbwWrOfKKG{xO=3Z;t&S3WG$4_hTlY@N+wR;n2k z_asoHQ_C0AWi0dhWvaUONIktUQ}gu4*KiP=DJredGgPbPJ|bxGc)8GWtD-gL?1(((k)>-HvV7xlIM)>T3cX5GoZciB7qO>Ip;) z62EAV30dytRL*O?_i=bXGdFO44$h8T_H9MlX<=o+qYxp|Jx(bJVheHBu6bl^+CjWO`@*NL_q{X4ShSm_``gN`Ex0g;C%Ww8 zdq-Omh=XUv*tXww;ry5&9&;Tie;M*TT`b|6i536pF>bKfD$TZ%s=?SepXkSiF!IGS z<%z<%@CQU#ny#OtQYSbHte*DB7a7g=HmK9PLcgxQvksNy?tQOVGRJ-Yt@c&Y@#dpO ztj#5lio_#dlW#+=kwM{Ij<7A%G%*qCO!10tQvJ`^wLP;u`?o;@jpi4p=`<5%R5Hr< z$dz9E8@B}Gd*m+fdDoJ>4$PfLm&x$;QGXHt0wV`Cl&7j9+Qy z{<1Ihv@P8&N&4|RBh_*;*@6!ppV#Jy7*sozLD2XL!Rpt9e`7*fx39se299>XK!ro) zWmq)C@bn92*XQE36?mry;3#P-1IluaOD2;Paspanj*FKz&M&HP^H8E3iTBZep+$su zp0N*fD_3D)b=q$30fGgnWZ{iw&PK83&UA`{_Gnt}kXu^v$H?z>1EYkLP8 zM;ilO2g84SBTXMaf)5{@|Ke5B5{0@qlQSe8J>NTMM$0L^y<^t363?hzmN*ac@=6kx zPtEl{VRhXhpXrM}%Z9Kg5sF2|L=d`Ym?nFO@ z%XNX8h||mV@D-W*X-K;tl4kySZimq@+dK{hk9kS;N#h8PX>VCpe^SGJ83vjp9zg*% zg*kukvu*4QY5wfBfA6!^0sCwu;a~N^A-IG{Rp^bPqMspI7c!%!h>B?jG7*tnjUy`v zJa&7zJ5xscK8BjMHs|-kSVKD;>0?6?t|Hnf>m!SHq?m01-but8h zRRZ0HZirq~sB-{y?|W9qIJ>s&^)CJ@Y%FAhTLX_!x>c!O)+P`o!p<&Lfk~xKVq?QU zSIi~YG@G3!FJnb61G7dB*|ire)sN7g15>n$XP2n&!?$T~2Naim-gGl&tw^2?iRlUj zJ5SzXbN#UiVcRE9q9oeaS`sex-g73C8|?-cN!VD;jp(Vs)g|bzes?wZQ&|Z6+(*~4 zbgYEPH~Z`J+3VMz`|_?>2UZ~OYjL-f5$+9OTWt>5Fg@5>Uu*Gpd;O0FEfoM;Yd$2m zFwgeL^jI-l0T(bi3K(I9Ts|K$E)W6C`R6=(^9i-~Lj-Ns#>ZR4luON#+tc9*larjT zjOy5&u!>Hx$%8E@yg45W5-3+$(O|5nLnTpk@)U?sMGG|Ieip^Uj5CvpjL9pg zgmD{ z6*S&Tj3ybam@A*l=^C+tGV3!C8;O8{fhQL$F{e<13>tJ&&4JqB?d!1I30!a z6!T>=2v;9Cy|pR`5*dA*8<#1mI)p?qQ)RlGl5R{|dEP9{HR^IML9alm;NmIdvh^%{ zo33=o0J|o-?3E^p;DipXRh)ySo7&tQ%$GI}nS}||dCIkFv2U`a%cilB5g7uy67x@T zEKSFBo}SPQDEE)PY^8TcbE81wDPh&(YoWHpym)7F?2)+t7}LSg{incE?3_QJWr5zh zn_xV3PB+x#hM)W9+n-O5l>@)iT>23q)uj#9LZnEL4knVQBhZ(RfuknRORqDvnpkd2 zNW93R{3e`5H{$)tLW0rRaGV<9s4234e>C@zM{e{B9O_SANaTXn($u6OA;@#JU7cei;Jvk(=#PjC6g?Qq-Yq4t@HGU55o7TGbd@K9?TS@arzLt~SS!>iBWyddy zASg&H7d~+4NqF*a6hOB!CR<@jkw-95uXfaE*2oXX1s37eQE5Y`@QjE$Q_-^8KtIwl z!X7lm{#EH^>dW-bD7tVoZ@8QQPNgQTJZMHeQMieIeLEa!Uk}>8KdKOfy+ze2o+S|9)m_yJIe9$0d~`n5E)Gk&m&-NTEm0PzN) zSMKejw2Y(2a|I^eMCR}6BlM?G%*1^}*`yj9%210Ioxjy`#!5?W3byt~e{53+p>Yy> z*4%#jn8!F33}s(@@Tn2t-o9$Az!pb;lWHbxT$Q^F$P^}2X#2v9+$83Dz9tBG`$K{Zz zc${;?_Cmc#4s1dU1=!%#f#vm!<%L1Pcl-8f|aodRM4RpR|v+m${U9Le@dQ^b);%E$sx4Up$qM#h{n|Ss)U-Qs2 zPDS3~k1^iSWYradB}ED6&6OH7fmWGg8iVHv!6M*I!qWUD2wS4yW?9)K-w#0f(+urq zCY!$b!uj%M{XhayR_`S4vp0z`)q}CH0I8s|S4U0qAckzAbe_uj8cD3*cge=d>9dq# zvoLnQ!Px5?>%Kba4m7E4Ucs0Xs=VvEL8nQx_Q$eyj=og~NZiTu&*3_R;gtFw zv|t(|Z?R%np2*YbZCqs|{t6d9vP|asOrj>c*Sw4|E%d`o9g`NZTZ75L!e{;e5<$DUemRXm0=6x%gK4f$Q-WJNkG< zT3CIYWcsQPq*kKI{`X^j{!ZLY{3bM+3R@^HRj7BHMZxPXgb>-bRpfqwoMnmlY%b>0 z)tbM)G3vbLQ2?n@Q@X5Te(d*Cuz7H6bMi7YX?)&@ne%-z6zEIGEg7Zg=fAv-I-?Y) zyM>pX-zv$fGRUe>9D4_^)7E@IFMKCUNV+y0*!?YVPS7JdM@64aw;By~j3?z73Ht)P z0}4fU$63&vOmZ^iV_Y~ks#c5A3>KJmYn~v_=MFjS#fBmSwV$U*?oB`IK$yu79_>ZU z>h06LE)d$-C;h3~mQ2)Z?dSFEX~(_})e4TksTFyH1YAY-V2*^dL;?< zeV(I~3Ku(cb*1jBeSQw2gv(WpnXX2cg5^?18YeUmP{# z3f1Yj4lkn9<)n@$)#Mt-?9#srU`=M1%RQxF%X}Zq!`v|>U?e7J5~Ch0&;er!Pot<+ zphMhw23d|3l@l8s9IUffnoq5&BCV);a3zr!S)lYatv&Wz+|0o`X{Gr@jsnXWWx3vT z1;cP4?IWMr^aydXoh_qW@{u<*BLX3EYM=VRvsu^$qk^JL&GgIBvTEt&R)@ZdV6AP0 z4+$ogv~W>Um*otx=)KW=O4Ig6EQ;E^Hmgrf=_hN-#TrflvZ>4y;fW@5Ayv%18YNu8 z(-%tRF0zg(5O}6KqADn&CFEXC)&4t3o7=6R7+X#=!k5%o7qOabo){=y%CV=oxuj2eufd?b3p|lKCQbW@?-cx!r%I9K}O9 zB+@?m43^adCK6(|@v(wtEvt+OTq!%jz$G%150boJ@G0d>$fnV}(x{BgSNnQCMU7Q5 zfdcP8Ma7C_Lff5)S`vH__STmbN{^fvwMr$Ikw@nxi;<;(+ma62!SOllJlQ9JS~{n^ zsQRR_oy8UuK%Tk@>$@r%zZ@nGh>PK_p6njMBWIZlD~Any`UOQZoVgiD9_SxGK+L-U zjpY-b?;R4W0s4Iu4B915dG|7_2qWh?1qgV7tT~dEtEwVOP{h$#$TmU!{J!1+Ive7| z24`@Ya|X)ub2c4XqE8s}ATqfFN%`xvi89U6LEGJ7ogX}xMM7gO$_3t2puK_#dlHCO zkj*(4zo0Ce^7d_dfmwv5F~*+vhwqvQ;<=O+yDE#b3BKK?_WP`3#(OknUlGp{hNl{K za|S#!<~)u^IW@YiA_=VT&ENBdKoVoB^wK9Q0R zgP60~jj7~{w|8r-;Pzy~;o$5IT13VdgmV1a{Hu>6NrOMugMEcH+I$~wU03^K z%_y=gq-0)xfh#IcWG(CL`|CQ4R1yg9{G~`NR=C=PM%h5qo;Um+7UYaZmGmDe2(i1| z316-ea~I0Fn0&WUM_PtIetfjQ(_0QckmpBU0v9A#7a17Sq{b7?!G=U*Pa_|~kjqTG zG-`6r*|i&X#uOLHG}UDe>%!wyzEx<7?Qj&>2%pPR8p&7x7CR< z6#4b0h(zEAg8_C>oX7NV`x((JFVdGg0wns|_Do%iV`!yk~28W6yE5g*?J|^pk=SBKfHAddPH+B zEc*!T;HH#SAZ*diPn3>{v4Qs3!Usr9ukC*8fgph{sRY$P`Id+HV{!DaaN zRl2;@$T5x_`6CcV_$k`2P@Wli!d9?ptJvxN67Z+*SUal&(VpfZf~sSd`k^TeXx8SH6mg>2K1Q; z=ZVQRA|Evssp6+b9W_>V8{5>(@lM-S{8cy@PBd)C3GlA%3p4QHVHt!N7v(vU7egjr z*$Q1ma`5KfUc#dD>Rqv$O(~EfW^(K1Ec_5q8AmG?Y`)S$d~U{=aQOo&^A!%$(!h@E zuP1UlZ@fsK!qyy%r>WMRxC-u5KcUFqMyP3^S)KQT)BGSXbXX6N}OL}NA{4v|N+w*6K5XS&`4I;?{Rk~2212@c8Ge&QngWJdz+ zH2tewmoNtT) zv#PYS0W08fFBKVn3n!RS10-pKpmcKaLL1%1&y#q1u%GlWQB_wL(D%2xk!`23FRz0o zfbH(Xpby|x!Ol?M(A4S9^*hRZxsH}_b!rz^p}X^`^}M4L4Sakwq(oFtsAyI5E{@a* ztrpSm^wk&zrEuUEwOUT5l*zGn8)2ihGLs+-F03YB%DhMX>b0P8qY5s27-Hr86VJik z3zj?LSbXosVbf8{-50WN8{pLWNb_7qcpnyCiwdznZ>lw=?u`^kp+d#W=hT_KIA(6G zy}x8s4T}cpQTg%X4m41^z_ra;QSw#zGL*m>Q!okJSVp)g8_78K!w$Q0JE}V1Oatr) zz`idGx&*>^9S;+0_G8iwe3|4*?)~_sb5bu+Y;iImkh~gsP^(m`Rfqj$AnY$*IyH4< z;VOA>QCf8gtzUeqehdkAUC-e~A7SGsBaH0YVydyukJMEd+Q*iX+lsnDZikDck4p29 z%xKR+tT^}naBj*N^5%Nmf+%HpDKoU=1YM{zvI+hLLRe}E_Wl@bqq5R}2k3tU@VfEf zYzh!=vC;h^o2Ex{D{Ne{;qr@^pxstaaCjpp#w0HmkZFzWqnE0Wu4+eu z4b$3rV!+||F<~qU@*;nBdRjfZGLE)dLK6GP2R}))NjpCmT;S6PO}xb6l#il}d47V( zXA*&rxxwm4X5i>JtxEAo$I;N<9Mn$7NDim-= zRACDHAR~}-5nJ5;ZEe(sgfkIAU;<%;O-CVvNdm+uE7jY~F~i&tsmeA=M@rM_gSsLD zhwZmyQ1IoJQ*10zlI0g8FmDYj7@ql9IX~f4r?g~{R--c>5i2p|B(Jx3c=lBx*DcF( z70f@mvY0HGsuU)wi6P&%$&eI>(aQ_Rw*FbvS7b7ETv#!pV&x5l@i%X{Pe~)NpVQH7 zV5+5##}X4plW#bt$xA`P8;PyZ;SL|*sI!fH+QaR4k>z_*>#es7)%G0jHCRaxC~NKI zU_=WEMh{unGB@d#N%DSw8!fbyom9kI7G|%_k6*hQz9@!n3*@jkl7@<17$27Eer&ts z5I5qMGOy}SE$us)`O1^+M#2!TDBBjz(A?cjv&fTy9VMhsjp>6{4N^_wJCAt9Oe4*O zv?xYVLj6Kyle50AD!vy3bNH}5yF0Gb)}f46lCDuZS#D91{>sgcIcyGse+p~XBY?#W zltDUn3qx;cxQL}1IutE)?SoiR)UR!3NtEYfAw&F6TTH}-vDodQcC;-=-V$Y#WR4Dk zVsWbyXT-M;dZnyS(R?QLKAO|kGG&h=B(^yuBEbG)Lgh*F{Y^xX7bc&X{KR}f4*Y=) z)G|Ze90`6{xMpRmcO!o*Biq2yK`Z-n8~EM$H}(R~3tL-e3}?>Aju6s1Ng&YfQCb6t zk*z0({B~Gbo?r`jz2QSOyAVzqGiT!3A43a_j&Gjn7qtATHbeZeOfCLuh2>F7liFz|X)@v{~C;shLqn%E==v=pJe zw#Vyory&IzkDjLQii4mmYr1-*O>djov5@rZza;kVv3K(HK*g|xP6?6u`ar0!M{Aht zNl52oM;?|Bgd!4e=J#drkBoHXv)@?=qU5chk9XoCF2c~+FQBBD6(+4TkimFH z+#IeJm<&TBq?o`tENNgo2ohn+G#=VsAGEJkJ1s0y^Xe?R^N>R!mMi@k>jukM^n8~p zEte36McJSSTwA$mo0&L1`CQ7LJf=I}xu_ZYTA|~MtHuUuGvTEv$Nl;$K1K8PE2_%2 zrGrp#{OY9PB}nDd9?<9Llil`WBFsn~uItWCnUk3=mm!T7Db*SxaxH{jh@4!Zp@%)P z$!l_qTfam()omFU4U`*BG5HbOdhtBWX3NlYcZz3&(v9WeTZEsny7-P763L6mIxS63 zwvt7xIlRN-A5DCs%%?e$L;9T=ZAG(9G_cpVkM(!~wgP<`osO|_0z6JO-%h1 zzaQ^ddey$kV?SBB%^6EN&PQTmdmu$>Xx-8-96C%khQpi(8JU++nxUGnq(;K=P^OgR zq`4tNGw_W+fcJ zuU%4LTcB~84k_1>#cBFHeMvw!q1suU6cgf2-S(*@)_p-g4l^&Gk{t&cXI@LqDt0Rj zRM(9ZLy;!-3-|@a>n9)FcA!4I##Y-QrmXFH9$u=tl0erOSfYU2s`#R$hFhc_u_C7(s&JMN`@{5%$O%& zadXL{vfp=jzAC{@4t;-&`FLu@X`>v8M#K(09z7kjTf~I`qmCG3se;{g|9m!kw3f}- zIInU5Kcz4w*&Qr^>n$Vkqx8%=d8^q*)#2lhL2BW`Ovl_F$`QxRJlYK%lU2nu+viM* z1S!7^AFDq7N^1Km-2O_XtoT`}NsM3bkEf%xy_i4a-n@Y6AIG;YX#ZZ9g&9y4ZaKnY z!TWsm1W(_kmMj_NRQkS6oZP#F2nN_h0R#{btoxD5d&hMJ%Ien%P#!l4P#9_~>k!f! ztZl*s_z_5N$^1y!91}l}&=!}X(Edsua4I3*rcG91`IO>LJJ0d6pJQjQ*&-z~ z%jQPbx61?$OH1kNAx#dh{j%?{N5qYVRHgSxrJ2gOAfwfu@(bOrO;K2gA|(lG@&T}u z4IGZ+7cUwDa41f}$HLtZ4VT8kuSE8l#H$LSyq4_g#Mh|&8@ry?yL!GpUb!MmZQy1K z^kZAF4K8ufKa`Db(fbrK8(RjB|4K)QC;17N8QMDGTji2Wc+}TsN=USlSFxKcL-L$u z{co=t7()@(Ia;2ltCa2_mfU@z?G`Kn#Z1mE>*DTPMuqD zoHkAF{}^S#7PdSnI6S523d65ia8|tdg(cKzYg@*H4pq~?cwEL&8#UC;JZ;_~>?8oh z)TDA&PkUQ@oq=&f?kCG{P2nQnvYLWz#=LJ>HH%Y1m9w+@YwTC72J?yBAXY+$8VC%!&ie(5E3^Ho|h#+ zIimJYjQEN>t9#3{Tf|uIK(fm-F{K$reF{N;`4o=fMe7_v`$sXuw1LD9)^p9GH?3nG z+JU2KmT^(ih)7wqVsp@TU#sVbqj#N?hjLaO%?hDcudsdUW1krJ zA;DhCrs$fs`cJ9fa(-JF%M)9)eZO4T%8G3QDX$(%*lJfxBDm0T;W}H#sItB2bb66K zZ#X4|#L2Wq>sCuwx6@vpY^}MlDs*ul89-R zbE)yzvsaiA+pJ_4&${~Ov)4RV1+4s%rHN4~XVYSh)|iEjrILgylQ|t|s$+V3dXpDxYGq*PEc8-N5by)wwFm@Mrycqn&4`j+ zryT|q8%N?R;J1H1-kEoQ0cso@-V1l9M85IMUYoTKJ|^@D@1-I@;G7KY>;XB(v}X3! zR=2$sO;XL$e4`~_m%$ofIz?*(N&>nxIDH+o=#JGYI4&ar5UewiCZwaEQ9!S?7e^Oy-e=pzh9M7 zBK6gRhOQ%Ag?$o~uIH$Wiy+d=QENhrfeIOhM=$mAScde;+m0US5K8c8!sjOe_OapH zzN4jnyF0(r1OOZG2Wi&7bzos_44nLY-H&|m2*Lp%doG{={M4-uZu(uPS%(IR!?f@r z35~xF*4hwQKRYrYA~ITMc-?`(OpFTUtHn!L%?AUsG1}_uP0WB)y(U>qgLEy5v6-xtrl z1{!qOR>A*_FJpmWXZ*8DEoT{hQCnu59pJB{-vqT`epGvl?j{G62ihDd`s z*_r4$I5_l}4LRtYLB)HzrRC@ujdE7xWMn9B8J91SlVKcTl3B_H#EOE1AP@fYaQwxn zo*@vU*HeDPv%?$;U|X-tUyK5Jv$L|WFtIbU>M=62FdG@N=+iT>GjXuf1NdbI6kQ`W zJzYZvXVB!xm-g@ZkN~H%%Du^U6P3B_G03&l;h*^)ov~Ux7NEvKiah%vyVXOJeYEXf zlv`Uf_vO5zfb0X#L1hpIc!VRrLKa;1Yf5vMLSwZvK9q2D!JhImQF(@T)gWxQZ0X`H*RScUj?oYMi~)h#BGimIYMW z)5x%v=aDzA*Vk9bZ;v@IqL{ouf4r~HC(uYhT9LAxp7TOBJpo%Zdp8jmEcBtJvjGFAb4_Oamazpby4SP;Cxkpdo z8YtT?A%tS4_5RGn>kBo2x&QkE$hN<=kaz3X)C$N&{_RTt>Tjc~Zw};ADFO89KVxcW z0O%S6%I}$e-Otbf5U)0}r+Evw*+hT@vRkj0W^a&Xcx6N?Lv-XUyz*(}j80l3KU+*Kc3ltf3nc#>h%WpL&wfsKWW@>mrP1@t2clEey$=mDpE!jU-|Nd3CJF?ewo&m}Y z+4~pYfI%!-K{Bt2?(J}7UDwWtx9vZ?|J!{yU=aN~klWjFz{Dkvt8X|?7`nKTWd2(f zkOY73c-_C`226bOjyTYjH(&&~j9Z<23@yE({BJt?`(7I`f*Rlm=SD|=Zn*&iXn)X5 zy4K6X8h8-?z6%Eo5O4=@y=4O?JyL(Gjl1z}j(w<|zgIcz%`pc+DL3o4^^WxIeK=s^ zp@g@@?rMnjihou8{p)qWd~e++{wDz#=qv>o@eUzU^cMN9{ctATzkLRb$ou%8p|}<2 zue)f#XgElfH}XKL-A=K)_CvJ$x0is?ECFXmHv@l*_8;#u0i)8g-J))|)!v}rwI8D1 zPY4G_jR2SrAk@Fp!-3%>v~J;E8rR*x-L)UW-Ot?yhEo7+MS)-y2L3;$dB93&fW(C*p~<-4Di35=!&u$~Xl{v}5f7*i?# z7IT8F>Azy$&twF~Oa!EQJ-`IYYy3AXw}$2$tUK(7^4(7&1I7x$_zUY^N*OSk+3>Ao zEK#jDXm{<0X!j4UfzkZ&{{;>B7#kQa>iib&J74>Mg}Z-73k(NM@DT3bPi+4U^_5G< z4eA{i4~4vc!}sq8V8EDnHuM#8_YLM<`yuB2kTNi)5cxgKdjV!(q&wRw z1OMe;kp8&*`@tVzBruwPkZwXjz_gXueq~&HvO8z|k|Q_ey8TCrzugVYJ$F<8hc;j< z3QW7m`qt*()xYKVy#u=4Mcj|+0Q3F*9_@c3JpT$oaJwtIg92v%VMyXW`^~ifsOBc- z08IP47Rt>g=&t_CcH90#`|ofB!f(|8W--Y6J=zaF{T*Fn5YC%T*5CC1-jX8zrhmOt z526F+{bo!1-vqb={3F2M0OQR>I8#|9rvUgNmmAM`d?G7+^^-MsCSJtpA(B{*b>Ok;XgnckgHS z$VZ{yOelh=G)bLS5w*Fwr>&s=;wY&=x)Uk z0uZnm{?X5!004ylEkFd!#~p6bKg;s24J_&3(V#m%t|iTS$Ojg51n zyLBt+-w~ucglkEM{{`WHizfl|afdsRevo%_J<9bXdm>)=b6TAS% zuoAjm5fAJC9RrHx0meQkOUY(S-G(AdM=pe z-M--7wf`Xe-+XGz9l~EW{qA+}uKqWN_jicoj{6%Ma*y`k<~+6cmis7?iW@2Jkp3I@ z_uUc}AOd=`m--WA0ani)!G|?4z{4f;$FE+CAp9HPE-(X3e=Yykia)Gx>ED`$zr#0o zD!LwETL69FU=A?#5mo1#SAWRty_*H!z`z%OyI}$c-0lQ~bO8Ux0Vh-C02&}5{|Csd BBbxvK literal 0 HcmV?d00001 From 47d7f467d9a8c28fb234db8af90bb342d3a15e6c Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Fri, 11 Jun 2021 11:02:15 +0200 Subject: [PATCH 254/704] Fix resolving HEAD reference if it's a packed ref --- src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 40cfc644..1d3b78b2 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -616,7 +616,9 @@ private GitObjectId ResolveReference(object reference) { if (!FileHelpers.TryOpen(Path.Combine(this.CommonDirectory, (string)reference), out FileStream? stream)) { - return GitObjectId.Empty; + // HEAD can point to a reference that's in the packed references and needs + // a full resolution. + return Lookup((string)reference) ?? GitObjectId.Empty; } using (stream) From ea9517bb6ca05e6272179aa7089b241334b6adfa Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Fri, 11 Jun 2021 11:55:16 +0200 Subject: [PATCH 255/704] Tweak GitRepository.Lookup error handling --- .../ManagedGit/GitRepository.cs | 97 ++++++++----------- 1 file changed, 43 insertions(+), 54 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 1d3b78b2..52c8b5ea 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -222,9 +222,7 @@ public object GetHeadAsReferenceOrSha() /// public GitObjectId GetHeadCommitSha() { - var reference = this.GetHeadAsReferenceOrSha(); - var objectId = this.ResolveReference(reference); - return objectId; + return this.Lookup("HEAD") ?? GitObjectId.Empty; } /// @@ -280,9 +278,17 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) /// The object ID referenced by if found; otherwise . public GitObjectId? Lookup(string objectish) { + bool skipObjectIdLookup = false; + if (objectish == "HEAD") { - return this.GetHeadCommitSha(); + var reference = this.GetHeadAsReferenceOrSha(); + if (reference is GitObjectId headObjectId) + { + return headObjectId; + } + + objectish = (string)reference; } var possibleLooseFileMatches = new List(); @@ -290,6 +296,7 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) { // Match on loose ref files by their canonical name. possibleLooseFileMatches.Add(Path.Combine(this.GitDirectory, objectish)); + skipObjectIdLookup = true; } else { @@ -341,6 +348,11 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) } } + if (skipObjectIdLookup) + { + return null; + } + if (objectish.Length == 40) { return GitObjectId.Parse(objectish); @@ -372,25 +384,26 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) objectish += "0"; } - var hex = ConvertHexStringToByteArray(objectish); - - foreach (var pack in this.packs.Value.Span) + if (TryConvertHexStringToByteArray(objectish, out var hex)) { - var objectId = pack.Lookup(hex, endsWithHalfByte); - - // It's possible for the same object to be present in both the object database and the pack files, - // or in multiple pack files. - if (objectId != null && !possibleObjectIds.Contains(objectId.Value)) + foreach (var pack in this.packs.Value.Span) { - if (possibleObjectIds.Count > 0) - { - // If objectish already resolved to at least one object which is different from the current - // object id, objectish is not well-defined; so stop resolving and return null instead. - return null; - } - else + var objectId = pack.Lookup(hex, endsWithHalfByte); + + // It's possible for the same object to be present in both the object database and the pack files, + // or in multiple pack files. + if (objectId != null && !possibleObjectIds.Contains(objectId.Value)) { - possibleObjectIds.Add(objectId.Value); + if (possibleObjectIds.Count > 0) + { + // If objectish already resolved to at least one object which is different from the current + // object id, objectish is not well-defined; so stop resolving and return null instead. + return null; + } + else + { + possibleObjectIds.Add(objectId.Value); + } } } } @@ -610,35 +623,6 @@ private bool TryGetObjectByPath(GitObjectId sha, string objectType, [NotNullWhen return true; } - private GitObjectId ResolveReference(object reference) - { - if (reference is string) - { - if (!FileHelpers.TryOpen(Path.Combine(this.CommonDirectory, (string)reference), out FileStream? stream)) - { - // HEAD can point to a reference that's in the packed references and needs - // a full resolution. - return Lookup((string)reference) ?? GitObjectId.Empty; - } - - using (stream) - { - Span objectId = stackalloc byte[40]; - stream!.Read(objectId); - - return GitObjectId.ParseHex(objectId); - } - } - else if (reference is GitObjectId) - { - return (GitObjectId)reference; - } - else - { - throw new GitException(); - } - } - private ReadOnlyMemory LoadPacks() { var packDirectory = Path.Combine(this.ObjectDirectory, "pack/"); @@ -689,22 +673,27 @@ private static string TrimEndingDirectorySeparator(string path) #endif } - private static byte[] ConvertHexStringToByteArray(string hexString) + private static bool TryConvertHexStringToByteArray(string hexString, out byte[]? data) { // https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array if (hexString.Length % 2 != 0) { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "The binary key cannot have an odd number of digits: {0}", hexString)); + data = null; + return false; } - byte[] data = new byte[hexString.Length / 2]; + data = new byte[hexString.Length / 2]; for (int index = 0; index < data.Length; index++) { string byteValue = hexString.Substring(index * 2, 2); - data[index] = byte.Parse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture); + if (byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) + { + data = null; + return false; + } } - return data; + return true; } /// From 35a11f534b6ff02984f5818f8b7db79cf39cdc55 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Fri, 11 Jun 2021 12:02:49 +0200 Subject: [PATCH 256/704] Fix flipped condition --- src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 52c8b5ea..c25efc43 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -686,7 +686,7 @@ private static bool TryConvertHexStringToByteArray(string hexString, out byte[]? for (int index = 0; index < data.Length; index++) { string byteValue = hexString.Substring(index * 2, 2); - if (byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) + if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) { data = null; return false; From 4d8ecca72eff6d8d1465652c46800d9912dffe14 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Fri, 11 Jun 2021 12:16:45 +0200 Subject: [PATCH 257/704] Hopefully fix worktree support --- src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index c25efc43..e7a6d851 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -295,7 +295,7 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) if (objectish.StartsWith("refs/", StringComparison.Ordinal)) { // Match on loose ref files by their canonical name. - possibleLooseFileMatches.Add(Path.Combine(this.GitDirectory, objectish)); + possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, objectish)); skipObjectIdLookup = true; } else From 311f4775683cf7bd6cb802be995afa795ea2f653 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 12 Jun 2021 14:16:55 -0600 Subject: [PATCH 258/704] Touch-up on perf and add a test --- .../GitContextTests.cs | 10 +++- .../ManagedGit/GitRepository.cs | 48 ++++++++++++------- 2 files changed, 39 insertions(+), 19 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/GitContextTests.cs b/src/NerdBank.GitVersioning.Tests/GitContextTests.cs index 81cf1a83..ccb93142 100644 --- a/src/NerdBank.GitVersioning.Tests/GitContextTests.cs +++ b/src/NerdBank.GitVersioning.Tests/GitContextTests.cs @@ -173,4 +173,12 @@ public void GetVersion_PackedHead() this.Context.TrySelectCommit("HEAD"); Assert.Equal("1.0.1", oracle.SimpleVersion.ToString()); } -} \ No newline at end of file + + [Fact] + public void HeadCanonicalName_PackedHead() + { + using var expandedRepo = TestUtilities.ExtractRepoArchive("PackedHeadRef"); + this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath)); + Assert.Equal("refs/heads/main", this.Context.HeadCanonicalName); + } +} diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index e7a6d851..459f23c6 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -8,6 +8,7 @@ using System.Linq; using System.Runtime.InteropServices; using System.Text; +using Validation; namespace Nerdbank.GitVersioning.ManagedGit { @@ -384,25 +385,29 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) objectish += "0"; } - if (TryConvertHexStringToByteArray(objectish, out var hex)) + if (objectish.Length <= 40 && objectish.Length % 2 == 0) { - foreach (var pack in this.packs.Value.Span) + Span decodedHex = stackalloc byte[objectish.Length / 2]; + if (TryConvertHexStringToByteArray(objectish, decodedHex)) { - var objectId = pack.Lookup(hex, endsWithHalfByte); - - // It's possible for the same object to be present in both the object database and the pack files, - // or in multiple pack files. - if (objectId != null && !possibleObjectIds.Contains(objectId.Value)) + foreach (var pack in this.packs.Value.Span) { - if (possibleObjectIds.Count > 0) - { - // If objectish already resolved to at least one object which is different from the current - // object id, objectish is not well-defined; so stop resolving and return null instead. - return null; - } - else + var objectId = pack.Lookup(decodedHex, endsWithHalfByte); + + // It's possible for the same object to be present in both the object database and the pack files, + // or in multiple pack files. + if (objectId != null && !possibleObjectIds.Contains(objectId.Value)) { - possibleObjectIds.Add(objectId.Value); + if (possibleObjectIds.Count > 0) + { + // If objectish already resolved to at least one object which is different from the current + // object id, objectish is not well-defined; so stop resolving and return null instead. + return null; + } + else + { + possibleObjectIds.Add(objectId.Value); + } } } } @@ -673,7 +678,7 @@ private static string TrimEndingDirectorySeparator(string path) #endif } - private static bool TryConvertHexStringToByteArray(string hexString, out byte[]? data) + private static bool TryConvertHexStringToByteArray(string hexString, Span data) { // https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array if (hexString.Length % 2 != 0) @@ -682,15 +687,22 @@ private static bool TryConvertHexStringToByteArray(string hexString, out byte[]? return false; } - data = new byte[hexString.Length / 2]; + Requires.Argument(data.Length == hexString.Length / 2, nameof(data), "Length must be exactly half that of " + nameof(hexString) + "."); for (int index = 0; index < data.Length; index++) { +#if NETCOREAPP3_1_OR_GREATER + ReadOnlySpan byteValue = hexString.AsSpan(index * 2, 2); + if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) + { + return false; + } +#else string byteValue = hexString.Substring(index * 2, 2); if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) { - data = null; return false; } +#endif } return true; From 69c33ed0be29de36e9fbd3188b55d0cd165d578a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 12 Jun 2021 16:20:35 -0600 Subject: [PATCH 259/704] Switch from PInvoke nuget dependency to CsWin32 Fixes #615 --- .../ManagedGit/FileHelpers.cs | 16 +++++++++------- src/NerdBank.GitVersioning/NativeMethods.json | 3 +++ src/NerdBank.GitVersioning/NativeMethods.txt | 2 ++ .../NerdBank.GitVersioning.csproj | 2 +- .../Nerdbank.GitVersioning.nuspec | 2 -- 5 files changed, 15 insertions(+), 10 deletions(-) create mode 100644 src/NerdBank.GitVersioning/NativeMethods.json create mode 100644 src/NerdBank.GitVersioning/NativeMethods.txt diff --git a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs index 623539a1..eb250db9 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs @@ -5,8 +5,7 @@ using System.IO; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; -using static PInvoke.Kernel32; -using FileShare = PInvoke.Kernel32.FileShare; +using Microsoft.Windows.Sdk; namespace Nerdbank.GitVersioning.ManagedGit { @@ -24,7 +23,7 @@ internal static bool TryOpen(string path, out FileStream? stream) { if (IsWindows) { - var handle = CreateFile(path, ACCESS_MASK.GenericRight.GENERIC_READ, FileShare.FILE_SHARE_READ, (SECURITY_ATTRIBUTES?)null, CreationDisposition.OPEN_EXISTING, CreateFileFlags.FILE_ATTRIBUTE_NORMAL, SafeObjectHandle.Null); + var handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_FLAGS.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATE_FLAGS.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); if (!handle.IsInvalid) { @@ -62,12 +61,15 @@ internal static unsafe bool TryOpen(ReadOnlySpan path, [NotNullWhen(true)] { if (IsWindows) { - var handle = CreateFile(path, ACCESS_MASK.GenericRight.GENERIC_READ, FileShare.FILE_SHARE_READ, null, CreationDisposition.OPEN_EXISTING, CreateFileFlags.FILE_ATTRIBUTE_NORMAL, SafeObjectHandle.Null); + HANDLE handle; + fixed (char* pPath = &path[0]) + { + handle = PInvoke.CreateFile(pPath, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_FLAGS.FILE_SHARE_READ, null, FILE_CREATE_FLAGS.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default); + } - if (!handle.IsInvalid) + if (!handle.Equals(Constants.INVALID_HANDLE_VALUE)) { - var fileHandle = new SafeFileHandle(handle.DangerousGetHandle(), ownsHandle: true); - handle.SetHandleAsInvalid(); + var fileHandle = new SafeFileHandle(handle, ownsHandle: true); stream = new FileStream(fileHandle, System.IO.FileAccess.Read); return true; } diff --git a/src/NerdBank.GitVersioning/NativeMethods.json b/src/NerdBank.GitVersioning/NativeMethods.json new file mode 100644 index 00000000..69d2bcc5 --- /dev/null +++ b/src/NerdBank.GitVersioning/NativeMethods.json @@ -0,0 +1,3 @@ +{ + "$schema": "https://aka.ms/CsWin32.schema.json" +} \ No newline at end of file diff --git a/src/NerdBank.GitVersioning/NativeMethods.txt b/src/NerdBank.GitVersioning/NativeMethods.txt new file mode 100644 index 00000000..885be08e --- /dev/null +++ b/src/NerdBank.GitVersioning/NativeMethods.txt @@ -0,0 +1,2 @@ +CreateFile +INVALID_HANDLE_VALUE diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index afeb8233..b196afbc 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -12,12 +12,12 @@ + - diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 30e035fc..48fc3455 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -23,7 +23,6 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - @@ -49,7 +48,6 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - From 546a678f93bd67af3589ae0e6a1d2c2ccadc488e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 13 Jun 2021 02:56:04 -0600 Subject: [PATCH 260/704] Update CsWin32 to fix `dotnet build` --- azure-pipelines.yml | 18 +++++++++--------- .../ManagedGit/FileHelpers.cs | 8 +++++--- .../NerdBank.GitVersioning.csproj | 2 +- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 10d8b58c..14753b51 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -58,13 +58,13 @@ stages: displayName: Configure git commit author for testing - task: UseDotNet@2 - displayName: Install .NET Core SDK 5.0.202 + displayName: Install .NET Core 5.0.202 SDK inputs: packageType: sdk version: 5.0.202 - task: UseDotNet@2 - displayName: Install .NET Core 3.1 + displayName: Install .NET Core 3.1 runtime inputs: packageType: runtime version: 3.1.x @@ -296,17 +296,17 @@ stages: vmImage: $(imageName) steps: - task: UseDotNet@2 - displayName: Install .NET Core SDK 2.1.811 + displayName: Install .NET Core 2.1 runtime inputs: - packageType: sdk - version: 2.1.811 + packageType: runtime + version: 2.1.x - task: UseDotNet@2 - displayName: Install .NET Core SDK 3.1.100 + displayName: Install .NET Core 3.1 runtime inputs: - packageType: sdk - version: 3.1.100 + packageType: runtime + version: 3.1.x - task: UseDotNet@2 - displayName: Install .NET Core SDK 5.0.202 + displayName: Install .NET Core 5.0.202 SDK inputs: packageType: sdk version: 5.0.202 diff --git a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs index eb250db9..e1d9713b 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs @@ -5,7 +5,9 @@ using System.IO; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; -using Microsoft.Windows.Sdk; +using Windows.Win32; +using Windows.Win32.Storage.FileSystem; +using Windows.Win32.System.SystemServices; namespace Nerdbank.GitVersioning.ManagedGit { @@ -23,7 +25,7 @@ internal static bool TryOpen(string path, out FileStream? stream) { if (IsWindows) { - var handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_FLAGS.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATE_FLAGS.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); + var handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); if (!handle.IsInvalid) { @@ -64,7 +66,7 @@ internal static unsafe bool TryOpen(ReadOnlySpan path, [NotNullWhen(true)] HANDLE handle; fixed (char* pPath = &path[0]) { - handle = PInvoke.CreateFile(pPath, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_FLAGS.FILE_SHARE_READ, null, FILE_CREATE_FLAGS.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default); + handle = PInvoke.CreateFile(pPath, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default); } if (!handle.Equals(Constants.INVALID_HANDLE_VALUE)) diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index b196afbc..d6dfbf49 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -12,7 +12,7 @@ - + From 8cfe442dbc59172078156bbde21fdd00bfdbcda8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 13 Jun 2021 06:55:01 -0600 Subject: [PATCH 261/704] Remove dotnet/pinvoke from 3rd party licenses file --- 3rdPartyNotices.txt | 25 ------------------------- src/Nerdbank.GitVersioning.sln | 5 +++-- 2 files changed, 3 insertions(+), 27 deletions(-) diff --git a/3rdPartyNotices.txt b/3rdPartyNotices.txt index f96a675c..3a888faa 100644 --- a/3rdPartyNotices.txt +++ b/3rdPartyNotices.txt @@ -127,31 +127,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -dotnet/PInvoke (https://github.com/dotnet/pinvoke) -============== - -MIT License - -Copyright (c) .NET Foundation and Contributors - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - Cake Contrib (https://github.com/cake-contrib/graphics) ============ diff --git a/src/Nerdbank.GitVersioning.sln b/src/Nerdbank.GitVersioning.sln index 66c96ce6..43ffb2c7 100644 --- a/src/Nerdbank.GitVersioning.sln +++ b/src/Nerdbank.GitVersioning.sln @@ -1,12 +1,13 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.28404.58 +# Visual Studio Version 17 +VisualStudioVersion = 17.0.31411.2 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4BD1A7CD-6F52-4F5A-825B-50E4D8C3ECFF}" ProjectSection(SolutionItems) = preProject ..\.editorconfig = ..\.editorconfig ..\.gitignore = ..\.gitignore + ..\3rdPartyNotices.txt = ..\3rdPartyNotices.txt ..\azure-pipelines.yml = ..\azure-pipelines.yml ..\build.ps1 = ..\build.ps1 Directory.Build.props = Directory.Build.props From e463aab30aae8b5ca6c8641c284c736c8db1f396 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 13 Jun 2021 21:21:14 -0600 Subject: [PATCH 262/704] Update Microsoft.Net.Compilers.Toolset to 3.10.0 --- src/Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 7f82c288..e283fab8 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -24,7 +24,7 @@ 2.0.312 - + From 2f9ae16d7de3980d88b3ca5af327f2f24bc0b483 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 15 Jun 2021 15:57:41 -0600 Subject: [PATCH 263/704] Update StyleCop.Analyzers to 1.2.0-beta.333 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index d375bb2b..7ea3c86b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,7 +34,7 @@ - + From 1f1cf8bbef88042cf14719b56d663dbcddcbacd5 Mon Sep 17 00:00:00 2001 From: rhodosaur Date: Sun, 20 Jun 2021 11:06:15 +0200 Subject: [PATCH 264/704] include 5E and DA values in zlib header check --- src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs index 31d11366..d21077f5 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs @@ -5,6 +5,7 @@ using System.Buffers; using System.IO; using System.IO.Compression; +using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -56,9 +57,9 @@ public ZLibStream(Stream stream, long length = -1) Span zlibHeader = stackalloc byte[2]; stream.ReadAll(zlibHeader); - if (zlibHeader[0] != 0x78 || (zlibHeader[1] != 0x01 && zlibHeader[1] != 0x9C)) + if (zlibHeader[0] != 0x78 || (zlibHeader[1] != 0x01 && zlibHeader[1] != 0x9C && zlibHeader[1] != 0x5E && zlibHeader[1] != 0xDA)) { - throw new GitException(); + throw new GitException($"Invalid zlib header {string.Join(" ", zlibHeader.ToArray().Select(b => $"{b:X2}"))}"); } } From 480626dc4bda26c47f12342dd3f1bbc7973324f8 Mon Sep 17 00:00:00 2001 From: rhodosaur Date: Sun, 20 Jun 2021 15:26:41 +0200 Subject: [PATCH 265/704] ditch linq for exception --- src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs index d21077f5..d4e68212 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs @@ -5,7 +5,6 @@ using System.Buffers; using System.IO; using System.IO.Compression; -using System.Linq; using System.Threading; using System.Threading.Tasks; @@ -59,7 +58,7 @@ public ZLibStream(Stream stream, long length = -1) if (zlibHeader[0] != 0x78 || (zlibHeader[1] != 0x01 && zlibHeader[1] != 0x9C && zlibHeader[1] != 0x5E && zlibHeader[1] != 0xDA)) { - throw new GitException($"Invalid zlib header {string.Join(" ", zlibHeader.ToArray().Select(b => $"{b:X2}"))}"); + throw new GitException($"Invalid zlib header {zlibHeader[0]:X2} {zlibHeader[1]:X2}"); } } From 29e05c03fb75ff4f5b6422edc171cad77b13c860 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 21 Jun 2021 08:32:15 -0600 Subject: [PATCH 266/704] Run IDExxxx analyzers in the build This helps the repo stay clean so users don't see a bunch of warnings in the error list when they open the solution from a team branch. --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index 7ea3c86b..bcc5a80d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -8,6 +8,7 @@ 9.0 enable latest + true true true From ce744862270a6515fae669bf84e7495e134b61d6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 21 Jun 2021 08:33:56 -0600 Subject: [PATCH 267/704] Update Nerdbank.GitVersioning to 3.4.216 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index bcc5a80d..bb311c67 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,7 +33,7 @@ - + From 68f4b7f1e1e0034f226f37722724a64d7af6723e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 21 Jun 2021 08:35:32 -0600 Subject: [PATCH 268/704] Update Microsoft.Net.Compilers.Toolset to 3.10.0 --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index bb311c67..88b2e583 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -30,7 +30,7 @@ - + From e2e7442f24077f786232e29513a4a91feb76276b Mon Sep 17 00:00:00 2001 From: Robert Dailey Date: Wed, 23 Jun 2021 10:50:55 -0500 Subject: [PATCH 269/704] Informational version supports four components If the user specifies a three-component version number in their `version.json`, for example `"1.2.3"`, then the InformationalVersion property will show something like `"1.2.3.50+metadata"`, where `50` is the build height. The previous behavior is still retained when users specify a two-component version number, such as `"1.2"`. --- .../BuildIntegrationTests.cs | 8 ++++++- .../VersionOracleTests.cs | 24 +++++++++++++++++++ src/NerdBank.GitVersioning/SemanticVersion.cs | 2 +- src/NerdBank.GitVersioning/VersionOptions.cs | 2 +- src/NerdBank.GitVersioning/VersionOracle.cs | 16 ++++++++++++- 5 files changed, 48 insertions(+), 4 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index b2ab89f5..cd6918d6 100644 --- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -1050,8 +1050,14 @@ private void AssertStandardProperties(VersionOptions versionOptions, BuildResult string expectedBuildMetadataWithoutCommitId = additionalBuildMetadata.Any() ? $"+{string.Join(".", additionalBuildMetadata)}" : string.Empty; + var optionalFourthComponent = versionOptions.VersionHeightPosition switch + { + SemanticVersion.Position.Revision => $".{idAsVersion.Revision}", + _ => "" + }; + Assert.Equal($"{version}", buildResult.AssemblyFileVersion); - Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{versionOptions.Version.Prerelease}{expectedBuildMetadata}", buildResult.AssemblyInformationalVersion); + Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{optionalFourthComponent}{versionOptions.Version.Prerelease}{expectedBuildMetadata}", buildResult.AssemblyInformationalVersion); // The assembly version property should always have four integer components to it, // per bug https://github.com/dotnet/Nerdbank.GitVersioning/issues/26 diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 4f10abf1..2b5b7c5f 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -66,6 +66,30 @@ public void Submodule_RecognizedWithCorrectVersion() } } + [Fact] + public void Informational_version_has_four_components_when_three_component_version_is_used() + { + var versionOptions = new VersionOptions { Version = SemanticVersion.Parse("1.2.3") }; + + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + this.AddCommits(20); + var oracle = new VersionOracle(this.Context); + Assert.StartsWith("1.2.3.21+", oracle.AssemblyInformationalVersion); + } + + [Fact] + public void Informational_version_has_three_components_when_two_component_version_is_used() + { + var versionOptions = new VersionOptions { Version = SemanticVersion.Parse("1.2") }; + + this.WriteVersionFile(versionOptions); + this.InitializeSourceControl(); + this.AddCommits(20); + var oracle = new VersionOracle(this.Context); + Assert.StartsWith("1.2.21+", oracle.AssemblyInformationalVersion); + } + [Fact] public void MajorMinorPrereleaseBuildMetadata() { diff --git a/src/NerdBank.GitVersioning/SemanticVersion.cs b/src/NerdBank.GitVersioning/SemanticVersion.cs index 9b503b46..ea69e2b3 100644 --- a/src/NerdBank.GitVersioning/SemanticVersion.cs +++ b/src/NerdBank.GitVersioning/SemanticVersion.cs @@ -76,7 +76,7 @@ public SemanticVersion(string version, string prerelease = null, string buildMet /// /// Identifies the various positions in a semantic version. /// - internal enum Position + public enum Position { /// /// The component. diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index 7aee1dfa..07b61b0d 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -421,7 +421,7 @@ public bool Inherit /// Gets the position in a computed version that the version height should appear. /// [JsonIgnore] - internal SemanticVersion.Position? VersionHeightPosition + public SemanticVersion.Position? VersionHeightPosition { get { diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 84c83019..126bcec7 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -75,6 +75,11 @@ public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? ov this.VersionOptions = this.CommittedVersion ?? this.WorkingVersion; this.Version = this.VersionOptions?.Version?.Version ?? Version0; + this.VersionHeightFieldPosition = this.VersionOptions?.VersionHeightPosition switch + { + SemanticVersion.Position.Revision => 4, + _ => 3 + }; // Override the typedVersion with the special build number and revision components, when available. if (context.IsRepository) @@ -103,6 +108,15 @@ public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? ov } } + /// + /// The field (component) position of the version height. + /// + /// + /// If the user specifies "1.2.3" as the version number, the field position is 4. + /// If the user specifies "1.2", then the field position is 3. For all other scenarios, it also is set to 3. + /// + public int VersionHeightFieldPosition { get; private set; } + /// /// Gets the that were deserialized from the contextual commit, if any. /// @@ -181,7 +195,7 @@ public IEnumerable BuildMetadataWithCommitId /// Gets the version string to use for the . /// public string AssemblyInformationalVersion => - $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersion}{FormatBuildMetadata(this.BuildMetadataWithCommitId)}"; + $"{this.Version.ToStringSafe(this.VersionHeightFieldPosition)}{this.PrereleaseVersion}{FormatBuildMetadata(this.BuildMetadataWithCommitId)}"; /// /// Gets or sets a value indicating whether the project is building From e7fab6db055c5173fa1cf105e48094283923175c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 28 Jun 2021 06:59:28 -0600 Subject: [PATCH 270/704] Update Ubuntu agent on AzP to 20.04 --- azure-pipelines/build.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index b4561394..cd39a76a 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -18,7 +18,7 @@ jobs: - job: Linux pool: - vmImage: Ubuntu 18.04 + vmImage: Ubuntu 20.04 steps: - checkout: self clean: true @@ -43,7 +43,7 @@ jobs: - Linux - macOS pool: - vmImage: Ubuntu 18.04 + vmImage: Ubuntu 20.04 condition: succeededOrFailed() steps: - checkout: self From d3b2f39ccc2ed8078da4d86302ac39ee2d007d52 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 28 Jun 2021 13:28:24 -0600 Subject: [PATCH 271/704] Use NuGetAuthenticate in AzP instead of hand installation This works around microsoft/artifacts-credprovider#244 --- azure-pipelines/install-dependencies.yml | 7 ++++++- init.ps1 | 10 +++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 7563bc1f..4f848b09 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -3,9 +3,14 @@ parameters: steps: +- task: NuGetAuthenticate@0 + displayName: Authenticate NuGet feeds + inputs: + forceReinstallCredentialProvider: true + - powershell: | $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors - .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites + .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites -NoNuGetCredProvider dotnet --info # Print mono version if it is present. diff --git a/init.ps1 b/init.ps1 index e5aad5bf..4cf910f2 100755 --- a/init.ps1 +++ b/init.ps1 @@ -20,6 +20,9 @@ Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. .PARAMETER NoPrerequisites Skips the installation of prerequisite software (e.g. SDKs, tools). +.PARAMETER NoNuGetCredProvider + Skips the installation of the NuGet credential provider. Useful in pipelines with the `NuGetAuthenticate` task, as a workaround for https://github.com/microsoft/artifacts-credprovider/issues/244. + This switch is ignored and installation is skipped when -NoPrerequisites is specified. .PARAMETER UpgradePrerequisites Takes time to install prerequisites even if they are already present in case they need to be upgraded. No effect if -NoPrerequisites is specified. @@ -35,6 +38,8 @@ Param ( [Parameter()] [switch]$NoPrerequisites, [Parameter()] + [switch]$NoNuGetCredProvider, + [Parameter()] [switch]$UpgradePrerequisites, [Parameter()] [switch]$NoRestore, @@ -45,7 +50,10 @@ Param ( $EnvVars = @{} if (!$NoPrerequisites) { - & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites + if (!$NoNuGetCredProvider) { + & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites + } + & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality if ($LASTEXITCODE -eq 3010) { Exit 3010 From 505f36a697ae0736f029b6e9baab9b54fdd611bb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 30 Jun 2021 18:26:45 -0600 Subject: [PATCH 272/704] Update .NET SDK --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 728ab674..34eb419f 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.202", + "version": "5.0.301", "rollForward": "patch", "allowPrerelease": false } From c0e8f4210567af6799ebd6343ae59dd6e547558e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 1 Jul 2021 06:50:34 -0600 Subject: [PATCH 273/704] Use batched CI --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2e4b2c15..a1435d91 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -1,4 +1,5 @@ trigger: + batch: true branches: include: - main From 3230021112457742dbc0a6c05f5088c19fe25156 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Jul 2021 07:19:49 -0600 Subject: [PATCH 274/704] Bump Nerdbank.GitVersioning from 3.4.216 to 3.4.220 (#106) Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.4.216 to 3.4.220. - [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases) - [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/compare/v3.4.216...v3.4.220) --- updated-dependencies: - dependency-name: Nerdbank.GitVersioning dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 88b2e583..d439a72c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,7 +33,7 @@ - + From 3a49199ce9cc05805877e6a0822e5b9e9f153804 Mon Sep 17 00:00:00 2001 From: Steve Bush Date: Sun, 25 Jul 2021 11:11:45 -0700 Subject: [PATCH 275/704] Add support for TargetFrameworks of the form netXX Add support for TargetFrameworks of the form netXX to Dotnet SDK installer script --- tools/Install-DotNetSdk.ps1 | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 91399997..00772a9e 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -51,6 +51,15 @@ Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$P $windowsDesktopRuntimeVersions += $v } } + + # Add target frameworks of the form: netXX + $targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% { + $v = $Matches[1] + $runtimeVersions += $v + if (-not ($IsMacOS -or $IsLinux)) { + $windowsDesktopRuntimeVersions += $v + } + } } Function Get-FileFromWeb([Uri]$Uri, $OutDir) { From fd43c77b00bc00d5fddf485f994a34f07313df15 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 25 Jul 2021 21:29:11 -0600 Subject: [PATCH 276/704] Update coverlet.msbuild and .NET SDK --- global.json | 2 +- test/Library.Tests/Library.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 34eb419f..d28f85bf 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.301", + "version": "5.0.302", "rollForward": "patch", "allowPrerelease": false } diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 38e325ac..660f9fb5 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -9,7 +9,7 @@ - + From 75791742ee3507c5d9ed86d64e40864094db7b32 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 27 Jul 2021 12:50:47 +0200 Subject: [PATCH 277/704] Add new NuGet signing certificate See https://devblogs.microsoft.com/nuget/the-nuget-org-repository-signing-certificate-will-be-updated-as-soon-as-march-15th-2021/ for more details --- src/nuget.config | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nuget.config b/src/nuget.config index 7ada9430..ede70863 100644 --- a/src/nuget.config +++ b/src/nuget.config @@ -13,6 +13,7 @@ Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer + From 7df66a372bac2ffeba50c923d0f7860b19bb5163 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 27 Jul 2021 12:53:41 +0200 Subject: [PATCH 278/704] Bump libgit2sharp to 0.27.0-preview-0102 --- src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index d6dfbf49..1119a781 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -10,7 +10,7 @@ - + From 4451779fd3fbd6867cbcca0b7cc77afe558bd1b5 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Tue, 27 Jul 2021 11:26:46 +0200 Subject: [PATCH 279/704] Run 32-bit tests --- azure-pipelines.yml | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 14753b51..c03e99ab 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -43,6 +43,7 @@ stages: windows: imageName: 'windows-2019' testModifier: + dotnet32: "\"C:\\Program Files (x86)\\dotnet\\dotnet.exe\"" variables: - ${{ if eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/') }}: - group: dotnetfoundation code signing @@ -69,6 +70,13 @@ stages: packageType: runtime version: 3.1.x + - pwsh: | + Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 + & .\dotnet-install.ps1 -Architecture x86 -Version 5.0.202 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + displayName: Install 32-bit .NET Core SDK 5.0.202, 3.1 + condition: ne(variables['dotnet32'], '') + - script: dotnet --info displayName: Show dotnet SDK info @@ -121,8 +129,22 @@ stages: --collect:"XPlat Code Coverage" -- RunConfiguration.DisableAppDomain=true - displayName: Run tests + displayName: Run x64 tests + workingDirectory: src + + - script: > + $(dotnet32) test NerdBank.GitVersioning.Tests + --no-build $(testModifier) + -c $(BuildConfiguration) + --filter "TestCategory!=FailsOnAzurePipelines" + --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.trx" + --results-directory $(Build.ArtifactStagingDirectory)/CodeCoverage/ + --collect:"XPlat Code Coverage" + -- + RunConfiguration.DisableAppDomain=true + displayName: Run x86 tests workingDirectory: src + condition: ne(variables['dotnet32'], '') - task: PublishCodeCoverageResults@1 displayName: Publish code coverage results From edc162175a43ce985c769f942ac063ea26a271ef Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Fri, 23 Jul 2021 16:37:10 +0200 Subject: [PATCH 280/704] GitPack: Don't use MemoryMappedFiles in 32-bit processes --- .../ManagedGit/GitPackTests.cs | 20 ++++++++++++-- .../ManagedGit/GitPack.cs | 27 ++++++++++++++----- 2 files changed, 38 insertions(+), 9 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs index 94905c70..6a55fe77 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs @@ -63,7 +63,15 @@ public void GetPackedObject() // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. var zlibStream = Assert.IsType(commitStream); var deflateStream = Assert.IsType(zlibStream.BaseStream); - var pooledStream = Assert.IsType(deflateStream.BaseStream); + + if (IntPtr.Size > 4) + { + var pooledStream = Assert.IsType(deflateStream.BaseStream); + } + else + { + var pooledStream = Assert.IsType(deflateStream.BaseStream); + } Assert.Equal(222, commitStream.Length); Assert.Equal("/zgldANj+jvgOwlecnOKylZDVQg=", Convert.ToBase64String(sha.ComputeHash(commitStream))); @@ -85,7 +93,15 @@ public void GetDeltafiedObject() var deltaStream = Assert.IsType(commitStream); var zlibStream = Assert.IsType(deltaStream.BaseStream); var deflateStream = Assert.IsType(zlibStream.BaseStream); - var pooledStream = Assert.IsType(deflateStream.BaseStream); + + if (IntPtr.Size > 4) + { + var pooledStream = Assert.IsType(deflateStream.BaseStream); + } + else + { + var directAccessStream = Assert.IsType(deflateStream.BaseStream); + } Assert.Equal(137, commitStream.Length); Assert.Equal("lZu/7nGb0n1UuO9SlPluFnSvj4o=", Convert.ToBase64String(sha.ComputeHash(commitStream))); diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs index 27c45c69..eff2eaf8 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs @@ -31,8 +31,8 @@ public class GitPack : IDisposable private readonly Func packStream; private readonly Lazy indexStream; private readonly GitPackCache cache; - private MemoryMappedFile packFile; - private MemoryMappedViewAccessor accessor; + private MemoryMappedFile? packFile = null; + private MemoryMappedViewAccessor? accessor = null; // Maps GitObjectIds to offets in the git pack. private readonly Dictionary offsets = new Dictionary(); @@ -98,8 +98,11 @@ public GitPack(GetObjectFromRepositoryDelegate getObjectFromRepositoryDelegate, this.indexStream = indexStream ?? throw new ArgumentNullException(nameof(indexStream)); this.cache = cache ?? new GitPackMemoryCache(); - this.packFile = MemoryMappedFile.CreateFromFile(this.packStream(), mapName: null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); - this.accessor = this.packFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); + if (IntPtr.Size > 4) + { + this.packFile = MemoryMappedFile.CreateFromFile(this.packStream(), mapName: null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); + this.accessor = this.packFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); + } } /// @@ -240,8 +243,8 @@ public void Dispose() this.indexReader.Value.Dispose(); } - this.accessor.Dispose(); - this.packFile.Dispose(); + this.accessor?.Dispose(); + this.packFile?.Dispose(); this.cache.Dispose(); } @@ -265,7 +268,17 @@ public void Dispose() private Stream GetPackStream() { - return new MemoryMappedStream(this.accessor); + // On 64-bit processes, we can use Memory Mapped Streams (the address space + // will be large enough to map the entire packfile). On 32-bit processes, + // we directly access the underlying stream. + if (IntPtr.Size > 4) + { + return new MemoryMappedStream(this.accessor); + } + else + { + return this.packStream(); + } } private GitPackIndexReader OpenIndex() From c955e1ff28d19063f106f562c863e3918448df29 Mon Sep 17 00:00:00 2001 From: Frederik Carlier Date: Fri, 23 Jul 2021 18:15:22 +0200 Subject: [PATCH 281/704] Make sure Streams are disposed of. --- .../ManagedGit/GitPackTests.cs | 26 +++++++++++++------ .../ManagedGit/GitPack.cs | 12 ++++++++- 2 files changed, 29 insertions(+), 9 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs index 6a55fe77..0c14a314 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs @@ -136,14 +136,24 @@ public void TryGetObjectTest() using (SHA1 sha = SHA1.Create()) { Assert.True(gitPack.TryGetObject(GitObjectId.Parse("f5b401f40ad83f13030e946c9ea22cb54cb853cd"), "commit", out Stream commitStream)); - - // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. - var zlibStream = Assert.IsType(commitStream); - var deflateStream = Assert.IsType(zlibStream.BaseStream); - var pooledStream = Assert.IsType(deflateStream.BaseStream); - - Assert.Equal(222, commitStream.Length); - Assert.Equal("/zgldANj+jvgOwlecnOKylZDVQg=", Convert.ToBase64String(sha.ComputeHash(commitStream))); + using (commitStream) + { + // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. + var zlibStream = Assert.IsType(commitStream); + var deflateStream = Assert.IsType(zlibStream.BaseStream); + + if (IntPtr.Size > 4) + { + var pooledStream = Assert.IsType(deflateStream.BaseStream); + } + else + { + var directAccessStream = Assert.IsType(deflateStream.BaseStream); + } + + Assert.Equal(222, commitStream.Length); + Assert.Equal("/zgldANj+jvgOwlecnOKylZDVQg=", Convert.ToBase64String(sha.ComputeHash(commitStream))); + } } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs index eff2eaf8..5d19128d 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs @@ -205,7 +205,17 @@ public Stream GetObject(long offset, string objectType) } var packStream = this.GetPackStream(); - Stream objectStream = GitPackReader.GetObject(this, packStream, offset, objectType, packObjectType); + Stream objectStream; + + try + { + objectStream = GitPackReader.GetObject(this, packStream, offset, objectType, packObjectType); + } + catch + { + packStream.Dispose(); + throw; + } return this.cache.Add(offset, objectStream); } From 357099c220379c6e8d99869e66f4f44625e0d3c4 Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 28 Jul 2021 12:06:52 +0200 Subject: [PATCH 282/704] Fix bugs with > 2 GB pack files --- .../ManagedGit/GitPackIndexMappedReader.cs | 2 +- src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs index 8f895ac1..279f0403 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs @@ -128,7 +128,7 @@ public override (long?, GitObjectId?) GetOffset(Span objectName, bool ends { // If the first bit of the offset address is set, the offset is stored as a 64-bit value in the table of 8-byte offset entries, // which follows the table of 4-byte offset entries: "large offsets are encoded as an index into the next table with the msbit set." - offset = offset & 0x7FF; + offset = offset & 0x7FFFFFFF; offsetBuffer = this.Value.Slice(offsetTableStart + 4 * objectCount + 8 * (int)offset, 8); var offset64 = BinaryPrimitives.ReadInt64BigEndian(offsetBuffer); diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs index 30d3bead..caebe49f 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs @@ -44,7 +44,7 @@ public static Stream GetObject(GitPack pack, Stream stream, long offset, string if (type == GitPackObjectType.OBJ_OFS_DELTA) { var baseObjectRelativeOffset = ReadVariableLengthInteger(stream); - var baseObjectOffset = (int)(offset - baseObjectRelativeOffset); + var baseObjectOffset = offset - baseObjectRelativeOffset; var deltaStream = new ZLibStream(stream, decompressedSize); var baseObjectStream = pack.GetObject(baseObjectOffset, objectType); @@ -98,9 +98,9 @@ private static (GitPackObjectType, long) ReadObjectHeader(Stream stream) return (type, length); } - private static int ReadVariableLengthInteger(Stream stream) + private static long ReadVariableLengthInteger(Stream stream) { - int offset = -1; + long offset = -1; int b; do From a7eaba90ef3c559bb81036d2b46e820b1b5bcfbd Mon Sep 17 00:00:00 2001 From: Filip Navara Date: Wed, 28 Jul 2021 16:31:02 +0200 Subject: [PATCH 283/704] Apply suggestions from code review Co-authored-by: Andrew Arnott --- src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs index caebe49f..a1eba9ae 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs @@ -44,7 +44,7 @@ public static Stream GetObject(GitPack pack, Stream stream, long offset, string if (type == GitPackObjectType.OBJ_OFS_DELTA) { var baseObjectRelativeOffset = ReadVariableLengthInteger(stream); - var baseObjectOffset = offset - baseObjectRelativeOffset; + long baseObjectOffset = offset - baseObjectRelativeOffset; var deltaStream = new ZLibStream(stream, decompressedSize); var baseObjectStream = pack.GetObject(baseObjectOffset, objectType); From 998b4dbed1cf203d8c423b13d9c5133b77f16232 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 Aug 2021 07:20:04 -0600 Subject: [PATCH 284/704] Bump Nerdbank.GitVersioning from 3.4.220 to 3.4.231 (#110) Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.4.220 to 3.4.231. - [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases) - [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/compare/v3.4.220...v3.4.231) --- updated-dependencies: - dependency-name: Nerdbank.GitVersioning dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index d439a72c..12555245 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,7 +33,7 @@ - + From 6a966c565f04e7b799f04f1cf0c10a668424652a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 7 Aug 2021 15:35:04 -0600 Subject: [PATCH 285/704] Rename `GitExtensionsTests` to `LibGit2GitExtensionsTests` This because the test class focuses only on libgit2. --- .../{GitExtensionsTests.cs => LibGit2GitExtensionsTests.cs} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename src/NerdBank.GitVersioning.Tests/{GitExtensionsTests.cs => LibGit2GitExtensionsTests.cs} (99%) diff --git a/src/NerdBank.GitVersioning.Tests/GitExtensionsTests.cs b/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs similarity index 99% rename from src/NerdBank.GitVersioning.Tests/GitExtensionsTests.cs rename to src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs index 7a8704dc..c6580a7d 100644 --- a/src/NerdBank.GitVersioning.Tests/GitExtensionsTests.cs +++ b/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs @@ -11,9 +11,9 @@ using Xunit.Abstractions; using Version = System.Version; -public partial class GitExtensionsTests : RepoTestBase +public class LibGit2GitExtensionsTests : RepoTestBase { - public GitExtensionsTests(ITestOutputHelper Logger) + public LibGit2GitExtensionsTests(ITestOutputHelper Logger) : base(Logger) { this.InitializeSourceControl(); From 3272834e568b0e3f8db54b436c58a50cd92f64af Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 7 Aug 2021 16:03:48 -0600 Subject: [PATCH 286/704] Delete dead code --- .../LibGit2GitExtensionsTests.cs | 16 ------------ .../LibGit2/LibGit2GitExtensions.cs | 26 ------------------- 2 files changed, 42 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs b/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs index c6580a7d..7f14277b 100644 --- a/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs +++ b/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs @@ -166,22 +166,6 @@ public void GetVersionHeight_ProgressAndReset(string version1, string version2, Assert.Equal(!versionHeightReset, height2 > height1); } - [Fact] - public void GetTruncatedCommitIdAsInteger_Roundtrip() - { - var firstCommit = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - var secondCommit = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - - int id1 = firstCommit.GetTruncatedCommitIdAsInt32(); - int id2 = secondCommit.GetTruncatedCommitIdAsInt32(); - - this.Logger.WriteLine($"Commit {firstCommit.Id.Sha.Substring(0, 8)} as int: {id1}"); - this.Logger.WriteLine($"Commit {secondCommit.Id.Sha.Substring(0, 8)} as int: {id2}"); - - Assert.Equal(firstCommit, this.LibGit2Repository.GetCommitFromTruncatedIdInteger(id1)); - Assert.Equal(secondCommit, this.LibGit2Repository.GetCommitFromTruncatedIdInteger(id2)); - } - [Fact] public void GetIdAsVersion_ReadsMajorMinorFromVersionTxt() { diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 3d17c5f6..9dabdbb2 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -97,18 +97,6 @@ public static int GetHeight(LibGit2Context context, Func? continue return GetCommitHeight(context.Commit, tracker, continueStepping); } - /// - /// Takes the first 4 bytes of a commit ID (i.e. first 8 characters of its hex-encoded SHA) - /// and returns them as an integer. - /// - /// The commit to identify with an integer. - /// The integer which identifies a commit. - public static int GetTruncatedCommitIdAsInt32(this Commit commit) - { - Requires.NotNull(commit, nameof(commit)); - return BitConverter.ToInt32(commit.Id.RawId, 0); - } - /// /// Takes the first 2 bytes of a commit ID (i.e. first 4 characters of its hex-encoded SHA) /// and returns them as an 16-bit unsigned integer. @@ -121,20 +109,6 @@ public static ushort GetTruncatedCommitIdAsUInt16(this Commit commit) return BitConverter.ToUInt16(commit.Id.RawId, 0); } - /// - /// Looks up a commit by an integer that captures the first for bytes of its ID. - /// - /// The repo to search for a matching commit. - /// The value returned from . - /// A matching commit. - public static Commit GetCommitFromTruncatedIdInteger(this Repository repo, int truncatedId) - { - Requires.NotNull(repo, nameof(repo)); - - byte[] rawId = BitConverter.GetBytes(truncatedId); - return repo.Lookup(EncodeAsHex(rawId)); - } - /// /// Returns the repository that belongs to. /// From 6668ac9259773d5dd4e42ced04d4676a919746e6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 7 Aug 2021 16:04:50 -0600 Subject: [PATCH 287/704] Always decode the first two bytes of a commit ID into `ushort` as big endian This fixes a non-deterministic version computation that varied based on endianness of the processor. Most computers use little-endian, which produced a decimal version that when converted back to hex with a typical calculator would have the first two commit ID bytes in swapped positions. Now with this change, we "fix" the endianness. We choose big endian since it won't swap the first two bytes like little endian did. But this presents another problem: all the generated versions now have a different value for the 4th integer component, and `nbgv get-commits` will no longer match a commit when it built using the little-endian version of NB.GV. I'll fix this in a subsequent commit so that this CLI tool will match on commits allowing the order to be swapped. Fixes #637 --- .../ManagedGit/GitObjectIdTests.cs | 2 +- .../VersionOracleTests.cs | 20 +++++++++++++++++++ .../LibGit2/LibGit2GitExtensions.cs | 6 +++--- .../ManagedGit/GitObjectId.cs | 2 +- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs index c06d8f67..baeb4ff7 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs @@ -93,7 +93,7 @@ public void AsUInt16Test() { // The hash code is the int32 representation of the first 4 bytes var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - Assert.Equal(0x914e, objectId.AsUInt16()); + Assert.Equal(0x4e91, objectId.AsUInt16()); Assert.Equal(0, GitObjectId.Empty.GetHashCode()); } diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 4f10abf1..7d992920 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -845,6 +845,26 @@ public void GitCommitIdShort() } } + [Fact] + public void GitCommidIdLeading16BitsDecodedWithBigEndian() + { + this.WriteVersionFile(new VersionOptions { Version = SemanticVersion.Parse("1.2"), GitCommitIdShortAutoMinimum = 4 }); + this.InitializeSourceControl(); + this.AddCommits(1); + var oracle = new VersionOracle(this.Context); + + string leadingFourChars = this.Context.GitCommitId.Substring(0, 4); + ushort expectedNumber = FromHex(leadingFourChars); + ushort actualNumber = checked((ushort)oracle.Version.Revision); + this.Logger.WriteLine("First two characters from commit ID in hex is {0}", leadingFourChars); + this.Logger.WriteLine("First two characters, converted to a number is {0}", expectedNumber); + this.Logger.WriteLine("Generated 16-bit ushort from commit ID is {0}, whose hex representation is {1}", actualNumber, ToHex(actualNumber)); + Assert.Equal(expectedNumber, actualNumber); + + static string ToHex(ushort number) => number.ToString("X"); + static ushort FromHex(string hex) => ushort.Parse(hex, System.Globalization.NumberStyles.HexNumber); + } + [Fact(Skip = "Slow test")] public void GetVersionHeight_VeryLongHistory() { diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 9dabdbb2..a0b46df1 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -3,8 +3,8 @@ namespace Nerdbank.GitVersioning.LibGit2 { using System; + using System.Buffers.Binary; using System.Collections.Generic; - using System.Globalization; using System.IO; using System.Linq; using System.Runtime.InteropServices; @@ -106,7 +106,7 @@ public static int GetHeight(LibGit2Context context, Func? continue public static ushort GetTruncatedCommitIdAsUInt16(this Commit commit) { Requires.NotNull(commit, nameof(commit)); - return BitConverter.ToUInt16(commit.Id.RawId, 0); + return BinaryPrimitives.ReadUInt16BigEndian(commit.Id.RawId); } /// @@ -301,7 +301,7 @@ private static bool IsCommitIdMismatch(Version version, VersionOptions versionOp /// True if the object's ID starts with after applying the . private static bool StartsWith(this ObjectId @object, ushort leadingBytes, ushort bitMask = 0xffff) { - ushort truncatedObjectId = BitConverter.ToUInt16(@object.RawId, 0); + ushort truncatedObjectId = BinaryPrimitives.ReadUInt16BigEndian(@object.RawId); return (truncatedObjectId & bitMask) == leadingBytes; } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs b/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs index b18d04a9..f21794b7 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs @@ -167,7 +167,7 @@ public override bool Equals(object? obj) /// /// A which represents the first two bytes of this . /// - public ushort AsUInt16() => BinaryPrimitives.ReadUInt16LittleEndian(this.Value.Slice(0, 2)); + public ushort AsUInt16() => BinaryPrimitives.ReadUInt16BigEndian(this.Value.Slice(0, 2)); /// /// Returns the SHA1 hash of this object. From de6ca295bb382fea61bd0760236fdd6f4bcb1bdd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 7 Aug 2021 20:28:50 -0600 Subject: [PATCH 288/704] Match commits based on versions that used either endian to calculate --- .../LibGit2GitExtensionsTests.cs | 14 ++++++++++++++ src/NerdBank.GitVersioning.Tests/TestUtilities.cs | 4 ++++ .../VersionOracleTests.cs | 7 ++----- .../LibGit2/LibGit2GitExtensions.cs | 11 ++++++++--- 4 files changed, 28 insertions(+), 8 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs b/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs index 7f14277b..b01ce4da 100644 --- a/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs +++ b/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -368,6 +369,19 @@ public void GetIdAsVersion_Roundtrip_UnstableOffset(int startingOffset, int offs } } + [Fact] + public void GetCommitsFromVersion_MatchesOnEitherEndian() + { + this.InitializeSourceControl(); + Commit commit = this.WriteVersionFile(new VersionOptions { Version = SemanticVersion.Parse("1.2"), GitCommitIdShortAutoMinimum = 4 }); + + Version originalVersion = new VersionOracle(this.Context).Version; + Version swappedEndian = new Version(originalVersion.Major, originalVersion.Minor, originalVersion.Build, BinaryPrimitives.ReverseEndianness((ushort)originalVersion.Revision)); + ushort twoBytesFromCommitId = checked((ushort)originalVersion.Revision); + Assert.Contains(commit, LibGit2GitExtensions.GetCommitsFromVersion(this.Context, originalVersion)); + Assert.Contains(commit, LibGit2GitExtensions.GetCommitsFromVersion(this.Context, swappedEndian)); + } + [Fact] public void GetIdAsVersion_Roundtrip_WithSubdirectoryVersionFiles() { diff --git a/src/NerdBank.GitVersioning.Tests/TestUtilities.cs b/src/NerdBank.GitVersioning.Tests/TestUtilities.cs index a67edbd1..cad5242a 100644 --- a/src/NerdBank.GitVersioning.Tests/TestUtilities.cs +++ b/src/NerdBank.GitVersioning.Tests/TestUtilities.cs @@ -79,6 +79,10 @@ internal static ExpandedRepo ExtractRepoArchive(string repoArchiveName) } } + internal static string ToHex(ushort number) => number.ToString("X"); + + internal static ushort FromHex(string hex) => ushort.Parse(hex, System.Globalization.NumberStyles.HexNumber); + internal class ExpandedRepo : IDisposable { internal ExpandedRepo(string repoPath) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 7d992920..1e0fc51f 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -854,15 +854,12 @@ public void GitCommidIdLeading16BitsDecodedWithBigEndian() var oracle = new VersionOracle(this.Context); string leadingFourChars = this.Context.GitCommitId.Substring(0, 4); - ushort expectedNumber = FromHex(leadingFourChars); + ushort expectedNumber = TestUtilities.FromHex(leadingFourChars); ushort actualNumber = checked((ushort)oracle.Version.Revision); this.Logger.WriteLine("First two characters from commit ID in hex is {0}", leadingFourChars); this.Logger.WriteLine("First two characters, converted to a number is {0}", expectedNumber); - this.Logger.WriteLine("Generated 16-bit ushort from commit ID is {0}, whose hex representation is {1}", actualNumber, ToHex(actualNumber)); + this.Logger.WriteLine("Generated 16-bit ushort from commit ID is {0}, whose hex representation is {1}", actualNumber, TestUtilities.ToHex(actualNumber)); Assert.Equal(expectedNumber, actualNumber); - - static string ToHex(ushort number) => number.ToString("X"); - static ushort FromHex(string hex) => ushort.Parse(hex, System.Globalization.NumberStyles.HexNumber); } [Fact(Skip = "Slow test")] diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index a0b46df1..aa27910b 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -284,7 +284,11 @@ private static bool IsCommitIdMismatch(Version version, VersionOptions versionOp ushort objectIdLeadingValue = (ushort)expectedCommitIdLeadingValue; ushort objectIdMask = (ushort)(objectIdLeadingValue == MaximumBuildNumberOrRevisionComponent ? 0xfffe : 0xffff); - return !commit.Id.StartsWith(objectIdLeadingValue, objectIdMask); + // Accept a big endian match or a little endian match. + // Nerdbank.GitVersioning up to v3.4 would produce versions based on the endianness of the CPU it ran on (typically little endian). + // Starting with v3.5, it deterministically used big endian. In order for `nbgv get-commits` to match on versions computed before and after the change, + // we match on either endian setting. + return !(commit.Id.StartsWith(objectIdLeadingValue, bigEndian: true, objectIdMask) || commit.Id.StartsWith(objectIdLeadingValue, bigEndian: false, objectIdMask)); } } @@ -298,10 +302,11 @@ private static bool IsCommitIdMismatch(Version version, VersionOptions versionOp /// The object whose ID is to be tested. /// The leading 16-bits to be tested. /// The mask that indicates which bits should be compared. + /// to read the first two bytes as big endian (v3.5+ behavior); to use little endian (v3.4 and earlier behavior). /// True if the object's ID starts with after applying the . - private static bool StartsWith(this ObjectId @object, ushort leadingBytes, ushort bitMask = 0xffff) + private static bool StartsWith(this ObjectId @object, ushort leadingBytes, bool bigEndian, ushort bitMask = 0xffff) { - ushort truncatedObjectId = BinaryPrimitives.ReadUInt16BigEndian(@object.RawId); + ushort truncatedObjectId = bigEndian ? BinaryPrimitives.ReadUInt16BigEndian(@object.RawId) : BinaryPrimitives.ReadUInt16LittleEndian(@object.RawId); return (truncatedObjectId & bitMask) == leadingBytes; } From 5789043fc06d0dd078a52c2e38b2e42c7839199a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 13 Aug 2021 22:33:00 -0600 Subject: [PATCH 289/704] Bump path-parse from 1.0.6 to 1.0.7 in /src/nerdbank-gitversioning.npm (#641) Bumps [path-parse](https://github.com/jbgutierrez/path-parse) from 1.0.6 to 1.0.7. - [Release notes](https://github.com/jbgutierrez/path-parse/releases) - [Commits](https://github.com/jbgutierrez/path-parse/commits/v1.0.7) --- updated-dependencies: - dependency-name: path-parse dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index 5d2beb75..c66da78b 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -2029,9 +2029,9 @@ path-is-absolute@^1.0.0: integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== path-root-regex@^0.1.0: version "0.1.2" From 1808050a987440698578162df0f4f077c86feb18 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 23 Aug 2021 08:51:43 -0600 Subject: [PATCH 290/704] Drop netcoreapp2.1 as a target It is no longer in its LTS lifecycle. --- azure-pipelines/dotnet.yml | 8 -------- test/Directory.Build.props | 2 +- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 34db9a40..50ba58f1 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -14,14 +14,6 @@ steps: testRunTitle: net472-$(Agent.JobName) condition: succeededOrFailed() -- task: DotNetCoreCLI@2 - displayName: dotnet test -f netcoreapp2.1 - inputs: - command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp2.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp2.1.binlog" - testRunTitle: netcoreapp2.1-$(Agent.JobName) - condition: succeededOrFailed() - - task: DotNetCoreCLI@2 displayName: dotnet test -f netcoreapp3.1 inputs: diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 4803641a..1b45d716 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,7 +2,7 @@ - net5.0;netcoreapp3.1;netcoreapp2.1;net472 + net5.0;netcoreapp3.1;net472 false true From 10ed82d6504eb858dfca86b69d0b732896556e9c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 23 Aug 2021 09:11:57 -0600 Subject: [PATCH 291/704] Suppress SA1401 (private fields) in tests --- test/.editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/.editorconfig b/test/.editorconfig index 19b19171..8aa791be 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -47,3 +47,6 @@ dotnet_diagnostic.CA1816.severity = silent # CA2007: Consider calling ConfigureAwait on the awaited task dotnet_diagnostic.CA2007.severity = none + +# SA1401: Fields should be private +dotnet_diagnostic.SA1401.severity = silent From f90f4949877855b010afdff5626dd238390ceb9d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 23 Aug 2021 11:40:33 -0600 Subject: [PATCH 292/704] Touch-up on code style --- .editorconfig | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 3f5b80ac..0689e4e0 100644 --- a/.editorconfig +++ b/.editorconfig @@ -129,7 +129,7 @@ csharp_indent_switch_labels = true csharp_indent_labels = flush_left # Prefer "var" everywhere -csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_for_built_in_types = false csharp_style_var_when_type_is_apparent = true:suggestion csharp_style_var_elsewhere = false:warning @@ -167,5 +167,8 @@ dotnet_diagnostic.SA1130.severity = silent # CA1508: Avoid dead conditional code dotnet_diagnostic.CA1508.severity = warning +# IDE1006: Naming Styles - StyleCop handles these for us +dotnet_diagnostic.IDE1006.severity = none + [*.sln] indent_style = tab From 9ead4781720fd277d41a16ea2ade0874e4282723 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 23 Aug 2021 16:06:41 -0600 Subject: [PATCH 293/704] Apply `is null` pattern and analyzer --- .editorconfig | 6 ++++++ src/Directory.Build.props | 6 +++++- .../BuildIntegrationTests.cs | 2 +- .../ManagedGit/DeltaStreamReaderTests.cs | 4 ++-- .../ReleaseManagerTests.cs | 4 ++-- src/NerdBank.GitVersioning.Tests/RepoTestBase.cs | 6 +++--- .../TestUtilities.cs | 2 +- .../VersionFileTests.cs | 2 +- .../AssemblyVersionOptionsConverter.cs | 2 +- .../CloudBuildServices/GitLab.cs | 4 ++-- .../CloudBuildServices/TeamCity.cs | 2 +- .../FilterPathJsonConverter.cs | 4 ++-- .../LibGit2/LibGit2GitExtensions.cs | 16 ++++++++-------- .../Managed/ManagedGitContext.cs | 6 +++--- .../Managed/ManagedGitExtensions.cs | 12 ++++++------ .../ManagedGit/GitCommitReader.cs | 2 +- .../ManagedGit/GitObjectId.cs | 2 +- src/NerdBank.GitVersioning/ManagedGit/GitPack.cs | 4 ++-- .../ManagedGit/GitPackDeltafiedStream.cs | 4 ++-- .../ManagedGit/GitPackIndexMappedReader.cs | 2 +- .../ManagedGit/GitPackReader.cs | 4 ++-- .../ManagedGit/GitRepository.cs | 10 +++++----- src/NerdBank.GitVersioning/ReleaseManager.cs | 8 ++++---- src/NerdBank.GitVersioning/SemanticVersion.cs | 4 ++-- .../SemanticVersionJsonConverter.cs | 2 +- src/NerdBank.GitVersioning/VersionOptions.cs | 8 +++----- src/NerdBank.GitVersioning/VersionOracle.cs | 2 +- .../ContextAwareTask.cs | 6 +++--- .../GetBuildVersion.cs | 8 ++++---- .../NativeVersionInfo.cs | 4 ++-- .../SetCloudBuildVariables.cs | 6 +++--- src/nbgv/Program.cs | 14 +++++++------- 32 files changed, 88 insertions(+), 80 deletions(-) diff --git a/.editorconfig b/.editorconfig index 98824c08..fb31b8c2 100644 --- a/.editorconfig +++ b/.editorconfig @@ -79,3 +79,9 @@ csharp_new_line_before_catch = true csharp_new_line_before_finally = true csharp_new_line_before_members_in_object_initializers = true csharp_new_line_before_members_in_anonymous_types = true + +# CSIsNull001: Use `is null` for null checks +dotnet_diagnostic.CSIsNull001.severity = warning + +# CSIsNull002: Use `is object` for non-null checks +dotnet_diagnostic.CSIsNull002.severity = warning diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 7f82c288..94a570b3 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -24,9 +24,13 @@ 2.0.312 - + + + all + runtime; build; native; contentfiles; analyzers + diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index b2ab89f5..d931f2e2 100644 --- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -219,7 +219,7 @@ public async Task GetBuildVersion_In_Git_But_Head_Lacks_VersionFile() var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later repo.Commit("empty", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); this.WriteVersionFile("3.4"); - Assumes.True(repo.Index[VersionFile.JsonFileName] == null); + Assumes.True(repo.Index[VersionFile.JsonFileName] is null); var buildResult = await this.BuildAsync(); Assert.Equal("3.4.0." + this.GetVersion().Revision, buildResult.BuildVersion); Assert.Equal("3.4.0+" + repo.Head.Tip.Id.Sha.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength), buildResult.AssemblyInformationalVersion); diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs index 2e475ca9..279e0a16 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs @@ -89,7 +89,7 @@ public void ReadStreamTest() DeltaInstruction? current; - while ((current = DeltaStreamReader.Read(stream)) != null) + while ((current = DeltaStreamReader.Read(stream)) is not null) { instructions.Add(current.Value); } @@ -139,7 +139,7 @@ public void ReadStreamTest_Memory() DeltaInstruction? current; - while ((current = DeltaStreamReader.Read(ref memory)) != null) + while ((current = DeltaStreamReader.Read(ref memory)) is not null) { instructions.Add(current.Value); } diff --git a/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs b/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs index c69f5120..c95500bf 100644 --- a/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs @@ -320,7 +320,7 @@ public void PrepareRelease_Master( // prepare release var releaseManager = new ReleaseManager(); - releaseManager.PrepareRelease(this.RepoPath, releaseUnstableTag, (nextVersion == null ? null : Version.Parse(nextVersion)), parameterVersionIncrement); + releaseManager.PrepareRelease(this.RepoPath, releaseUnstableTag, (nextVersion is null ? null : Version.Parse(nextVersion)), parameterVersionIncrement); // check if a branch was created Assert.Contains(this.LibGit2Repository.Branches, branch => branch.FriendlyName == expectedBranchName); @@ -394,7 +394,7 @@ public void PrepareRelease_MasterWithVersionDecrement(string initialVersion, str // running PrepareRelease should result in an error // because we're trying to add a prerelease tag to a version without prerelease tag this.AssertError( - () => new ReleaseManager().PrepareRelease(this.RepoPath, releaseUnstableTag, (nextVersion == null ? null : Version.Parse(nextVersion))), + () => new ReleaseManager().PrepareRelease(this.RepoPath, releaseUnstableTag, (nextVersion is null ? null : Version.Parse(nextVersion))), ReleasePreparationError.VersionDecrement); } diff --git a/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs b/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs index 4bcd8bbb..5cc81647 100644 --- a/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs +++ b/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs @@ -143,7 +143,7 @@ protected void AddCommits(int count = 1) protected Commit? WriteVersionTxtFile(string version = "1.2", string prerelease = "", string? relativeDirectory = null) { - if (relativeDirectory == null) + if (relativeDirectory is null) { relativeDirectory = string.Empty; } @@ -163,7 +163,7 @@ protected void AddCommits(int count = 1) { Requires.NotNull(versionData, nameof(versionData)); - if (relativeDirectory == null) + if (relativeDirectory is null) { relativeDirectory = string.Empty; } @@ -197,7 +197,7 @@ protected void AddCommits(int count = 1) if (Path.GetExtension(relativeFilePath) == ".json") { string txtFilePath = relativeFilePath.Substring(0, relativeFilePath.Length - 4) + "txt"; - if (!File.Exists(Path.Combine(this.RepoPath, txtFilePath)) && this.LibGit2Repository.Index[txtFilePath] != null) + if (!File.Exists(Path.Combine(this.RepoPath, txtFilePath)) && this.LibGit2Repository.Index[txtFilePath] is not null) { this.LibGit2Repository.Index.Remove(txtFilePath); } diff --git a/src/NerdBank.GitVersioning.Tests/TestUtilities.cs b/src/NerdBank.GitVersioning.Tests/TestUtilities.cs index a67edbd1..6d61fbf1 100644 --- a/src/NerdBank.GitVersioning.Tests/TestUtilities.cs +++ b/src/NerdBank.GitVersioning.Tests/TestUtilities.cs @@ -54,7 +54,7 @@ internal static void ExtractEmbeddedResource(string resourcePath, string extract using (var stream = GetEmbeddedResource(resourcePath)) { - Requires.Argument(stream != null, nameof(resourcePath), "Resource not found."); + Requires.Argument(stream is not null, nameof(resourcePath), "Resource not found."); using (var extractedFile = File.OpenWrite(extractedFilePath)) { stream.CopyTo(extractedFile); diff --git a/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs b/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs index a4ad2af3..f6330e61 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs @@ -140,7 +140,7 @@ public void SetVersion_WritesSimplestFile(string version, string assemblyVersion var versionOptions = new VersionOptions { Version = SemanticVersion.Parse(version), - AssemblyVersion = assemblyVersion != null || precision != null ? new VersionOptions.AssemblyVersionOptions(assemblyVersion != null ? new Version(assemblyVersion) : null, precision) : null, + AssemblyVersion = assemblyVersion is not null || precision is not null ? new VersionOptions.AssemblyVersionOptions(assemblyVersion is not null ? new Version(assemblyVersion) : null, precision) : null, VersionHeightOffset = versionHeightOffset, Inherit = inherit, }; diff --git a/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs b/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs index 0f88e0f5..0e88f638 100644 --- a/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs +++ b/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs @@ -51,7 +51,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var data = value as VersionOptions.AssemblyVersionOptions; - if (data != null) + if (data is not null) { if (data.PrecisionOrDefault == VersionOptions.DefaultVersionPrecision && !this.includeDefaults) { diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs b/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs index aa0c649a..21abebd2 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs @@ -14,13 +14,13 @@ internal class GitLab : ICloudBuild { public string BuildingBranch => - Environment.GetEnvironmentVariable("CI_COMMIT_TAG") == null ? + Environment.GetEnvironmentVariable("CI_COMMIT_TAG") is null ? $"refs/heads/{Environment.GetEnvironmentVariable("CI_COMMIT_REF_NAME")}" : null; public string BuildingRef => this.BuildingBranch ?? this.BuildingTag; public string BuildingTag => - Environment.GetEnvironmentVariable("CI_COMMIT_TAG") != null ? + Environment.GetEnvironmentVariable("CI_COMMIT_TAG") is not null ? $"refs/tags/{Environment.GetEnvironmentVariable("CI_COMMIT_TAG")}" : null; public string GitCommitId => Environment.GetEnvironmentVariable("CI_COMMIT_SHA"); diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs b/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs index e4df2b69..ec0cd84b 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs @@ -19,7 +19,7 @@ internal class TeamCity : ICloudBuild public string GitCommitId => Environment.GetEnvironmentVariable("BUILD_VCS_NUMBER"); - public bool IsApplicable => this.GitCommitId != null; + public bool IsApplicable => this.GitCommitId is not null; public bool IsPullRequest => false; diff --git a/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs b/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs index acd57e03..304c41f0 100644 --- a/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs +++ b/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs @@ -22,7 +22,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist throw new NotSupportedException(); } - if (this.repoRelativeBaseDirectory == null) + if (this.repoRelativeBaseDirectory is null) { throw new ArgumentNullException(nameof(this.repoRelativeBaseDirectory), $"Base directory must not be null to be able to deserialize filter paths. Ensure that one was passed to {nameof(VersionOptions.GetJsonSettings)}, and that the version.json file is being written to a Git repository."); } @@ -37,7 +37,7 @@ public override void WriteJson(JsonWriter writer, object value, JsonSerializer s throw new NotSupportedException(); } - if (this.repoRelativeBaseDirectory == null) + if (this.repoRelativeBaseDirectory is null) { throw new ArgumentNullException(nameof(this.repoRelativeBaseDirectory), $"Base directory must not be null to be able to serialize filter paths. Ensure that one was passed to {nameof(VersionOptions.GetJsonSettings)}, and that the version.json file is being written to a Git repository."); } diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 3d17c5f6..045c647a 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -60,13 +60,13 @@ internal static int GetVersionHeight(LibGit2Context context, Version? baseVersio var tracker = new GitWalkTracker(context); var versionOptions = tracker.GetVersion(context.Commit); - if (versionOptions == null) + if (versionOptions is null) { return 0; } var baseSemVer = - baseVersion != null ? SemanticVersion.Parse(baseVersion.ToString()) : + baseVersion is not null ? SemanticVersion.Parse(baseVersion.ToString()) : versionOptions.Version ?? SemVer0; var versionHeightPosition = versionOptions.VersionHeightPosition; @@ -174,7 +174,7 @@ public static IEnumerable GetCommitsFromVersion(LibGit2Context context, var tracker = new GitWalkTracker(context); var possibleCommits = from commit in GetCommitsReachableFromRefs(context.Repository) let commitVersionOptions = tracker.GetVersion(commit) - where commitVersionOptions != null + where commitVersionOptions is not null where !IsCommitIdMismatch(version, commitVersionOptions, commit) where !IsVersionHeightMismatch(version, commitVersionOptions, commit, tracker) select commit; @@ -221,7 +221,7 @@ private static bool CommitMatchesVersion(this Commit commit, SemanticVersion exp var commitVersionData = tracker.GetVersion(commit); var semVerFromFile = commitVersionData?.Version; - if (semVerFromFile == null) + if (semVerFromFile is null) { return false; } @@ -250,7 +250,7 @@ private static bool CommitMatchesVersion(this Commit commit, Version expectedVer var commitVersionData = tracker.GetVersion(commit); var semVerFromFile = commitVersionData?.Version; - if (semVerFromFile == null) + if (semVerFromFile is null) { return false; } @@ -422,7 +422,7 @@ bool ContainsRelevantChanges(IEnumerable changes) => int height = 1; - if (includePaths != null) + if (includePaths is not null) { // If there are no include paths, or any of the include // paths refer to the root of the repository, then do not @@ -527,8 +527,8 @@ internal static Version GetIdAsVersionHelper(this Commit? commit, VersionOptions // Don't use the ?? coalescing operator here because the position property getters themselves can return null, which should NOT be overridden with our default. // The default value is only appropriate if versionOptions itself is null. - var versionHeightPosition = versionOptions != null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; - var commitIdPosition = versionOptions != null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; + var versionHeightPosition = versionOptions is not null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; + var commitIdPosition = versionOptions is not null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; // The compiler (due to WinPE header requirements) only allows 16-bit version components, // and forbids 0xffff as a value. diff --git a/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs b/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs index d42f1aec..a6d4fab5 100644 --- a/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs +++ b/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs @@ -94,7 +94,7 @@ internal override int CalculateVersionHeight(VersionOptions? committedVersion, V { var workingCopyVersion = workingVersion?.Version?.Version; - if (workingCopyVersion == null || !workingCopyVersion.Equals(headCommitVersion)) + if (workingCopyVersion is null || !workingCopyVersion.Equals(headCommitVersion)) { // The working copy has changed the major.minor version. // So by definition the version height is 0, since no commit represents it yet. @@ -153,8 +153,8 @@ private Version GetIdAsVersionHelper(VersionOptions? versionOptions, int version // Don't use the ?? coalescing operator here because the position property getters themselves can return null, which should NOT be overridden with our default. // The default value is only appropriate if versionOptions itself is null. - var versionHeightPosition = versionOptions != null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; - var commitIdPosition = versionOptions != null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; + var versionHeightPosition = versionOptions is not null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; + var commitIdPosition = versionOptions is not null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; // The compiler (due to WinPE header requirements) only allows 16-bit version components, // and forbids 0xffff as a value. diff --git a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs b/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs index 58b8206e..2f05103e 100644 --- a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs +++ b/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs @@ -35,13 +35,13 @@ internal static int GetVersionHeight(ManagedGitContext context, Version? baseVer var tracker = new GitWalkTracker(context); var versionOptions = tracker.GetVersion(context.Commit.Value); - if (versionOptions == null) + if (versionOptions is null) { return 0; } var baseSemVer = - baseVersion != null ? SemanticVersion.Parse(baseVersion.ToString()) : + baseVersion is not null ? SemanticVersion.Parse(baseVersion.ToString()) : versionOptions.Version ?? SemVer0; var versionHeightPosition = versionOptions.VersionHeightPosition; @@ -69,7 +69,7 @@ private static bool CommitMatchesVersion(GitCommit commit, SemanticVersion expec var commitVersionData = tracker.GetVersion(commit); var semVerFromFile = commitVersionData?.Version; - if (commitVersionData == null || semVerFromFile == null) + if (commitVersionData is null || semVerFromFile is null) { return false; } @@ -167,7 +167,7 @@ bool TryCalculateHeight(GitCommit commit) int height = 1; - if (pathFilters != null) + if (pathFilters is not null) { var relevantCommit = true; @@ -250,7 +250,7 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git isRelevant = IsRelevantCommit( repository, repository.GetTree(entry.Sha), - parentEntry == null ? GitTree.Empty : repository.GetTree(parentEntry.Sha), + parentEntry is null ? GitTree.Empty : repository.GetTree(parentEntry.Sha), $"{fullPath}/", filters); } @@ -262,7 +262,7 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git } } - if (parentEntry != null) + if (parentEntry is not null) { parent.Children.Remove(child.Key); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs index 25b22e49..8af84e05 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs @@ -38,7 +38,7 @@ public static class GitCommitReader /// public static GitCommit Read(Stream stream, GitObjectId sha, bool readAuthor = false) { - if (stream == null) + if (stream is null) { throw new ArgumentNullException(nameof(stream)); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs b/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs index b18d04a9..76b5d672 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs @@ -174,7 +174,7 @@ public override bool Equals(object? obj) /// public override string ToString() { - if (this.sha == null) + if (this.sha is null) { this.sha = this.CreateString(0, 20); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs index 5d19128d..576dd50d 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs @@ -146,7 +146,7 @@ public bool TryGetObject(GitObjectId objectId, string objectType, out Stream? va { var offset = this.GetOffset(objectId); - if (offset == null) + if (offset is null) { value = null; return false; @@ -268,7 +268,7 @@ public void Dispose() var indexReader = this.indexReader.Value; var offset = indexReader.GetOffset(objectId); - if (offset != null) + if (offset is not null) { this.offsets.Add(objectId, offset.Value); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs index f2ab7d0e..3cff6c53 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs @@ -169,7 +169,7 @@ protected override void Dispose(bool disposing) private bool TryGetInstruction(out DeltaInstruction instruction) { - if (this.current != null && this.offset < this.current.Value.Size) + if (this.current is not null && this.offset < this.current.Value.Size) { instruction = this.current.Value; return true; @@ -177,7 +177,7 @@ private bool TryGetInstruction(out DeltaInstruction instruction) this.current = DeltaStreamReader.Read(this.deltaStream); - if (this.current == null) + if (this.current is null) { instruction = default; return false; diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs index 279f0403..b3690166 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs @@ -32,7 +32,7 @@ public unsafe class GitPackIndexMappedReader : GitPackIndexReader /// public GitPackIndexMappedReader(FileStream stream) { - if (stream == null) + if (stream is null) { throw new ArgumentNullException(nameof(stream)); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs index a1eba9ae..354060d4 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs @@ -13,12 +13,12 @@ internal static class GitPackReader public static Stream GetObject(GitPack pack, Stream stream, long offset, string objectType, GitPackObjectType packObjectType) { - if (pack == null) + if (pack is null) { throw new ArgumentNullException(nameof(pack)); } - if (stream == null) + if (stream is null) { throw new ArgumentNullException(nameof(stream)); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 459f23c6..05e8fd53 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -192,7 +192,7 @@ public string ShortenObjectId(GitObjectId objectId, int minimum) { var objectish = sha.Substring(0, length); - if (this.Lookup(objectish) != null) + if (this.Lookup(objectish) is not null) { return objectish; } @@ -263,7 +263,7 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) { using (Stream? stream = this.GetObjectBySha(sha, "commit")) { - if (stream == null) + if (stream is null) { throw new GitException($"The commit {sha} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; } @@ -396,7 +396,7 @@ public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) // It's possible for the same object to be present in both the object database and the pack files, // or in multiple pack files. - if (objectId != null && !possibleObjectIds.Contains(objectId.Value)) + if (objectId is not null && !possibleObjectIds.Contains(objectId.Value)) { if (possibleObjectIds.Count > 0) { @@ -435,7 +435,7 @@ public GitTree GetTree(GitObjectId sha) { using (Stream? stream = this.GetObjectBySha(sha, "tree")) { - if (stream == null) + if (stream is null) { throw new GitException($"The tree {sha} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; } @@ -461,7 +461,7 @@ public GitObjectId GetTreeEntry(GitObjectId treeId, ReadOnlySpan nodeName) { using (Stream? treeStream = this.GetObjectBySha(treeId, "tree")) { - if (treeStream == null) + if (treeStream is null) { throw new GitException($"The tree {treeId} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; } diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index e30efa6a..a59e4739 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -243,7 +243,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag = // get the current version var versionOptions = context.VersionFile.GetVersion(); - if (versionOptions == null) + if (versionOptions is null) { this.stderr.WriteLine($"Failed to load version file for directory '{projectDirectory}'."); throw new ReleasePreparationException(ReleasePreparationError.NoVersionFile); @@ -274,7 +274,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag = var nextDevVersion = this.GetNextDevVersion(versionOptions, nextVersion, versionIncrement); // check if the release branch already exists - if (repository.Branches[releaseBranchName] != null) + if (repository.Branches[releaseBranchName] is not null) { this.stderr.WriteLine($"Cannot create branch '{releaseBranchName}' because it already exists."); throw new ReleasePreparationException(ReleasePreparationError.BranchAlreadyExists); @@ -371,7 +371,7 @@ private void UpdateVersion(LibGit2Context context, SemanticVersion oldVersion, S private Signature GetSignature(Repository repository) { var signature = repository.Config.BuildSignature(DateTimeOffset.Now); - if (signature == null) + if (signature is null) { this.stderr.WriteLine("Cannot create commits in this repo because git user name and email are not configured."); throw new ReleasePreparationException(ReleasePreparationError.UserNotConfigured); @@ -430,7 +430,7 @@ private SemanticVersion GetNextDevVersion(VersionOptions versionOptions, Version var currentVersion = versionOptions.Version; SemanticVersion nextDevVersion; - if (nextVersionOverride != null) + if (nextVersionOverride is not null) { nextDevVersion = new SemanticVersion(nextVersionOverride, currentVersion.Prerelease, currentVersion.BuildMetadata); } diff --git a/src/NerdBank.GitVersioning/SemanticVersion.cs b/src/NerdBank.GitVersioning/SemanticVersion.cs index 9b503b46..ad07b529 100644 --- a/src/NerdBank.GitVersioning/SemanticVersion.cs +++ b/src/NerdBank.GitVersioning/SemanticVersion.cs @@ -155,7 +155,7 @@ internal SemanticVersion.Position? VersionHeightPosition /// /// Gets a value indicating whether this instance is the default "0.0" instance. /// - internal bool IsDefault => this.Version?.Major == 0 && this.Version.Minor == 0 && this.Version.Build == -1 && this.Version.Revision == -1 && this.Prerelease == null && this.BuildMetadata == null; + internal bool IsDefault => this.Version?.Major == 0 && this.Version.Minor == 0 && this.Version.Build == -1 && this.Version.Revision == -1 && this.Prerelease is null && this.BuildMetadata is null; /// /// Gets the debugger display for this instance. @@ -239,7 +239,7 @@ public override string ToString() /// true if the instances have equal values; false otherwise. public bool Equals(SemanticVersion other) { - if (other == null) + if (other is null) { return false; } diff --git a/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs b/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs index a064cb19..a4ae7f34 100644 --- a/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs +++ b/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs @@ -32,7 +32,7 @@ public override object ReadJson(JsonReader reader, Type objectType, object exist public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { var version = value as SemanticVersion; - if (version != null) + if (version is not null) { writer.WriteValue(version.ToString()); return; diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index 7aee1dfa..cac77f86 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -570,9 +570,7 @@ internal bool IsDefaultVersionTheOnlyPropertySet { get { - return this.Version != null - && this.AssemblyVersion == null - && (this.CloudBuild?.IsDefault ?? true) + return this.Version is not null && this.AssemblyVersion is null && (this.CloudBuild?.IsDefault ?? true) && this.VersionHeightOffset == 0 && !this.SemVer1NumericIdentifierPadding.HasValue && !this.Inherit; @@ -693,7 +691,7 @@ public bool Equals(NuGetPackageVersionOptions? x, NuGetPackageVersionOptions? y) return true; } - if (x == null || y == null) + if (x is null || y is null) { return false; } @@ -1575,7 +1573,7 @@ public bool Equals(ReleaseOptions? x, ReleaseOptions? y) /// public int GetHashCode(ReleaseOptions? obj) { - if (obj == null) + if (obj is null) return 0; unchecked diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 84c83019..93a11394 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -294,7 +294,7 @@ public IDictionary CloudBuildAllVars var properties = this.GetType().GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); foreach (var property in properties) { - if (property.GetCustomAttribute() == null) + if (property.GetCustomAttribute() is null) { var value = property.GetValue(this); if (value is object) diff --git a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs index b4c1e51b..f3bb3e17 100644 --- a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs +++ b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs @@ -31,11 +31,11 @@ public override bool Execute() var outerProperties = this.GetType().GetRuntimeProperties().ToDictionary(i => i.Name); var innerProperties = innerTaskType.GetRuntimeProperties().ToDictionary(i => i.Name); var propertiesDiscovery = from outerProperty in outerProperties.Values - where outerProperty.SetMethod != null && outerProperty.GetMethod != null + where outerProperty.SetMethod is not null && outerProperty.GetMethod is not null let innerProperty = innerProperties[outerProperty.Name] select new { outerProperty, innerProperty }; var propertiesMap = propertiesDiscovery.ToArray(); - var outputPropertiesMap = propertiesMap.Where(pair => pair.outerProperty.GetCustomAttribute() != null).ToArray(); + var outputPropertiesMap = propertiesMap.Where(pair => pair.outerProperty.GetCustomAttribute() is not null).ToArray(); foreach (var propertyPair in propertiesMap) { @@ -54,7 +54,7 @@ public override bool Execute() return result; #else // On .NET Framework (on Windows), we find native binaries by adding them to our PATH. - if (this.UnmanagedDllDirectory != null) + if (this.UnmanagedDllDirectory is not null) { string pathEnvVar = Environment.GetEnvironmentVariable("PATH"); string[] searchPaths = pathEnvVar.Split(Path.PathSeparator); diff --git a/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs b/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs index 2a9c00d4..77b79342 100644 --- a/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs +++ b/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs @@ -237,7 +237,7 @@ protected override bool ExecuteInner() oracle.PublicRelease = string.Equals(this.DefaultPublicRelease, "true", StringComparison.OrdinalIgnoreCase); } - if (this.BuildMetadata != null) + if (this.BuildMetadata is not null) { oracle.BuildMetadata.AddRange(this.BuildMetadata.Split(';')); } @@ -259,7 +259,7 @@ protected override bool ExecuteInner() this.PrereleaseVersion = oracle.PrereleaseVersion; this.GitCommitId = oracle.GitCommitId; this.GitCommitIdShort = oracle.GitCommitIdShort; - this.GitCommitDateTicks = oracle.GitCommitDate != null ? oracle.GitCommitDate.Value.UtcTicks.ToString(CultureInfo.InvariantCulture) : null; + this.GitCommitDateTicks = oracle.GitCommitDate is not null ? oracle.GitCommitDate.Value.UtcTicks.ToString(CultureInfo.InvariantCulture) : null; this.GitVersionHeight = oracle.VersionHeight; this.BuildMetadataFragment = oracle.BuildMetadataFragment; this.CloudBuildNumber = oracle.CloudBuildNumberEnabled ? oracle.CloudBuildNumber : null; @@ -279,7 +279,7 @@ protected override bool ExecuteInner() var allVariables = oracle.CloudBuildAllVars .Select(item => new TaskItem(item.Key, new Dictionary { { "Value", item.Value } })); - if (cloudBuildVersionVars != null) + if (cloudBuildVersionVars is not null) { cloudBuildVersionVars = cloudBuildVersionVars .Union(allVariables); @@ -290,7 +290,7 @@ protected override bool ExecuteInner() } } - if (cloudBuildVersionVars != null) + if (cloudBuildVersionVars is not null) { this.CloudBuildVersionVars = cloudBuildVersionVars.ToArray(); } diff --git a/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs index 8709c89e..8153a545 100644 --- a/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs @@ -106,7 +106,7 @@ BLOCK NBGV_VERSION_BLOCK public override bool Execute() { this.generator = this.CreateGenerator(); - if (this.generator != null) + if (this.generator is not null) { this.generator.StartFile(); @@ -300,7 +300,7 @@ protected void AddCodeComment(string comment, string token) { var sr = new StringReader(comment); string line; - while ((line = sr.ReadLine()) != null) + while ((line = sr.ReadLine()) is not null) { this.codeBuilder.Append(token); this.codeBuilder.AppendLine(line); diff --git a/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs b/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs index 9939043d..b721152c 100644 --- a/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs +++ b/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs @@ -20,7 +20,7 @@ public class SetCloudBuildVariables : Task public override bool Execute() { var cloudBuild = CloudBuild.Active; - if (cloudBuild != null) + if (cloudBuild is not null) { var envVars = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -42,7 +42,7 @@ public override bool Execute() } } - if (this.CloudBuildVersionVars != null) + if (this.CloudBuildVersionVars is not null) { foreach (var variable in this.CloudBuildVersionVars) { @@ -82,7 +82,7 @@ private void PipeOutputToMSBuildLog(string output, bool warning) using (var logReader = new StringReader(output)) { string line; - while ((line = logReader.ReadLine()) != null) + while ((line = logReader.ReadLine()) is not null) { // The prefix is presumed to nullify the effect in a real cloud build, // yet make it detectable by a unit test. diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 7df6b7bf..e9ae5d75 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -282,7 +282,7 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList met } var oracle = new VersionOracle(context, CloudBuild.Active); - if (metadata != null) + if (metadata is not null) { oracle.BuildMetadata.AddRange(metadata); } @@ -418,7 +418,7 @@ private static int OnGetVersionCommand(string project, IReadOnlyList met } var property = oracle.GetType().GetProperty(variable, CaseInsensitiveFlags); - if (property == null) + if (property is null) { Console.Error.WriteLine("Variable \"{0}\" not a version property.", variable); return (int)ExitCodes.BadVariable; @@ -447,7 +447,7 @@ private static int OnSetVersionCommand(string project, string version) using var context = GitContext.Create(searchPath, writable: true); var existingOptions = context.VersionFile.GetVersion(out string actualDirectory); string versionJsonPath; - if (existingOptions != null) + if (existingOptions is not null) { existingOptions.Version = semver; versionJsonPath = context.VersionFile.SetVersion(actualDirectory, existingOptions); @@ -598,7 +598,7 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata using var context = GitContext.Create(searchPath, writable: AlwaysUseLibGit2); var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild); - if (metadata != null) + if (metadata is not null) { oracle.BuildMetadata.AddRange(metadata); } @@ -620,7 +620,7 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata } } - if (define != null) + if (define is not null) { foreach (string def in define) { @@ -641,7 +641,7 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata } } - if (activeCloudBuild != null) + if (activeCloudBuild is not null) { if (string.IsNullOrEmpty(version)) { From 8a884fa9e744384cb0370574e0436ba0a36c52cc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Aug 2021 16:54:57 -0600 Subject: [PATCH 294/704] Create a ProjectReference item for inner .targets invocation This allows consumers of NB.GV to use `msbuild -graph -isolate` without seeing errors about unpredicted MSBuild task invocations. See the [MSBuild static graph][1] for more information. [1]: https://github.com/dotnet/msbuild/blob/main/documentation/specs/static-graph.md#what-is-static-graph --- .../Nerdbank.GitVersioning.Inner.targets | 6 +++ .../build/Nerdbank.GitVersioning.targets | 45 +++++++++++-------- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets index a1a5a4d9..8075fb21 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets @@ -42,5 +42,11 @@ + + + + + + \ No newline at end of file diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 9e39ea91..5598dbab 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -62,28 +62,37 @@ <_NBGV_BuildingRef>$(_NBGV_BuildingTag) <_NBGV_BuildingRef Condition=" '$(_NBGV_BuildingRef)' == '' ">$(_NBGV_BuildingBranch) + + $(MSBuildProjectDirectory) + $(NBGV_InnerGlobalProperties)GitRepoRoot=$(GitRepoRoot); + $(NBGV_InnerGlobalProperties)PublicRelease=$(PublicRelease); + $(NBGV_InnerGlobalProperties)_NBGV_BuildingRef=$(_NBGV_BuildingRef); + $(NBGV_InnerGlobalProperties)ProjectPathRelativeToGitRepoRoot=$(ProjectPathRelativeToGitRepoRoot); + $(NBGV_InnerGlobalProperties)ProjectDirectory=$(GitVersionBaseDirectory); + $(NBGV_InnerGlobalProperties)OverrideBuildNumberOffset=$(OverrideBuildNumberOffset); + $(MSBuildThisFileDirectory)Nerdbank.GitVersioning.Inner.targets - - - $(MSBuildProjectDirectory) - - GitRepoRoot=$(GitRepoRoot); - PublicRelease=$(PublicRelease); - BuildMetadata=@(BuildMetadata, ','); - _NBGV_BuildingRef=$(_NBGV_BuildingRef); - ProjectPathRelativeToGitRepoRoot=$(ProjectPathRelativeToGitRepoRoot); - ProjectDirectory=$(GitVersionBaseDirectory); - OverrideBuildNumberOffset=$(OverrideBuildNumberOffset); - - $(MSBuildThisFileDirectory)Nerdbank.GitVersioning.Inner.targets - + + + + - - - - + + + + GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars + $(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ','); + @(NBGV_GlobalPropertiesToRemove) + + false + false + false + + + + From 3545d140094004829d0dbf3cc7ff53005fcfb749 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Aug 2021 17:25:27 -0600 Subject: [PATCH 295/704] Suppress Configuration and Platform from causing version recalculation --- .../build/Nerdbank.GitVersioning.targets | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 5598dbab..a6e47aac 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -76,6 +76,8 @@ + + From 12869492cfcb060254753a04d02f75b6ee7c13a3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Aug 2021 17:28:10 -0600 Subject: [PATCH 296/704] Fix build metadata, and force reuse of the P2P item --- .../build/Nerdbank.GitVersioning.targets | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index a6e47aac..13619213 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -91,13 +91,18 @@ false false false + true - + @@ -114,7 +119,11 @@ - + From dc12ff8fee518d784ddecfc0284c212262fc3e9f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Aug 2021 17:32:49 -0600 Subject: [PATCH 297/704] Remove RuntimeIdentifier from global properties that propagate --- .../build/Nerdbank.GitVersioning.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 13619213..37eaea04 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -76,6 +76,7 @@ + From 1c1be613d4665c75f4dd52539cf7d510102987ee Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Aug 2021 18:21:57 -0600 Subject: [PATCH 298/704] Drop .NET Core 2.1 SDK support 2.1 has fallen out of its LTS lifetime, and the docker images have been removed. --- azure-pipelines.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c03e99ab..26a3ac28 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -14,8 +14,6 @@ resources: containers: - container: xenial image: andrewarnott/linux-buildagent - - container: bionic-2.1 - image: microsoft/dotnet:2.1-sdk-bionic - container: bionic image: mcr.microsoft.com/dotnet/core/sdk:3.1-bionic - container: focal @@ -272,8 +270,6 @@ stages: # xenial: # containerImage: xenial # configureContainerCommand: 'sudo apt update && sudo apt-get install -y git' - Ubuntu_Bionic_2_1: - containerImage: bionic-2.1 Ubuntu_Bionic: containerImage: bionic Ubuntu_Focal: From 4a7a492cf3b4c0afb328b52446c720ea27226df3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 27 Aug 2021 18:26:43 -0600 Subject: [PATCH 299/704] Call out error when @(BuildMetadata) changes too late --- .../build/Nerdbank.GitVersioning.targets | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 37eaea04..62e6fc2f 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -79,6 +79,8 @@ + + <_BuildMetadataSnapped Include="@(BuildMetadata)" /> @@ -97,6 +99,8 @@ + + Date: Wed, 1 Sep 2021 11:48:29 -0600 Subject: [PATCH 300/704] Bump Microsoft.NET.Test.Sdk from 16.10.0 to 16.11.0 (#114) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.10.0 to 16.11.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.10.0...v16.11.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 660f9fb5..c66b7aac 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From ad83aa039c3868874a928c92aa886726a7623d2d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Sep 2021 11:48:43 -0600 Subject: [PATCH 301/704] Bump Microsoft.Net.Compilers.Toolset from 3.10.0 to 3.11.0 (#113) Bumps [Microsoft.Net.Compilers.Toolset](https://github.com/dotnet/roslyn) from 3.10.0 to 3.11.0. - [Release notes](https://github.com/dotnet/roslyn/releases) - [Changelog](https://github.com/dotnet/roslyn/blob/main/docs/Breaking%20API%20Changes.md) - [Commits](https://github.com/dotnet/roslyn/commits) --- updated-dependencies: - dependency-name: Microsoft.Net.Compilers.Toolset dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 12555245..c732a3a9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -30,7 +30,7 @@ - + From 2e44aa4932b89e62b2be59f39af428ade8ee0572 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 1 Sep 2021 12:34:59 -0600 Subject: [PATCH 302/704] Merge pull request #650 from dotnet/dockerDocs Document considerations for building inside a container --- doc/cloudbuild.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/cloudbuild.md b/doc/cloudbuild.md index 0fc2ca19..80520aca 100644 --- a/doc/cloudbuild.md +++ b/doc/cloudbuild.md @@ -148,9 +148,21 @@ We define a GitHub Action that installs the `nbgv` CLI tool, provides version da Check out [nerdbank-gitversioning on the GitHub Actions marketplace](https://github.com/marketplace/actions/nerdbank-gitversioning). ### TeamCity + TeamCity does not expose the build branch by default as an environment variable. This can be exposed by adding an environment variable called BUILD_GIT_BRANCH with the value of `%teamcity.build.vcs.branch.%` where `` is the root id described on the TeamCity VCS roots page. Details on this variable can be found on the [TeamCity docs](https://confluence.jetbrains.com/display/TCD8/Predefined+Build+Parameters). +### Docker build + +When building inside a docker container, special considerations may apply: + +1. Make sure the container has access to the entire repo, including the `.git` directory. +2. Certain environment variables from the CI system may need to be exposed to the container. + When a CI system checks out a 'detached head', computing the version relies on environment variables to know which 'branch' was checked out, among other things. + You can look up the specific environment variables that are necessary for your particular CI service by looking for their names in the `src/NerdBank.GitVersioning/CloudBuildServices` directory of this repo. + For example [these lines](https://github.com/dotnet/Nerdbank.GitVersioning/blob/dd4dff99c5c44634d9041dde7a2ee104db821a10/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs#L24-L26) identify the two environment variables that are required for an Azure Pipelines CI system. + When using `docker run` yourself in your build script, you can add `--env BUILD_SOURCEBRANCH --env SYSTEM_TEAMPROJECTID` to your command line to pass-through those environment variables to your container. + [Issue37]: https://github.com/dotnet/Nerdbank.GitVersioning/issues/37 From 9ac560c10f1a1e4f6397519d66956f0f8bfddc3b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 1 Sep 2021 22:36:19 -0600 Subject: [PATCH 303/704] Fix SDK installation on ARM64 --- tools/Install-DotNetSdk.ps1 | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 00772a9e..67c66c1e 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -29,6 +29,9 @@ $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot # Look up actual required .NET Core SDK version from global.json $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" +$arch = 'x64' +if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' } + # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() $windowsDesktopRuntimeVersions = @() @@ -51,7 +54,7 @@ Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$P $windowsDesktopRuntimeVersions += $v } } - + # Add target frameworks of the form: netXX $targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% { $v = $Matches[1] @@ -86,7 +89,7 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { $Version = $versionInfo[-1] } - Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-x64.exe" -OutDir "$DotNetInstallScriptRoot" + Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-$arch.exe" -OutDir "$DotNetInstallScriptRoot" } Function Install-DotNet($Version, [switch]$Runtime) { @@ -103,7 +106,7 @@ Function Install-DotNet($Version, [switch]$Runtime) { } $switches = @( - '-Architecture','x64' + '-Architecture',$arch ) $envVars = @{ # For locally installed dotnet, skip first time experience which takes a long time From c70330018b2f9c772ef886819baf47537214d84e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Sep 2021 15:55:41 -0600 Subject: [PATCH 304/704] Update StyleCop.Analyzers version --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index c732a3a9..277c9cde 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -35,7 +35,7 @@ - + From b2453ab34a09cfb47c3d34e8cf912af611a5283e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Sep 2021 21:07:23 -0600 Subject: [PATCH 305/704] Fix position of runsettings in .editorconfig --- .editorconfig | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.editorconfig b/.editorconfig index 0689e4e0..6015ff48 100644 --- a/.editorconfig +++ b/.editorconfig @@ -20,11 +20,11 @@ insert_final_newline = true trim_trailing_whitespace = true # Xml project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,runsettings}] +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] indent_size = 2 # Xml config files -[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}] indent_size = 2 # JSON files From eba9acb28b6c66b40a14d7759365b20a9d89df0f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Sep 2021 20:49:50 -0600 Subject: [PATCH 306/704] Update .NET SDK to 5.0.400 --- .devcontainer/Dockerfile | 2 +- global.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 4e770766..88949946 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0.202-focal +FROM mcr.microsoft.com/dotnet/sdk:5.0.400-focal # 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/global.json b/global.json index d28f85bf..9f36eab1 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.302", + "version": "5.0.400", "rollForward": "patch", "allowPrerelease": false } From 09a13ca93d61d7f1745d023e14b167b4066a85e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sat, 11 Sep 2021 16:52:57 +0200 Subject: [PATCH 307/704] Move implementation of the "cloud" command out of Program.cs into the "CloudCommand" class --- src/NerdBank.GitVersioning/CloudCommand.cs | 176 +++++++++++++++++++++ src/nbgv/Program.cs | 78 +++------ 2 files changed, 199 insertions(+), 55 deletions(-) create mode 100644 src/NerdBank.GitVersioning/CloudCommand.cs diff --git a/src/NerdBank.GitVersioning/CloudCommand.cs b/src/NerdBank.GitVersioning/CloudCommand.cs new file mode 100644 index 00000000..d85566c9 --- /dev/null +++ b/src/NerdBank.GitVersioning/CloudCommand.cs @@ -0,0 +1,176 @@ +namespace Nerdbank.GitVersioning +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Linq; + using Validation; + + /// + /// Implementation of the "nbgv cloud" command that updates the build environments variables with version variables + /// + public class CloudCommand + { + /// + /// Defines the possible errors of the "cloud" command + /// + public enum CloudCommandError + { + /// + /// Teh specified CI system was not found + /// + NoCloudBuildProviderMatch, + + /// + /// A cloud variable was defined multiple times + /// + DuplicateCloudVariable, + + /// + /// No supported cloud build environment could be detected + /// + NoCloudBuildEnvDetected + } + + /// + /// Exception indicating an error while setting build variables + /// + public class CloudCommandException : Exception + { + /// + /// Gets the error that occurred. + /// + public CloudCommandError Error { get; } + + /// + /// Initializes a new instance of + /// + /// The message that describes the error. + /// The error that occurred. + public CloudCommandException(string message, CloudCommandError error) : base(message) => this.Error = error; + } + + private readonly TextWriter stdout; + private readonly TextWriter stderr; + + /// + /// Initializes a new instance of . + /// + /// The to write output to (e.g. ). + /// The to write error messages to (e.g. ). + public CloudCommand(TextWriter outputWriter = null, TextWriter errorWriter = null) + { + this.stdout = outputWriter ?? TextWriter.Null; + this.stderr = errorWriter ?? TextWriter.Null; + } + + + /// + /// Adds version variables to the the current cloud build environment. + /// + /// Thrown when the build environment could not be updated. + /// + /// The path to the directory which may (or its ancestors may) define the version file. + /// + /// + /// Optionally adds an identifier to the build metadata part of a semantic version. + /// + /// + /// The string to use for the cloud build number. If not specified, the computed version will be used. + /// + /// + /// The CI system to activate. If not specified, auto-detection will be used. + /// + /// + /// Controls whether to define all version variables as cloud build variables. + /// + /// + /// Controls whether to define common version variables as cloud build variables. + /// + /// + /// Additional cloud build variables to define. + /// + /// + /// Force usage of LibGit2 for accessing the git repository. + /// + public void SetBuildVariables(string projectDirectory, IEnumerable metadata, string version, string ciSystem, bool allVars, bool commonVars, IEnumerable> additionalVariables, bool alwaysUseLibGit2) + { + Requires.NotNull(projectDirectory, nameof(projectDirectory)); + Requires.NotNull(additionalVariables, nameof(additionalVariables)); + + ICloudBuild activeCloudBuild = CloudBuild.Active; + if (!string.IsNullOrEmpty(ciSystem)) + { + int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, ciSystem, StringComparison.OrdinalIgnoreCase)); + if (matchingIndex == -1) + { + throw new CloudCommandException( + $"No cloud provider found by the name: \"{ciSystem}\"", + CloudCommandError.NoCloudBuildProviderMatch); + } + + activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex]; + } + + using var context = GitContext.Create(projectDirectory, writable: alwaysUseLibGit2); + var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild); + if (metadata is not null) + { + oracle.BuildMetadata.AddRange(metadata); + } + + var variables = new Dictionary(); + if (allVars) + { + foreach (var pair in oracle.CloudBuildAllVars) + { + variables.Add(pair.Key, pair.Value); + } + } + + if (commonVars) + { + foreach (var pair in oracle.CloudBuildVersionVars) + { + variables.Add(pair.Key, pair.Value); + } + } + + foreach (var kvp in additionalVariables) + { + if (variables.ContainsKey(kvp.Key)) + { + throw new CloudCommandException( + $"Cloud build variable \"{kvp.Key}\" specified more than once.", + CloudCommandError.DuplicateCloudVariable); + } + + variables[kvp.Key] = kvp.Value; + } + + if (activeCloudBuild is not null) + { + if (string.IsNullOrEmpty(version)) + { + version = oracle.CloudBuildNumber; + } + + activeCloudBuild.SetCloudBuildNumber(version, this.stdout, this.stderr); + + foreach (var pair in variables) + { + activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, this.stdout, this.stderr); + } + } + else + { + throw new CloudCommandException( + "No cloud build detected.", + CloudCommandError.NoCloudBuildEnvDetected); + } + } + + + private static string[] CloudProviderNames => CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name).ToArray(); + } +} diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index b68a1fef..e507d38e 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -583,43 +583,7 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata return (int)ExitCodes.NoGitRepo; } - ICloudBuild activeCloudBuild = CloudBuild.Active; - if (!string.IsNullOrEmpty(ciSystem)) - { - int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, ciSystem, StringComparison.OrdinalIgnoreCase)); - if (matchingIndex == -1) - { - Console.Error.WriteLine("No cloud provider found by the name: \"{0}\"", ciSystem); - return (int)ExitCodes.NoCloudBuildProviderMatch; - } - - activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex]; - } - - using var context = GitContext.Create(searchPath, writable: AlwaysUseLibGit2); - var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild); - if (metadata is not null) - { - oracle.BuildMetadata.AddRange(metadata); - } - - var variables = new Dictionary(); - if (allVars) - { - foreach (var pair in oracle.CloudBuildAllVars) - { - variables.Add(pair.Key, pair.Value); - } - } - - if (commonVars) - { - foreach (var pair in oracle.CloudBuildVersionVars) - { - variables.Add(pair.Key, pair.Value); - } - } - + var additionalVariables = new Dictionary(); if (define is not null) { foreach (string def in define) @@ -631,37 +595,41 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata return (int)ExitCodes.BadCloudVariable; } - if (variables.ContainsKey(split[0])) + if (additionalVariables.ContainsKey(split[0])) { Console.Error.WriteLine($"Cloud build variable \"{split[0]}\" specified more than once."); return (int)ExitCodes.DuplicateCloudVariable; } - variables[split[0]] = split[1]; + additionalVariables[split[0]] = split[1]; } } - if (activeCloudBuild is not null) + try + { + var cloudCommand = new CloudCommand(Console.Out, Console.Error); + cloudCommand.SetBuildVariables(searchPath, metadata, version, ciSystem, allVars, commonVars, additionalVariables, AlwaysUseLibGit2); + } + catch (CloudCommand.CloudCommandException ex) { - if (string.IsNullOrEmpty(version)) + Console.Error.WriteLine(ex.Message); + // map error codes + switch (ex.Error) { - version = oracle.CloudBuildNumber; + case CloudCommand.CloudCommandError.NoCloudBuildProviderMatch: + return (int)ExitCodes.NoCloudBuildProviderMatch; + case CloudCommand.CloudCommandError.DuplicateCloudVariable: + return (int)ExitCodes.DuplicateCloudVariable; + case CloudCommand.CloudCommandError.NoCloudBuildEnvDetected: + return (int)ExitCodes.NoCloudBuildEnvDetected; + default: + Report.Fail($"{nameof(CloudCommand.CloudCommandError)}: {ex.Error}"); + return -1; } + } - activeCloudBuild.SetCloudBuildNumber(version, Console.Out, Console.Error); - - foreach (var pair in variables) - { - activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, Console.Out, Console.Error); - } + return (int)ExitCodes.OK; - return (int)ExitCodes.OK; - } - else - { - Console.Error.WriteLine("No cloud build detected."); - return (int)ExitCodes.NoCloudBuildEnvDetected; - } } private static int OnPrepareReleaseCommand(string project, string nextVersion, string versionIncrement, string format, string tag) From 66ae53bdd5b3ad6b1f1b4568be8f92b1addf0d0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sat, 11 Sep 2021 18:48:32 +0200 Subject: [PATCH 308/704] Add "GitVersioningCloud" alias to Cake.GitVersioning --- .../GitVersioningAliases.cs | 57 +++++++++++++++---- .../GitVersioningCloudProvider.cs | 53 +++++++++++++++++ .../GitVersioningCloudSettings.cs | 42 ++++++++++++++ .../GitVersioningCloudProviderTests.cs | 30 ++++++++++ .../NerdBank.GitVersioning.Tests.csproj | 1 + 5 files changed, 173 insertions(+), 10 deletions(-) create mode 100644 src/Cake.GitVersioning/GitVersioningCloudProvider.cs create mode 100644 src/Cake.GitVersioning/GitVersioningCloudSettings.cs create mode 100644 src/NerdBank.GitVersioning.Tests/GitVersioningCloudProviderTests.cs diff --git a/src/Cake.GitVersioning/GitVersioningAliases.cs b/src/Cake.GitVersioning/GitVersioningAliases.cs index 346420e0..b0cd0676 100644 --- a/src/Cake.GitVersioning/GitVersioningAliases.cs +++ b/src/Cake.GitVersioning/GitVersioningAliases.cs @@ -1,15 +1,11 @@ -using System.IO; -using System.Reflection; -using Cake.Core; -using Cake.Core.Annotations; -using Nerdbank.GitVersioning; - -namespace Cake.GitVersioning +namespace Cake.GitVersioning { using System; - using System.Linq; - - using Validation; + using System.IO; + using System.Reflection; + using Cake.Core; + using Cake.Core.Annotations; + using Nerdbank.GitVersioning; /// /// Contains functionality for using Nerdbank.GitVersioning. @@ -45,5 +41,46 @@ public static VersionOracle GitVersioningGetVersion(this ICakeContext cakeContex var gitContext = GitContext.Create(fullProjectDirectory); return new VersionOracle(gitContext, cloudBuild: CloudBuild.Active); } + + /// + /// Adds versioning information to the current build environment's variables. + /// + /// + /// Task("SetBuildVersion") + /// .Does(() => + /// { + /// GitVersioningCloud() + /// }); + /// + /// The context. + /// Directory to start the search for version.json. + /// The settings to use for updating variables. + [CakeMethodAlias] + public static void GitVersioningCloud(this ICakeContext cakeContext, string projectDirectory = ".", GitVersioningCloudSettings settings = null) + { + var fullProjectDirectory = (new DirectoryInfo(projectDirectory)).FullName; + + string directoryName = Path.GetDirectoryName(Assembly.GetAssembly(typeof(GitVersioningAliases)).Location); + + if (string.IsNullOrWhiteSpace(directoryName)) + { + throw new InvalidOperationException("Could not locate the Cake.GitVersioning library"); + } + + settings ??= new GitVersioningCloudSettings(); + + var cloudCommand = new CloudCommand(Console.Out, Console.Error); + cloudCommand.SetBuildVariables( + fullProjectDirectory, + settings.Metadata, + settings.Version, + settings.CISystem?.ToString(), + settings.AllVariables, + settings.CommonVariables, + settings.AdditionalVariables, + false + ); + } + } } diff --git a/src/Cake.GitVersioning/GitVersioningCloudProvider.cs b/src/Cake.GitVersioning/GitVersioningCloudProvider.cs new file mode 100644 index 00000000..5a658028 --- /dev/null +++ b/src/Cake.GitVersioning/GitVersioningCloudProvider.cs @@ -0,0 +1,53 @@ +namespace Cake.GitVersioning +{ + /// + /// Defines the supported cloud build providers for the alias. + /// + public enum GitVersioningCloudProvider + { + /// + /// Use AppVeyor cloud build provider. + /// + AppVeyor, + + /// + /// Use Azure Pipeline / Visual Studio Team Services / TFS cloud build provider. + /// + VisualStudioTeamServices, + + /// + /// Use GitHub Actions cloud build provider. + /// + GitHubActions, + + /// + /// Use the TeamCity cloud build provider. + /// + TeamCity, + + /// + /// Use the Atlassian Bamboo cloud build provider. + /// + AtlassianBamboo, + + /// + /// Use the Jenkins cloud build provider. + /// + Jenkins, + + /// + /// Use the GitLab CI cloud build provider. + /// + GitLab, + + /// + /// Use the Travis CI cloud build provider. + /// + Travis, + + /// + /// Use the Jetbrains Space cloud build provider. + /// + SpaceAutomation, + } +} diff --git a/src/Cake.GitVersioning/GitVersioningCloudSettings.cs b/src/Cake.GitVersioning/GitVersioningCloudSettings.cs new file mode 100644 index 00000000..ea703a8e --- /dev/null +++ b/src/Cake.GitVersioning/GitVersioningCloudSettings.cs @@ -0,0 +1,42 @@ +namespace Cake.GitVersioning +{ + using System.Collections.Generic; + + /// + /// Defines settings for the alias. + /// + public class GitVersioningCloudSettings + { + /// + /// The string to use for the cloud build number. + /// If not value os specified, the computed version will be used. + /// + public string Version { get; set; } = null; + + /// + /// Adds an identifier to the build metadata part of a semantic version. + /// + public IList Metadata { get; set; } = new List(); + + /// + /// Force activation for a particular CI system. If not specified, + /// auto-detection will be used. + /// + public GitVersioningCloudProvider? CISystem { get; set; } = null; + + /// + /// Defines ALL version variables as cloud build variables, with a "NBGV_" prefix. + /// + public bool AllVariables { get; set; } = false; + + /// + /// Defines a few common version variables as cloud build variables, with a "Git" prefix. + /// + public bool CommonVariables { get; set; } = false; + + /// + /// Additional cloud build variables to define. + /// + public IDictionary AdditionalVariables { get; set; } = new Dictionary(); + } +} diff --git a/src/NerdBank.GitVersioning.Tests/GitVersioningCloudProviderTests.cs b/src/NerdBank.GitVersioning.Tests/GitVersioningCloudProviderTests.cs new file mode 100644 index 00000000..2e22e39c --- /dev/null +++ b/src/NerdBank.GitVersioning.Tests/GitVersioningCloudProviderTests.cs @@ -0,0 +1,30 @@ +using System; +using System.Linq; +using Cake.GitVersioning; +using Nerdbank.GitVersioning; +using Xunit; + +/// +/// Tests to verify the enum (part of the Cake integration) is up-to-date +/// +public class GitVersioningCloudProviderTests +{ + [Fact] + public void HasExpectedValues() + { + var expectedValues = CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name); + var actualValues = Enum.GetNames(typeof(GitVersioningCloudProvider)); + + var missingValues = expectedValues.Except(actualValues); + Assert.True( + !missingValues.Any(), + $"Enumeration is missing the following values of supported cloud build providers: {string.Join(", ", missingValues)}" + ); + + var redundantValues = actualValues.Except(expectedValues); + Assert.True( + !redundantValues.Any(), + $"Enumeration contains values which were not found among supported cloud build providers: {string.Join(",", redundantValues)}" + ); + } +} diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 9e4bd7ef..a6f0f23a 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -28,6 +28,7 @@ + From e94bf29eed1dc1ba106f263e2e5ac1c27aa0c096 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 13 Sep 2021 08:59:25 -0600 Subject: [PATCH 309/704] Build on ubuntu 20.04 in Github workflows This matches what we were already doing on Azure Pipelines. --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 8567b4c9..1b3b6b13 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,7 @@ jobs: fail-fast: false matrix: os: - - ubuntu-18.04 + - ubuntu-20.04 - macos-latest - windows-latest From 9c06ecb7ee50f4fef66dd82ff1bbe9949e3e2d31 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 13 Sep 2021 09:00:17 -0600 Subject: [PATCH 310/704] Publish variables, symbols and deployables from non-Windows agents too --- .github/workflows/build.yml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1b3b6b13..b8499b90 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -61,9 +61,8 @@ jobs: - name: Upload variables uses: actions/upload-artifact@v1 with: - name: variables + name: variables-${{ runner.os }} path: obj/_artifacts/variables - if: runner.os == 'Windows' continue-on-error: true - name: Upload build_logs if: always() @@ -89,16 +88,15 @@ jobs: - name: Upload symbols uses: actions/upload-artifact@v1 with: - name: symbols + name: symbols-${{ runner.os }} path: obj/_artifacts/symbols - if: runner.os == 'Windows' continue-on-error: true - name: Upload deployables uses: actions/upload-artifact@v1 with: - name: deployables + name: deployables-${{ runner.os }} path: obj/_artifacts/deployables - if: always() && runner.os == 'Windows' + if: always() - name: Publish code coverage results to codecov.io run: bash <(curl -s https://codecov.io/bash) shell: bash From 4854ca17b0473bc9627bd457bcfcc03cfdf7e59c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 13 Sep 2021 09:30:47 -0600 Subject: [PATCH 311/704] Fix up symbol collection off-Windows --- azure-pipelines/Convert-PDB.ps1 | 12 +++++++++--- azure-pipelines/Get-SymbolFiles.ps1 | 26 ++++++++++++++------------ azure-pipelines/artifacts/symbols.ps1 | 10 ++-------- 3 files changed, 25 insertions(+), 23 deletions(-) diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1 index 7a20305d..2d394e72 100644 --- a/azure-pipelines/Convert-PDB.ps1 +++ b/azure-pipelines/Convert-PDB.ps1 @@ -18,13 +18,19 @@ [string]$OutputPath ) + if ($IsMacOS -or $IsLinux) { + Write-Error "This script only works on Windows" + return + } + $version = '1.1.0-beta2-21101-01' - $baseDir = "$PSScriptRoot\..\obj\tools" - $pdb2pdbpath = "$baseDir\Microsoft.DiaSymReader.Pdb2Pdb.$version\tools\Pdb2Pdb.exe" + $baseDir = "$PSScriptRoot/../obj/tools" + $pdb2pdbpath = "$baseDir/Microsoft.DiaSymReader.Pdb2Pdb.$version/tools/Pdb2Pdb.exe" if (-not (Test-Path $pdb2pdbpath)) { if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } $baseDir = (Resolve-Path $baseDir).Path # Normalize it - & (& $PSScriptRoot\Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null + Write-Verbose "& (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null" + & (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null } $args = $DllPath,'/out',$OutputPath,'/nowarn','0021' diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1 index bba177f1..45afe7c2 100644 --- a/azure-pipelines/Get-SymbolFiles.ps1 +++ b/azure-pipelines/Get-SymbolFiles.ps1 @@ -17,7 +17,7 @@ $WindowsPdbSubDirName = "symstore" $ActivityName = "Collecting symbols from $Path" Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" -$PDBs = Get-ChildItem -rec "$Path\*.pdb" |? { $_.FullName -notmatch "\W$WindowsPdbSubDirName\W" } +$PDBs = Get-ChildItem -rec "$Path/*.pdb" |? { $_.FullName -notmatch "\W$WindowsPdbSubDirName\W" } # Filter PDBs to product OR test related. $testregex = "unittest|tests" @@ -44,8 +44,8 @@ $PDBs |% { } } |% { # Collect the DLLs/EXEs as well. - $dllPath = "$($_.Directory)\$($_.BaseName).dll" - $exePath = "$($_.Directory)\$($_.BaseName).exe" + $dllPath = "$($_.Directory)/$($_.BaseName).dll" + $exePath = "$($_.Directory)/$($_.BaseName).exe" if (Test-Path $dllPath) { $BinaryImagePath = $dllPath } elseif (Test-Path $exePath) { @@ -54,14 +54,16 @@ $PDBs |% { Write-Output $BinaryImagePath - # Convert the PDB to legacy Windows PDBs - Write-Host "Converting PDB for $_" -ForegroundColor DarkGray - $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" - if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } - & "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb" - if ($LASTEXITCODE -ne 0) { - Write-Warning "PDB conversion of `"$_`" failed." - } + if (-not ($IsMacOS -or $IsLinux)) { + # Convert the PDB to legacy Windows PDBs + Write-Host "Converting PDB for $_" -ForegroundColor DarkGray + $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" + if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } + & "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb" + if ($LASTEXITCODE -ne 0) { + Write-Warning "PDB conversion of `"$_`" failed." + } - Write-Output "$WindowsPdbDir\$($_.BaseName).pdb" + Write-Output "$WindowsPdbDir\$($_.BaseName).pdb" + } } diff --git a/azure-pipelines/artifacts/symbols.ps1 b/azure-pipelines/artifacts/symbols.ps1 index b3451ce1..8704571e 100644 --- a/azure-pipelines/artifacts/symbols.ps1 +++ b/azure-pipelines/artifacts/symbols.ps1 @@ -1,11 +1,5 @@ -# This doesn't work off Windows, nor do we need to convert symbols on multiple OS agents -if ($IsMacOS -or $IsLinux) { - return; -} - -$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin") -if (!(Test-Path $BinPath)) { return } -$symbolfiles = & "$PSScriptRoot\..\Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique +$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") +$symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique @{ "$BinPath" = $SymbolFiles; From 4438c0718d81c15796eaa4cadd96352ed436825b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Sep 2021 14:27:58 -0600 Subject: [PATCH 312/704] Update to latest dotnet-install script --- tools/Install-DotNetSdk.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 67c66c1e..73dae25f 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -154,10 +154,10 @@ if ($DotNetInstallDir) { } if ($IsMacOS -or $IsLinux) { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/49d5da7f7d313aa65d24fe95cc29767faef553fd/src/dotnet-install.sh" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/49d5da7f7d313aa65d24fe95cc29767faef553fd/src/dotnet-install.ps1" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.ps1" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } From f220004889a1ac02ac55cafcc84b737be04f4ad1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Sep 2021 07:14:15 -0600 Subject: [PATCH 313/704] Capture dumps from test hangs on Mac/Linux --- .github/workflows/Linux.runsettings | 15 ++++++++++++++- .github/workflows/macOS.runsettings | 15 ++++++++++++++- azure-pipelines/Darwin.runsettings | 15 ++++++++++++++- azure-pipelines/Linux.runsettings | 15 ++++++++++++++- azure-pipelines/artifacts/testResults.ps1 | 2 +- 5 files changed, 57 insertions(+), 5 deletions(-) diff --git a/.github/workflows/Linux.runsettings b/.github/workflows/Linux.runsettings index b444e819..5e2244a0 100644 --- a/.github/workflows/Linux.runsettings +++ b/.github/workflows/Linux.runsettings @@ -1 +1,14 @@ - + + + + + + + + + %GITHUB_WORKSPACE% + + + + + diff --git a/.github/workflows/macOS.runsettings b/.github/workflows/macOS.runsettings index b444e819..5e2244a0 100644 --- a/.github/workflows/macOS.runsettings +++ b/.github/workflows/macOS.runsettings @@ -1 +1,14 @@ - + + + + + + + + + %GITHUB_WORKSPACE% + + + + + diff --git a/azure-pipelines/Darwin.runsettings b/azure-pipelines/Darwin.runsettings index b444e819..0b43ecb0 100644 --- a/azure-pipelines/Darwin.runsettings +++ b/azure-pipelines/Darwin.runsettings @@ -1 +1,14 @@ - + + + + + + + + + %BUILD_ARTIFACTSTAGINGDIRECTORY% + + + + + diff --git a/azure-pipelines/Linux.runsettings b/azure-pipelines/Linux.runsettings index b444e819..0b43ecb0 100644 --- a/azure-pipelines/Linux.runsettings +++ b/azure-pipelines/Linux.runsettings @@ -1 +1,14 @@ - + + + + + + + + + %BUILD_ARTIFACTSTAGINGDIRECTORY% + + + + + diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 index 1e4c4c4e..7895ddca 100644 --- a/azure-pipelines/artifacts/testResults.ps1 +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -2,7 +2,7 @@ if ($env:AGENT_TEMPDIRECTORY) { # The DotNetCoreCLI uses an alternate location to publish these files $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' @{ - $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); + $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); } } else { $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" From da2dbc0e905c0b6045c7f51875848fa50cad9b7e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Sep 2021 07:56:31 -0600 Subject: [PATCH 314/704] Remove ResultsDirectory tag --- .github/workflows/Linux.runsettings | 2 -- .github/workflows/Windows.runsettings | 2 -- .github/workflows/macOS.runsettings | 2 -- azure-pipelines/Darwin.runsettings | 2 -- azure-pipelines/Linux.runsettings | 2 -- azure-pipelines/Windows_NT.runsettings | 2 -- 6 files changed, 12 deletions(-) diff --git a/.github/workflows/Linux.runsettings b/.github/workflows/Linux.runsettings index 5e2244a0..db20611f 100644 --- a/.github/workflows/Linux.runsettings +++ b/.github/workflows/Linux.runsettings @@ -5,8 +5,6 @@ - - %GITHUB_WORKSPACE% diff --git a/.github/workflows/Windows.runsettings b/.github/workflows/Windows.runsettings index 5e2244a0..db20611f 100644 --- a/.github/workflows/Windows.runsettings +++ b/.github/workflows/Windows.runsettings @@ -5,8 +5,6 @@ - - %GITHUB_WORKSPACE% diff --git a/.github/workflows/macOS.runsettings b/.github/workflows/macOS.runsettings index 5e2244a0..db20611f 100644 --- a/.github/workflows/macOS.runsettings +++ b/.github/workflows/macOS.runsettings @@ -5,8 +5,6 @@ - - %GITHUB_WORKSPACE% diff --git a/azure-pipelines/Darwin.runsettings b/azure-pipelines/Darwin.runsettings index 0b43ecb0..db20611f 100644 --- a/azure-pipelines/Darwin.runsettings +++ b/azure-pipelines/Darwin.runsettings @@ -5,8 +5,6 @@ - - %BUILD_ARTIFACTSTAGINGDIRECTORY% diff --git a/azure-pipelines/Linux.runsettings b/azure-pipelines/Linux.runsettings index 0b43ecb0..db20611f 100644 --- a/azure-pipelines/Linux.runsettings +++ b/azure-pipelines/Linux.runsettings @@ -5,8 +5,6 @@ - - %BUILD_ARTIFACTSTAGINGDIRECTORY% diff --git a/azure-pipelines/Windows_NT.runsettings b/azure-pipelines/Windows_NT.runsettings index 0b43ecb0..db20611f 100644 --- a/azure-pipelines/Windows_NT.runsettings +++ b/azure-pipelines/Windows_NT.runsettings @@ -5,8 +5,6 @@ - - %BUILD_ARTIFACTSTAGINGDIRECTORY% From ecbaf97d74980f7455d3426f0138611992acc256 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Sep 2021 08:32:30 -0600 Subject: [PATCH 315/704] Update SDK to 5.0.401 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 9f36eab1..3057bb45 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.400", + "version": "5.0.401", "rollForward": "patch", "allowPrerelease": false } From 81c94c836706ab435c7f68b6d68536a4a0fecfc2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Sep 2021 14:29:35 -0600 Subject: [PATCH 316/704] Retarget the nbgv tool against netcoreapp3.1 now that netcoreapp2.1 is out of service --- src/nbgv/nbgv.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 63465683..88e07bdf 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -4,7 +4,7 @@ nbgv True Exe - netcoreapp2.1 + netcoreapp3.1 Nerdbank.GitVersioning.Tool A .NET Core Tool that can install, read and set version information based on git history, using Nerdbank.GitVersioning. From 5f5a1dd576ec819b6e34ccb78af0fb6710252935 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Sep 2021 14:39:41 -0600 Subject: [PATCH 317/704] Add `SkipGetTargetFrameworkProperties=true` to further hide our P2P --- .../build/Nerdbank.GitVersioning.targets | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 62e6fc2f..33a2910f 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -93,6 +93,7 @@ false false + true false true From c6e1c42538791867f155884ab1482fab1e4380ed Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Sep 2021 23:09:26 -0600 Subject: [PATCH 318/704] Remove .NET Core 3.0 from test battery --- azure-pipelines.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 26a3ac28..c83f59e3 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,8 +18,6 @@ resources: image: mcr.microsoft.com/dotnet/core/sdk:3.1-bionic - container: focal image: mcr.microsoft.com/dotnet/core/sdk:3.1-focal - - container: disco-3.0 - image: mcr.microsoft.com/dotnet/core/sdk:3.0-disco - container: archlinux image: andrewarnott/archlinux @@ -274,8 +272,6 @@ stages: containerImage: bionic Ubuntu_Focal: containerImage: focal - Ubuntu_Disco_3_0: - containerImage: disco-3.0 # Arch_Linux: # containerImage: archlinux # configureContainerCommand: 'sudo pacman -Sy --noconfirm git dotnet-sdk openssl-1.0' From 7f83a80bddb544c675f85be6d048f55f528e9d05 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 16 Sep 2021 08:51:19 -0600 Subject: [PATCH 319/704] Move cake test to a new project dedicated to cake And some other touch-ups --- azure-pipelines.yml | 17 ++++++++++-- .../Cake.GitVersioning.Tests.csproj | 27 +++++++++++++++++++ .../GitVersioningCloudProviderTests.cs | 0 .../Cake.GitVersioning.csproj | 1 - .../GitVersioningAliases.cs | 1 + .../GitVersioningCloudSettings.cs | 21 ++++++++------- .../NerdBank.GitVersioning.Tests.csproj | 1 - .../{ => Commands}/CloudCommand.cs | 18 ++++++------- .../LibGit2/LibGit2Context.cs | 2 +- src/NerdBank.GitVersioning/ReleaseManager.cs | 6 ++--- src/nbgv/Program.cs | 1 + 11 files changed, 69 insertions(+), 26 deletions(-) create mode 100644 src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj rename src/{NerdBank.GitVersioning.Tests => Cake.GitVersioning.Tests}/GitVersioningCloudProviderTests.cs (100%) rename src/NerdBank.GitVersioning/{ => Commands}/CloudCommand.cs (95%) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 26a3ac28..fcbbce85 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -122,7 +122,7 @@ stages: --no-build $(testModifier) -c $(BuildConfiguration) --filter "TestCategory!=FailsOnAzurePipelines" - --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.trx" + --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.x64.trx" --results-directory $(Build.ArtifactStagingDirectory)/CodeCoverage/ --collect:"XPlat Code Coverage" -- @@ -135,7 +135,7 @@ stages: --no-build $(testModifier) -c $(BuildConfiguration) --filter "TestCategory!=FailsOnAzurePipelines" - --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.trx" + --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.x86.trx" --results-directory $(Build.ArtifactStagingDirectory)/CodeCoverage/ --collect:"XPlat Code Coverage" -- @@ -144,6 +144,19 @@ stages: workingDirectory: src condition: ne(variables['dotnet32'], '') + - script: > + dotnet test Cake.GitVersioning.Tests + --no-build $(testModifier) + -c $(BuildConfiguration) + --filter "TestCategory!=FailsOnAzurePipelines" + --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.cake.trx" + --results-directory $(Build.ArtifactStagingDirectory)/CodeCoverage/ + --collect:"XPlat Code Coverage" + -- + RunConfiguration.DisableAppDomain=true + displayName: Run cake tests + workingDirectory: src + - task: PublishCodeCoverageResults@1 displayName: Publish code coverage results inputs: diff --git a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj new file mode 100644 index 00000000..d00d3d53 --- /dev/null +++ b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -0,0 +1,27 @@ + + + + net5.0;net461 + false + true + false + true + true + full + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + diff --git a/src/NerdBank.GitVersioning.Tests/GitVersioningCloudProviderTests.cs b/src/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/GitVersioningCloudProviderTests.cs rename to src/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index ea18fd5e..9e352dec 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -2,7 +2,6 @@ netstandard2.0 - true true Chris Crutchfield, Andrew Arnott andarno diff --git a/src/Cake.GitVersioning/GitVersioningAliases.cs b/src/Cake.GitVersioning/GitVersioningAliases.cs index b0cd0676..aff32240 100644 --- a/src/Cake.GitVersioning/GitVersioningAliases.cs +++ b/src/Cake.GitVersioning/GitVersioningAliases.cs @@ -6,6 +6,7 @@ using Cake.Core; using Cake.Core.Annotations; using Nerdbank.GitVersioning; + using Nerdbank.GitVersioning.Commands; /// /// Contains functionality for using Nerdbank.GitVersioning. diff --git a/src/Cake.GitVersioning/GitVersioningCloudSettings.cs b/src/Cake.GitVersioning/GitVersioningCloudSettings.cs index ea703a8e..1082373b 100644 --- a/src/Cake.GitVersioning/GitVersioningCloudSettings.cs +++ b/src/Cake.GitVersioning/GitVersioningCloudSettings.cs @@ -1,5 +1,8 @@ -namespace Cake.GitVersioning +#nullable enable + +namespace Cake.GitVersioning { + using System; using System.Collections.Generic; /// @@ -8,35 +11,35 @@ public class GitVersioningCloudSettings { /// - /// The string to use for the cloud build number. - /// If not value os specified, the computed version will be used. + /// The string to use for the cloud build number. + /// If no value is specified, the computed version will be used. /// - public string Version { get; set; } = null; + public string? Version { get; set; } /// /// Adds an identifier to the build metadata part of a semantic version. /// - public IList Metadata { get; set; } = new List(); + public List Metadata { get; } = new(); /// /// Force activation for a particular CI system. If not specified, /// auto-detection will be used. /// - public GitVersioningCloudProvider? CISystem { get; set; } = null; + public GitVersioningCloudProvider? CISystem { get; set; } /// /// Defines ALL version variables as cloud build variables, with a "NBGV_" prefix. /// - public bool AllVariables { get; set; } = false; + public bool AllVariables { get; set; } /// /// Defines a few common version variables as cloud build variables, with a "Git" prefix. /// - public bool CommonVariables { get; set; } = false; + public bool CommonVariables { get; set; } /// /// Additional cloud build variables to define. /// - public IDictionary AdditionalVariables { get; set; } = new Dictionary(); + public Dictionary AdditionalVariables { get; } = new(StringComparer.OrdinalIgnoreCase); } } diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index a6f0f23a..9e4bd7ef 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -28,7 +28,6 @@ - diff --git a/src/NerdBank.GitVersioning/CloudCommand.cs b/src/NerdBank.GitVersioning/Commands/CloudCommand.cs similarity index 95% rename from src/NerdBank.GitVersioning/CloudCommand.cs rename to src/NerdBank.GitVersioning/Commands/CloudCommand.cs index d85566c9..8a78fa7f 100644 --- a/src/NerdBank.GitVersioning/CloudCommand.cs +++ b/src/NerdBank.GitVersioning/Commands/CloudCommand.cs @@ -1,4 +1,4 @@ -namespace Nerdbank.GitVersioning +namespace Nerdbank.GitVersioning.Commands { using System; using System.Collections.Generic; @@ -7,7 +7,7 @@ using Validation; /// - /// Implementation of the "nbgv cloud" command that updates the build environments variables with version variables + /// Implementation of the "nbgv cloud" command that updates the build environments variables with version variables. /// public class CloudCommand { @@ -17,23 +17,23 @@ public class CloudCommand public enum CloudCommandError { /// - /// Teh specified CI system was not found + /// The specified CI system was not found. /// NoCloudBuildProviderMatch, /// - /// A cloud variable was defined multiple times + /// A cloud variable was defined multiple times. /// DuplicateCloudVariable, /// - /// No supported cloud build environment could be detected + /// No supported cloud build environment could be detected. /// - NoCloudBuildEnvDetected + NoCloudBuildEnvDetected, } /// - /// Exception indicating an error while setting build variables + /// Exception indicating an error while setting build variables. /// public class CloudCommandException : Exception { @@ -43,7 +43,7 @@ public class CloudCommandException : Exception public CloudCommandError Error { get; } /// - /// Initializes a new instance of + /// Initializes a new instance of class. /// /// The message that describes the error. /// The error that occurred. @@ -79,7 +79,7 @@ public CloudCommand(TextWriter outputWriter = null, TextWriter errorWriter = nul /// The string to use for the cloud build number. If not specified, the computed version will be used. /// /// - /// The CI system to activate. If not specified, auto-detection will be used. + /// The CI system to activate. If not specified, auto-detection will be used. /// /// /// Controls whether to define all version variables as cloud build variables. diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs index aabe0ac2..65cd8bba 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs @@ -77,7 +77,7 @@ public override bool TrySelectCommit(string committish) } /// - public override void Stage(string path) => Commands.Stage(this.Repository, path); + public override void Stage(string path) => global::LibGit2Sharp.Commands.Stage(this.Repository, path); /// public override string GetShortUniqueCommitId(int minLength) => this.Repository.ObjectDatabase.ShortenObjectId(this.Commit, minLength); diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index 6656a73e..23a926f2 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -295,7 +295,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag = // create release branch and update version var releaseBranch = repository.CreateBranch(releaseBranchName); - Commands.Checkout(repository, releaseBranch); + global::LibGit2Sharp.Commands.Checkout(repository, releaseBranch); this.UpdateVersion(context, versionOptions.Version, releaseVersion); if (outputMode == ReleaseManagerOutputMode.Text) @@ -304,7 +304,7 @@ public void PrepareRelease(string projectDirectory, string releaseUnstableTag = } // update version on main branch - Commands.Checkout(repository, originalBranchName); + global::LibGit2Sharp.Commands.Checkout(repository, originalBranchName); this.UpdateVersion(context, versionOptions.Version, nextDevVersion); if (outputMode == ReleaseManagerOutputMode.Text) @@ -371,7 +371,7 @@ private void UpdateVersion(LibGit2Context context, SemanticVersion oldVersion, S versionOptions.Version = newVersion; var filePath = context.VersionFile.SetVersion(context.AbsoluteProjectDirectory, versionOptions, includeSchemaProperty: true); - Commands.Stage(context.Repository, filePath); + global::LibGit2Sharp.Commands.Stage(context.Repository, filePath); // Author a commit only if we effectively changed something. if (!context.Repository.Head.Tip.Tree.Equals(context.Repository.Index.WriteToTree())) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index e507d38e..65fda285 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -12,6 +12,7 @@ namespace Nerdbank.GitVersioning.Tool using System.Threading; using System.Threading.Tasks; using Microsoft.Build.Construction; + using Nerdbank.GitVersioning.Commands; using Nerdbank.GitVersioning.LibGit2; using Newtonsoft.Json; using NuGet.Common; From c40c9aebdd65f83563ca1c2e612b45c70c3fcb68 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 16 Sep 2021 10:11:59 -0600 Subject: [PATCH 320/704] Add new project to solution --- src/Nerdbank.GitVersioning.sln | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Nerdbank.GitVersioning.sln b/src/Nerdbank.GitVersioning.sln index 43ffb2c7..9077863c 100644 --- a/src/Nerdbank.GitVersioning.sln +++ b/src/Nerdbank.GitVersioning.sln @@ -32,6 +32,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.GitVersioning", "Cake. EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Benchmarks", "NerdBank.GitVersioning.Benchmarks\Nerdbank.GitVersioning.Benchmarks.csproj", "{B0B7955D-E51F-4091-BF7F-55D07D381D15}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.GitVersioning.Tests", "Cake.GitVersioning.Tests\Cake.GitVersioning.Tests.csproj", "{D68829FE-24D8-4ADD-8525-17F47C6FE257}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -64,6 +66,10 @@ Global {B0B7955D-E51F-4091-BF7F-55D07D381D15}.Debug|Any CPU.Build.0 = Debug|Any CPU {B0B7955D-E51F-4091-BF7F-55D07D381D15}.Release|Any CPU.ActiveCfg = Release|Any CPU {B0B7955D-E51F-4091-BF7F-55D07D381D15}.Release|Any CPU.Build.0 = Release|Any CPU + {D68829FE-24D8-4ADD-8525-17F47C6FE257}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D68829FE-24D8-4ADD-8525-17F47C6FE257}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D68829FE-24D8-4ADD-8525-17F47C6FE257}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D68829FE-24D8-4ADD-8525-17F47C6FE257}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE From 2760f83092f056bfd803b5e30f3846e3e6992129 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 16 Sep 2021 10:45:45 -0600 Subject: [PATCH 321/704] Fix build break --- src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index d00d3d53..83a8f9bf 100644 --- a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -16,6 +16,7 @@ + runtime; build; native; contentfiles; analyzers; buildtransitive From 3866cd6c40195d015b7a567436779471e7cea5db Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 21 Sep 2021 09:53:32 -0600 Subject: [PATCH 322/704] Add test for version height with path filters and merge conflict This demonstrates the repro for #658 --- .../VersionOracleTests.cs | 32 +++++++++++++++++++ 1 file changed, 32 insertions(+) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 4f10abf1..9ae579d6 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -751,6 +751,38 @@ public void GetVersion_PathFilterInTwoDeepSubDirAndVersionBump() Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); } + [Fact] + public void GetVersion_PathFilterPlusMerge() + { + this.InitializeSourceControl(withInitialCommit: false); + this.WriteVersionFile(new VersionOptions + { + Version = new SemanticVersion("1.0"), + PathFilters = new FilterPath[] { new FilterPath(".", string.Empty) }, + }); + + string conflictedFilePath = Path.Combine(this.RepoPath, "foo.txt"); + + File.WriteAllText(conflictedFilePath, "foo"); + Commands.Stage(this.LibGit2Repository, conflictedFilePath); + this.LibGit2Repository.Commit("Add foo.txt with foo content.", this.Signer, this.Signer); + Branch originalBranch = this.LibGit2Repository.Head; + + Branch topicBranch = this.LibGit2Repository.Branches.Add("topic", "HEAD~1"); + Commands.Checkout(this.LibGit2Repository, topicBranch); + File.WriteAllText(conflictedFilePath, "bar"); + Commands.Stage(this.LibGit2Repository, conflictedFilePath); + this.LibGit2Repository.Commit("Add foo.txt with bar content.", this.Signer, this.Signer); + + Commands.Checkout(this.LibGit2Repository, originalBranch); + MergeResult result = this.LibGit2Repository.Merge(topicBranch, this.Signer, new MergeOptions { FileConflictStrategy = CheckoutFileConflictStrategy.Ours }); + Assert.Equal(MergeStatus.Conflicts, result.Status); + Commands.Stage(this.LibGit2Repository, conflictedFilePath); + this.LibGit2Repository.Commit("Merge two branches", this.Signer, this.Signer); + + Assert.Equal(3, this.GetVersionHeight()); + } + [Fact] public void GetVersionHeight_ProjectDirectoryDifferentToVersionJsonDirectory() { From 96be5aae2f99f1ff7b123948d67a2635f04988ca Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 21 Sep 2021 09:53:32 -0600 Subject: [PATCH 323/704] Count merge commits in path filtered height if any parent changed it The managed git implementation had it correctly implemented, according to the code comments in the libgit2 implementation. But those code comments did not match the *code* in the libgit2 implementation. As a result, the managed git code did not match. In this commit I correct the libgit2 impl code comments to describe what the code *actually* does. Then I fix the identical code comment and code in the managed git implementation to match. Fixes #658 --- .../LibGit2/LibGit2GitExtensions.cs | 4 +- .../Managed/ManagedGitExtensions.cs | 56 +++++++++++-------- 2 files changed, 35 insertions(+), 25 deletions(-) diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 045c647a..b2ff2d35 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -433,8 +433,8 @@ bool ContainsRelevantChanges(IEnumerable changes) => : includePaths; // If the diff between this commit and any of its parents - // does not touch a path that we care about, don't bump the - // height. + // touches a path that we care about, bump the height. + // A no-parent commit is relevant if it introduces anything in the filtered path. var relevantCommit = commit.Parents.Any() ? commit.Parents.Any(parent => ContainsRelevantChanges(commit.GetRepository().Diff diff --git a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs b/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs index 2f05103e..e51bf4ea 100644 --- a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs +++ b/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs @@ -169,22 +169,27 @@ bool TryCalculateHeight(GitCommit commit) if (pathFilters is not null) { - var relevantCommit = true; - - foreach (var parentId in commit.Parents) + // If the diff between this commit and any of its parents + // touches a path that we care about, bump the height. + bool relevantCommit = false, anyParents = false; + foreach (GitObjectId parentId in commit.Parents) { - var parent = repository.GetCommit(parentId); - relevantCommit = IsRelevantCommit(repository, commit, parent, pathFilters); - - // If the diff between this commit and any of its parents - // does not touch a path that we care about, don't bump the - // height. - if (!relevantCommit) + anyParents = true; + GitCommit parent = repository.GetCommit(parentId); + if (IsRelevantCommit(repository, commit, parent, pathFilters)) { + // No need to scan further, as a positive match will never turn negative. + relevantCommit = true; break; } } + if (!anyParents) + { + // A no-parent commit is relevant if it introduces anything in the filtered path. + relevantCommit = IsRelevantCommit(repository, commit, parent: default(GitCommit), pathFilters); + } + if (!relevantCommit) { height = 0; @@ -214,12 +219,12 @@ private static bool IsRelevantCommit(GitRepository repository, GitCommit commit, return IsRelevantCommit( repository, repository.GetTree(commit.Tree), - repository.GetTree(parent.Tree), + parent != default ? repository.GetTree(parent.Tree) : null, relativePath: string.Empty, filters); } - private static bool IsRelevantCommit(GitRepository repository, GitTree tree, GitTree parent, string relativePath, IReadOnlyList filters) + private static bool IsRelevantCommit(GitRepository repository, GitTree tree, GitTree? parent, string relativePath, IReadOnlyList filters) { // Walk over all child nodes in the current tree. If a child node was found in the parent, // remove it, so that after the iteration the parent contains all nodes which have been @@ -231,8 +236,9 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git // If the entry is not present in the parent commit, it was added; // if the Sha does not match, it was modified. - if (!parent.Children.TryGetValue(child.Key, out parentEntry) - || parentEntry.Sha != child.Value.Sha) + if (parent is null || + !parent.Children.TryGetValue(child.Key, out parentEntry) || + parentEntry.Sha != child.Value.Sha) { // Determine whether the change was relevant. var fullPath = $"{relativePath}{entry.Name}"; @@ -264,23 +270,27 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git if (parentEntry is not null) { + Assumes.NotNull(parent); parent.Children.Remove(child.Key); } } // Inspect removed entries (i.e. present in parent but not in the current tree) - foreach (var child in parent.Children) + if (parent is not null) { - // Determine whether the change was relevant. - var fullPath = Path.Combine(relativePath, child.Key); + foreach (var child in parent.Children) + { + // Determine whether the change was relevant. + var fullPath = Path.Combine(relativePath, child.Key); - bool isRelevant = - filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)) - && !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase)); + bool isRelevant = + filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)) + && !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase)); - if (isRelevant) - { - return true; + if (isRelevant) + { + return true; + } } } From c13d166c4ef191f34a2048196ad2cdf80fa0e6e3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 22 Sep 2021 20:36:40 -0600 Subject: [PATCH 324/704] Update nbgv to ship MSBuild 16.9 This is the latest version that still supports netcoreapp3.1. This should fix the problem of parsing msbuild project files with metadata as xml attributes. --- src/nbgv/nbgv.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 63465683..3529a9c4 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -15,7 +15,7 @@ - + From 496c3592312faf23363554baf773cb837dd054d6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 22 Sep 2021 20:37:02 -0600 Subject: [PATCH 325/704] Fix capitalization in nbgv source code --- src/nbgv/Program.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index e9ae5d75..8691e2c7 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -347,16 +347,16 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList metadata, string format, string variable, string commitIsh) + private static int OnGetVersionCommand(string project, IReadOnlyList metadata, string format, string variable, string commitish) { if (string.IsNullOrEmpty(format)) { format = DefaultOutputFormat; } - if (string.IsNullOrEmpty(commitIsh)) + if (string.IsNullOrEmpty(commitish)) { - commitIsh = DefaultRef; + commitish = DefaultRef; } string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); @@ -368,9 +368,9 @@ private static int OnGetVersionCommand(string project, IReadOnlyList met return (int)ExitCodes.NoGitRepo; } - if (!context.TrySelectCommit(commitIsh)) + if (!context.TrySelectCommit(commitish)) { - Console.Error.WriteLine("rev-parse produced no commit for {0}", commitIsh); + Console.Error.WriteLine("rev-parse produced no commit for {0}", commitish); return (int)ExitCodes.BadGitRef; } From 5e7a00ed24415bc6a76fe076ae76f7d5f10d9df8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 22 Sep 2021 20:48:49 -0600 Subject: [PATCH 326/704] Defend against losing the first exception's message when Exception.ToString() throws --- src/nbgv/Program.cs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 8691e2c7..a85abf6b 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -215,9 +215,23 @@ private static Parser BuildCommandLine() } } }, (MiddlewareOrder)(-3000)) // MiddlewareOrderInternal.ExceptionHandler so [parse] directive is accurate. + .UseExceptionHandler((ex, context) => PrintException(ex, context)) .Build(); } + private static void PrintException(Exception ex, InvocationContext context) + { + try + { + Console.Error.WriteLine("Unhandled exception: {0}", ex); + } + catch (Exception ex2) + { + Console.Error.WriteLine("Unhandled exception: {0}", ex.Message); + Console.Error.WriteLine("Unhandled exception while trying to print string version of the above exception: {0}", ex2); + } + } + private static int MainInner(string[] args) { try From 2b80c11d91883b91a02cb16fed824e198b20f951 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 22 Sep 2021 20:58:58 -0600 Subject: [PATCH 327/704] Update nbgv's NuGet dependency to 5.11.0 Fixes #588 --- src/nbgv/Program.cs | 2 +- src/nbgv/nbgv.csproj | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index a85abf6b..aad07d3f 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -773,7 +773,7 @@ private static async Task GetLatestPackageVersionAsync(string packageId, var providers = new List>(); providers.AddRange(Repository.Provider.GetCoreV3()); // Add v3 API support - var sourceRepositoryProvider = new SourceRepositoryProvider(settings, providers); + var sourceRepositoryProvider = new SourceRepositoryProvider(new PackageSourceProvider(settings), providers); // Select package sources based on NuGet.Config files or given options, as 'nuget.exe restore' command does // See also 'DownloadCommandBase.GetPackageSources(ISettings)' at https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/NuGet.CommandLine/Commands/DownloadCommandBase.cs diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 3529a9c4..031878f0 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -10,8 +10,7 @@ - - + From f2f5228c29825b696b965f8b74fcc82efa275220 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 22 Sep 2021 21:39:24 -0600 Subject: [PATCH 328/704] Revise the preprocessor symbols we use --- src/NerdBank.GitVersioning/ManagedGit/GitPack.cs | 6 +++--- .../ManagedGit/GitPackDeltafiedStream.cs | 2 +- .../ManagedGit/GitPackMemoryCacheStream.cs | 2 +- .../ManagedGit/GitPackMemoryCacheViewStream.cs | 2 +- .../ManagedGit/GitPackPooledStream.cs | 2 +- .../ManagedGit/GitRepository.cs | 10 +++++----- .../ManagedGit/MemoryMappedStream.cs | 2 +- .../ManagedGit/StreamExtensions.cs | 14 ++++++++++++-- .../ManagedGit/ZLibStream.cs | 4 ++-- 9 files changed, 27 insertions(+), 17 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs index 576dd50d..995659e6 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs @@ -39,7 +39,7 @@ public class GitPack : IDisposable // A histogram which tracks the objects which have been retrieved from this GitPack. The key is the offset // of the object. Used to get some insights in usage patterns. -#if DEBUG && !NETSTANDARD +#if DEBUG private readonly Dictionary histogram = new Dictionary(); #endif @@ -172,7 +172,7 @@ public bool TryGetObject(GitObjectId objectId, string objectType, out Stream? va /// public Stream GetObject(long offset, string objectType) { -#if DEBUG && !NETSTANDARD +#if DEBUG if (!this.histogram.TryAdd(offset, 1)) { this.histogram[offset] += 1; @@ -230,7 +230,7 @@ public void GetCacheStatistics(StringBuilder builder) { builder.AppendLine($"Git Pack:"); -#if DEBUG && !NETSTANDARD +#if DEBUG int histogramCount = 25; builder.AppendLine($"Top {histogramCount} / {this.histogram.Count} items:"); diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs index 3cff6c53..9b73a7bb 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs @@ -64,7 +64,7 @@ public override long Position set => throw new NotImplementedException(); } -#if NETSTANDARD +#if NETSTANDARD2_0 /// /// Reads a sequence of bytes from the current and advances the position /// within the stream by the number of bytes read. diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs index 9f1b38be..66fa2f04 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs @@ -37,7 +37,7 @@ public override void Flush() throw new NotSupportedException(); } -#if NETSTANDARD +#if NETSTANDARD2_0 public int Read(Span buffer) #else /// diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs index b1a58549..e91b67c1 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs @@ -37,7 +37,7 @@ public override int Read(byte[] buffer, int offset, int count) return this.Read(buffer.AsSpan(offset, count)); } -#if NETSTANDARD +#if NETSTANDARD2_0 public int Read(Span buffer) #else /// diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs index fb2dca16..74cde41e 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs @@ -62,7 +62,7 @@ public override void Flush() this.stream.Flush(); } -#if !NETSTANDARD +#if !NETSTANDARD2_0 /// public override int Read(Span buffer) { diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index 05e8fd53..c079b951 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -28,7 +28,7 @@ public class GitRepository : IDisposable private readonly List alternates = new List(); -#if DEBUG && !NETSTANDARD +#if DEBUG private Dictionary histogram = new Dictionary(); #endif @@ -524,7 +524,7 @@ public GitObjectId GetTreeEntry(GitObjectId treeId, ReadOnlySpan nodeName) /// public bool TryGetObjectBySha(GitObjectId sha, string objectType, out Stream? value) { -#if DEBUG && !NETSTANDARD +#if DEBUG if (!this.histogram.TryAdd(sha, 1)) { this.histogram[sha] += 1; @@ -566,7 +566,7 @@ public string GetCacheStatistics() { StringBuilder builder = new StringBuilder(); -#if DEBUG && !NETSTANDARD +#if DEBUG int histogramCount = 25; builder.AppendLine("Overall repository:"); @@ -659,7 +659,7 @@ private ReadOnlyMemory LoadPacks() private static string TrimEndingDirectorySeparator(string path) { -#if NETSTANDARD +#if NETSTANDARD2_0 if (string.IsNullOrEmpty(path) || path.Length == 1) { return path; @@ -690,7 +690,7 @@ private static bool TryConvertHexStringToByteArray(string hexString, Span Requires.Argument(data.Length == hexString.Length / 2, nameof(data), "Length must be exactly half that of " + nameof(hexString) + "."); for (int index = 0; index < data.Length; index++) { -#if NETCOREAPP3_1_OR_GREATER +#if !NETSTANDARD2_0 ReadOnlySpan byteValue = hexString.AsSpan(index * 2, 2); if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) { diff --git a/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs index c7c0e82b..8128dbf4 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs @@ -72,7 +72,7 @@ public override int Read(byte[] buffer, int offset, int count) return read; } -#if !NETSTANDARD +#if !NETSTANDARD2_0 /// public override int Read(Span buffer) { diff --git a/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs b/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs index 98d382fa..550431c8 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs @@ -2,7 +2,6 @@ using System; using System.Buffers; -using System.Diagnostics; using System.IO; namespace Nerdbank.GitVersioning.ManagedGit @@ -78,7 +77,7 @@ public static int ReadMbsInt(this Stream stream) return value; } -#if NETSTANDARD +#if NETSTANDARD2_0 /// /// Reads a sequence of bytes from the current stream and advances the position within the stream by /// the number of bytes read. @@ -139,6 +138,17 @@ public static void Write(this Stream stream, Span span) ArrayPool.Shared.Return(buffer); } } + + internal static bool TryAdd(this System.Collections.Generic.IDictionary dictionary, TKey key, TValue value) + { + if (dictionary.ContainsKey(key)) + { + return false; + } + + dictionary.Add(key, value); + return true; + } #endif } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs index d4e68212..4a350e30 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs @@ -94,7 +94,7 @@ public override int Read(byte[] array, int offset, int count) return read; } -#if !NETSTANDARD +#if !NETSTANDARD2_0 /// public override int Read(Span buffer) { @@ -112,7 +112,7 @@ public override async Task ReadAsync(byte[] array, int offset, int count, C return read; } -#if !NETSTANDARD +#if !NETSTANDARD2_0 /// public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) { From 115681fcf4f994c08a9a8cd74da6f1a26e09ebc5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 22 Sep 2021 21:41:46 -0600 Subject: [PATCH 329/704] Build `validate/*` branches --- azure-pipelines.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index edcbe16e..e5e9a73c 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -4,6 +4,7 @@ trigger: include: - master - 'v*.*' + - 'validate/*' paths: exclude: - doc From 7edb4e6e4f50b6cb62ba2330f40c5dbbe305b43f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Sep 2021 06:25:22 -0600 Subject: [PATCH 330/704] Style touch-ups --- .../BuildIntegrationTests.cs | 7 +----- src/NerdBank.GitVersioning/SemanticVersion.cs | 2 +- src/NerdBank.GitVersioning/VersionOracle.cs | 22 ++++++------------- 3 files changed, 9 insertions(+), 22 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index cd6918d6..901a8f59 100644 --- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -1049,12 +1049,7 @@ private void AssertStandardProperties(VersionOptions versionOptions, BuildResult } string expectedBuildMetadataWithoutCommitId = additionalBuildMetadata.Any() ? $"+{string.Join(".", additionalBuildMetadata)}" : string.Empty; - - var optionalFourthComponent = versionOptions.VersionHeightPosition switch - { - SemanticVersion.Position.Revision => $".{idAsVersion.Revision}", - _ => "" - }; + string optionalFourthComponent = versionOptions.VersionHeightPosition == SemanticVersion.Position.Revision ? $".{idAsVersion.Revision}" : string.Empty; Assert.Equal($"{version}", buildResult.AssemblyFileVersion); Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{optionalFourthComponent}{versionOptions.Version.Prerelease}{expectedBuildMetadata}", buildResult.AssemblyInformationalVersion); diff --git a/src/NerdBank.GitVersioning/SemanticVersion.cs b/src/NerdBank.GitVersioning/SemanticVersion.cs index ea69e2b3..eda34d1f 100644 --- a/src/NerdBank.GitVersioning/SemanticVersion.cs +++ b/src/NerdBank.GitVersioning/SemanticVersion.cs @@ -129,7 +129,7 @@ public enum Position /// /// Gets the position in a computed version that the version height should appear. /// - internal SemanticVersion.Position? VersionHeightPosition + public SemanticVersion.Position? VersionHeightPosition { get { diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 126bcec7..df138809 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -25,6 +25,11 @@ public class VersionOracle private readonly ICloudBuild? cloudBuild; + /// + /// The number of version components (up to the 4 integers) to include in . + /// + private readonly int assemblyInformationalVersionComponentCount; + /// /// Initializes a new instance of the class. /// @@ -75,11 +80,7 @@ public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? ov this.VersionOptions = this.CommittedVersion ?? this.WorkingVersion; this.Version = this.VersionOptions?.Version?.Version ?? Version0; - this.VersionHeightFieldPosition = this.VersionOptions?.VersionHeightPosition switch - { - SemanticVersion.Position.Revision => 4, - _ => 3 - }; + this.assemblyInformationalVersionComponentCount = this.VersionOptions?.VersionHeightPosition == SemanticVersion.Position.Revision ? 4 : 3; // Override the typedVersion with the special build number and revision components, when available. if (context.IsRepository) @@ -108,15 +109,6 @@ public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? ov } } - /// - /// The field (component) position of the version height. - /// - /// - /// If the user specifies "1.2.3" as the version number, the field position is 4. - /// If the user specifies "1.2", then the field position is 3. For all other scenarios, it also is set to 3. - /// - public int VersionHeightFieldPosition { get; private set; } - /// /// Gets the that were deserialized from the contextual commit, if any. /// @@ -195,7 +187,7 @@ public IEnumerable BuildMetadataWithCommitId /// Gets the version string to use for the . /// public string AssemblyInformationalVersion => - $"{this.Version.ToStringSafe(this.VersionHeightFieldPosition)}{this.PrereleaseVersion}{FormatBuildMetadata(this.BuildMetadataWithCommitId)}"; + $"{this.Version.ToStringSafe(this.assemblyInformationalVersionComponentCount)}{this.PrereleaseVersion}{FormatBuildMetadata(this.BuildMetadataWithCommitId)}"; /// /// Gets or sets a value indicating whether the project is building From 04544dcde313bc25a6ed33f196816d48210fade1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Sep 2021 14:31:02 -0600 Subject: [PATCH 331/704] Update Nerdbank.GitVersioning to 3.5.37-alpha This gets `msbuild -graph -isolate` working. Note when using `dotnet build` the `-graph -isolate` switches must be combined with `--no-restore` to workaround https://github.com/dotnet/msbuild/issues/6856. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 277c9cde..0df35e99 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -33,7 +33,7 @@ - + From f6bc832d634d56f1107a29f747159c06c32eb892 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Sep 2021 15:30:05 -0600 Subject: [PATCH 332/704] Optimize the build for just one version applied everywhere --- Directory.Build.props | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index 0df35e99..9184728d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,6 +12,9 @@ true true + + $(MSBuildThisFileDirectory) + embedded From 934d5f208f748fcdaf99e628c36c127246af99e6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Sep 2021 15:36:27 -0600 Subject: [PATCH 333/704] Add a collection for prepended paths --- init.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/init.ps1 b/init.ps1 index 4cf910f2..cb86c6ca 100755 --- a/init.ps1 +++ b/init.ps1 @@ -48,6 +48,7 @@ Param ( ) $EnvVars = @{} +$PrependPath = @() if (!$NoPrerequisites) { if (!$NoNuGetCredProvider) { @@ -82,7 +83,7 @@ try { } } - & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars | Out-Null + & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars -PrependPath $PrependPath | Out-Null } catch { Write-Error $error[0] From 62687e5afd6515409d332ee7cbbba5e38ea45885 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Sep 2021 16:56:28 -0600 Subject: [PATCH 334/704] Stabilize package restore in the face of outside influences --- nuget.config | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/nuget.config b/nuget.config index 68f36551..22f7b809 100644 --- a/nuget.config +++ b/nuget.config @@ -8,4 +8,8 @@ + + + + From f667e35825854645e6a0974e92f5c50e1f154708 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 30 Sep 2021 12:36:45 -0600 Subject: [PATCH 335/704] Fix NRE in GitContext.Create --- src/NerdBank.GitVersioning/GitContext.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/NerdBank.GitVersioning/GitContext.cs b/src/NerdBank.GitVersioning/GitContext.cs index e9d9114b..b11b7e5d 100644 --- a/src/NerdBank.GitVersioning/GitContext.cs +++ b/src/NerdBank.GitVersioning/GitContext.cs @@ -122,6 +122,8 @@ public void Dispose() /// public static GitContext Create(string path, string? committish = null, bool writable = false) { + Requires.NotNull(path, nameof(path)); + if (TryFindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath)) { GitContext result = writable From 49c2745eeca44c8fd18bbbfc9a663d7ba77e6580 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 30 Sep 2021 12:57:11 -0600 Subject: [PATCH 336/704] Drop netcoreapp2.1 support Target netcoreapp3.1 instead. v2.1 is no longer supported. --- azure-pipelines.yml | 7 +------ .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- .../Nerdbank.GitVersioning.Tasks.csproj | 6 +++--- .../Nerdbank.GitVersioning.nuspec | 15 +++++++-------- src/nerdbank-gitversioning.npm/ts/core.ts | 2 +- 5 files changed, 13 insertions(+), 19 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index e5e9a73c..9eae32e4 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -107,7 +107,7 @@ stages: displayName: Build LKG package workingDirectory: src/Nerdbank.GitVersioning.Tasks - - script: dotnet publish -c $(BuildConfiguration) -o ../nerdbank-gitversioning.npm/out/nbgv.cli/tools/netcoreapp2.1/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog" + - script: dotnet publish -c $(BuildConfiguration) -o ../nerdbank-gitversioning.npm/out/nbgv.cli/tools/netcoreapp3.1/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog" displayName: Publish nbgv tool workingDirectory: src/nbgv @@ -323,11 +323,6 @@ stages: pool: vmImage: $(imageName) steps: - - task: UseDotNet@2 - displayName: Install .NET Core 2.1 runtime - inputs: - packageType: runtime - version: 2.1.x - task: UseDotNet@2 displayName: Install .NET Core 3.1 runtime inputs: diff --git a/src/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/src/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index 555f1caf..53f34443 100644 --- a/src/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/src/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;netcoreapp2.1;net5.0 + netcoreapp3.1;net5.0 $(TargetFrameworks);net461 Exe true diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj index 468bc18a..da481512 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj @@ -1,6 +1,6 @@  - net461;netcoreapp2.1 + net461;netcoreapp3.1 true Nerdbank.GitVersioning.nuspec @@ -26,7 +26,7 @@ - MSBuildCore\ + MSBuildCore\ MSBuildFull\ @@ -83,7 +83,7 @@ - + diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 48fc3455..47223cac 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -40,14 +40,13 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - - - - - - - - + + + + + + + diff --git a/src/nerdbank-gitversioning.npm/ts/core.ts b/src/nerdbank-gitversioning.npm/ts/core.ts index c093eb8c..9fcddeea 100644 --- a/src/nerdbank-gitversioning.npm/ts/core.ts +++ b/src/nerdbank-gitversioning.npm/ts/core.ts @@ -5,6 +5,6 @@ const nbgvPath = 'nbgv.cli'; export function getNbgvCommand(dotnetCommand?: string): string { var command = dotnetCommand || 'dotnet'; - const nbgvDll = path.join(__dirname, nbgvPath, "tools", "netcoreapp2.1", "any", "nbgv.dll"); + const nbgvDll = path.join(__dirname, nbgvPath, "tools", "netcoreapp3.1", "any", "nbgv.dll"); return `${command} "${nbgvDll}"`; } From b3758969fe93c4cb56a11f04a56c43ca51606ee9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 30 Sep 2021 12:57:17 -0600 Subject: [PATCH 337/704] Update .NET SDK to 5.0.401 --- azure-pipelines.yml | 12 ++++++------ global.json | 4 +++- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 9eae32e4..d90b8fba 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -56,10 +56,10 @@ stages: displayName: Configure git commit author for testing - task: UseDotNet@2 - displayName: Install .NET Core 5.0.202 SDK + displayName: Install .NET Core 5.0.401 SDK inputs: packageType: sdk - version: 5.0.202 + version: 5.0.401 - task: UseDotNet@2 displayName: Install .NET Core 3.1 runtime @@ -69,9 +69,9 @@ stages: - pwsh: | Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 - & .\dotnet-install.ps1 -Architecture x86 -Version 5.0.202 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + & .\dotnet-install.ps1 -Architecture x86 -Version 5.0.401 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose - displayName: Install 32-bit .NET Core SDK 5.0.202, 3.1 + displayName: Install 32-bit .NET Core SDK 5.0.401, 3.1 condition: ne(variables['dotnet32'], '') - script: dotnet --info @@ -329,10 +329,10 @@ stages: packageType: runtime version: 3.1.x - task: UseDotNet@2 - displayName: Install .NET Core 5.0.202 SDK + displayName: Install .NET Core 5.0.401 SDK inputs: packageType: sdk - version: 5.0.202 + version: 5.0.401 - script: dotnet --info displayName: Show dotnet SDK info - bash: | diff --git a/global.json b/global.json index 66a8a8b2..3057bb45 100644 --- a/global.json +++ b/global.json @@ -1,5 +1,7 @@ { "sdk": { - "version": "5.0.202" + "version": "5.0.401", + "rollForward": "patch", + "allowPrerelease": false } } From ccae4b2e7701f9d7236c035f33fc0d702b80271e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 3 Oct 2021 14:01:00 -0600 Subject: [PATCH 338/704] Place obj folders in the same hierarchy as the source appears in the repo This avoids inadvertent obj dir collisions when the project name matches, which tends to happen when using dirs.proj. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 9184728d..3b53649a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -2,7 +2,7 @@ Debug $(MSBuildThisFileDirectory) - $(RepoRootPath)obj\$(MSBuildProjectName)\ + $(RepoRootPath)obj\$([MSBuild]::MakeRelative($(RepoRootPath), $(MSBuildProjectDirectory)))\ $(RepoRootPath)bin\$(MSBuildProjectName)\ $(RepoRootPath)bin\Packages\$(Configuration)\ 9.0 From 26afcd2276a2b0df4157d1594c260fd264a6adcd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 3 Oct 2021 14:01:13 -0600 Subject: [PATCH 339/704] Calculate the version just once for the whole repo --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index 3b53649a..8a8effea 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,6 +11,7 @@ true true true + $(RepoRootPath) $(MSBuildThisFileDirectory) From 392da69055086b58b6296379aa6c502a5b2ba947 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 3 Oct 2021 14:01:33 -0600 Subject: [PATCH 340/704] Opt into the WPF nuget fix in .NET 5 SDK --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index 8a8effea..6e481b01 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,6 +11,7 @@ true true true + true $(RepoRootPath) From cb72788b3ef1dfee35e163a60ba098f9342d62dc Mon Sep 17 00:00:00 2001 From: Lori <791039+Lorilatschki@users.noreply.github.com> Date: Thu, 7 Oct 2021 14:24:09 +0200 Subject: [PATCH 341/704] fix: extend error message in case there are uncommited changes, in order to get the files which are causing the issue (#666) * fix: extend error message in case there are uncommited changes, in order to get the files which are causing the issue This will make it possible, that the .gitignore file will be extended to exclude the temp files who are causing the issue in related repos. This fix is related to #603 --- src/NerdBank.GitVersioning/ReleaseManager.cs | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index 23a926f2..09fc5aa8 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; + using System.Linq; using LibGit2Sharp; using Nerdbank.GitVersioning.LibGit2; using Newtonsoft.Json; @@ -408,9 +409,13 @@ private LibGit2Context GetRepository(string projectDirectory) // abort if there are any pending changes - if (libgit2context.Repository.RetrieveStatus().IsDirty) + var status = libgit2context.Repository.RetrieveStatus(); + if (status.IsDirty) { - this.stderr.WriteLine($"Uncommitted changes in directory '{projectDirectory}'."); + var changedFiles = status.OfType().ToList(); + var changesFilesFormatted = string.Join(Environment.NewLine, changedFiles.Select(t => $"- {t.FilePath} changed with {nameof(FileStatus)} {t.State}")); + this.stderr.WriteLine($"Uncommitted changes ({changedFiles.Count}) in directory '{projectDirectory}':"); + this.stderr.WriteLine(changesFilesFormatted); throw new ReleasePreparationException(ReleasePreparationError.UncommittedChanges); } From 8094b0aac7e7ef8cb7b1c3b3cfd64455b0986973 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 8 Oct 2021 17:55:07 -0600 Subject: [PATCH 342/704] Set indent size for msbuildproj files --- .editorconfig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.editorconfig b/.editorconfig index 6015ff48..c561b381 100644 --- a/.editorconfig +++ b/.editorconfig @@ -20,7 +20,7 @@ insert_final_newline = true trim_trailing_whitespace = true # Xml project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj}] indent_size = 2 # Xml config files From bc15604c3b18cb0e11881e1d1656a34e93f99b5c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 7 Oct 2021 17:41:11 -0600 Subject: [PATCH 343/704] Add property that can disable the private MSBuild task invocation This allows Nerdbank.GitVersioning to (once again) work under quickbuild. --- .../BuildIntegrationTests.cs | 22 +++++++ .../NerdBank.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.nuspec | 6 +- .../build/InProjectVersionComputation.targets | 20 ++++++ .../build/MSBuildTargetCaching.targets | 60 ++++++++++++++++++ .../Nerdbank.GitVersioning.Common.targets | 1 + ...Nerdbank.GitVersioning.Inner.Empty.targets | 9 +++ .../Nerdbank.GitVersioning.Inner.targets | 12 ++-- .../build/Nerdbank.GitVersioning.props | 15 +++++ .../build/Nerdbank.GitVersioning.targets | 63 ++----------------- .../Nerdbank.GitVersioning.props | 4 ++ 11 files changed, 147 insertions(+), 67 deletions(-) create mode 100644 src/Nerdbank.GitVersioning.Tasks/build/InProjectVersionComputation.targets create mode 100644 src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets create mode 100644 src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.Empty.targets create mode 100644 src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props create mode 100644 src/Nerdbank.GitVersioning.Tasks/buildCrossTargeting/Nerdbank.GitVersioning.props diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index 3b4e00ea..57727e10 100644 --- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -39,6 +39,25 @@ protected override void ApplyGlobalProperties(IDictionary global => globalProperties["NBGV_GitEngine"] = "Managed"; } +[Trait("Engine", "Managed")] +[Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests. +public class BuildIntegrationInProjectManagedTests : BuildIntegrationTests +{ + public BuildIntegrationInProjectManagedTests(ITestOutputHelper logger) + : base(logger) + { + } + + protected override GitContext CreateGitContext(string path, string committish = null) + => GitContext.Create(path, committish, writable: false); + + protected override void ApplyGlobalProperties(IDictionary globalProperties) + { + globalProperties["NBGV_GitEngine"] = "Managed"; + globalProperties["NBGV_CacheMode"] = "None"; + } +} + [Trait("Engine", "LibGit2")] [Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests. public class BuildIntegrationLibGit2Tests : BuildIntegrationTests @@ -57,6 +76,7 @@ protected override void ApplyGlobalProperties(IDictionary global public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture { + private const string GitVersioningPropsFileName = "NerdBank.GitVersioning.props"; private const string GitVersioningTargetsFileName = "NerdBank.GitVersioning.targets"; private const string UnitTestCloudBuildPrefix = "UnitTest: "; private static readonly string[] ToxicEnvironmentVariablePrefixes = new string[] @@ -1175,6 +1195,7 @@ private ProjectRootElement CreateNativeProjectRootElement(string projectDirector { var pre = ProjectRootElement.Create(reader, this.projectCollection); pre.FullPath = Path.Combine(projectDirectory, projectName); + pre.InsertAfterChild(pre.CreateImportElement(Path.Combine(this.RepoPath, GitVersioningPropsFileName)), null); pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName)); return pre; } @@ -1186,6 +1207,7 @@ private ProjectRootElement CreateProjectRootElement(string projectDirectory, str { var pre = ProjectRootElement.Create(reader, this.projectCollection); pre.FullPath = Path.Combine(projectDirectory, projectName); + pre.InsertAfterChild(pre.CreateImportElement(Path.Combine(this.RepoPath, GitVersioningPropsFileName)), null); pre.AddImport(Path.Combine(this.RepoPath, GitVersioningTargetsFileName)); return pre; } diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 9e4bd7ef..e82aaab4 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -12,7 +12,7 @@ - + false Targets\%(FileName)%(Extension) diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 47223cac..47107c37 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -48,9 +48,13 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - + + + + + diff --git a/src/Nerdbank.GitVersioning.Tasks/build/InProjectVersionComputation.targets b/src/Nerdbank.GitVersioning.Tasks/build/InProjectVersionComputation.targets new file mode 100644 index 00000000..349fff64 --- /dev/null +++ b/src/Nerdbank.GitVersioning.Tasks/build/InProjectVersionComputation.targets @@ -0,0 +1,20 @@ + + + + + + + @(BuildMetadata, ',') + + + + + + + + + + + + diff --git a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets new file mode 100644 index 00000000..9bf0e1e0 --- /dev/null +++ b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets @@ -0,0 +1,60 @@ + + + $(NBGV_InnerGlobalProperties)GitRepoRoot=$(GitRepoRoot); + $(NBGV_InnerGlobalProperties)PublicRelease=$(PublicRelease); + $(NBGV_InnerGlobalProperties)_NBGV_BuildingRef=$(_NBGV_BuildingRef); + $(NBGV_InnerGlobalProperties)ProjectPathRelativeToGitRepoRoot=$(ProjectPathRelativeToGitRepoRoot); + $(NBGV_InnerGlobalProperties)GitVersionBaseDirectory=$(GitVersionBaseDirectory); + $(NBGV_InnerGlobalProperties)OverrideBuildNumberOffset=$(OverrideBuildNumberOffset); + $(NBGV_InnerGlobalProperties)NBGV_CacheMode=$(NBGV_CacheMode); + + + + + + + + + + <_BuildMetadataSnapped Include="@(BuildMetadata)" /> + + + + + + GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars + $(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ','); + @(NBGV_GlobalPropertiesToRemove) + + + false + false + true + false + true + + + + + + + + + + + + + + + + + diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Common.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Common.targets index 047e2420..a360732f 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Common.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Common.targets @@ -1,6 +1,7 @@  + <_NBGV_Common_Targets_Imported>true <_NBGV_PlatformSuffix Condition=" '$(_NBGV_PlatformSuffix)' == '' and '$(MSBuildRuntimeType)' == 'Core' ">MSBuildCore/ <_NBGV_PlatformSuffix Condition=" '$(_NBGV_PlatformSuffix)' == '' ">MSBuildFull/ $(MSBuildThisFileDirectory)$(_NBGV_PlatformSuffix) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.Empty.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.Empty.targets new file mode 100644 index 00000000..02f61168 --- /dev/null +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.Empty.targets @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets index 8075fb21..1cbafadb 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets @@ -1,7 +1,7 @@  - + @@ -18,7 +18,7 @@ BuildingRef="$(_NBGV_BuildingRef)" BuildMetadata="$(BuildMetadata.Replace(',',';'))" DefaultPublicRelease="$(PublicRelease)" - ProjectDirectory="$(ProjectDirectory)" + ProjectDirectory="$(GitVersionBaseDirectory)" GitRepoRoot="$(GitRepoRoot)" ProjectPathRelativeToGitRepoRoot="$(ProjectPathRelativeToGitRepoRoot)" OverrideBuildNumberOffset="$(OverrideBuildNumberOffset)" @@ -42,11 +42,7 @@ - - - - - - + + \ No newline at end of file diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props new file mode 100644 index 00000000..5ebd8c16 --- /dev/null +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props @@ -0,0 +1,15 @@ + + + + None + MSBuildTargetCaching + + diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 33a2910f..abc90c9e 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -25,7 +25,7 @@ false - + @@ -37,7 +37,7 @@ - false + false @@ -64,54 +64,9 @@ <_NBGV_BuildingRef Condition=" '$(_NBGV_BuildingRef)' == '' ">$(_NBGV_BuildingBranch) $(MSBuildProjectDirectory) - $(NBGV_InnerGlobalProperties)GitRepoRoot=$(GitRepoRoot); - $(NBGV_InnerGlobalProperties)PublicRelease=$(PublicRelease); - $(NBGV_InnerGlobalProperties)_NBGV_BuildingRef=$(_NBGV_BuildingRef); - $(NBGV_InnerGlobalProperties)ProjectPathRelativeToGitRepoRoot=$(ProjectPathRelativeToGitRepoRoot); - $(NBGV_InnerGlobalProperties)ProjectDirectory=$(GitVersionBaseDirectory); - $(NBGV_InnerGlobalProperties)OverrideBuildNumberOffset=$(OverrideBuildNumberOffset); - $(MSBuildThisFileDirectory)Nerdbank.GitVersioning.Inner.targets - - - - - - - - <_BuildMetadataSnapped Include="@(BuildMetadata)" /> - - - - - - GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars - $(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ','); - @(NBGV_GlobalPropertiesToRemove) - - - false - false - true - false - true - - - - - - - - - - - + %(Value) - - - - - + + + + + + From f0e05d18c0cce260fb2a92b2e415d5fe67f70047 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 8 Oct 2021 06:49:43 -0600 Subject: [PATCH 344/704] Allow sharing version computation with a user-owned project Quickbuild requires that every P2P be to a git-controlled project. This makes it incompatible with NB.GV's running the MSBuild task to one of its own .targets files. To workaround this, a quickbuild user will have to define their own project that does nothing but compute the version using NB.GV, and then set `NBGV_CachingProjectReference` to the full path to this custom project. Note that no actual *caching* occurs at this stage when under quickbuild because quickbuild uses a new top-level msbuild call for every project. We'll need to combine this with caching version info to a file on disk for this to be a perf improvement in quickbuild. --- doc/quickbuild.md | 55 +++++++++++++++++++ .../NerdBank.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.nuspec | 2 +- .../build/MSBuildTargetCaching.targets | 17 ++++-- .../Nerdbank.GitVersioning.Inner.targets | 2 - .../build/Nerdbank.GitVersioning.props | 5 ++ .../build/Nerdbank.GitVersioning.targets | 1 + ...r.Empty.targets => PrivateP2PCaching.proj} | 5 +- 8 files changed, 80 insertions(+), 9 deletions(-) create mode 100644 doc/quickbuild.md rename src/Nerdbank.GitVersioning.Tasks/build/{Nerdbank.GitVersioning.Inner.Empty.targets => PrivateP2PCaching.proj} (65%) diff --git a/doc/quickbuild.md b/doc/quickbuild.md new file mode 100644 index 00000000..0fc733b5 --- /dev/null +++ b/doc/quickbuild.md @@ -0,0 +1,55 @@ +# Microsoft's (internal) quickbuild + +Nerdbank.GitVersioning supports the Microsoft-internal quickbuild/cloudbuild tool. + +It works out of the box, but each project will recompute the version, which may accumulate to a significant increase in overall build time. + +🚧 A future version of Nerdbank.GitVersioning will cache version information as a file so that the following instructions will be effective. 🚧 + +To calculate the version just once for an entire build, a few manual steps are required. + +1. Create this project in your repo. The suggested location is `VersionGeneration/VersionGeneration.msbuildproj`. + + ```xml + + + net5.0 + false + true + VersionGenerationTarget + + + ``` + + The `TargetFramework` property value is not important as no assemblies are built by this project, + but a value is nonetheless required for NuGet to be willing to consume the Nerdbank.GitVersioning package reference + (which is referenced in Directory.Build.props as described later). + +1. Add the SDK version to your repo-root level `global.json` file, if it is not already present. + The [latest available version from nuget.org](https://www.nuget.org/packages/microsoft.build.notargets) is recommended. + + ```json + { + "msbuild-sdks": { + "Microsoft.Build.NoTargets": "3.1.0" + } + } + ``` + +1. Modify your repo-root level `Directory.Build.props` file to contain these elements: + + ```xml + + + $(MSBuildThisFileDirectory) + + + + MSBuildTargetCaching + $(MSBuildThisFileDirectory)VersionGeneration\VersionGeneration.msbuildproj + + + + + + ``` diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index e82aaab4..1e9f8e11 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -12,7 +12,7 @@ - + false Targets\%(FileName)%(Extension) diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 47107c37..668b210e 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -52,9 +52,9 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - + diff --git a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets index 9bf0e1e0..7e2b97ca 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets @@ -6,22 +6,30 @@ $(NBGV_InnerGlobalProperties)ProjectPathRelativeToGitRepoRoot=$(ProjectPathRelativeToGitRepoRoot); $(NBGV_InnerGlobalProperties)GitVersionBaseDirectory=$(GitVersionBaseDirectory); $(NBGV_InnerGlobalProperties)OverrideBuildNumberOffset=$(OverrideBuildNumberOffset); - $(NBGV_InnerGlobalProperties)NBGV_CacheMode=$(NBGV_CacheMode); - - <_BuildMetadataSnapped Include="@(BuildMetadata)" /> + + + $(NBGV_InnerGlobalProperties)Configuration=Release; + $(NBGV_InnerGlobalProperties)Platform=AnyCPU; + + + + + + - + GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars $(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ','); @(NBGV_GlobalPropertiesToRemove) @@ -32,6 +40,7 @@ true false true + all diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets index 1cbafadb..ac037a13 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.targets @@ -43,6 +43,4 @@ - - \ No newline at end of file diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props index 5ebd8c16..0c994a77 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.props @@ -11,5 +11,10 @@ --> None MSBuildTargetCaching + + + $(MSBuildThisFileDirectory)PrivateP2PCaching.proj diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index abc90c9e..232ee06b 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -38,6 +38,7 @@ false + false diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.Empty.targets b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj similarity index 65% rename from src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.Empty.targets rename to src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 02f61168..0245b1ae 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.Inner.Empty.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -1,4 +1,7 @@ - + + + + From e929e74b8ebae06be457c0e617a5ce5de45ce42c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 11 Oct 2021 09:48:27 -0600 Subject: [PATCH 345/704] Suppress `cloudBuild.buildNumber: null` being written for `nbgv prepare-release` Fixes #630 --- src/NerdBank.GitVersioning/VersionOptions.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index cac77f86..767155c6 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -934,6 +934,7 @@ public bool? SetVersionVariables /// /// Gets or sets options around how and whether to set the build number preset by the cloud build with one enriched with version information. /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public CloudBuildNumberOptions? BuildNumber { get => this.buildNumber; From 6cd48ff31414e2004ebb579d6a9e3e2ab4d422df Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 11 Oct 2021 15:07:39 -0600 Subject: [PATCH 346/704] Move TargetFramework properties into projects They cause more confusion and issues being imported than its worth. --- src/Directory.Build.props | 4 ---- src/Library/Library.csproj | 4 +++- test/Directory.Build.props | 1 - test/Library.Tests/Library.Tests.csproj | 1 + 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 165d2ddd..77d94765 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,7 +1,3 @@ - - - netstandard2.0 - diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index 61718a1f..4641dbd6 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -1,3 +1,5 @@ - + + netstandard2.0 + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 1b45d716..449a06e4 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -2,7 +2,6 @@ - net5.0;netcoreapp3.1;net472 false true diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index c66b7aac..9a0a5820 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -1,6 +1,7 @@ + net5.0;netcoreapp3.1;net472 From 759e5a586b72872756eeb2313ee33c4a1517d75b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 12 Oct 2021 17:15:08 -0600 Subject: [PATCH 347/704] Fix `dotnet publish` on an app that uses NB.GV Fixes #671 --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 0245b1ae..2f4991ac 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -7,6 +7,7 @@ + \ No newline at end of file From 5265bd95160fc94920a3bf723e839cd00fda5ca1 Mon Sep 17 00:00:00 2001 From: Lubos Hladik Date: Wed, 20 Oct 2021 20:19:43 +0200 Subject: [PATCH 348/704] Add retry to SetCloudBuildVariable method in VisualStudioTeamServices. --- .../CloudBuildServices/VisualStudioTeamServices.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs b/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs index 0b3da5f2..fcaf7f1d 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs @@ -33,7 +33,8 @@ public IReadOnlyDictionary SetCloudBuildNumber(string buildNumbe public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) { - (stdout ?? Console.Out).WriteLine($"##vso[task.setvariable variable={name};]{value}"); + Utilities.FileOperationWithRetry(() => + (stdout ?? Console.Out).WriteLine($"##vso[task.setvariable variable={name};]{value}")); return GetDictionaryFor(name, value); } From 72bf8fec2c46ee74fa53c8eacd8f7fcca02d4ba9 Mon Sep 17 00:00:00 2001 From: Daniel Abbatt Date: Fri, 22 Oct 2021 12:39:26 +0100 Subject: [PATCH 349/704] Update public_vs_stable.md to replace 'master' with 'main' Update public_vs_stable.md to replace 'master' with 'main' as most repository conventions are now to use 'main' as a replacement for 'master'. --- doc/public_vs_stable.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/doc/public_vs_stable.md b/doc/public_vs_stable.md index 058790e0..d1f180cf 100644 --- a/doc/public_vs_stable.md +++ b/doc/public_vs_stable.md @@ -53,14 +53,14 @@ That's what Nerdbank.GitVersioning's "public release" flag is for. Let's dive in There are traces of linear history in your repo. Any commit in git can be formally shown to be either older or newer than any other commit belonging to the same branch, similar to any two versions in SemVer can. Within a single branch then, you have linear history. -If you always ship from `master` for example, then `master` can act as your linear parallel to your semver-world of public releases. -To capture this, you can tell Nerdbank.GitVersioning that you ship out of master in your version.json file: +If you always ship from `main` for example, then `main` can act as your linear parallel to your semver-world of public releases. +To capture this, you can tell Nerdbank.GitVersioning that you ship out of main in your version.json file: ```json { "version": "1.2", "publicReleaseRefSpec": [ - "^refs/heads/master$" + "^refs/heads/main$" ] } ``` @@ -68,7 +68,7 @@ To capture this, you can tell Nerdbank.GitVersioning that you ship out of master But what exactly does this `publicReleaseRefSpec` property do? It tells Nerdbank.GitVersioning which branch(es) to assume belong to your publicly visible linear history. When building such a branch, it's safe to build packages that have only a version number. -So building either of a couple of commits along the master branch where 1.2 is the specified version might produce a package versioned as 1.2.5 for the 5th commit and 1.2.9 for the 9th commit. +So building either of a couple of commits along the main branch where 1.2 is the specified version might produce a package versioned as 1.2.5 for the 5th commit and 1.2.9 for the 9th commit. When you're *not* building from a "public release" branch, Nerdbank.GitVersioning delivers on several requirements: @@ -79,13 +79,13 @@ When you're *not* building from a "public release" branch, Nerdbank.GitVersionin Nerdbank.GitVersioning accomplishes these objectives by appending a special pre-release suffix to _everything_ built in a non-public release branch. This prerelease tag is based on the git commit ID being built. For example if you're building a topic branch from version 1.2 with a commit ID starting with c0ffeebeef, the SemVer-compliant version produced for that build would be `1.2-c0ffeebeef`. If the version.json indicated this is `-beta` software, the two prerelease tags would be combined to form `1.2-beta-c0ffeebeef`. -If in addition to shipping out of `master` you also service past releases, you might name those branches with a convention of v*Major*.*Minor* (e.g. v1.2, v1.3) and then add the pattern to your version.json file's `publicReleaseRefSpec` array: +If in addition to shipping out of `main` you also service past releases, you might name those branches with a convention of v*Major*.*Minor* (e.g. v1.2, v1.3) and then add the pattern to your version.json file's `publicReleaseRefSpec` array: ```json { "version": "1.2", "publicReleaseRefSpec": [ - "^refs/heads/master$", // main releases ship from master + "^refs/heads/main$", // main releases ship from main "^refs/heads/v\\d+\\.\\d+$" // servicing releases ship from vX.Y branches ] } @@ -111,17 +111,17 @@ To force public release versioning, you can add the `/p:PublicRelease=true` swit To force a *non*-public release build, you can similarly specify `/p:PublicRelease=false`. This can be useful when testing a topic branch will build successfully after merging into a stable, public release branch by forcing a local build to build as a public release. -For example suppose `master` builds a stable 1.2 package, and your topic branch builds `1.2-c0ffeebeef` because it's a non-public release. +For example suppose `main` builds a stable 1.2 package, and your topic branch builds `1.2-c0ffeebeef` because it's a non-public release. In your topic branch you've made some package dependency changes that *might* have introduced a dependency on some other unstable package. Your package manager didn't complain because your package version was unstable anyway due to the `-c0ffeebeef` suffix. -But you know once you merge into `master`, it will be a stable package again and your package manager might complain that a stable package shouldn't depend on a prerelease package. +But you know once you merge into `main`, it will be a stable package again and your package manager might complain that a stable package shouldn't depend on a prerelease package. You can force such warnings to show up in your topic branch by building with the `/p:PublicRelease=true` switch. ### More on why and when git commit hashes are useful -Consider that master builds a 1.2 version, and has a version height of 10. So its package version will be 1.2.10. Now imagine a developer branches off a "fixBug" topic branch from that point and begins changing code. As part of changing and testing that code, a package is built and consumed. Note the developer may not have even committed a change yet, so the version and height is *still* 1.2.10. We *don't* want a package version collision, so the topic branch produces a package version of `1.2.10-gc0ffee`. Now *both* the official master version and the topic branch version can both be restored and populate the nuget cache on a machine without conflicting and causing bizarre inconsistent behaviors that boggle the mind. :) +Consider that main builds a 1.2 version, and has a version height of 10. So its package version will be 1.2.10. Now imagine a developer branches off a "fixBug" topic branch from that point and begins changing code. As part of changing and testing that code, a package is built and consumed. Note the developer may not have even committed a change yet, so the version and height is *still* 1.2.10. We *don't* want a package version collision, so the topic branch produces a package version of `1.2.10-gc0ffee`. Now *both* the official main version and the topic branch version can both be restored and populate the nuget cache on a machine without conflicting and causing bizarre inconsistent behaviors that boggle the mind. :) -Or, if the topic branch *has* committed and moved onto 1.2.11, that could still collide because `master` may have moved on as well, using that same version. But since the topic branch always adds `-gc0ffee` hash suffixes to the package version, it won't conflict. -Also: you don't want a topic branch to be seen as newer and better than what's in the master branch unless the user is explicitly opting into unstable behavior, so the `-gc0ffee` suffix is useful because it forces the package to be seen as "unstable". Once it merges with `master`, it will drop its `-gc0ffee` suffix, but will retain any other `-prerelease` tag specified in the version.json file. +Or, if the topic branch *has* committed and moved onto 1.2.11, that could still collide because `main` may have moved on as well, using that same version. But since the topic branch always adds `-gc0ffee` hash suffixes to the package version, it won't conflict. +Also: you don't want a topic branch to be seen as newer and better than what's in the main branch unless the user is explicitly opting into unstable behavior, so the `-gc0ffee` suffix is useful because it forces the package to be seen as "unstable". Once it merges with `main`, it will drop its `-gc0ffee` suffix, but will retain any other `-prerelease` tag specified in the version.json file. [nbgv_prepare-release]: https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/nbgv-cli.md#preparing-a-release From 295a5328208e65883c9a3add6fdfdba3bd14b34a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 06:24:16 -0600 Subject: [PATCH 350/704] Include README in nupkg --- src/Library/Library.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index 4641dbd6..a7547da1 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -1,5 +1,9 @@ netstandard2.0 + README.md + + + From d3cb4c585962ff32716f4e6c22a3ebe905a6e8a4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 06:38:13 -0600 Subject: [PATCH 351/704] Revert "Include README in nupkg" This reverts commit 295a5328208e65883c9a3add6fdfdba3bd14b34a. This is due to https://github.com/NuGet/Home/issues/10791. We can reapply the readme after switching to .NET SDK 6.0. --- src/Library/Library.csproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index a7547da1..4641dbd6 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -1,9 +1,5 @@ netstandard2.0 - README.md - - - From 2174046dee68180b06a3de37420161cfa4566dbb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 06:38:42 -0600 Subject: [PATCH 352/704] Reapply "Include README in nupkg" This reverts commit d3cb4c585962ff32716f4e6c22a3ebe905a6e8a4. --- src/Library/Library.csproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index 4641dbd6..a7547da1 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -1,5 +1,9 @@ netstandard2.0 + README.md + + + From 35d6e39de7af4dab08dedaed597e77dc9339d05e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 06:50:35 -0600 Subject: [PATCH 353/704] Add empty Clean target --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 2f4991ac..64321534 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -10,4 +10,6 @@ - \ No newline at end of file + + + From 5fa2a94852e82ada595c6d3a7c112670d9590493 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 06:51:05 -0600 Subject: [PATCH 354/704] Update to .NET 6 SDK --- Directory.Build.props | 3 +-- global.json | 4 ++-- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 6e481b01..fac9c677 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,8 +34,7 @@ - - + diff --git a/global.json b/global.json index 3057bb45..973759e1 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "5.0.401", + "version": "6.0.100-rc.2.21505.57", "rollForward": "patch", - "allowPrerelease": false + "allowPrerelease": true } } From 346548ac0da1ae678c32af3b0381df4c34277a0b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 07:31:30 -0600 Subject: [PATCH 355/704] Search for .NET 5+ runtime requirements --- tools/Install-DotNetSdk.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 73dae25f..42789930 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -47,7 +47,7 @@ Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$P } } } - $targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% { + $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% { $v = $Matches[1] $runtimeVersions += $v if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) { From ef76eb2d0d8cc2d90ce4eee2cd07d485b18ecedf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 08:20:31 -0600 Subject: [PATCH 356/704] Use C# 10 syntax --- Directory.Build.props | 4 ++-- src/Library/Calculator.cs | 39 ++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index fac9c677..38102b59 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,8 +5,9 @@ $(RepoRootPath)obj\$([MSBuild]::MakeRelative($(RepoRootPath), $(MSBuildProjectDirectory)))\ $(RepoRootPath)bin\$(MSBuildProjectName)\ $(RepoRootPath)bin\Packages\$(Configuration)\ - 9.0 + 10.0 enable + enable latest true true @@ -34,7 +35,6 @@ - diff --git a/src/Library/Calculator.cs b/src/Library/Calculator.cs index 9156a1a3..706c341d 100644 --- a/src/Library/Calculator.cs +++ b/src/Library/Calculator.cs @@ -1,29 +1,26 @@ // Copyright (c) COMPANY-PLACEHOLDER. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Library -{ - using System; +namespace Library; +/// +/// My first class. +/// +public static class Calculator +{ /// - /// My first class. + /// Adds two integers. /// - public static class Calculator - { - /// - /// Adds two integers. - /// - /// The first integer. - /// The second integer. - /// The sum of the two integers. - public static int Add(int a, int b) => a + b; + /// The first integer. + /// The second integer. + /// The sum of the two integers. + public static int Add(int a, int b) => a + b; - /// - /// Subtracts one integer from another. - /// - /// The original integer. - /// The integer to subtract. - /// The difference between the two integers. - public static int Subtract(int a, int b) => a - b; - } + /// + /// Subtracts one integer from another. + /// + /// The original integer. + /// The integer to subtract. + /// The difference between the two integers. + public static int Subtract(int a, int b) => a - b; } From 2cc62417f55390b6ef18b69c51fe3b1ec7dc1082 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Oct 2021 08:22:53 -0600 Subject: [PATCH 357/704] Remove WPF workaround that isn't necessary with the .NET 6 SDK --- Directory.Build.props | 1 - 1 file changed, 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 38102b59..38d8582d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,6 @@ true true true - true $(RepoRootPath) From a280dfc4ad77431e75a359b37c27886cf3a3afe7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Nov 2021 13:00:43 +0000 Subject: [PATCH 358/704] Bump Microsoft.NET.Test.Sdk from 16.11.0 to 17.0.0 Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 16.11.0 to 17.0.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v16.11.0...v17.0.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 9a0a5820..ebd5df8f 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -11,7 +11,7 @@ - + From 19a28c557915ac59149e1abd0f5e157093a9dad1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 1 Nov 2021 14:44:34 -0600 Subject: [PATCH 359/704] Fixes `nbgv get-commits` to require version matching We previously were only looking at version height and (optional) commit ID. We were (amazingly enough) not bothering to look at the major.minor version specified in the version.json file. --- .../GitExtensionsTests.cs | 12 +++ .../LibGit2/LibGit2GitExtensions.cs | 2 +- src/NerdBank.GitVersioning/SemanticVersion.cs | 76 +++++++++++++------ src/NerdBank.GitVersioning/VersionOptions.cs | 19 +---- 4 files changed, 65 insertions(+), 44 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/GitExtensionsTests.cs b/src/NerdBank.GitVersioning.Tests/GitExtensionsTests.cs index 7a8704dc..9caeb14a 100644 --- a/src/NerdBank.GitVersioning.Tests/GitExtensionsTests.cs +++ b/src/NerdBank.GitVersioning.Tests/GitExtensionsTests.cs @@ -129,6 +129,18 @@ public void GetCommitsFromVersion_WithPathFilters() LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 2, 3)).OrderBy(c => c.Sha)); } + [Fact] + public void GetCommitsFromVersion_WithMajorMinorChecks() + { + Commit v1_0_50 = this.WriteVersionFile(new VersionOptions { Version = SemanticVersion.Parse("1.0.50-preview.{height}") }); + Commit v1_1_50 = this.WriteVersionFile(new VersionOptions { Version = SemanticVersion.Parse("1.1.50-preview.{height}") }); + + Assert.Empty(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 0))); + Assert.Empty(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 0, 49))); + Assert.Equal(v1_0_50, Assert.Single(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 0, 50)))); + Assert.Equal(v1_1_50, Assert.Single(LibGit2GitExtensions.GetCommitsFromVersion(this.Context, new Version(1, 1, 50)))); + } + [Theory] [InlineData("2.2", "2.2-alpha.{height}", 1, 1, true)] [InlineData("2.2", "2.3", 1, 1, true)] diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index b2ff2d35..0c54b49b 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -174,7 +174,7 @@ public static IEnumerable GetCommitsFromVersion(LibGit2Context context, var tracker = new GitWalkTracker(context); var possibleCommits = from commit in GetCommitsReachableFromRefs(context.Repository) let commitVersionOptions = tracker.GetVersion(commit) - where commitVersionOptions is not null + where commitVersionOptions?.Version?.IsMatchingVersion(version) is true where !IsCommitIdMismatch(version, commitVersionOptions, commit) where !IsVersionHeightMismatch(version, commitVersionOptions, commit, tracker) select commit; diff --git a/src/NerdBank.GitVersioning/SemanticVersion.cs b/src/NerdBank.GitVersioning/SemanticVersion.cs index ad07b529..1fedc024 100644 --- a/src/NerdBank.GitVersioning/SemanticVersion.cs +++ b/src/NerdBank.GitVersioning/SemanticVersion.cs @@ -152,6 +152,28 @@ internal SemanticVersion.Position? VersionHeightPosition } } + /// + /// Gets the position in a computed version that the first 16 bits of a git commit ID should appear, if any. + /// + internal SemanticVersion.Position? GitCommitIdPosition + { + get + { + // We can only store the git commit ID info after there was a place to put the version height. + // We don't want to store the commit ID (which is effectively a random integer) in the revision slot + // if the version height does not appear, or only appears later (in the -prerelease tag) since that + // would mess up version ordering. + if (this.VersionHeightPosition == SemanticVersion.Position.Build) + { + return SemanticVersion.Position.Revision; + } + else + { + return null; + } + } + } + /// /// Gets a value indicating whether this instance is the default "0.0" instance. /// @@ -286,40 +308,44 @@ internal static bool WillVersionChangeResetVersionHeight(SemanticVersion first, return false; } - internal static int ReadVersionPosition(Version version, SemanticVersion.Position position) + internal static int ReadVersionPosition(Version version, Position position) { Requires.NotNull(version, nameof(version)); - switch (position) + return position switch { - case SemanticVersion.Position.Major: - return version.Major; - case SemanticVersion.Position.Minor: - return version.Minor; - case SemanticVersion.Position.Build: - return version.Build; - case SemanticVersion.Position.Revision: - return version.Revision; - default: - throw new ArgumentOutOfRangeException(nameof(position), position, "Must be one of the 4 integer parts."); - } + Position.Major => version.Major, + Position.Minor => version.Minor, + Position.Build => version.Build, + Position.Revision => version.Revision, + _ => throw new ArgumentOutOfRangeException(nameof(position), position, "Must be one of the 4 integer parts."), + }; } - internal int ReadVersionPosition(SemanticVersion.Position position) + internal int ReadVersionPosition(Position position) => ReadVersionPosition(this.Version, position); + + /// + /// Checks whether a given version may have been produced by this semantic version. + /// + /// The version to test. + /// if the is a match; otherwise. + internal bool IsMatchingVersion(Version version) { - switch (position) + Position lastPositionToConsider = Position.Revision; + if (this.VersionHeightPosition <= lastPositionToConsider) { - case SemanticVersion.Position.Major: - return this.Version.Major; - case SemanticVersion.Position.Minor: - return this.Version.Minor; - case SemanticVersion.Position.Build: - return this.Version.Build; - case SemanticVersion.Position.Revision: - return this.Version.Revision; - default: - throw new ArgumentOutOfRangeException(nameof(position), position, "Must be one of the 4 integer parts."); + lastPositionToConsider = this.VersionHeightPosition.Value - 1; } + + for (Position i = Position.Major; i <= lastPositionToConsider; i++) + { + if (this.ReadVersionPosition(i) != ReadVersionPosition(version, i)) + { + return false; + } + } + + return true; } /// diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index 767155c6..03eccce2 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -433,24 +433,7 @@ internal SemanticVersion.Position? VersionHeightPosition /// Gets the position in a computed version that the first 16 bits of a git commit ID should appear, if any. /// [JsonIgnore] - internal SemanticVersion.Position? GitCommitIdPosition - { - get - { - // We can only store the git commit ID info after there was a place to put the version height. - // We don't want to store the commit ID (which is effectively a random integer) in the revision slot - // if the version height does not appear, or only appears later (in the -prerelease tag) since that - // would mess up version ordering. - if (this.VersionHeightPosition == SemanticVersion.Position.Build) - { - return SemanticVersion.Position.Revision; - } - else - { - return null; - } - } - } + internal SemanticVersion.Position? GitCommitIdPosition => this.version?.GitCommitIdPosition; /// /// Gets the debugger display for this instance. From d68e6e9b8d61f79aca503402b255f0e08376172f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 2 Nov 2021 06:09:10 -0600 Subject: [PATCH 360/704] Fix/clarify docs about cloud builds --- doc/cloudbuild.md | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-) diff --git a/doc/cloudbuild.md b/doc/cloudbuild.md index 80520aca..9230c4c0 100644 --- a/doc/cloudbuild.md +++ b/doc/cloudbuild.md @@ -76,14 +76,14 @@ This means you can use these variables in subsequent steps in your cloud build such as publishing artifacts, so that your richer version information can be expressed in the publish location or artifact name. -Enable this feature by setting the `cloudBuild.setVersionVariables` field -in your `version.json` file to `true`, as shown below: +This feature is enabled by default via the `cloudBuild.setVersionVariables` field +in your `version.json` file, which defaults as shown below: ```json { "version": "1.0", "cloudBuild": { - "setVersionVariables": true + "setVersionVariables": true // the default value } } ``` @@ -106,7 +106,18 @@ Setting both of these fields to `true` means that a few variables will be define While each individual MSBuild project has its own version computed, the versions across projects are usually the same so long as you have one `version.json` file at the root of your repo. If you choose to enable setting of cloud build variables in that root version.json file, each project that builds will take a turn setting those cloud build variables. This is perhaps more work than is necessary, and when some projects compute versions differently it can lead to inconsistently defined cloud build variables, based on non-deterministic build ordering of your projects. -You can reduce log message noise and control for non-deterministic cloud build variables by *not* setting any of the `cloudBuild` options in your root version.json file. Two options are described below to set the cloud build number and variables just once in your build. +You can reduce log message noise and control for non-deterministic cloud build variables by disabling all the settings under the `cloudBuild` options in your root version.json file (including disabling default behavior): + +```js +{ + "version": "1.0", + "cloudBuild": { + "setVersionVariables": false // override the default value of true + } +} +``` + +Two options are described below to set the cloud build number and variables just once in your build. #### Set the cloud build number as a build step @@ -117,7 +128,7 @@ dotnet tool install --tool-path . nbgv .\nbgv cloud ``` -The above will set just the cloud build number, but switches to the `nbgv cloud` command will cause other build variables to also be set. +The above will set just the cloud build number, but switches you can add to the `nbgv cloud` command will cause other build variables to also be set. See a working sample in [a VSTS YAML file](https://github.com/Humanizr/Humanizer/blob/11bd9fd99c151f2e84eb9d4fa082a6c077504c9f/azure-pipelines.yml#L21-L29). From ab053bb6cc903ac4a48ba198f126b5e021905e33 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 2 Nov 2021 06:13:29 -0600 Subject: [PATCH 361/704] Disable default, redundant NB.GV behavior We already call `nbgv cloud` in the cloud builds, so there is no need to set certain pipeline variables with every project. In fact given a couple bugs that have come into NB.GV lately around issues on [AzP](https://github.com/dotnet/Nerdbank.GitVersioning/pull/675) or [GitHub Actions](https://github.com/dotnet/Nerdbank.GitVersioning/issues/683) around setting pipeline variables, this should improve build reliability. --- version.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/version.json b/version.json index f0da4f6a..39add986 100644 --- a/version.json +++ b/version.json @@ -4,5 +4,8 @@ "publicReleaseRefSpec": [ "^refs/heads/main$", "^refs/heads/v\\d+(?:\\.\\d+)?$" - ] + ], + "cloudBuild": { + "setVersionVariables": false + } } From 16d30af64f26f62e547805ebcb002b1efd3f7a6d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 2 Nov 2021 10:29:57 -0600 Subject: [PATCH 362/704] Log artifact warnings in more cases We were not warning when *groups* would be defined by an artifact collector even if all those groups were empty. --- azure-pipelines/artifacts/_all.ps1 | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index efd6bdb3..db10c5ff 100755 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -25,10 +25,9 @@ Function EnsureTrailingSlash($path) { Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse |% { $ArtifactName = $_.BaseName + $totalFileCount = 0 $fileGroups = & $_ - if (!$fileGroups -or $fileGroups.Count -eq 0) { - Write-Warning "No files found for the `"$ArtifactName`" artifact." - } else { + if ($fileGroups) { $fileGroups.GetEnumerator() | % { $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key.ToString()), [UriKind]::Absolute) $_.Value | % { @@ -46,7 +45,12 @@ Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse |% { Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) Write-Output $artifact + $totalFileCount += 1 } } } + + if ($totalFileCount -eq 0) { + Write-Warning "No files found for the `"$ArtifactName`" artifact." + } } From cbf38a43293df070b8dc0cf8f365e2b237f4bd22 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 8 Nov 2021 12:31:26 -0700 Subject: [PATCH 363/704] Use .NET SDK 6.0.100 GA --- global.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/global.json b/global.json index 973759e1..e2af429b 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,7 @@ { "sdk": { - "version": "6.0.100-rc.2.21505.57", + "version": "6.0.100", "rollForward": "patch", - "allowPrerelease": true + "allowPrerelease": false } } From 45b46cb2643d1cec801b5b080671e0ce1ad244a0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Nov 2021 08:00:36 -0700 Subject: [PATCH 364/704] Fix packing a project that references NB.GV --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 64321534..2b44dbcf 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -12,4 +12,7 @@ + + + From 4582d85ab68fe930a4b2016a7351322a0e6672db Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Nov 2021 08:25:49 -0700 Subject: [PATCH 365/704] Collect coverage in non-multitargeting environments --- azure-pipelines/artifacts/coverageResults.ps1 | 4 ++-- azure-pipelines/publish-codecoverage.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 index addbf85c..8fdb3f72 100644 --- a/azure-pipelines/artifacts/coverageResults.ps1 +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -3,7 +3,7 @@ $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") # Prepare code coverage reports for merging on another machine if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) { Write-Host "Substituting $env:SYSTEM_DEFAULTWORKINGDIRECTORY with `"{reporoot}`"" - $reports = Get-ChildItem "$RepoRoot/bin/coverage.*.cobertura.xml" -Recurse + $reports = Get-ChildItem "$RepoRoot/bin/coverage.*cobertura.xml" -Recurse $reports |% { $content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape($env:SYSTEM_DEFAULTWORKINGDIRECTORY), "{reporoot}" } Set-Content -Path $_ -Value $content -Encoding UTF8 @@ -16,7 +16,7 @@ if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } @{ $RepoRoot = ( - @(Get-ChildItem "$RepoRoot\bin\coverage.*.cobertura.xml" -Recurse) + + @(Get-ChildItem "$RepoRoot\bin\coverage.*cobertura.xml" -Recurse) + (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) ); } diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index d83eb64a..3667b976 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -19,7 +19,7 @@ steps: dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.8.5 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" - $reports = Get-ChildItem -Recurse "$(Pipeline.Workspace)/coverage.*.cobertura.xml" + $reports = Get-ChildItem -Recurse "$(Pipeline.Workspace)/coverage.*cobertura.xml" $reports |% { $content = Get-Content -Path $_ |% { $_.Replace("{reporoot}", "$(System.DefaultWorkingDirectory)") } Set-Content -Path $_ -Value $content -Encoding UTF8 From 920947343737b964b1f84a4359529286bb9b869f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 18 Nov 2021 21:43:01 -0700 Subject: [PATCH 366/704] Touch-ups --- .devcontainer/Dockerfile | 2 +- .vscode/settings.json | 12 ++++++------ Directory.Build.props | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 88949946..c47acfaa 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:5.0.400-focal +FROM mcr.microsoft.com/dotnet/sdk:6.0.100-focal # 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/.vscode/settings.json b/.vscode/settings.json index 00aaed88..3ae1371c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,8 +1,8 @@ { - "files.trimTrailingWhitespace": true, - "files.insertFinalNewline": true, - "files.trimFinalNewlines": true, - "omnisharp.enableEditorConfigSupport": true, - "omnisharp.enableImportCompletion": true, - "omnisharp.enableRoslynAnalyzers": true + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableImportCompletion": true, + "omnisharp.enableRoslynAnalyzers": true } diff --git a/Directory.Build.props b/Directory.Build.props index 38d8582d..0ce1cbb7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -12,7 +12,6 @@ true true true - $(RepoRootPath) $(MSBuildThisFileDirectory) From 686e55d0f99445c0db83bdbe45d14722a5597651 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 19 Nov 2021 12:41:18 -0700 Subject: [PATCH 367/704] Add Apply-Template.ps1 script to automate template updates --- Apply-Template.ps1 | 27 +++++++++++++++++++++++++++ Expand-Template.ps1 | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 Apply-Template.ps1 diff --git a/Apply-Template.ps1 b/Apply-Template.ps1 new file mode 100644 index 00000000..544b7a7c --- /dev/null +++ b/Apply-Template.ps1 @@ -0,0 +1,27 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS +Applies the template to another repo in a semi-destructive way. +Always apply to a clean working copy so that undesired updates can be easily reverted. +.PARAMETER Path +The path to the root of the repo to be updated with the latest version of this template. +#> + +[CmdletBinding(SupportsShouldProcess, ConfirmImpact='Medium')] +Param( + [Parameter(Mandatory=$true)] + [ValidateScript({Test-Path $_})] + [string]$Path +) + +Write-Host "Updating $Path" +robocopy /mir $PSScriptRoot/azure-pipelines $Path/azure-pipelines +robocopy /mir $PSScriptRoot/.devcontainer $Path/.devcontainer +robocopy /mir $PSScriptRoot/.github $Path/.github +robocopy /mir $PSScriptRoot/.vscode $Path/.vscode +robocopy /mir $PSScriptRoot/tools $Path/tools +robocopy $PSScriptRoot $Path Directory.Build.* global.json init.* azure-pipelines.yml .gitignore .gitattributes .editorconfig +robocopy $PSScriptRoot/src $Path/src Directory.Build.* .editorconfig +robocopy $PSScriptRoot/test $Path/test Directory.Build.* .editorconfig +Remove-Item $Path/azure-pipelines/expand-template.yml diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index d665e56a..9e4d4973 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -180,7 +180,7 @@ try { Replace-Placeholders -Path "azure-pipelines.yml" -Replacements $YmlReplacements # Self destruct - git rm Expand-Template.* + git rm Expand-Template.* Apply-Template.ps1 if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } git rm :/azure-pipelines/expand-template.yml if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } From 805c87a603471d8cb6af194e727304ae05d1579b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 19 Nov 2021 15:49:51 -0700 Subject: [PATCH 368/704] Build on VS 2022 agents --- azure-pipelines/build.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index cd39a76a..a1f5e786 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -1,6 +1,9 @@ parameters: - windowsPool: Hosted Windows 2019 with VS2019 - includeMacOS: +- name: windowsPool + type: object + default: + vmImage: windows-2022 +- name: includeMacOS jobs: - job: Windows From 4fb29c86e9d117361e15454ba5d82a2f4e39259b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 19 Nov 2021 16:27:20 -0700 Subject: [PATCH 369/704] Update Microsoft.SourceLink.GitHub package version --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 0ce1cbb7..2e771602 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -34,7 +34,7 @@ - + From 8e739091c7bb31ca7e8fb34d67008ac83aeca884 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 22 Nov 2021 15:39:06 -0700 Subject: [PATCH 370/704] Add Publish target Closes #688, I hope. --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 2b44dbcf..56045246 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -13,6 +13,7 @@ - + + From 2eb1688704d5de2990fd51407b2ec64ac41019d3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 22 Nov 2021 15:48:47 -0700 Subject: [PATCH 371/704] Collect diagnostic test logs --- azure-pipelines/artifacts/testResults.ps1 | 20 +++++++++++++------- azure-pipelines/dotnet.yml | 6 +++--- 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 index 7895ddca..862155da 100644 --- a/azure-pipelines/artifacts/testResults.ps1 +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -1,12 +1,18 @@ +$result = @{} + if ($env:AGENT_TEMPDIRECTORY) { # The DotNetCoreCLI uses an alternate location to publish these files $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' - @{ - $env:AGENT_TEMPDIRECTORY = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); - } -} else { + $result[$env:AGENT_TEMPDIRECTORY] = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); +} +else { $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" - @{ - $testRoot = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File); - } + $result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File) +} + +$testlogsPath = "$env:BUILD_ARTIFACTSTAGINGDIRECTORY\test_logs" +if (Test-Path $testlogsPath) { + $result[$testlogsPath] = Get-ChildItem "$testlogsPath\*"; } + +$result diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 50ba58f1..70cd23ee 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -10,7 +10,7 @@ steps: displayName: dotnet test -f net472 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net472.binlog" + arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net472.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net472.txt" testRunTitle: net472-$(Agent.JobName) condition: succeededOrFailed() @@ -18,7 +18,7 @@ steps: displayName: dotnet test -f netcoreapp3.1 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp3.1.binlog" + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp3.1.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/netcoreapp3.1.txt" testRunTitle: netcoreapp3.1-$(Agent.JobName) condition: succeededOrFailed() @@ -26,7 +26,7 @@ steps: displayName: dotnet test -f net5.0 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f net5.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net5.0.binlog" + arguments: --no-build -c $(BuildConfiguration) -f net5.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net5.0.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net5.0.txt" testRunTitle: net5.0-$(Agent.JobName) condition: succeededOrFailed() From df52bbc7da6d37808c1e0095bea0ba3e1905697d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 22 Nov 2021 15:49:06 -0700 Subject: [PATCH 372/704] Remove CA1508, which has too many false positives --- .editorconfig | 3 --- 1 file changed, 3 deletions(-) diff --git a/.editorconfig b/.editorconfig index c561b381..0d75b34a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -164,9 +164,6 @@ csharp_prefer_braces = true:silent # SA1130: Use lambda syntax dotnet_diagnostic.SA1130.severity = silent -# CA1508: Avoid dead conditional code -dotnet_diagnostic.CA1508.severity = warning - # IDE1006: Naming Styles - StyleCop handles these for us dotnet_diagnostic.IDE1006.severity = none From b3ff2155fd766d95e947d639cbefc00ed2eff3b5 Mon Sep 17 00:00:00 2001 From: Gleb Krasilich Date: Tue, 23 Nov 2021 16:46:55 +0300 Subject: [PATCH 373/704] Fixed ParentEnumerator.MoveNext() and added corresponding tests --- .../ManagedGit/GitCommitReaderTests.cs | 18 ++++++++++++ ...t-ab39e8acac105fa0db88514f259341c9f0201b22 | 28 +++++++++++++++++++ .../ManagedGit/GitCommit.cs | 2 +- 3 files changed, 47 insertions(+), 1 deletion(-) create mode 100644 src/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs index c8f068c1..ea4feeab 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs @@ -1,5 +1,6 @@ using System; using System.IO; +using System.Linq; using Nerdbank.GitVersioning.ManagedGit; using Xunit; @@ -31,5 +32,22 @@ public void ReadTest() // Committer and commit message are not read } } + + [Fact] + public void ReadCommitWithThreeParents() + { + using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\commit-ab39e8acac105fa0db88514f259341c9f0201b22")) + { + var commit = GitCommitReader.Read(stream, GitObjectId.Parse("ab39e8acac105fa0db88514f259341c9f0201b22"), readAuthor: true); + + Assert.Equal(3, commit.Parents.Count()); + + Assert.Collection( + commit.Parents, + c => Assert.Equal("e0b4d66ef7915417e04e88d5fa173185bb940029", c.ToString()), + c => Assert.Equal("10e67ce38fbee44b3f5584d4f9df6de6c5f4cc5c", c.ToString()), + c => Assert.Equal("a7fef320334121af85dce4b9b731f6c9a9127cfd", c.ToString())); + } + } } } diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 b/src/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 new file mode 100644 index 00000000..f1b78e1f --- /dev/null +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 @@ -0,0 +1,28 @@ +tree 0f118b0345501ba18c15e149c9ae49ce07352485 +parent e0b4d66ef7915417e04e88d5fa173185bb940029 +parent 10e67ce38fbee44b3f5584d4f9df6de6c5f4cc5c +parent a7fef320334121af85dce4b9b731f6c9a9127cfd +author Atsushi Eno 1278350964 -0000 +committer Atsushi Eno 1278350964 -0000 + +2010-07-05 Atsushi Enomoto + + * ChannelDispatcher.cs : + moved IChannelDispatcherBoundListener from HttpChannelListener.cs. + + * SvcHttpHandler.cs : removed old code and #if blocks. + + * HttpStandaloneReplyChannel.cs + HttpStandaloneRequestContext.cs + HttpStandaloneChannelListener.cs + HttpReplyChannel.cs + HttpRequestContext.cs + HttpChannelListener.cs : renamed former 3 files to latter 3 files. + + * System.ServiceModel.dll.sources : + renamed new HTTP channel listener implementation sources, and + removed old sources. + + + +svn path=/trunk/mcs/; revision=159913 diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs b/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs index b9448a42..2e27acd5 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs @@ -164,7 +164,7 @@ public bool MoveNext() { 0 => this.owner.FirstParent.HasValue, 1 => this.owner.SecondParent.HasValue, - _ => this.owner.AdditionalParents?.Count >= this.position - 2, + _ => this.owner.AdditionalParents?.Count > this.position - 2, }; } From 061aaa7347fd458dd438126567a6b1f358d009b3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 23 Nov 2021 10:28:07 -0700 Subject: [PATCH 374/704] Avoid using yarn task --- azure-pipelines.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 26a3ac28..f3820f43 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -93,12 +93,11 @@ stages: nugetConfigPath: src/nuget.config workingDirectory: src - - task: YarnInstaller@3 - displayName: 'Use Yarn 1.x' - - task: Yarn@3 - displayName: 'Yarn install' - inputs: - projectDirectory: 'src/nerdbank-gitversioning.npm' + - script: npm i -g yarn@">=1.22 <2.0" + displayName: Installing yarn + + - script: yarn --cwd src/nerdbank-gitversioning.npm + displayName: Installing NPM packages - script: dotnet build -c $(BuildConfiguration) --no-restore /t:build,pack /bl:"$(Build.ArtifactStagingDirectory)/build_logs/msbuild.binlog" displayName: Build NuGet package and tests From 4fc64ef2c2e4c369be40dcb98e3e6f66565ab05c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 23 Nov 2021 15:27:10 -0700 Subject: [PATCH 375/704] Build with the .NET 6.0 SDK --- azure-pipelines.yml | 34 +++++++++++++------ global.json | 2 +- src/Directory.Build.props | 1 - .../NerdBank.GitVersioning.Tests.csproj | 2 +- 4 files changed, 25 insertions(+), 14 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 5f5f95f3..914908dd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -54,24 +54,31 @@ stages: git config --global user.name ci git config --global user.email me@ci.com displayName: Configure git commit author for testing + - task: UseDotNet@2 + displayName: Install .NET Core 3.1 runtime + inputs: + packageType: runtime + version: 3.1.x - task: UseDotNet@2 - displayName: Install .NET Core 5.0.401 SDK + displayName: Install .NET 5.0 SDK inputs: - packageType: sdk - version: 5.0.401 + packageType: sdk # necessary for msbuild tests to run on .NET 5 runtime + version: 5.0.x - task: UseDotNet@2 - displayName: Install .NET Core 3.1 runtime + displayName: Install .NET 6.0 SDK inputs: - packageType: runtime - version: 3.1.x + packageType: sdk + version: 6.0.100 + - pwsh: | Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 - & .\dotnet-install.ps1 -Architecture x86 -Version 5.0.401 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose - & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose - displayName: Install 32-bit .NET Core SDK 5.0.401, 3.1 + & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose -Runtime dotnet + & .\dotnet-install.ps1 -Architecture x86 -Channel 5.0 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.100 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + displayName: Install 32-bit .NET SDK and runtimes condition: ne(variables['dotnet32'], '') - script: dotnet --info @@ -328,10 +335,15 @@ stages: packageType: runtime version: 3.1.x - task: UseDotNet@2 - displayName: Install .NET Core 5.0.401 SDK + displayName: Install .NET 5.0 runtime + inputs: + packageType: runtime + version: 5.0.x + - task: UseDotNet@2 + displayName: Install .NET 6.0.100 SDK inputs: packageType: sdk - version: 5.0.401 + version: 6.0.100 - script: dotnet --info displayName: Show dotnet SDK info - bash: | diff --git a/global.json b/global.json index 3057bb45..e2af429b 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "5.0.401", + "version": "6.0.100", "rollForward": "patch", "allowPrerelease": false } diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 94a570b3..03b4fdf0 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -24,7 +24,6 @@ 2.0.312 - diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 1e9f8e11..e4a6fb16 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -36,7 +36,7 @@ - + From 48d4e9b2f54b4622439dc2b7150fafeea4c2a30d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 23 Nov 2021 21:18:42 -0700 Subject: [PATCH 376/704] Update a few nuget dependencies --- .../Cake.GitVersioning.Tests.csproj | 2 +- src/Directory.Build.props | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 83a8f9bf..819813ea 100644 --- a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 03b4fdf0..b0eb61dc 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -24,9 +24,9 @@ 2.0.312 - - - + + + all runtime; build; native; contentfiles; analyzers From 348855696b36a16dd08f4fc69ea27eb99d31e5ff Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 23 Nov 2021 21:22:27 -0700 Subject: [PATCH 377/704] Update libgit2sharp to 0.27.0-preview-0158 --- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 3 ++- src/Directory.Build.props | 2 +- src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj | 2 +- .../Nerdbank.GitVersioning.nuspec | 9 +++++---- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 9e352dec..49b38e6a 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -41,7 +41,8 @@ - + + diff --git a/src/Directory.Build.props b/src/Directory.Build.props index b0eb61dc..105676df 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -21,7 +21,7 @@ - 2.0.312 + 2.0.315-alpha.0.9 diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index 1119a781..6f004727 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 668b210e..28b573e0 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -32,12 +32,13 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - - + + + - - + + From 8205a85f6edee2e7523aaa18e8be91a3817693e5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 25 Nov 2021 07:43:24 -0700 Subject: [PATCH 378/704] Fix path calculation to OSX native libgit2 binaries --- src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 676dff15..76eff1f3 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -173,7 +173,7 @@ public static IEnumerable GetCommitsFromVersion(LibGit2Context context, } else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - return Path.Combine(basePath, "lib", "osx"); + return Path.Combine(basePath, "lib", "osx", RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm_64" : "x86_64"); } return null; From c5db1efad8a160ec9869b4e1cf0b72b07b59526f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 25 Nov 2021 22:26:34 -0700 Subject: [PATCH 379/704] Fix ARM detection on Linux The `$env:PROCESSOR_ARCHITECTURE` environment variable simply isn't set on linux. --- tools/Install-DotNetSdk.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 42789930..f5a300a4 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -29,8 +29,7 @@ $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot # Look up actual required .NET Core SDK version from global.json $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" -$arch = 'x64' -if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' } +$arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() From c9ed75c04a722207de4f79a2cb17f558b8ae4641 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 29 Nov 2021 16:17:37 -0700 Subject: [PATCH 380/704] Format whitespace in init.ps1 --- init.ps1 | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/init.ps1 b/init.ps1 index cb86c6ca..774ead58 100755 --- a/init.ps1 +++ b/init.ps1 @@ -31,10 +31,10 @@ .PARAMETER AccessToken An optional access token for authenticating to Azure Artifacts authenticated feeds. #> -[CmdletBinding(SupportsShouldProcess=$true)] +[CmdletBinding(SupportsShouldProcess = $true)] Param ( - [ValidateSet('repo','user','machine')] - [string]$InstallLocality='user', + [ValidateSet('repo', 'user', 'machine')] + [string]$InstallLocality = 'user', [Parameter()] [switch]$NoPrerequisites, [Parameter()] @@ -68,8 +68,8 @@ if (!$NoPrerequisites) { } # Workaround nuget credential provider bug that causes very unreliable package restores on Azure Pipelines -$env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS=20 -$env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS=20 +$env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS = 20 +$env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS = 20 Push-Location $PSScriptRoot try { From 7cd385ab604c9e7e3f747b342edcea34a16bd40a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 29 Nov 2021 17:01:18 -0700 Subject: [PATCH 381/704] Add private p2p targets for VSIX project compatibility --- .../build/PrivateP2PCaching.proj | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 56045246..db020b2f 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -13,7 +13,11 @@ - + + + + + From b75b239dfc8258e7c5d8c60ea9b4bc338392293f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 1 Dec 2021 11:57:57 -0700 Subject: [PATCH 382/704] Suppress powershell interpreting of AzP macros --- azure-pipelines/publish-codecoverage.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 3667b976..a0862be3 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -18,10 +18,10 @@ steps: - powershell: | dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.8.5 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj - Write-Host "Substituting {reporoot} with $(System.DefaultWorkingDirectory)" - $reports = Get-ChildItem -Recurse "$(Pipeline.Workspace)/coverage.*cobertura.xml" + Write-Host 'Substituting {reporoot} with $(System.DefaultWorkingDirectory)' + $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/coverage.*cobertura.xml' $reports |% { - $content = Get-Content -Path $_ |% { $_.Replace("{reporoot}", "$(System.DefaultWorkingDirectory)") } + $content = Get-Content -Path $_ |% { $_.Replace('{reporoot}', '$(System.DefaultWorkingDirectory)') } Set-Content -Path $_ -Value $content -Encoding UTF8 } $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ })) From e1fafe9b84943d228456c3595a547c2d62a8acc0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 2 Dec 2021 10:55:44 -0700 Subject: [PATCH 383/704] Secure p/invoke native library loads --- src/AssemblyInfo.cs | 6 ++++++ src/Directory.Build.targets | 4 ++++ 2 files changed, 10 insertions(+) create mode 100644 src/AssemblyInfo.cs diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs new file mode 100644 index 00000000..81feda27 --- /dev/null +++ b/src/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) COMPANY-PLACEHOLDER. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; + +[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index e7edee55..566ab4fc 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -1,3 +1,7 @@ + + + + From 1be4fa9788b5295754319602b6524de64f865a42 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 2 Dec 2021 16:50:33 -0700 Subject: [PATCH 384/704] Fix regression in platform detection in Windows Powershell --- tools/Install-DotNetSdk.ps1 | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index f5a300a4..3c82ee2b 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -30,6 +30,10 @@ $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" $arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture +if (!$arch) { # Windows Powershell leaves this blank + $arch = 'x64' + if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' } +} # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() From 81634e306fd8a561434c42687ee7f3f84b4a0067 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 3 Dec 2021 06:40:03 -0700 Subject: [PATCH 385/704] Set basic version build variables in pipeline --- azure-pipelines/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index a1f5e786..796be61d 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -13,7 +13,7 @@ jobs: clean: true - template: install-dependencies.yml - - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud' + - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' displayName: Set build number - template: dotnet.yml From e4ef595f167a6848292a1c121bee85c7ae1cae09 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 3 Dec 2021 08:06:54 -0700 Subject: [PATCH 386/704] Patch AssemblyInfo.cs --- Apply-Template.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apply-Template.ps1 b/Apply-Template.ps1 index 544b7a7c..0d3f3d8e 100644 --- a/Apply-Template.ps1 +++ b/Apply-Template.ps1 @@ -22,6 +22,6 @@ robocopy /mir $PSScriptRoot/.github $Path/.github robocopy /mir $PSScriptRoot/.vscode $Path/.vscode robocopy /mir $PSScriptRoot/tools $Path/tools robocopy $PSScriptRoot $Path Directory.Build.* global.json init.* azure-pipelines.yml .gitignore .gitattributes .editorconfig -robocopy $PSScriptRoot/src $Path/src Directory.Build.* .editorconfig +robocopy $PSScriptRoot/src $Path/src Directory.Build.* .editorconfig AssemblyInfo.cs robocopy $PSScriptRoot/test $Path/test Directory.Build.* .editorconfig Remove-Item $Path/azure-pipelines/expand-template.yml From 52d37aebaa5b7f119810d2fba3977006f99ef289 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 3 Dec 2021 08:15:02 -0700 Subject: [PATCH 387/704] Update Nerdbank.GitVersioning --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2e771602..3b2b143b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -35,7 +35,7 @@ - + From 5dc86af1975fd0568fb49276a7037c295184991c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Dec 2021 13:22:16 -0700 Subject: [PATCH 388/704] Suppress CA2243 in generated AssemblyInfo file --- .../AssemblyInfoTest.cs | 6 +++++ .../AssemblyVersionInfo.cs | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs b/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs index f8fc5fb2..253fdeb6 100644 --- a/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs +++ b/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs @@ -57,6 +57,8 @@ public void FSharpGenerator(bool? thisAssemblyClass) // //------------------------------------------------------------------------------ +#nowarn ""CA2243"" + namespace AssemblyInfo [] [] @@ -133,6 +135,8 @@ public void CSharpGenerator(bool? thisAssemblyClass) // //------------------------------------------------------------------------------ +#pragma warning disable CA2243 + [assembly: System.Reflection.AssemblyVersionAttribute(""1.3.0.0"")] [assembly: System.Reflection.AssemblyFileVersionAttribute(""1.3.1.0"")] [assembly: System.Reflection.AssemblyInformationalVersionAttribute("""")] @@ -188,6 +192,8 @@ public void VisualBasicGenerator(bool? thisAssemblyClass) ' '------------------------------------------------------------------------------ +#Disable Warning CA2243 + diff --git a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs index fa9aa863..2f39ca05 100644 --- a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs @@ -315,6 +315,8 @@ public string BuildCode() { this.generator.AddComment(FileHeaderComment); this.generator.AddBlankLine(); + this.generator.AddAnalysisSuppressions(); + this.generator.AddBlankLine(); this.generator.EmitNamespaceIfRequired(this.RootNamespace ?? "AssemblyInfo"); this.GenerateAssemblyAttributes(); @@ -545,6 +547,13 @@ internal CodeGenerator() this.codeBuilder = new StringBuilder(); } + protected virtual IEnumerable WarningCodesToSuppress { get; } = new string[] + { + "CA2243", // Attribute string literals should parse correctly + }; + + internal abstract void AddAnalysisSuppressions(); + internal abstract void AddComment(string comment); internal abstract void DeclareAttribute(Type type, string arg); @@ -586,6 +595,11 @@ protected void AddCodeComment(string comment, string token) private class FSharpCodeGenerator : CodeGenerator { + internal override void AddAnalysisSuppressions() + { + this.codeBuilder.AppendLine($"#nowarn {string.Join(" ", this.WarningCodesToSuppress.Select(c => $"\"{c}\""))}"); + } + internal override void AddComment(string comment) { this.AddCodeComment(comment, "//"); @@ -636,6 +650,11 @@ internal override void StartThisAssemblyClass() private class CSharpCodeGenerator : CodeGenerator { + internal override void AddAnalysisSuppressions() + { + this.codeBuilder.AppendLine($"#pragma warning disable {string.Join(", ", this.WarningCodesToSuppress)}"); + } + internal override void AddComment(string comment) { this.AddCodeComment(comment, "//"); @@ -680,6 +699,11 @@ internal override void EndThisAssemblyClass() private class VisualBasicCodeGenerator : CodeGenerator { + internal override void AddAnalysisSuppressions() + { + this.codeBuilder.AppendLine($"#Disable Warning {string.Join(", ", this.WarningCodesToSuppress)}"); + } + internal override void AddComment(string comment) { this.AddCodeComment(comment, "'"); From b050b19070aef1b278ac14a6d99cd488bcfa6432 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Sep 2021 23:09:26 -0600 Subject: [PATCH 389/704] Remove .NET Core 3.0 from test battery --- azure-pipelines.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f3820f43..ccc17c8e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -18,8 +18,6 @@ resources: image: mcr.microsoft.com/dotnet/core/sdk:3.1-bionic - container: focal image: mcr.microsoft.com/dotnet/core/sdk:3.1-focal - - container: disco-3.0 - image: mcr.microsoft.com/dotnet/core/sdk:3.0-disco - container: archlinux image: andrewarnott/archlinux @@ -273,8 +271,6 @@ stages: containerImage: bionic Ubuntu_Focal: containerImage: focal - Ubuntu_Disco_3_0: - containerImage: disco-3.0 # Arch_Linux: # containerImage: archlinux # configureContainerCommand: 'sudo pacman -Sy --noconfirm git dotnet-sdk openssl-1.0' From 5aeb2a83ac671a2c8601b809382f73fbcd3b74d5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Dec 2021 13:41:32 -0700 Subject: [PATCH 390/704] Avoid name collision in `GenerateAssemblyVersionInfo` MSBuild target Fixes #698 --- .../BuildIntegrationTests.cs | 17 +++++++++++------ .../build/Nerdbank.GitVersioning.targets | 8 ++++---- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index 57727e10..29477bf4 100644 --- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -897,7 +897,7 @@ public async Task AssemblyInfo_HasKeyData(string keyFile, bool delaySigned) this.testProject.AddProperty("DelaySign", delaySigned.ToString()); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal); + var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); string versionCsContent = File.ReadAllText( Path.GetFullPath( Path.Combine( @@ -951,7 +951,7 @@ public async Task AssemblyInfo_NotProducedWithoutCodeDomProvider() propertyGroup.AddProperty("Language", "NoCodeDOMProviderForThisLanguage"); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal, assertSuccessfulBuild: false); + var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal, assertSuccessfulBuild: false); Assert.Equal(BuildResultCode.Failure, result.BuildResult.OverallResult); string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile")); Assert.False(File.Exists(versionCsFilePath)); @@ -968,10 +968,10 @@ public async Task AssemblyInfo_Suppressed() var propertyGroup = this.testProject.CreatePropertyGroupElement(); this.testProject.AppendChild(propertyGroup); propertyGroup.AddProperty("Language", "NoCodeDOMProviderForThisLanguage"); - propertyGroup.AddProperty(Targets.GenerateAssemblyVersionInfo, "false"); + propertyGroup.AddProperty(Properties.GenerateAssemblyVersionInfo, "false"); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal); + var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile")); Assert.False(File.Exists(versionCsFilePath)); Assert.Empty(result.LoggedEvents.OfType()); @@ -991,7 +991,7 @@ public async Task AssemblyInfo_SuppressedImplicitlyByTargetExt() propertyGroup.AddProperty("TargetExt", ".notdll"); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyVersionInfo, logVerbosity: LoggerVerbosity.Minimal); + var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile")); Assert.False(File.Exists(versionCsFilePath)); Assert.Empty(result.LoggedEvents.OfType()); @@ -1263,10 +1263,15 @@ private static class Targets internal const string Build = "Build"; internal const string GetBuildVersion = "GetBuildVersion"; internal const string GetNuGetPackageVersion = "GetNuGetPackageVersion"; - internal const string GenerateAssemblyVersionInfo = "GenerateAssemblyVersionInfo"; + internal const string GenerateAssemblyNBGVVersionInfo = "GenerateAssemblyNBGVVersionInfo"; internal const string GenerateNativeVersionInfo = "GenerateNativeVersionInfo"; } + private static class Properties + { + internal const string GenerateAssemblyVersionInfo = "GenerateAssemblyVersionInfo"; + } + private class BuildResults { internal BuildResults(BuildResult buildResult, IReadOnlyList loggedEvents) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 232ee06b..cf4ae4e2 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -47,12 +47,12 @@ - GenerateAssemblyVersionInfo; + GenerateAssemblyNBGVVersionInfo; $(PrepareResourcesDependsOn) - GenerateAssemblyVersionInfo; + GenerateAssemblyNBGVVersionInfo; $(CoreCompileDependsOn) @@ -112,7 +112,7 @@ - + $([MSBuild]::NormalizePath('$(IntermediateOutputPath)', '$(AssemblyName).Version$(DefaultLanguageSourceExtension)')) $(VersionSourceFile).new @@ -215,7 +215,7 @@ + DependsOnTargets="GenerateAssemblyNBGVVersionInfo"> From 6e06b206b2abf3016b74ba46bad467e389aad97a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Dec 2021 13:54:34 -0700 Subject: [PATCH 391/704] Rename msbuild target `GenerateNativeVersionInfo` to `GenerateNativeNBGVVersionInfo` This just keeps things consistent with the rename in the last commit and further avoids a future msbuild target name collision. --- src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs | 2 +- .../build/Nerdbank.GitVersioning.targets | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index 29477bf4..86d70cdb 100644 --- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -1264,7 +1264,7 @@ private static class Targets internal const string GetBuildVersion = "GetBuildVersion"; internal const string GetNuGetPackageVersion = "GetNuGetPackageVersion"; internal const string GenerateAssemblyNBGVVersionInfo = "GenerateAssemblyNBGVVersionInfo"; - internal const string GenerateNativeVersionInfo = "GenerateNativeVersionInfo"; + internal const string GenerateNativeNBGVVersionInfo = "GenerateNativeNBGVVersionInfo"; } private static class Properties diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index cf4ae4e2..a5c5fe58 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -42,7 +42,7 @@ - GenerateNativeVersionInfo; + GenerateNativeNBGVVersionInfo; $(PrepareForBuildDependsOn); @@ -156,7 +156,7 @@ - + $([MSBuild]::NormalizePath('$(IntermediateOutputPath)', '$(AssemblyName).Version.rc')) $(VersionSourceFile).new From d486cf65d67ede83006f1869a199c9b5dd4267ef Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 27 Dec 2021 16:51:34 -0700 Subject: [PATCH 392/704] Update schema to encourage 3-4 component assembly versions as well The product already supported it, but the schema and tests did not reflect this. Closes #703 --- src/NerdBank.GitVersioning.Tests/VersionFileTests.cs | 2 ++ src/NerdBank.GitVersioning/VersionOptions.cs | 2 +- src/NerdBank.GitVersioning/version.schema.json | 12 ++++++------ 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs b/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs index f6330e61..016481fd 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs @@ -92,6 +92,8 @@ public void IsVersionDefined_String_ConsiderAncestorFolders() [Theory] [InlineData("2.3", null, null, 0, null, @"{""version"":""2.3""}")] [InlineData("2.3", "2.2", VersionOptions.VersionPrecision.Minor, 0, null, @"{""version"":""2.3"",""assemblyVersion"":""2.2""}")] + [InlineData("2.3", "1.2.3", VersionOptions.VersionPrecision.Minor, 0, null, @"{""version"":""2.3"",""assemblyVersion"":{""version"":""1.2.3""}}")] + [InlineData("2.3", "1.2.3.4", VersionOptions.VersionPrecision.Minor, 0, null, @"{""version"":""2.3"",""assemblyVersion"":{""version"":""1.2.3.4""}}")] [InlineData("2.3", "2.2", VersionOptions.VersionPrecision.Minor, -1, new[] { "refs/heads/master" }, @"{""version"":""2.3"",""assemblyVersion"":""2.2"",""versionHeightOffset"":-1,""publicReleaseRefSpec"":[""refs/heads/master""]}")] [InlineData("2.3", "2.2", VersionOptions.VersionPrecision.Minor, -1, new[] { "refs/heads/master" }, @"{""version"":""2.3"",""assemblyVersion"":""2.2"",""buildNumberOffset"":-1,""publicReleaseRefSpec"":[""refs/heads/master""]}")] [InlineData("2.3", "2.2", VersionOptions.VersionPrecision.Minor, 0, null, @"{""version"":""2.3"",""assemblyVersion"":{""version"":""2.2""}}")] diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index 03eccce2..8d82f9eb 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -741,7 +741,7 @@ public AssemblyVersionOptions(AssemblyVersionOptions copyFrom) } /// - /// Gets or sets the major.minor components of the assembly version. + /// Gets or sets the components of the assembly version (2-4 components). /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public Version? Version diff --git a/src/NerdBank.GitVersioning/version.schema.json b/src/NerdBank.GitVersioning/version.schema.json index 1e402b08..f51741ea 100644 --- a/src/NerdBank.GitVersioning/version.schema.json +++ b/src/NerdBank.GitVersioning/version.schema.json @@ -39,13 +39,13 @@ "default": false }, "assemblyVersion": { - "description": "The x.y version to use particularly for the AssemblyVersionAttribute instead of the default. This is useful when maintaining assembly binding compatibility on the desktop .NET Framework is important even though AssemblyFileVersion may change.", + "description": "The a.b[.c[.d]] version to use particularly for the AssemblyVersionAttribute instead of the default. This is useful when maintaining assembly binding compatibility on the desktop .NET Framework is important even though AssemblyFileVersion may change.", "oneOf": [ - { "$ref": "#/definitions/majorMinorVersion" }, + { "$ref": "#/definitions/twoToFourComponentVersion" }, { "type": "object", "properties": { - "version": { "$ref": "#/definitions/majorMinorVersion" }, + "version": { "$ref": "#/definitions/twoToFourComponentVersion" }, "precision": { "type": "string", "description": "Identifies the last component to be explicitly set in the version.", @@ -193,10 +193,10 @@ } } }, - "majorMinorVersion": { + "twoToFourComponentVersion": { "type": "string", - "description": "A major.minor version", - "pattern": "^\\d+\\.\\d+$" + "description": "A major.minor[.build[.revision]] version (2-4 version components).", + "pattern": "^\\d+\\.\\d+(?:\\.\\d+(?:\\.\\d+)?)?$" } } } From f2e167e57ecaca1acc66374ac268e445d4156c80 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 27 Dec 2021 16:57:38 -0700 Subject: [PATCH 393/704] Update Install-DotNetSdk.ps1 script --- tools/Install-DotNetSdk.ps1 | 143 +++++++++++++++++++++++++++--------- 1 file changed, 108 insertions(+), 35 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 47548418..2300d752 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -2,19 +2,19 @@ <# .SYNOPSIS -Installs the .NET SDK specified in the global.json file at the root of this repository, -along with supporting .NET Core runtimes used for testing. + Installs the .NET SDK specified in the global.json file at the root of this repository, + along with supporting .NET Core runtimes used for testing. .DESCRIPTION -This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, -unless `-InstallLocality machine` is specified. + This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, + unless `-InstallLocality machine` is specified. .PARAMETER InstallLocality -A value indicating whether dependencies should be installed locally to the repo or at a per-user location. -Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. -Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. -Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. -When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. -Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. -Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. + A value indicating whether dependencies should be installed locally to the repo or at a per-user location. + Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. + Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. + Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. + When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. + Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. + Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( @@ -29,20 +29,43 @@ $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot # Look up actual required .NET Core SDK version from global.json $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" +$arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture +if (!$arch) { # Windows Powershell leaves this blank + $arch = 'x64' + if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' } +} + # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() +$windowsDesktopRuntimeVersions = @() Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { $projXml = [xml](Get-Content -Path $_) - $targetFrameworks = $projXml.Project.PropertyGroup.TargetFramework - if (!$targetFrameworks) { - $targetFrameworks = $projXml.Project.PropertyGroup.TargetFrameworks - if ($targetFrameworks) { - $targetFrameworks = $targetFrameworks -Split ';' + $pg = $projXml.Project.PropertyGroup + if ($pg) { + $targetFrameworks = $pg.TargetFramework + if (!$targetFrameworks) { + $targetFrameworks = $pg.TargetFrameworks + if ($targetFrameworks) { + $targetFrameworks = $targetFrameworks -Split ';' + } } } - $targetFrameworks |? { $_ -match 'netcoreapp(\d+\.\d+)' } |% { - $runtimeVersions += $Matches[1] + $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% { + $v = $Matches[1] + $runtimeVersions += $v + if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) { + $windowsDesktopRuntimeVersions += $v + } } + + # Add target frameworks of the form: netXX + $targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% { + $v = $Matches[1] + $runtimeVersions += $v + if (-not ($IsMacOS -or $IsLinux)) { + $windowsDesktopRuntimeVersions += $v + } + } } Function Get-FileFromWeb([Uri]$Uri, $OutDir) { @@ -69,7 +92,7 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { $Version = $versionInfo[-1] } - Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-x64.exe" -OutDir "$DotNetInstallScriptRoot" + Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-$arch.exe" -OutDir "$DotNetInstallScriptRoot" } Function Install-DotNet($Version, [switch]$Runtime) { @@ -77,14 +100,16 @@ Function Install-DotNet($Version, [switch]$Runtime) { Write-Host "Downloading .NET Core $sdkSubstring$Version..." $Installer = Get-InstallerExe -Version $Version -Runtime:$Runtime Write-Host "Installing .NET Core $sdkSubstring$Version..." - cmd /c start /wait $Installer /install /quiet - if ($LASTEXITCODE -ne 0) { + cmd /c start /wait $Installer /install /passive /norestart + if ($LASTEXITCODE -eq 3010) { + Write-Verbose "Restart required" + } elseif ($LASTEXITCODE -ne 0) { throw "Failure to install .NET Core SDK" } } $switches = @( - '-Architecture','x64' + '-Architecture',$arch ) $envVars = @{ # For locally installed dotnet, skip first time experience which takes a long time @@ -92,20 +117,28 @@ $envVars = @{ } if ($InstallLocality -eq 'machine') { - if ($IsWindows) { + if ($IsMacOS -or $IsLinux) { + $DotNetInstallDir = '/usr/share/dotnet' + } else { + $restartRequired = $false if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { Install-DotNet -Version $sdkVersion + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) } $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { Install-DotNet -Version $_ -Runtime + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) } } + if ($restartRequired) { + Write-Host -ForegroundColor Yellow "System restart required" + Exit 3010 + } + return - } else { - $DotNetInstallDir = '/usr/share/dotnet' } } elseif ($InstallLocality -eq 'repo') { $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet" @@ -118,16 +151,16 @@ if ($InstallLocality -eq 'machine') { Write-Host "Installing .NET Core SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue if ($DotNetInstallDir) { - $switches += '-InstallDir',$DotNetInstallDir + $switches += '-InstallDir',"`"$DotNetInstallDir`"" $envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0' $envVars['DOTNET_ROOT'] = $DotNetInstallDir } if ($IsMacOS -or $IsLinux) { - $DownloadUri = "https://dot.net/v1/dotnet-install.sh" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { - $DownloadUri = "https://dot.net/v1/dotnet-install.ps1" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.ps1" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } @@ -138,22 +171,62 @@ if (-not (Test-Path $DotNetInstallScriptPath)) { } } +# In case the script we invoke is in a directory with spaces, wrap it with single quotes. +# In case the path includes single quotes, escape them. +$DotNetInstallScriptPathExpression = $DotNetInstallScriptPath.Replace("'", "''") +$DotNetInstallScriptPathExpression = "& '$DotNetInstallScriptPathExpression'" + +$anythingInstalled = $false +$global:LASTEXITCODE = 0 + if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches" + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Version $sdkVersion $switches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches -DryRun" } -$switches += '-Runtime','dotnet' +$dotnetRuntimeSwitches = $switches + '-Runtime','dotnet' -$runtimeVersions | Get-Unique |% { +$runtimeVersions | Sort-Object -Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches" + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } } else { - Invoke-Expression -Command "$DotNetInstallScriptPath -Channel $_ $switches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches -DryRun" + } +} + +$windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop' + +$windowsDesktopRuntimeVersions | Sort-Object -Unique |% { + if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches -DryRun" } } if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) { - & "$PSScriptRoot/../azure-pipelines/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null + & "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null +} + +if ($anythingInstalled -and ($InstallLocality -ne 'machine') -and !$env:TF_BUILD -and !$env:GITHUB_ACTIONS) { + Write-Warning ".NET Core runtimes or SDKs were installed to a non-machine location. Perform your builds or open Visual Studio from this same environment in order for tools to discover the location of these dependencies." } From 52961016d5f5e3522794d1a9ab51c51eb13e40b7 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 28 Dec 2021 14:32:43 -0700 Subject: [PATCH 394/704] Allow AssemblyVersion to be set explicitly without being altered by the rest of the computed build version **Breaking change**: The `assemblyVersion.precision` property in the `version.json` file is now ignored if `assemblyVersion.version` is set to a non-null value. When set, `assemblyVersion.version` is taken literally. Specifying `assemblyVersion.precision` alone will still set the assembly version based on the ordinary computed `version` as it did before. The schema has been updated to reflect that specifying `assemblyVersion.version` *and* `assemblyVersion.precision` is an error. Fixes #703 --- .../BuildIntegrationTests.cs | 18 ++++++++----- .../VersionOracleTests.cs | 26 ++++++++++++++++++ src/NerdBank.GitVersioning/VersionOracle.cs | 27 +++++++++++++------ .../version.schema.json | 9 ++++++- 4 files changed, 65 insertions(+), 15 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index d931f2e2..900ae2bb 100644 --- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -1009,13 +1009,19 @@ private static Version GetExpectedAssemblyVersion(VersionOptions versionOptions, { // Function should be very similar to VersionOracle.GetAssemblyVersion() var assemblyVersion = (versionOptions?.AssemblyVersion?.Version ?? versionOptions.Version.Version).EnsureNonNegativeComponents(); - var precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision; - assemblyVersion = new System.Version( - assemblyVersion.Major, - precision >= VersionOptions.VersionPrecision.Minor ? assemblyVersion.Minor : 0, - precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0, - precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0); + if (versionOptions?.AssemblyVersion?.Version is null) + { + VersionOptions.VersionPrecision precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision; + assemblyVersion = version; + + assemblyVersion = new Version( + assemblyVersion.Major, + precision >= VersionOptions.VersionPrecision.Minor ? assemblyVersion.Minor : 0, + precision >= VersionOptions.VersionPrecision.Build ? assemblyVersion.Build : 0, + precision >= VersionOptions.VersionPrecision.Revision ? assemblyVersion.Revision : 0); + } + return assemblyVersion; } diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 9ae579d6..ba8427c5 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -259,6 +259,32 @@ public void SemVerStableNonPublicVersionShortened() Assert.Matches(@"^2.3.1-g[a-f0-9]{7}$", oracle.ChocolateyPackageVersion); } + [Theory] + [InlineData("1.2.0.0", null, null)] + [InlineData("1.0.0.0", null, VersionOptions.VersionPrecision.Major)] + [InlineData("1.2.0.0", null, VersionOptions.VersionPrecision.Minor)] + [InlineData("1.2.1.0", null, VersionOptions.VersionPrecision.Build)] + [InlineData("2.3.4.0", "2.3.4", null)] + [InlineData("2.3.4.0", "2.3.4", VersionOptions.VersionPrecision.Minor)] + [InlineData("2.3.4.0", "2.3.4", VersionOptions.VersionPrecision.Build)] + [InlineData("2.3.4.0", "2.3.4.0", VersionOptions.VersionPrecision.Revision)] + public void CustomAssemblyVersion(string expectedAssemblyVersion, string prescribedAssemblyVersion, VersionOptions.VersionPrecision? precision) + { + this.InitializeSourceControl(withInitialCommit: false); + this.WriteVersionFile(new VersionOptions + { + Version = new SemanticVersion("1.2"), + AssemblyVersion = new VersionOptions.AssemblyVersionOptions + { + Version = prescribedAssemblyVersion is object ? new Version(prescribedAssemblyVersion) : null, + Precision = precision, + }, + }); + + VersionOracle oracle = this.GetVersionOracle(); + Assert.Equal(expectedAssemblyVersion, oracle.AssemblyVersion.ToString()); + } + [Fact] public void DefaultNuGetPackageVersionIsSemVer1PublicRelease() { diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 93a11394..6f37d4cf 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -444,14 +444,25 @@ private static Version GetAssemblyVersion(Version version, VersionOptions? versi // If there is no repo, "version" could have uninitialized components (-1). version = version.EnsureNonNegativeComponents(); - var assemblyVersion = versionOptions?.AssemblyVersionOrDefault.Version ?? new System.Version(version.Major, version.Minor); - var precision = versionOptions?.AssemblyVersionOrDefault.PrecisionOrDefault; - - assemblyVersion = new System.Version( - assemblyVersion.Major, - precision >= VersionOptions.VersionPrecision.Minor ? assemblyVersion.Minor : 0, - precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0, - precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0); + Version assemblyVersion; + + if (versionOptions?.AssemblyVersion?.Version is not null) + { + // When specified explicitly, use the assembly version as the user defines it. + assemblyVersion = versionOptions.AssemblyVersion.Version; + } + else + { + // Otherwise consider precision to base the assembly version off of the main computed version. + VersionOptions.VersionPrecision precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision; + + assemblyVersion = new Version( + version.Major, + precision >= VersionOptions.VersionPrecision.Minor ? version.Minor : 0, + precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0, + precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0); + } + return assemblyVersion.EnsureNonNegativeComponents(4); } diff --git a/src/NerdBank.GitVersioning/version.schema.json b/src/NerdBank.GitVersioning/version.schema.json index f51741ea..3590beba 100644 --- a/src/NerdBank.GitVersioning/version.schema.json +++ b/src/NerdBank.GitVersioning/version.schema.json @@ -44,8 +44,15 @@ { "$ref": "#/definitions/twoToFourComponentVersion" }, { "type": "object", + "additionalProperties": false, + "properties": { + "version": { "$ref": "#/definitions/twoToFourComponentVersion" } + } + }, + { + "type": "object", + "additionalProperties": false, "properties": { - "version": { "$ref": "#/definitions/twoToFourComponentVersion" }, "precision": { "type": "string", "description": "Identifies the last component to be explicitly set in the version.", From 7b5474309d805700a1f125fd8076d9dcb90ad890 Mon Sep 17 00:00:00 2001 From: Aaron Sherber Date: Mon, 3 Jan 2022 16:04:15 -0500 Subject: [PATCH 395/704] Always update nbgv version in props on install --- src/nbgv/Program.cs | 60 ++++++++++++++++++++++++++------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index d48c15f8..61129a44 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -320,43 +320,53 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList i.ItemType == PackageReferenceItemType && i.Include == PackageId)) + // Validate given sources + foreach (var src in source) { - // Validate given sources - foreach (var src in source) + // TODO: Can declare Option to validate argument during parsing. + if (!Uri.TryCreate(src, UriKind.Absolute, out var _)) { - // TODO: Can declare Option to validate argument during parsing. - if (!Uri.TryCreate(src, UriKind.Absolute, out var _)) - { - Console.Error.WriteLine($"\"{src}\" is not a valid NuGet package source."); - return (int)ExitCodes.InvalidNuGetPackageSource; - } + Console.Error.WriteLine($"\"{src}\" is not a valid NuGet package source."); + return (int)ExitCodes.InvalidNuGetPackageSource; } + } - string packageVersion = GetLatestPackageVersionAsync(PackageId, path, source).GetAwaiter().GetResult(); - if (string.IsNullOrEmpty(packageVersion)) - { - string verifyPhrase = source.Any() - ? "Please verify the given 'source' option(s)." - : "Please verify the package sources in the NuGet.Config files."; - Console.Error.WriteLine($"Latest stable version of the {PackageId} package could not be determined. " + verifyPhrase); - return (int)ExitCodes.PackageIdNotFound; - } + string packageVersion = GetLatestPackageVersionAsync(PackageId, path, source).GetAwaiter().GetResult(); + if (string.IsNullOrEmpty(packageVersion)) + { + string verifyPhrase = source.Any() + ? "Please verify the given 'source' option(s)." + : "Please verify the package sources in the NuGet.Config files."; + Console.Error.WriteLine($"Latest stable version of the {PackageId} package could not be determined. " + verifyPhrase); + return (int)ExitCodes.PackageIdNotFound; + } - var item = propsFile.AddItem( + const string PackageReferenceItemType = "PackageReference"; + const string PrivateAssetsMetadataName = "PrivateAssets"; + const string VersionMetadataName = "Version"; + + var item = propsFile.Items.FirstOrDefault(i => i.ItemType == PackageReferenceItemType && i.Include == PackageId); + + if (item is null) + { + item = propsFile.AddItem( PackageReferenceItemType, PackageId, new Dictionary { - { "Version", packageVersion }, - { "PrivateAssets", "all" }, + { PrivateAssetsMetadataName, "all" }, + { VersionMetadataName, packageVersion } }); - item.Condition = "!Exists('packages.config')"; - - propsFile.Save(directoryBuildPropsPath); } + else + { + var versionMetadata = item.Metadata.Single(m => m.Name == VersionMetadataName); + versionMetadata.Value = packageVersion; + } + + item.Condition = "!Exists('packages.config')"; + propsFile.Save(directoryBuildPropsPath); context.Stage(directoryBuildPropsPath); return (int)ExitCodes.OK; From dbd3cd8d0cd7c4defb3c957c85dd90299e68cf5a Mon Sep 17 00:00:00 2001 From: Aaron Sherber Date: Mon, 3 Jan 2022 17:16:35 -0500 Subject: [PATCH 396/704] Don't clobber existing version with default --- src/nbgv/Program.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 61129a44..43da7fa8 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -299,7 +299,7 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList Date: Thu, 6 Jan 2022 12:01:40 -0700 Subject: [PATCH 397/704] Allow a way for consumers to supply their own targets to the private P2P target Closes #688 --- .../build/MSBuildTargetCaching.targets | 1 + src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets index 7e2b97ca..3f6a01b6 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets @@ -6,6 +6,7 @@ $(NBGV_InnerGlobalProperties)ProjectPathRelativeToGitRepoRoot=$(ProjectPathRelativeToGitRepoRoot); $(NBGV_InnerGlobalProperties)GitVersionBaseDirectory=$(GitVersionBaseDirectory); $(NBGV_InnerGlobalProperties)OverrideBuildNumberOffset=$(OverrideBuildNumberOffset); + $(NBGV_InnerGlobalProperties)NBGV_PrivateP2PAuxTargets=$(NBGV_PrivateP2PAuxTargets); diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index db020b2f..8e6aa161 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -20,4 +20,6 @@ + + From 06fb9182bf043a37137cf852ecf2e179127bb177 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 6 Jan 2022 12:55:02 -0700 Subject: [PATCH 398/704] List breaking changes in github release notes --- azure-pipelines/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 0f794f6a..613b925c 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -39,6 +39,7 @@ stages: changeLogType: issueBased changeLogLabels: | [ + { "label" : "breaking changes", "displayName" : "Breaking changes", "state" : "closed" }, { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } ] From 7d3854818197dfd9995a552bd32263d3d8ae7479 Mon Sep 17 00:00:00 2001 From: Anton Curmanschii <39066090+AntonC9018@users.noreply.github.com> Date: Sun, 9 Jan 2022 20:41:33 +0000 Subject: [PATCH 399/704] Update nbgv-cli.md --- doc/nbgv-cli.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/nbgv-cli.md b/doc/nbgv-cli.md index db865e21..3c9f46af 100644 --- a/doc/nbgv-cli.md +++ b/doc/nbgv-cli.md @@ -150,9 +150,9 @@ will generate output similar to this: } ``` -The JSON object has to properties: +The JSON object has two properties: -- `CurrentBranch` provides information about the branch `prepare-release` was started on (typically `master`) +- `CurrentBranch` provides information about the branch that `prepare-release` was started on (typically `master`) - `NewBranch` provides information about the new branch created by the command. For each branch, the following properties are provided: From c31f6ad1e0ffaf45e333da288419a9e17529f2b0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 13 Jan 2022 08:26:38 -0700 Subject: [PATCH 400/704] Fix Expand-Template to replace tokens in AssemblyInfo.cs --- Expand-Template.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Expand-Template.ps1 b/Expand-Template.ps1 index 9e4d4973..d203d85f 100755 --- a/Expand-Template.ps1 +++ b/Expand-Template.ps1 @@ -145,6 +145,9 @@ try { 'Library'=$LibraryName 'COMPANY-PLACEHOLDER'=$Author } + Replace-Placeholders -Path "src/AssemblyInfo.cs" -Replacements @{ + 'COMPANY-PLACEHOLDER'=$Author + } Replace-Placeholders -Path "LICENSE" -Replacements @{ 'COMPANY-PLACEHOLDER'=$Author } From 6cf12a28d7447b8921e2854937ee09d1a10b8bbb Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 13 Jan 2022 08:09:07 -0700 Subject: [PATCH 401/704] Enable publishing of artifacts in multiple passes When an artifact is not ready yet, but other artifacts are and must be prepared, we can now run `artifacts/_pipelines.ps1` multiple times in the pipeline. To opt out of an earlier pass, the artifact script need only produce 0 files. After an artifact script returns some files, that artifact will be published and will not be published again. This is similar to `variables/_pipelines.ps1` behavior, which we already run twice. --- azure-pipelines/artifacts/_all.ps1 | 84 ++++++++++++++---------- azure-pipelines/artifacts/_pipelines.ps1 | 5 ++ azure-pipelines/artifacts/_stage_all.ps1 | 2 +- 3 files changed, 55 insertions(+), 36 deletions(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index db10c5ff..afe42be3 100755 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -1,18 +1,24 @@ #!/usr/bin/env pwsh -# This script returns all the artifacts that should be collected after a build. -# -# Each powershell artifact is expressed as an object with these properties: -# Source - the full path to the source file -# ArtifactName - the name of the artifact to upload to -# ContainerFolder - the relative path within the artifact in which the file should appear -# -# Each artifact aggregating .ps1 script should return a hashtable: -# Key = path to the directory from which relative paths within the artifact should be calculated -# Value = an array of paths (absolute or relative to the BaseDirectory) to files to include in the artifact. -# FileInfo objects are also allowed. - -$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +<# +.SYNOPSIS + This script returns all the artifacts that should be collected after a build. + Each powershell artifact is expressed as an object with these properties: + Source - the full path to the source file + ArtifactName - the name of the artifact to upload to + ContainerFolder - the relative path within the artifact in which the file should appear + Each artifact aggregating .ps1 script should return a hashtable: + Key = path to the directory from which relative paths within the artifact should be calculated + Value = an array of paths (absolute or relative to the BaseDirectory) to files to include in the artifact. + FileInfo objects are also allowed. +.PARAMETER Force + Executes artifact scripts even if they have already been uploaded. +#> + +param ( + [string]$ArtifactNameSuffix, + [switch]$Force +) Function EnsureTrailingSlash($path) { if ($path.length -gt 0 -and !$path.EndsWith('\') -and !$path.EndsWith('/')) { @@ -22,35 +28,43 @@ Function EnsureTrailingSlash($path) { $path.Replace('\', [IO.Path]::DirectorySeparatorChar) } -Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse |% { - $ArtifactName = $_.BaseName +Function Test-ArtifactUploaded($artifactName) { + $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" + Test-Path "env:$varName" +} - $totalFileCount = 0 - $fileGroups = & $_ - if ($fileGroups) { - $fileGroups.GetEnumerator() | % { - $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key.ToString()), [UriKind]::Absolute) - $_.Value | % { - if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { - $_ = $_.FullName - } +Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { + $ArtifactName = $_.BaseName + if ($Force -or !(Test-ArtifactUploaded($ArtifactName + $ArtifactNameSuffix))) { + $totalFileCount = 0 + $fileGroups = & $_ + if ($fileGroups) { + $fileGroups.GetEnumerator() | % { + $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key.ToString()), [UriKind]::Absolute) + $_.Value | ? { $_ } | % { + if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { + $_ = $_.FullName + } - $artifact = New-Object -TypeName PSObject - Add-Member -InputObject $artifact -MemberType NoteProperty -Name ArtifactName -Value $ArtifactName + $artifact = New-Object -TypeName PSObject + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ArtifactName -Value $ArtifactName - $SourceFullPath = New-Object Uri ($BaseDirectory, $_) - Add-Member -InputObject $artifact -MemberType NoteProperty -Name Source -Value $SourceFullPath.LocalPath + $SourceFullPath = New-Object Uri ($BaseDirectory, $_) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Source -Value $SourceFullPath.LocalPath - $RelativePath = [Uri]::UnescapeDataString($BaseDirectory.MakeRelative($SourceFullPath)) - Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) + $RelativePath = [Uri]::UnescapeDataString($BaseDirectory.MakeRelative($SourceFullPath)) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) - Write-Output $artifact - $totalFileCount += 1 + Write-Output $artifact + $totalFileCount += 1 + } } } - } - if ($totalFileCount -eq 0) { - Write-Warning "No files found for the `"$ArtifactName`" artifact." + if ($totalFileCount -eq 0) { + Write-Warning "No files found for the `"$ArtifactName`" artifact." + } + } else { + Write-Host "Skipping $ArtifactName because it has already been uploaded." -ForegroundColor DarkGray } } diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index 5bca7c6c..73a3af0a 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -7,4 +7,9 @@ param ( & "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% { Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" + + # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts + # will skip this one from a check in the _all.ps1 script. + $varName = "ARTIFACTUPLOADED_$($_.Name.ToUpper())" + Write-Host "##vso[task.setvariable variable=$varName]true" } diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index 4e6a6dbe..4788a3f5 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -38,7 +38,7 @@ function Create-SymbolicLink { } # Stage all artifacts -$Artifacts = & "$PSScriptRoot\_all.ps1" +$Artifacts = & "$PSScriptRoot\_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix $Artifacts |% { $DestinationFolder = (Join-Path (Join-Path $ArtifactStagingFolder "$($_.ArtifactName)$ArtifactNameSuffix") $_.ContainerFolder).TrimEnd('\') $Name = "$(Split-Path $_.Source -Leaf)" From 5db33f2f900c8960fcad1624de89385e049b47d4 Mon Sep 17 00:00:00 2001 From: Nick Jones Date: Thu, 20 Jan 2022 16:35:57 -0500 Subject: [PATCH 402/704] "more than one project" Fixes a simple omission. --- doc/pathFilters.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/pathFilters.md b/doc/pathFilters.md index 5ac237a7..76fcaad5 100644 --- a/doc/pathFilters.md +++ b/doc/pathFilters.md @@ -2,7 +2,7 @@ ## Problem -Some repositories may contain more than project. This is sometimes referred to as a _mono repo_ (as opposed to having a repo for each project - _many repo_). Imagine a repository structured as: +Some repositories may contain more than one project. This is sometimes referred to as a _mono repo_ (as opposed to having a repo for each project - _many repo_). Imagine a repository structured as: - / - Foo/ From c01e120589f2d9642b78335c219f65540aad7adb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Feb 2022 08:24:29 -0700 Subject: [PATCH 403/704] Bump coverlet.msbuild from 3.1.0 to 3.1.1 (#134) Bumps [coverlet.msbuild](https://github.com/coverlet-coverage/coverlet) from 3.1.0 to 3.1.1. - [Release notes](https://github.com/coverlet-coverage/coverlet/releases) - [Commits](https://github.com/coverlet-coverage/coverlet/commits) --- updated-dependencies: - dependency-name: coverlet.msbuild dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index ebd5df8f..b3fc51f0 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From 88988319bebd9cdd5390de9f79e1000d34a24e88 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 1 Feb 2022 10:20:25 -0700 Subject: [PATCH 404/704] Update StyleCop.Analyzers Switch to the .Unstable package ID so that dependabot will help us keep it current even though it seems to be ever-unstable lately. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3b2b143b..f913d080 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,7 +37,7 @@ - + From ad7449bd60ea86c89861957843a7293d3b4a8e56 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 1 Feb 2022 10:52:26 -0700 Subject: [PATCH 405/704] Update sample test, which was sporting dead code --- test/Library.Tests/CalculatorTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/CalculatorTests.cs b/test/Library.Tests/CalculatorTests.cs index 44e89aaa..042e7d94 100644 --- a/test/Library.Tests/CalculatorTests.cs +++ b/test/Library.Tests/CalculatorTests.cs @@ -14,7 +14,7 @@ public CalculatorTests() public void AddOrSubtract() { // This tests aggregation of code coverage across test runs. -#if NETCOREAPP2_1 +#if NETCOREAPP3_1 Assert.Equal(3, Calculator.Add(1, 2)); #else Assert.Equal(-1, Calculator.Subtract(1, 2)); From 8ef6d0681b469e121d77080262383498fb22f96c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 2 Feb 2022 20:47:23 -0700 Subject: [PATCH 406/704] Update Nerdbank.GitVersioning --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index f913d080..e6f1f4ad 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -35,7 +35,7 @@ - + From ae5e025248ae617c174e42fe5d934b07890f34e3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 2 Feb 2022 20:50:26 -0700 Subject: [PATCH 407/704] Add explanatory comment for using unstable stylecop id --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index e6f1f4ad..a8f35b37 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,6 +37,7 @@ + From dcf939351c44b76905308cb5dbc85bb385e48f92 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 09:33:45 -0700 Subject: [PATCH 408/704] Capture netcoreapp3.1 TFM test crash dump naming pattern on linux --- azure-pipelines/artifacts/testResults.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 index 862155da..2f894c97 100644 --- a/azure-pipelines/artifacts/testResults.ps1 +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -3,7 +3,9 @@ $result = @{} if ($env:AGENT_TEMPDIRECTORY) { # The DotNetCoreCLI uses an alternate location to publish these files $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' - $result[$env:AGENT_TEMPDIRECTORY] = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse }); + $result[$env:AGENT_TEMPDIRECTORY] = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { + Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\*_crashdump.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse + }); } else { $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" From 4a85ff84c82c79b9d800eadaa3a99c83b0e5ce3d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 09:12:58 -0700 Subject: [PATCH 409/704] Replace runsettings files with switches --- .github/workflows/Linux.runsettings | 12 ------------ .github/workflows/Windows.runsettings | 12 ------------ .github/workflows/build.yml | 2 +- .github/workflows/macOS.runsettings | 12 ------------ azure-pipelines/Darwin.runsettings | 12 ------------ azure-pipelines/Linux.runsettings | 12 ------------ azure-pipelines/Windows_NT.runsettings | 12 ------------ azure-pipelines/dotnet.yml | 6 +++--- 8 files changed, 4 insertions(+), 76 deletions(-) delete mode 100644 .github/workflows/Linux.runsettings delete mode 100644 .github/workflows/Windows.runsettings delete mode 100644 .github/workflows/macOS.runsettings delete mode 100644 azure-pipelines/Darwin.runsettings delete mode 100644 azure-pipelines/Linux.runsettings delete mode 100644 azure-pipelines/Windows_NT.runsettings diff --git a/.github/workflows/Linux.runsettings b/.github/workflows/Linux.runsettings deleted file mode 100644 index db20611f..00000000 --- a/.github/workflows/Linux.runsettings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/.github/workflows/Windows.runsettings b/.github/workflows/Windows.runsettings deleted file mode 100644 index db20611f..00000000 --- a/.github/workflows/Windows.runsettings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b8499b90..ba968ab8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: - name: pack run: dotnet pack --no-build -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/pack.binlog" - name: test - run: dotnet test --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --settings "${{ github.workspace }}/.github/workflows/${{ runner.os }}.runsettings" + run: dotnet test --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --blame-hang-timeout 30s --blame-crash" - name: Update pipeline variables based on build outputs run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh diff --git a/.github/workflows/macOS.runsettings b/.github/workflows/macOS.runsettings deleted file mode 100644 index db20611f..00000000 --- a/.github/workflows/macOS.runsettings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/azure-pipelines/Darwin.runsettings b/azure-pipelines/Darwin.runsettings deleted file mode 100644 index db20611f..00000000 --- a/azure-pipelines/Darwin.runsettings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/azure-pipelines/Linux.runsettings b/azure-pipelines/Linux.runsettings deleted file mode 100644 index db20611f..00000000 --- a/azure-pipelines/Linux.runsettings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/azure-pipelines/Windows_NT.runsettings b/azure-pipelines/Windows_NT.runsettings deleted file mode 100644 index db20611f..00000000 --- a/azure-pipelines/Windows_NT.runsettings +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 70cd23ee..506eb645 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -10,7 +10,7 @@ steps: displayName: dotnet test -f net472 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net472.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net472.txt" + arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --blame-hang-timeout 30s --blame-crash /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net472.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net472.txt;TraceLevel=info" testRunTitle: net472-$(Agent.JobName) condition: succeededOrFailed() @@ -18,7 +18,7 @@ steps: displayName: dotnet test -f netcoreapp3.1 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp3.1.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/netcoreapp3.1.txt" + arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --blame-hang-timeout 30s --blame-crash /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp3.1.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/netcoreapp3.1.txt;TraceLevel=info" testRunTitle: netcoreapp3.1-$(Agent.JobName) condition: succeededOrFailed() @@ -26,7 +26,7 @@ steps: displayName: dotnet test -f net5.0 inputs: command: test - arguments: --no-build -c $(BuildConfiguration) -f net5.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --settings "$(Build.Repository.LocalPath)/azure-pipelines/$(Agent.OS).runsettings" /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net5.0.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net5.0.txt" + arguments: --no-build -c $(BuildConfiguration) -f net5.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --blame-hang-timeout 30s --blame-crash /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net5.0.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net5.0.txt;TraceLevel=info" testRunTitle: net5.0-$(Agent.JobName) condition: succeededOrFailed() From 9fb050e9d04dc1eb1a0257c239fc557637d74efc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 12:32:40 -0700 Subject: [PATCH 410/704] Fix GitHub workflow file syntax error (#137) --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ba968ab8..3be17746 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: - name: pack run: dotnet pack --no-build -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/pack.binlog" - name: test - run: dotnet test --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --blame-hang-timeout 30s --blame-crash" + run: dotnet test --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --blame-hang-timeout 30s --blame-crash - name: Update pipeline variables based on build outputs run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh From da8eef4ed65b12c824b3b2782a4c503fe1b68a4c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 12:39:56 -0700 Subject: [PATCH 411/704] Build and pack in one step --- .github/workflows/build.yml | 4 +--- azure-pipelines/dotnet.yml | 5 +---- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 3be17746..574cf524 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -39,9 +39,7 @@ jobs: run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh - name: build - run: dotnet build --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/build.binlog" - - name: pack - run: dotnet pack --no-build -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/pack.binlog" + run: dotnet build -t:build,pack --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/build.binlog" - name: test run: dotnet test --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --blame-hang-timeout 30s --blame-crash - name: Update pipeline variables based on build outputs diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 506eb645..d7469c64 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -1,11 +1,8 @@ steps: -- script: dotnet build --no-restore -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" +- script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" displayName: dotnet build -- script: dotnet pack --no-build -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/pack.binlog" - displayName: dotnet pack - - task: DotNetCoreCLI@2 displayName: dotnet test -f net472 inputs: From 1699ddf88159c2fc54a8488592df939fb3708398 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 09:59:54 -0700 Subject: [PATCH 412/704] Replace several `DotNetCoreCLI` task with one `dotnet test` task Closes #136 --- .../Get-ArtifactsStagingDirectory.ps1 | 13 +++++++ azure-pipelines/artifacts/_stage_all.ps1 | 9 +---- azure-pipelines/dotnet-test-cloud.ps1 | 37 +++++++++++++++++++ azure-pipelines/dotnet.yml | 25 +------------ 4 files changed, 53 insertions(+), 31 deletions(-) create mode 100644 azure-pipelines/Get-ArtifactsStagingDirectory.ps1 create mode 100644 azure-pipelines/dotnet-test-cloud.ps1 diff --git a/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 new file mode 100644 index 00000000..d96b1610 --- /dev/null +++ b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 @@ -0,0 +1,13 @@ +Param( + [switch]$CleanIfLocal +) +if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { + $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY +} else { + $ArtifactStagingFolder = Join-Path (Resolve-Path $PSScriptRoot/..) (Join-Path obj _artifacts) + if ($CleanIfLocal -and (Test-Path $ArtifactStagingFolder)) { + Remove-Item $ArtifactStagingFolder -Recurse -Force + } +} + +$ArtifactStagingFolder diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index 4788a3f5..af398a2e 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -7,14 +7,7 @@ param ( ) $RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot (Join-Path .. ..))) -if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { - $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY -} else { - $ArtifactStagingFolder = Join-Path $RepoRoot (Join-Path obj _artifacts) - if (Test-Path $ArtifactStagingFolder) { - Remove-Item $ArtifactStagingFolder -Recurse -Force - } -} +$ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" -CleanIfLocal function Create-SymbolicLink { param ( diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 new file mode 100644 index 00000000..c8642453 --- /dev/null +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -0,0 +1,37 @@ +Param( + [string]$Configuration='Debug', + [string]$Agent='Local', + [switch]$PublishResults +) + +$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..') +$ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" + +dotnet test $RepoRoot ` + --no-build ` + -c $Configuration ` + --filter "TestCategory!=FailsInCloudTest" ` + -p:CollectCoverage=true ` + --blame-hang-timeout 30s ` + --blame-crash ` + -bl:"$ArtifactStagingFolder/build_logs/test.binlog" ` + --diag "$ArtifactStagingFolder/test_logs/diag.log;TraceLevel=info" ` + --logger trx + +$unknownCounter = 0 +Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { + Copy-Item $_ -Destination $ArtifactStagingFolder/test_logs/ + + if ($PublishResults) { + $x = [xml](Get-Content -Path $_) + $storage = $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')[0].storage -replace '\\','/' + if ($storage -match '/(?[^/]+)/(?[^/]+)\.dll$') { + $runTitle = "$($matches.lib) ($($matches.tfm), $Agent)" + } else { + $unknownCounter += 1; + $runTitle = "unknown$unknownCounter ($Agent)"; + } + + Write-Host "##vso[results.publish type=VSTest;runTitle=$runTitle;publishRunAttachments=true;resultFiles=$_;failTaskOnFailedTests=true;testRunSystem=VSTS - PTR;]" + } +} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index d7469c64..2d2d7027 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -3,29 +3,8 @@ steps: - script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" displayName: dotnet build -- task: DotNetCoreCLI@2 - displayName: dotnet test -f net472 - inputs: - command: test - arguments: --no-build -c $(BuildConfiguration) -f net472 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --blame-hang-timeout 30s --blame-crash /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net472.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net472.txt;TraceLevel=info" - testRunTitle: net472-$(Agent.JobName) - condition: succeededOrFailed() - -- task: DotNetCoreCLI@2 - displayName: dotnet test -f netcoreapp3.1 - inputs: - command: test - arguments: --no-build -c $(BuildConfiguration) -f netcoreapp3.1 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --blame-hang-timeout 30s --blame-crash /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_netcoreapp3.1.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/netcoreapp3.1.txt;TraceLevel=info" - testRunTitle: netcoreapp3.1-$(Agent.JobName) - condition: succeededOrFailed() - -- task: DotNetCoreCLI@2 - displayName: dotnet test -f net5.0 - inputs: - command: test - arguments: --no-build -c $(BuildConfiguration) -f net5.0 --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --blame-hang-timeout 30s --blame-crash /bl:"$(Build.ArtifactStagingDirectory)/build_logs/test_net5.0.binlog" --diag "$(Build.ArtifactStagingDirectory)/test_logs/net5.0.txt;TraceLevel=info" - testRunTitle: net5.0-$(Agent.JobName) - condition: succeededOrFailed() +- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults + displayName: dotnet test - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true From 04f05d67b81aacbdfd9cd5c89c57425a55f2a727 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 13:29:25 -0700 Subject: [PATCH 413/704] Drop redundant build verbosity switch --- azure-pipelines/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 2d2d7027..86b7eb82 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -1,6 +1,6 @@ steps: -- script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /v:m /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" +- script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" displayName: dotnet build - powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults From 849e4b8e01691f784a9a74385a225ec82c5e8068 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 15:25:48 -0700 Subject: [PATCH 414/704] Simplify Join-Path expressions --- azure-pipelines/Get-ArtifactsStagingDirectory.ps1 | 2 +- azure-pipelines/artifacts/Variables.ps1 | 8 ++++---- azure-pipelines/artifacts/_stage_all.ps1 | 3 +-- azure-pipelines/dotnet-test-cloud.ps1 | 2 +- 4 files changed, 7 insertions(+), 8 deletions(-) diff --git a/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 index d96b1610..723574f5 100644 --- a/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 +++ b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 @@ -4,7 +4,7 @@ Param( if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY } else { - $ArtifactStagingFolder = Join-Path (Resolve-Path $PSScriptRoot/..) (Join-Path obj _artifacts) + $ArtifactStagingFolder = [System.IO.Path]::GetFullPath("$PSScriptRoot/../obj/_artifacts") if ($CleanIfLocal -and (Test-Path $ArtifactStagingFolder)) { Remove-Item $ArtifactStagingFolder -Recurse -Force } diff --git a/azure-pipelines/artifacts/Variables.ps1 b/azure-pipelines/artifacts/Variables.ps1 index c6330cd3..4bc6d216 100644 --- a/azure-pipelines/artifacts/Variables.ps1 +++ b/azure-pipelines/artifacts/Variables.ps1 @@ -2,13 +2,13 @@ # It "snaps" the values of these variables where we can compute them during the build, # and otherwise captures the scripts to run later during an Azure Pipelines environment release. -$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot (Join-Path .. ..))) -$ArtifactBasePath = Join-Path $RepoRoot (Join-Path obj _artifacts) +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot/../..") +$ArtifactBasePath = "$RepoRoot/obj/_artifacts" $VariablesArtifactPath = Join-Path $ArtifactBasePath variables if (-not (Test-Path $VariablesArtifactPath)) { New-Item -ItemType Directory -Path $VariablesArtifactPath | Out-Null } # Copy variables, either by value if the value is calculable now, or by script -Get-ChildItem -Path (Join-Path $PSScriptRoot (Join-Path .. variables)) |% { +Get-ChildItem "$PSScriptRoot/../variables" |% { $value = $null if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts # First check the environment variables in case the variable was set in a queued build @@ -35,7 +35,7 @@ Get-ChildItem -Path (Join-Path $PSScriptRoot (Join-Path .. variables)) |% { $value = Get-Content -Path $_.FullName } - Set-Content -Path (Join-Path $VariablesArtifactPath $_.Name) -Value $value + Set-Content -Path "$VariablesArtifactPath/$($_.Name)" -Value $value } @{ diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index af398a2e..87421d56 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -6,7 +6,6 @@ param ( [string]$ArtifactNameSuffix ) -$RepoRoot = [System.IO.Path]::GetFullPath((Join-Path $PSScriptRoot (Join-Path .. ..))) $ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" -CleanIfLocal function Create-SymbolicLink { @@ -33,7 +32,7 @@ function Create-SymbolicLink { # Stage all artifacts $Artifacts = & "$PSScriptRoot\_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix $Artifacts |% { - $DestinationFolder = (Join-Path (Join-Path $ArtifactStagingFolder "$($_.ArtifactName)$ArtifactNameSuffix") $_.ContainerFolder).TrimEnd('\') + $DestinationFolder = [System.IO.Path]::GetFullPath("$ArtifactStagingFolder/$($_.ArtifactName)$ArtifactNameSuffix/$($_.ContainerFolder)").TrimEnd('\') $Name = "$(Split-Path $_.Source -Leaf)" #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index c8642453..a7a63a02 100644 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -4,7 +4,7 @@ Param( [switch]$PublishResults ) -$RepoRoot = Resolve-Path (Join-Path $PSScriptRoot '..') +$RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path $ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" dotnet test $RepoRoot ` From e9df7075913bfea945429fa29f1322c2fcdc6e30 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 16:11:09 -0700 Subject: [PATCH 415/704] Collect and publish symbols from every build agent Accommodates https://github.com/microsoft/azure-pipelines-tasks/issues/13821 by publish symbols on a Windows agent Closes #135 --- azure-pipelines/Convert-PDB.ps1 | 43 ---------------- azure-pipelines/Get-SymbolFiles.ps1 | 20 ++------ azure-pipelines/artifacts/symbols.ps1 | 1 + azure-pipelines/artifacts/test_symbols.ps1 | 9 +--- azure-pipelines/build.yml | 6 ++- azure-pipelines/dotnet.yml | 18 ------- azure-pipelines/publish-symbols.yml | 59 ++++++++++++++++++++++ 7 files changed, 70 insertions(+), 86 deletions(-) delete mode 100644 azure-pipelines/Convert-PDB.ps1 create mode 100644 azure-pipelines/publish-symbols.yml diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1 deleted file mode 100644 index 2d394e72..00000000 --- a/azure-pipelines/Convert-PDB.ps1 +++ /dev/null @@ -1,43 +0,0 @@ -<# -.SYNOPSIS - Converts between Windows PDB and Portable PDB formats. -.PARAMETER DllPath - The path to the DLL whose PDB is to be converted. -.PARAMETER PdbPath - The path to the PDB to convert. May be omitted if the DLL was compiled on this machine and the PDB is still at its original path. -.PARAMETER OutputPath - The path of the output PDB to write. -#> -#Function Convert-PortableToWindowsPDB() { - Param( - [Parameter(Mandatory=$true,Position=0)] - [string]$DllPath, - [Parameter()] - [string]$PdbPath, - [Parameter(Mandatory=$true,Position=1)] - [string]$OutputPath - ) - - if ($IsMacOS -or $IsLinux) { - Write-Error "This script only works on Windows" - return - } - - $version = '1.1.0-beta2-21101-01' - $baseDir = "$PSScriptRoot/../obj/tools" - $pdb2pdbpath = "$baseDir/Microsoft.DiaSymReader.Pdb2Pdb.$version/tools/Pdb2Pdb.exe" - if (-not (Test-Path $pdb2pdbpath)) { - if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } - $baseDir = (Resolve-Path $baseDir).Path # Normalize it - Write-Verbose "& (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null" - & (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null - } - - $args = $DllPath,'/out',$OutputPath,'/nowarn','0021' - if ($PdbPath) { - $args += '/pdb',$PdbPath - } - - Write-Verbose "$pdb2pdbpath $args" - & $pdb2pdbpath $args -#} diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1 index 45afe7c2..d4c5289a 100644 --- a/azure-pipelines/Get-SymbolFiles.ps1 +++ b/azure-pipelines/Get-SymbolFiles.ps1 @@ -1,10 +1,10 @@ <# .SYNOPSIS - Collect the list of PDBs built in this repo, after converting them from portable to Windows PDBs. + Collect the list of PDBs built in this repo. .PARAMETER Path - The root path to recursively search for PDBs. + The directory to recursively search for PDBs. .PARAMETER Tests - A switch indicating to find test-related PDBs instead of product-only PDBs. + A switch indicating to find PDBs only for test binaries instead of only for shipping shipping binaries. #> [CmdletBinding()] param ( @@ -53,17 +53,5 @@ $PDBs |% { } Write-Output $BinaryImagePath - - if (-not ($IsMacOS -or $IsLinux)) { - # Convert the PDB to legacy Windows PDBs - Write-Host "Converting PDB for $_" -ForegroundColor DarkGray - $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" - if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } - & "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath "$WindowsPdbDir\$($_.BaseName).pdb" - if ($LASTEXITCODE -ne 0) { - Write-Warning "PDB conversion of `"$_`" failed." - } - - Write-Output "$WindowsPdbDir\$($_.BaseName).pdb" - } + Write-Output $_.FullName } diff --git a/azure-pipelines/artifacts/symbols.ps1 b/azure-pipelines/artifacts/symbols.ps1 index 8704571e..9e2c7bd5 100644 --- a/azure-pipelines/artifacts/symbols.ps1 +++ b/azure-pipelines/artifacts/symbols.ps1 @@ -1,4 +1,5 @@ $BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") +if (!(Test-Path $BinPath)) { return } $symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique @{ diff --git a/azure-pipelines/artifacts/test_symbols.ps1 b/azure-pipelines/artifacts/test_symbols.ps1 index d65ad0ae..ce2b6481 100644 --- a/azure-pipelines/artifacts/test_symbols.ps1 +++ b/azure-pipelines/artifacts/test_symbols.ps1 @@ -1,11 +1,6 @@ -# This doesn't work off Windows, nor do we need to convert symbols on multiple OS agents -if ($IsMacOS -or $IsLinux) { - return; -} - -$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin") +$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") if (!(Test-Path $BinPath)) { return } -$symbolfiles = & "$PSScriptRoot\..\Get-SymbolFiles.ps1" -Path $BinPath -Tests | Get-Unique +$symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath -Tests | Get-Unique @{ "$BinPath" = $SymbolFiles; diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 796be61d..f779fd12 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -45,8 +45,7 @@ jobs: - Windows - Linux - macOS - pool: - vmImage: Ubuntu 20.04 + pool: ${{ parameters.windowsPool }} # Use Windows agent because PublishSymbols task requires it (https://github.com/microsoft/azure-pipelines-tasks/issues/13821). condition: succeededOrFailed() steps: - checkout: self @@ -54,6 +53,9 @@ jobs: - template: install-dependencies.yml parameters: initArgs: -NoRestore + - template: publish-symbols.yml + parameters: + includeMacOS: ${{ parameters.includeMacOS }} - template: publish-codecoverage.yml parameters: includeMacOS: ${{ parameters.includeMacOS }} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 86b7eb82..a103adfd 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -16,24 +16,6 @@ steps: displayName: Publish artifacts condition: succeededOrFailed() -- task: PublishSymbols@2 - inputs: - SymbolsFolder: $(Build.ArtifactStagingDirectory)/symbols-$(Agent.JobName) - SearchPattern: '**/*.pdb' - IndexSources: false - SymbolServerType: TeamServices - displayName: Publish symbols to symbol server - condition: eq(variables['Agent.OS'], 'Windows_NT') # Execute on failed test runs too. Windows-only till https://github.com/microsoft/azure-pipelines-tasks/issues/13821 is fixed. - -- task: PublishSymbols@2 - inputs: - SymbolsFolder: $(Build.ArtifactStagingDirectory)/test_symbols-$(Agent.JobName) - SearchPattern: '**/*.pdb' - IndexSources: false - SymbolServerType: TeamServices - displayName: Publish test symbols to symbol server - condition: and(failed(), eq(variables['Agent.OS'], 'Windows_NT')) # Execute on failed test runs only. - - bash: bash <(curl -s https://codecov.io/bash) displayName: Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') diff --git a/azure-pipelines/publish-symbols.yml b/azure-pipelines/publish-symbols.yml new file mode 100644 index 00000000..c45eff02 --- /dev/null +++ b/azure-pipelines/publish-symbols.yml @@ -0,0 +1,59 @@ +parameters: + includeMacOS: + +steps: +- task: DownloadPipelineArtifact@2 + inputs: + artifact: symbols-Windows + path: $(Pipeline.Workspace)/symbols/Windows + displayName: Download Windows symbols + continueOnError: true +- task: DownloadPipelineArtifact@2 + inputs: + artifact: symbols-Linux + path: $(Pipeline.Workspace)/symbols/Linux + displayName: Download Linux symbols + continueOnError: true +- task: DownloadPipelineArtifact@2 + inputs: + artifact: symbols-macOS + path: $(Pipeline.Workspace)/symbols/macOS + displayName: Download macOS symbols + continueOnError: true + condition: ${{ parameters.includeMacOS }} + +- task: DownloadPipelineArtifact@2 + inputs: + artifact: test_symbols-Windows + path: $(Pipeline.Workspace)/test_symbols/Windows + displayName: Download Windows test symbols + continueOnError: true +- task: DownloadPipelineArtifact@2 + inputs: + artifact: test_symbols-Linux + path: $(Pipeline.Workspace)/test_symbols/Linux + displayName: Download Linux test symbols + continueOnError: true +- task: DownloadPipelineArtifact@2 + inputs: + artifact: test_symbols-macOS + path: $(Pipeline.Workspace)/test_symbols/macOS + displayName: Download macOS test symbols + continueOnError: true + condition: ${{ parameters.includeMacOS }} + +- task: PublishSymbols@2 + inputs: + SymbolsFolder: $(Pipeline.Workspace)/symbols + SearchPattern: '**/*.pdb' + IndexSources: false + SymbolServerType: TeamServices + displayName: Publish symbols + +- task: PublishSymbols@2 + inputs: + SymbolsFolder: $(Pipeline.Workspace)/test_symbols + SearchPattern: '**/*.pdb' + IndexSources: false + SymbolServerType: TeamServices + displayName: Publish test symbols From 6ecd99be42bc60e4bb359e84e9ec12dadc863403 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 16:20:49 -0700 Subject: [PATCH 416/704] Do not include product symbols with test symbols --- azure-pipelines/Get-SymbolFiles.ps1 | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1 index d4c5289a..fccb1bb1 100644 --- a/azure-pipelines/Get-SymbolFiles.ps1 +++ b/azure-pipelines/Get-SymbolFiles.ps1 @@ -13,19 +13,12 @@ param ( [switch]$Tests ) -$WindowsPdbSubDirName = "symstore" - $ActivityName = "Collecting symbols from $Path" Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" -$PDBs = Get-ChildItem -rec "$Path/*.pdb" |? { $_.FullName -notmatch "\W$WindowsPdbSubDirName\W" } +$PDBs = Get-ChildItem -rec "$Path/*.pdb" # Filter PDBs to product OR test related. $testregex = "unittest|tests" -if ($Tests) { - $PDBs = $PDBs |? { $_.FullName -match $testregex } -} else { - $PDBs = $PDBs |? { $_.FullName -notmatch $testregex } -} Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" $PDBsByHash = @{} @@ -42,6 +35,12 @@ $PDBs |% { $PDBsByHash.Add($_.Hash, $_.FullName) Write-Output $_ } +} |? { + if ($Tests) { + $_.FullName -match $testregex + } else { + $_.FullName -notmatch $testregex + } } |% { # Collect the DLLs/EXEs as well. $dllPath = "$($_.Directory)/$($_.BaseName).dll" From e67a6e4b39d1625ebcea0dcf89f34c458984e1d4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Feb 2022 17:38:54 -0700 Subject: [PATCH 417/704] Update GitHub Actions to more closely resemble AzP --- .github/workflows/build.yml | 31 +++++++++++++------ .../Get-ArtifactsStagingDirectory.ps1 | 2 ++ azure-pipelines/artifacts/build_logs.ps1 | 11 ++----- azure-pipelines/dotnet-test-cloud.ps1 | 2 ++ 4 files changed, 29 insertions(+), 17 deletions(-) mode change 100644 => 100755 azure-pipelines/dotnet-test-cloud.ps1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 574cf524..18ae3e28 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -34,14 +34,20 @@ jobs: run: | ./init.ps1 -UpgradePrerequisites dotnet --info + + # Print mono version if it is present. + if (Get-Command mono -ErrorAction SilentlyContinue) { + mono --version + } shell: pwsh - name: Set pipeline variables based on source run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh - name: build - run: dotnet build -t:build,pack --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"bin/build_logs/build.binlog" + run: dotnet build -t:build,pack --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"${{ runner.temp }}/_artifacts/build_logs/build.binlog" - name: test - run: dotnet test --no-build -c ${{ env.BUILDCONFIGURATION }} /bl:"bin/build_logs/test.binlog" --filter "TestCategory!=FailsInCloudTest" -v n /p:CollectCoverage=true --logger trx --blame-hang-timeout 30s --blame-crash + run: azure-pipelines/dotnet-test-cloud.ps1 -Configuration ${{ env.BUILDCONFIGURATION }} -Agent ${{ runner.os }} + shell: pwsh - name: Update pipeline variables based on build outputs run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh @@ -54,46 +60,53 @@ jobs: uses: actions/upload-artifact@v1 with: name: projectAssetsJson-${{ runner.os }} - path: obj/_artifacts/projectAssetsJson + path: ${{ runner.temp }}/_artifacts/projectAssetsJson continue-on-error: true - name: Upload variables uses: actions/upload-artifact@v1 with: name: variables-${{ runner.os }} - path: obj/_artifacts/variables + path: ${{ runner.temp }}/_artifacts/Variables continue-on-error: true - name: Upload build_logs if: always() uses: actions/upload-artifact@v1 with: name: build_logs-${{ runner.os }} - path: obj/_artifacts/build_logs + path: ${{ runner.temp }}/_artifacts/build_logs + continue-on-error: true + - name: Upload test_logs + if: always() + uses: actions/upload-artifact@v1 + with: + name: test_logs-${{ runner.os }} + path: ${{ runner.temp }}/_artifacts/test_logs continue-on-error: true - name: Upload testResults if: always() uses: actions/upload-artifact@v1 with: name: testResults-${{ runner.os }} - path: obj/_artifacts/testResults + path: ${{ runner.temp }}/_artifacts/testResults continue-on-error: true - name: Upload coverageResults if: always() uses: actions/upload-artifact@v1 with: name: coverageResults-${{ runner.os }} - path: obj/_artifacts/coverageResults + path: ${{ runner.temp }}/_artifacts/coverageResults continue-on-error: true - name: Upload symbols uses: actions/upload-artifact@v1 with: name: symbols-${{ runner.os }} - path: obj/_artifacts/symbols + path: ${{ runner.temp }}/_artifacts/symbols continue-on-error: true - name: Upload deployables uses: actions/upload-artifact@v1 with: name: deployables-${{ runner.os }} - path: obj/_artifacts/deployables + path: ${{ runner.temp }}/_artifacts/deployables if: always() - name: Publish code coverage results to codecov.io run: bash <(curl -s https://codecov.io/bash) diff --git a/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 index 723574f5..391e5713 100644 --- a/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 +++ b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 @@ -3,6 +3,8 @@ Param( ) if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY +} elseif ($env:RUNNER_TEMP) { + $ArtifactStagingFolder = "$env:RUNNER_TEMP\_artifacts" } else { $ArtifactStagingFolder = [System.IO.Path]::GetFullPath("$PSScriptRoot/../obj/_artifacts") if ($CleanIfLocal -and (Test-Path $ArtifactStagingFolder)) { diff --git a/azure-pipelines/artifacts/build_logs.ps1 b/azure-pipelines/artifacts/build_logs.ps1 index b55ba48f..f05358e0 100644 --- a/azure-pipelines/artifacts/build_logs.ps1 +++ b/azure-pipelines/artifacts/build_logs.ps1 @@ -1,12 +1,7 @@ -if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { - $artifactsRoot = $env:BUILD_ARTIFACTSTAGINGDIRECTORY -} else { - $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") - $artifactsRoot = "$RepoRoot\bin" -} +$ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" -if (!(Test-Path $artifactsRoot/build_logs)) { return } +if (!(Test-Path $ArtifactStagingFolder/build_logs)) { return } @{ - "$artifactsRoot/build_logs" = (Get-ChildItem -Recurse "$artifactsRoot/build_logs") + "$ArtifactStagingFolder/build_logs" = (Get-ChildItem -Recurse "$ArtifactStagingFolder/build_logs") } diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 old mode 100644 new mode 100755 index a7a63a02..440bd890 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -1,3 +1,5 @@ +#!/usr/bin/env pwsh + Param( [string]$Configuration='Debug', [string]$Agent='Local', From fea1a21244fa5def174d2fdec214a14d7e1f1010 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sat, 5 Feb 2022 13:33:41 +0100 Subject: [PATCH 418/704] Add "precision" settting to the "nugetPackageVersion" section in the version.json file --- doc/versionJson.md | 1 + .../VersionFileTests.cs | 32 ++++++++++++++++++ .../VersionOptionsTests.cs | 27 +++++++++++++++ src/NerdBank.GitVersioning/VersionOptions.cs | 33 +++++++++++++++++-- .../version.schema.json | 6 ++++ 5 files changed, 97 insertions(+), 2 deletions(-) diff --git a/doc/versionJson.md b/doc/versionJson.md index ff3ae7d7..09e65202 100644 --- a/doc/versionJson.md +++ b/doc/versionJson.md @@ -39,6 +39,7 @@ The content of the version.json file is a JSON serialized object with these prop "gitCommitIdShortAutoMinimum": 0, // optional. Set to use the short commit ID abbreviation provided by the git repository. "nugetPackageVersion": { "semVer": 1 // optional. Set to either 1 or 2 to control how the NuGet package version string is generated. Default is 1. + "precision": "build" // optional. Use when you want to a more or less precise package version than the default major.minor.build. }, "pathFilters": [ // optional list of paths to consider when calculating version height. diff --git a/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs b/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs index 016481fd..afeedc2a 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs @@ -608,6 +608,38 @@ public void GetVersion_ProducesAbsolutePath() Assert.True(Path.IsPathRooted(actualDirectory)); } + + [Theory] + [InlineData(1)] + [InlineData(2)] + public void GetVersion_ReadNuGetPackageVersionSettings_SemVer(int semVer) + { + var json = $@"{{ ""version"" : ""1.0"", ""nugetPackageVersion"" : {{ ""semVer"" : {semVer} }} }}"; + var path = Path.Combine(this.RepoPath, "version.json"); + File.WriteAllText(path, json); + + var versionOptions = this.Context.VersionFile.GetVersion(); + + Assert.NotNull(versionOptions.NuGetPackageVersion); + Assert.NotNull(versionOptions.NuGetPackageVersion.SemVer); + Assert.Equal(semVer, versionOptions.NuGetPackageVersion.SemVer); + } + + [Theory] + [CombinatorialData] + public void GetVersion_ReadNuGetPackageVersionSettings_Precision(VersionOptions.VersionPrecision precision) + { + var json = $@"{{ ""version"" : ""1.0"", ""nugetPackageVersion"" : {{ ""precision"" : ""{precision}"" }} }}"; + var path = Path.Combine(this.RepoPath, "version.json"); + File.WriteAllText(path, json); + + var versionOptions = this.Context.VersionFile.GetVersion(); + + Assert.NotNull(versionOptions.NuGetPackageVersion); + Assert.NotNull(versionOptions.NuGetPackageVersion.Precision); + Assert.Equal(precision, versionOptions.NuGetPackageVersion.Precision); + } + private void AssertPathHasVersion(string committish, string absolutePath, VersionOptions expected) { var actual = this.GetVersionOptions(absolutePath, committish); diff --git a/src/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs index a0d6571a..603f02fe 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs @@ -178,6 +178,7 @@ public void CannotWriteToDefaultInstances() Assert.Throws(() => options.CloudBuildOrDefault.BuildNumberOrDefault.IncludeCommitIdOrDefault.Where = VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata); Assert.Throws(() => options.CloudBuildOrDefault.SetVersionVariables = true); Assert.Throws(() => options.NuGetPackageVersionOrDefault.SemVer = 2); + Assert.Throws(() => options.NuGetPackageVersionOrDefault.Precision = VersionOptions.VersionPrecision.Revision); Assert.Throws(() => options.ReleaseOrDefault.BranchName = "BranchName"); Assert.Throws(() => options.ReleaseOrDefault.VersionIncrement = VersionOptions.ReleaseVersionIncrement.Major); Assert.Throws(() => options.ReleaseOrDefault.FirstUnstableTag = "-tag"); @@ -226,4 +227,30 @@ public void ReleaseOptions_Equality() Assert.NotEqual(ro3, ro5); Assert.NotEqual(ro5, ro6); } + + [Fact] + public void NuGetPackageVersionOptions_Equality() + { + var npvo1a = new VersionOptions.NuGetPackageVersionOptions { }; + var npvo1b = new VersionOptions.NuGetPackageVersionOptions { }; + Assert.Equal(npvo1a, npvo1b); + + var npvo2a = new VersionOptions.NuGetPackageVersionOptions + { + SemVer = 2 + }; + Assert.NotEqual(npvo2a, npvo1a); + + var npvo3a = new VersionOptions.NuGetPackageVersionOptions + { + Precision = VersionOptions.VersionPrecision.Revision + }; + Assert.NotEqual(npvo3a, npvo1a); + + var npvo4a = new VersionOptions.NuGetPackageVersionOptions + { + Precision = VersionOptions.VersionPrecision.Build + }; + Assert.Equal(npvo4a, npvo1a); // Equal because we haven't changed defaults. + } } diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index e02730f5..b1eb6338 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -584,6 +584,7 @@ public class NuGetPackageVersionOptions : IEquatable { isFrozen = true, semVer = 1.0f, + precision = VersionPrecision.Build }; [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -592,6 +593,9 @@ public class NuGetPackageVersionOptions : IEquatable [DebuggerBrowsable(DebuggerBrowsableState.Never)] private float? semVer; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private VersionPrecision? precision; + /// /// Initializes a new instance of the class. /// @@ -623,6 +627,22 @@ public float? SemVer [JsonIgnore] public float? SemVerOrDefault => this.SemVer ?? DefaultInstance.SemVer; + /// + /// Gets or sets number of version components to include when generating the package version. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public VersionPrecision? Precision + { + get => this.precision; + set => this.SetIfNotReadOnly(ref this.precision, value); + } + + /// + /// Gets the number of version components to include when generating the package version. + /// + [JsonIgnore] + public VersionPrecision PrecisionOrDefault => this.Precision ?? DefaultInstance.Precision!.Value; + /// /// Gets a value indicating whether this instance rejects all attempts to mutate it. /// @@ -679,13 +699,22 @@ public bool Equals(NuGetPackageVersionOptions? x, NuGetPackageVersionOptions? y) return false; } - return x.SemVerOrDefault == y.SemVerOrDefault; + return x.SemVerOrDefault == y.SemVerOrDefault && + x.PrecisionOrDefault == y.PrecisionOrDefault; } /// public int GetHashCode(NuGetPackageVersionOptions? obj) { - return obj?.SemVerOrDefault.GetHashCode() ?? 0; + if (obj is null) + return 0; + + unchecked + { + var hash = obj.SemVerOrDefault.GetHashCode() * 397; + hash ^= obj.PrecisionOrDefault.GetHashCode(); + return hash; + } } } } diff --git a/src/NerdBank.GitVersioning/version.schema.json b/src/NerdBank.GitVersioning/version.schema.json index 3590beba..3d50d72f 100644 --- a/src/NerdBank.GitVersioning/version.schema.json +++ b/src/NerdBank.GitVersioning/version.schema.json @@ -108,6 +108,12 @@ "default": 1, "minimum": 1, "maximum": 2 + }, + "precision": { + "type": "string", + "description": "Specifies the number of components to include in the NuGet package version.", + "enum": [ "major", "minor", "build", "revision" ], + "default": "build" } } }, From 0782df51093495bc8ce4302ada702516cd25064a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sat, 5 Feb 2022 16:58:30 +0100 Subject: [PATCH 419/704] Respect the precision setting when calculating the NuGet package version --- .../VersionOracleTests.cs | 86 +++++++++++++++++++ src/NerdBank.GitVersioning/VersionOptions.cs | 7 +- src/NerdBank.GitVersioning/VersionOracle.cs | 53 ++++++++++-- 3 files changed, 136 insertions(+), 10 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index cf0388b8..19dd790d 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -372,6 +372,92 @@ public void CanSetSemVer2ForNuGetPackageVersionPublicRelease() Assert.Equal($"7.8.9-foo.25", oracle.NuGetPackageVersion); } + [Theory] + // + // SemVer 1 + // + // 2 version fields configured in version.json + [InlineData(1, "1.2", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(1, "1.2", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(1, "1.2", VersionOptions.VersionPrecision.Build, "1.2.1")] + [InlineData(1, "1.2", VersionOptions.VersionPrecision.Revision, "1.2.1.")] + // 2 version fields configured in version.json + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] + // 4 version fields configured in version.json + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] + // 2 version fields with git height in prerelease tag configured in version.json + [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] + [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] + [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.0-alpha-0001")] + [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.0.0-alpha-0001")] + // 3 version fields with git height in prerelease tag configured in version.json + [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] + [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] + [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha-0001")] + [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.0-alpha-0001")] + // 4 version fields with git height in prerelease tag configured in version.json + [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] + [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] + [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha-0001")] + [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.4-alpha-0001")] + // + // SemVer 2 + // + // 2 version fields configured in version.json + [InlineData(2, "1.2", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(2, "1.2", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(2, "1.2", VersionOptions.VersionPrecision.Build, "1.2.1")] + [InlineData(2, "1.2", VersionOptions.VersionPrecision.Revision, "1.2.1.")] + // 3 version fields configured in version.json + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] + // 4 version fields configured in version.json + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] + // 2 version fields with git height in prerelease tag configured in version.json + [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] + [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] + [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.0-alpha.1")] + [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.0.0-alpha.1")] + // 3 version fields with git height in prerelease tag configured in version.json + [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] + [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] + [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha.1")] + [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.0-alpha.1")] + // 4 version fields with git height in prerelease tag configured in version.json + [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] + [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] + [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha.1")] + [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.4-alpha.1")] + public void CanSetPrecisionForNuGetPackageVersion(int semVer, string version, VersionOptions.VersionPrecision precision, string expectedPackageVersion) + { + VersionOptions workingCopyVersion = new VersionOptions + { + Version = SemanticVersion.Parse(version), + NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions + { + SemVer = semVer, + Precision = precision + } + }; + this.WriteVersionFile(workingCopyVersion); + this.InitializeSourceControl(); + var oracle = new VersionOracle(this.Context); + oracle.PublicRelease = true; + expectedPackageVersion = expectedPackageVersion.Replace("", oracle.Version.Revision.ToString()); + Assert.Equal(expectedPackageVersion, oracle.NuGetPackageVersion); + } + [Fact] public void CanSetSemVer2ForNuGetPackageVersionNonPublicRelease() { diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index b1eb6338..b93bd9d1 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -584,7 +584,7 @@ public class NuGetPackageVersionOptions : IEquatable { isFrozen = true, semVer = 1.0f, - precision = VersionPrecision.Build + precision = DefaultPrecision, }; [DebuggerBrowsable(DebuggerBrowsableState.Never)] @@ -596,6 +596,11 @@ public class NuGetPackageVersionOptions : IEquatable [DebuggerBrowsable(DebuggerBrowsableState.Never)] private VersionPrecision? precision; + /// + /// Default value for . + /// + public const VersionPrecision DefaultPrecision = VersionPrecision.Build; + /// /// Initializes a new instance of the class. /// diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index ed0cd1f7..c911c3b0 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -353,7 +353,7 @@ public IDictionary CloudBuildVersionVars /// /// Gets the version to use for NuGet packages. /// - public string NuGetPackageVersion => this.VersionOptions?.NuGetPackageVersionOrDefault.SemVerOrDefault == 1 ? this.NuGetSemVer1 : this.SemVer2; + public string NuGetPackageVersion => this.VersionOptions?.NuGetPackageVersionOrDefault.SemVerOrDefault == 1 ? this.NuGetSemVer1 : this.NuGetSemVer2; /// /// Gets the version to use for Chocolatey packages. @@ -414,8 +414,39 @@ public IDictionary CloudBuildVersionVars /// Gets a SemVer 1.0 compliant string that represents this version, including the -gCOMMITID suffix /// when is false. /// - private string NuGetSemVer1 => - $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersionSemVer1}{this.NuGetSemVer1BuildMetadata}"; + private string NuGetSemVer1 + { + get + { + var precision = this.VersionOptions?.NuGetPackageVersionOrDefault.PrecisionOrDefault ?? VersionOptions.NuGetPackageVersionOptions.DefaultPrecision; + var version = this.Version.EnsureNonNegativeComponents(); + version = ApplyVersionPrecision(version, precision); + + // If precision is set to include the 4th version component, return all 4 version fields, otherwise return 3 fields. + var fieldCount = precision >= VersionOptions.VersionPrecision.Revision ? 4 : 3; + + return $"{version.ToStringSafe(fieldCount)}{this.PrereleaseVersionSemVer1}{this.NuGetSemVer1BuildMetadata}"; + } + } + + /// + /// Gets a SemVer 2.0 compliant string that represents this version, including the -gCOMMITID suffix + /// when is false. + /// + private string NuGetSemVer2 + { + get + { + var precision = this.VersionOptions?.NuGetPackageVersionOrDefault.PrecisionOrDefault ?? VersionOptions.NuGetPackageVersionOptions.DefaultPrecision; + var version = this.Version.EnsureNonNegativeComponents(); + version = ApplyVersionPrecision(version, precision); + + // If precision is set to include the 4th version component, return all 4 version fields, otherwise return 3 fields. + var fieldCount = precision >= VersionOptions.VersionPrecision.Revision ? 4 : 3; + + return $"{version.ToStringSafe(fieldCount)}{this.PrereleaseVersion}{this.SemVer2BuildMetadata}"; + } + } /// /// Gets the build metadata that is appropriate for SemVer2 use. @@ -461,17 +492,21 @@ private static Version GetAssemblyVersion(Version version, VersionOptions? versi { // Otherwise consider precision to base the assembly version off of the main computed version. VersionOptions.VersionPrecision precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision; - - assemblyVersion = new Version( - version.Major, - precision >= VersionOptions.VersionPrecision.Minor ? version.Minor : 0, - precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0, - precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0); + assemblyVersion = ApplyVersionPrecision(version, precision); } return assemblyVersion.EnsureNonNegativeComponents(4); } + private static Version ApplyVersionPrecision(Version version, VersionOptions.VersionPrecision precision) + { + return new Version( + version.Major, + precision >= VersionOptions.VersionPrecision.Minor ? version.Minor : 0, + precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0, + precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0); + } + /// /// Replaces any macros found in a prerelease or build metadata string. /// From a6e4aebeb698f9773bde5790bb8c6e84ff96f91b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sun, 13 Feb 2022 18:27:49 +0100 Subject: [PATCH 420/704] Add additional test cases to VersionOracleTests For the test "CanSetPrecisionForNuGetPackageVersion", add test cases to verify the NuGet package version is computed correctly when a static prerelease tag is configured in version.json --- .../VersionOracleTests.cs | 70 +++++++++++++------ 1 file changed, 50 insertions(+), 20 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 19dd790d..715bee46 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -381,26 +381,41 @@ public void CanSetSemVer2ForNuGetPackageVersionPublicRelease() [InlineData(1, "1.2", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(1, "1.2", VersionOptions.VersionPrecision.Build, "1.2.1")] [InlineData(1, "1.2", VersionOptions.VersionPrecision.Revision, "1.2.1.")] - // 2 version fields configured in version.json - [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] - [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] - [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] - [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] - // 4 version fields configured in version.json - [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] - [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] - [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] - [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] + // 2 version fields and a static prerelease tag configured in version.json + [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] + [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] + [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Build, "1.2.1-alpha")] + [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Revision, "1.2.1.-alpha")] // 2 version fields with git height in prerelease tag configured in version.json [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.0-alpha-0001")] [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.0.0-alpha-0001")] + // 3 version fields configured in version.json + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] + // 3 version fields and a static prerelease tag configured in version.json + [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] + [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] + [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] + [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.1-alpha")] // 3 version fields with git height in prerelease tag configured in version.json [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha-0001")] [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.0-alpha-0001")] + // 4 version fields configured in version.json + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] + // 4 version fields and a static prerelease tag configured in version.json + [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] + [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] + [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] + [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.4-alpha")] // 4 version fields with git height in prerelease tag configured in version.json [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] @@ -414,26 +429,41 @@ public void CanSetSemVer2ForNuGetPackageVersionPublicRelease() [InlineData(2, "1.2", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(2, "1.2", VersionOptions.VersionPrecision.Build, "1.2.1")] [InlineData(2, "1.2", VersionOptions.VersionPrecision.Revision, "1.2.1.")] - // 3 version fields configured in version.json - [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] - [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] - [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] - [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] - // 4 version fields configured in version.json - [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] - [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] - [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] - [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] + // 2 version fields and a static prerelease tag configured in version.json + [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] + [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] + [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Build, "1.2.1-alpha")] + [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Revision, "1.2.1.-alpha")] // 2 version fields with git height in prerelease tag configured in version.json [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.0-alpha.1")] [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.0.0-alpha.1")] + // 3 version fields configured in version.json + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] + // 3 version fields and a static prerelease tag configured in version.json + [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] + [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] + [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] + [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.1-alpha")] // 3 version fields with git height in prerelease tag configured in version.json [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha.1")] [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.0-alpha.1")] + // 4 version fields configured in version.json + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] + [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] + // 4 version fields and a static prerelease tag configured in version.json + [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] + [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] + [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] + [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.4-alpha")] // 4 version fields with git height in prerelease tag configured in version.json [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] From 65e9b1882a8ac3c25e6b0457288209b5cf98e5c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sun, 13 Feb 2022 18:35:49 +0100 Subject: [PATCH 421/704] Fix typo in doc/versionJson.md --- doc/versionJson.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/versionJson.md b/doc/versionJson.md index 09e65202..910a03e3 100644 --- a/doc/versionJson.md +++ b/doc/versionJson.md @@ -39,7 +39,7 @@ The content of the version.json file is a JSON serialized object with these prop "gitCommitIdShortAutoMinimum": 0, // optional. Set to use the short commit ID abbreviation provided by the git repository. "nugetPackageVersion": { "semVer": 1 // optional. Set to either 1 or 2 to control how the NuGet package version string is generated. Default is 1. - "precision": "build" // optional. Use when you want to a more or less precise package version than the default major.minor.build. + "precision": "build" // optional. Use when you want to use a more or less precise package version than the default major.minor.build. }, "pathFilters": [ // optional list of paths to consider when calculating version height. From b245ff9b6602f3f0c3068438b65a94df277986f3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 16 Feb 2022 11:29:46 -0700 Subject: [PATCH 422/704] Set Platform=AnyCPU on inner P2P to satisfy MSBuild platform negotiation This avoids this warning in consumers with platform negotiation enabled: > warning MSB3982: EnableDynamicPlatformResolution is true but referenced project 'C:\Users\andarno\.nuget\packages\nerdbank.gitversioning\3.5.83-alpha-gd9ed2fe031\build\PrivateP2PCaching.proj' has no 'Platforms' metadata set. It will be built without a specified platform. --- .../build/MSBuildTargetCaching.targets | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets index 3f6a01b6..8f864fc5 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets @@ -17,22 +17,13 @@ <_BuildMetadataSnapped Include="@(BuildMetadata)" /> - - - $(NBGV_InnerGlobalProperties)Configuration=Release; - $(NBGV_InnerGlobalProperties)Platform=AnyCPU; - - - - - - GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars $(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ','); + Configuration=Release + Platform=AnyCPU @(NBGV_GlobalPropertiesToRemove) From 8a837f711324dce3d66570271c9cc3a62dc8e2d0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 17 Feb 2022 09:09:17 -0700 Subject: [PATCH 423/704] Activate msbuild 17's platform negotiation feature Not that this template repo itself requires it, but it's a great baseline to start with as it means the repo will grow nicely as it gets more complicated for real projects. --- Directory.Build.props | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index a8f35b37..935550c9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -13,6 +13,10 @@ true true + + true + true + $(MSBuildThisFileDirectory) @@ -35,7 +39,7 @@ - + From 6d43f405a40780746d9428746fbde3215c838e21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andreas=20Gr=C3=BCnwald?= Date: Sun, 13 Feb 2022 20:19:42 +0100 Subject: [PATCH 424/704] Include all four version components in the cloud build number if three or more components are set in the version file If the version in version.json specifies three or four version components, include all four version fields in the cloud build number. If three components are set in the version file, the git height is encoded as fourth component and should thus be included to make the cloud build number unique. If four components are set, include the fourth component to ensure the cloud build number is at least as precise as the value in the version file. --- .../VersionOracleTests.cs | 55 +++++++++++++++++++ src/NerdBank.GitVersioning/VersionOracle.cs | 15 ++++- 2 files changed, 67 insertions(+), 3 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 715bee46..1b121956 100644 --- a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -3,6 +3,7 @@ using System.Linq; using LibGit2Sharp; using Nerdbank.GitVersioning; +using Nerdbank.GitVersioning.ManagedGit; using Xunit; using Xunit.Abstractions; using Version = System.Version; @@ -1071,4 +1072,58 @@ public void GetVersionHeight_VeryLongHistory() this.GetVersionHeight(); } + [Theory] + // 2 version fields configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2", "1.2.1+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2", "1.2.1.")] + // 2 version fields and a static prerelease tag configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2-alpha", "1.2.1-alpha+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2-alpha", "1.2.1.-alpha")] + // 2 version fields with git height in prerelease tag configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2-alpha.{height}", "1.2-alpha.1+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2-alpha.{height}", "1.2-alpha.1")] + // 3 version fields configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3", "1.2.3.1+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3", "1.2.3.1")] + // 3 version fields and a static prerelease tag configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3-alpha", "1.2.3.1-alpha+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3-alpha", "1.2.3.1-alpha")] + // 3 version fields with git height in prerelease tag configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3-alpha.{height}", "1.2.3-alpha.1+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3-alpha.{height}", "1.2.3-alpha.1")] + // 4 version fields configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3.4", "1.2.3.4+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3.4", "1.2.3.4")] + // 4 version fields and a static prerelease tag configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3.4-alpha", "1.2.3.4-alpha+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3.4-alpha", "1.2.3.4-alpha")] + // 4 version fields with git height in prerelease tag configured in version.json + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3.4-alpha.{height}", "1.2.3.4-alpha.1+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3.4-alpha.{height}", "1.2.3.4-alpha.1")] + public void CloudBuildNumber_4thPosition(VersionOptions.CloudBuildNumberCommitWhere where, string version, string expectedCloudBuildNumber) + { + VersionOptions workingCopyVersion = new VersionOptions + { + Version = SemanticVersion.Parse(version), + CloudBuild = new VersionOptions.CloudBuildOptions + { + BuildNumber = new VersionOptions.CloudBuildNumberOptions + { + IncludeCommitId = new VersionOptions.CloudBuildNumberCommitIdOptions + { + When = VersionOptions.CloudBuildNumberCommitWhen.Always, + Where = where + } + } + } + }; + this.WriteVersionFile(workingCopyVersion); + this.InitializeSourceControl(); + var oracle = new VersionOracle(this.Context); + oracle.PublicRelease = true; + expectedCloudBuildNumber = expectedCloudBuildNumber.Replace("", GitObjectId.Parse(oracle.GitCommitId).AsUInt16().ToString()); + expectedCloudBuildNumber = expectedCloudBuildNumber.Replace("", oracle.GitCommitIdShort); + + Assert.Equal(expectedCloudBuildNumber, oracle.CloudBuildNumber); + } } diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index c911c3b0..a416e79e 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -129,11 +129,20 @@ public string CloudBuildNumber var commitIdOptions = this.CloudBuildNumberOptions.IncludeCommitIdOrDefault; bool includeCommitInfo = commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.Always || (commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.NonPublicReleaseOnly && !this.PublicRelease); - bool commitIdInRevision = includeCommitInfo && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent; bool commitIdInBuildMetadata = includeCommitInfo && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata; - Version buildNumberVersion = commitIdInRevision ? this.Version : this.SimpleVersion; + + // Include the revision in the build number if, either + // - The commit id is configured to be included as a revision or + // - 3 version fields are configured in version.json (and thus the version height is encoded as revision) or + // - 4 version fields are configured in version.json. + bool includeRevision = includeCommitInfo && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent || + this.VersionOptions?.Version?.VersionHeightPosition == SemanticVersion.Position.Revision || + this.VersionOptions?.Version?.Version.Revision != -1; + string buildNumberMetadata = FormatBuildMetadata(commitIdInBuildMetadata ? this.BuildMetadataWithCommitId : this.BuildMetadata); - return buildNumberVersion + this.PrereleaseVersion + buildNumberMetadata; + + Version buildNumberVersion = includeRevision ? this.Version : this.SimpleVersion; + return $"{buildNumberVersion}{this.PrereleaseVersion}{buildNumberMetadata}"; } } From a803831c66647bb775cf1febd2117966ad6b801d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 6 Mar 2022 07:12:33 -0700 Subject: [PATCH 425/704] Bump Microsoft.NET.Test.Sdk from 17.0.0 to 17.1.0 (#143) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.0.0 to 17.1.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v17.0.0...v17.1.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index b3fc51f0..e75f6ae8 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -11,7 +11,7 @@ - + From 25fa06401e58cdd3037106914d3e9febe230f80f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 6 Mar 2022 14:25:10 +0000 Subject: [PATCH 426/704] Bump coverlet.msbuild from 3.1.1 to 3.1.2 (#144) --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index e75f6ae8..077d8d8f 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From 4d9c33d9e4c5e263aec482aa0786bd7227280d6d Mon Sep 17 00:00:00 2001 From: Hugo Dahl Date: Wed, 2 Mar 2022 20:28:24 -0600 Subject: [PATCH 427/704] Break out of for loop on success Addresses item 1 of issue #726 --- src/Shared/Utilities.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Shared/Utilities.cs b/src/Shared/Utilities.cs index 9e375f66..c20f34a0 100644 --- a/src/Shared/Utilities.cs +++ b/src/Shared/Utilities.cs @@ -19,6 +19,7 @@ internal static void FileOperationWithRetry(Action operation) try { operation(); + break; } catch (IOException ex) when (ex.HResult == ProcessCannotAccessFileHR && retriesLeft > 0) { From b6e44c3bf9cf0162883638828caea08ccacc3f74 Mon Sep 17 00:00:00 2001 From: Hugo Dahl Date: Wed, 2 Mar 2022 20:38:28 -0600 Subject: [PATCH 428/704] Use 'File.AppendLine()' to generate output Let the 'System.IO.File' provider handle newlines between entries rather than manually inserting them Addresses item 2 of #726 --- src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs b/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs index 48ca3bbf..f3931042 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs @@ -28,7 +28,7 @@ public IReadOnlyDictionary SetCloudBuildNumber(string buildNumbe public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) { - Utilities.FileOperationWithRetry(() => File.AppendAllText(EnvironmentFile, $"{Environment.NewLine}{name}={value}{Environment.NewLine}")); + Utilities.FileOperationWithRetry(() => File.AppendAllLines(EnvironmentFile, new [] {$"{name}={value}"})); return GetDictionaryFor(name, value); } From f1581aacb92bda75bce2bd68ed44a698f2bf1884 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 8 Mar 2022 09:02:53 -0700 Subject: [PATCH 429/704] Update .NET SDK to 6.0.200 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index e2af429b..6bfbd177 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100", + "version": "6.0.200", "rollForward": "patch", "allowPrerelease": false } From cfa18ae4623dae6215f666d02acd2d7cb856a3c6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 9 Mar 2022 17:14:01 -0700 Subject: [PATCH 430/704] Re-enable transitive P2Ps Because it isn't actually required for msbuild platform negotiation. --- Directory.Build.props | 1 - 1 file changed, 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 935550c9..e70a74bb 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -15,7 +15,6 @@ true - true $(MSBuildThisFileDirectory) From be4a5a74d705d876b1f0e28debd8c49147b78e19 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Mar 2022 17:15:11 -0600 Subject: [PATCH 431/704] Fix NullReferenceException thrown when PATH is empty/missing --- src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs index f3bb3e17..7ba03cb6 100644 --- a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs +++ b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs @@ -56,7 +56,7 @@ where outerProperty.SetMethod is not null && outerProperty.GetMethod is not null // On .NET Framework (on Windows), we find native binaries by adding them to our PATH. if (this.UnmanagedDllDirectory is not null) { - string pathEnvVar = Environment.GetEnvironmentVariable("PATH"); + string pathEnvVar = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; string[] searchPaths = pathEnvVar.Split(Path.PathSeparator); if (!searchPaths.Contains(this.UnmanagedDllDirectory, StringComparer.OrdinalIgnoreCase)) { From e92074087c0087bcbdcbfe7bf86030d9f09f1bde Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 25 Mar 2022 09:22:42 -0600 Subject: [PATCH 432/704] Improve TargetFramework detection --- tools/Install-DotNetSdk.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 3c82ee2b..d1da4250 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -42,12 +42,12 @@ Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$P $projXml = [xml](Get-Content -Path $_) $pg = $projXml.Project.PropertyGroup if ($pg) { - $targetFrameworks = $pg.TargetFramework - if (!$targetFrameworks) { - $targetFrameworks = $pg.TargetFrameworks - if ($targetFrameworks) { - $targetFrameworks = $targetFrameworks -Split ';' - } + $targetFrameworks = @() + $tf = $pg.TargetFramework + $targetFrameworks += $tf + $tfs = $pg.TargetFrameworks + if ($tfs) { + $targetFrameworks = $tfs -Split ';' } } $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% { From 7e34288f4cf0fbb6f1f86c7a05199a7330b50eda Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 30 Mar 2022 07:20:08 -0600 Subject: [PATCH 433/704] Fix Install-DotNetSdk.ps1 for Windows machine-wide installations --- tools/Install-DotNetSdk.ps1 | 44 +++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 3c82ee2b..6b584f1c 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -72,6 +72,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile = Join-Path $OutDir $Uri.Segments[-1] if (!(Test-Path $OutFile)) { Write-Verbose "Downloading $Uri..." + if (!(Test-Path $OutDir)) { mkdir $OutDir } try { (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) } finally { @@ -87,12 +88,51 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { if ($Runtime) { $sdkOrRuntime = 'Runtime' } # Get the latest/actual version for the specified one - if (([Version]$Version).Build -eq -1) { + $TypedVersion = [Version]$Version + if ($TypedVersion.Build -eq -1) { $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/latest.version" -UseBasicParsing) $Version = $versionInfo[-1] } - Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-$arch.exe" -OutDir "$DotNetInstallScriptRoot" + $majorMinor = "$($TypedVersion.Major).$($TypedVersion.Minor)" + $ReleasesFile = Join-Path $DotNetInstallScriptRoot "$majorMinor\releases.json" + if (!(Test-Path $ReleasesFile)) { + Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile) + } + + $releases = Get-Content $ReleasesFile | ConvertFrom-Json + $url = $null + foreach ($release in $releases.releases) { + $filesElement = $null + if ($Runtime) { + if ($release.runtime.version -eq $Version) { + $filesElement = $release.runtime.files + } + } else { + if ($release.sdk.version -eq $Version) { + $filesElement = $release.sdk.files + } + } + + if ($filesElement) { + foreach ($file in $filesElement) { + if ($file.rid -eq "win-$arch") { + $url = $file.url + Break + } + } + + if ($url) { + Break + } + } + } + + if ($url) { + Get-FileFromWeb -Uri $url -OutDir $DotNetInstallScriptRoot + } else { + Write-Error "Unable to find release of $sdkOrRuntime v$Version" + } } Function Install-DotNet($Version, [switch]$Runtime) { From 3aeff335e600bb8968e1fd7d1eb2d9a05900c328 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 30 Mar 2022 18:13:34 -0600 Subject: [PATCH 434/704] Ignore launchSettings.json --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index d060a300..71645608 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.user *.userosscache *.sln.docstates +launchSettings.json # User-specific files (MonoDevelop/Xamarin Studio) *.userprefs From b917529de6555deb96fbcccda3ce986659259cd9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 31 Mar 2022 07:50:18 -0600 Subject: [PATCH 435/704] Replace deployments with ordinary jobs --- azure-pipelines/release.yml | 87 +++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index bfe5987c..029b654d 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -13,60 +13,51 @@ stages: - stage: GitHubRelease displayName: GitHub Release jobs: - - deployment: create + - job: create pool: vmImage: ubuntu-latest - environment: No-Approval - strategy: - runOnce: - deploy: - steps: - - download: none - - powershell: | - Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" - displayName: Set pipeline name - - task: GitHubRelease@1 - displayName: GitHub release (create) - inputs: - gitHubConnection: # TODO: fill in service connection here - repositoryName: $(Build.Repository.Name) - target: $(resources.pipeline.CI.sourceCommit) - tagSource: userSpecifiedTag - tag: v$(resources.pipeline.CI.runName) - title: v$(resources.pipeline.CI.runName) - isDraft: true # After running this step, visit the new draft release, edit, and publish. - changeLogCompareToRelease: lastNonDraftRelease - changeLogType: issueBased - changeLogLabels: | - [ - { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, - { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } - ] + steps: + - powershell: | + Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" + displayName: Set pipeline name + - task: GitHubRelease@1 + displayName: GitHub release (create) + inputs: + gitHubConnection: # TODO: fill in service connection here + repositoryName: $(Build.Repository.Name) + target: $(resources.pipeline.CI.sourceCommit) + tagSource: userSpecifiedTag + tag: v$(resources.pipeline.CI.runName) + title: v$(resources.pipeline.CI.runName) + isDraft: true # After running this step, visit the new draft release, edit, and publish. + changeLogCompareToRelease: lastNonDraftRelease + changeLogType: issueBased + changeLogLabels: | + [ + { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, + { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } + ] - stage: nuget_org displayName: nuget.org dependsOn: GitHubRelease jobs: - - deployment: push + - job: push pool: vmImage: ubuntu-latest - environment: No-Approval - strategy: - runOnce: - deploy: - steps: - - download: CI - artifact: deployables-Windows - displayName: Download deployables-Windows artifact - patterns: 'deployables-Windows/*' - - task: NuGetToolInstaller@1 - displayName: Use NuGet 5.x - inputs: - versionSpec: 5.x - - task: NuGetCommand@2 - displayName: NuGet push - inputs: - command: push - packagesToPush: $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg - nuGetFeedType: external - publishFeedCredentials: # TODO: fill in service connection here + steps: + - download: CI + artifact: deployables-Windows + displayName: Download deployables-Windows artifact + patterns: 'deployables-Windows/*' + - task: NuGetToolInstaller@1 + displayName: Use NuGet 5.x + inputs: + versionSpec: 5.x + - task: NuGetCommand@2 + displayName: NuGet push + inputs: + command: push + packagesToPush: $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg + nuGetFeedType: external + publishFeedCredentials: # TODO: fill in service connection here From efe7fddda409bb2241a6a6aacdd1a91367c1585d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 31 Mar 2022 09:15:01 -0600 Subject: [PATCH 436/704] Simplify release and CI package push --- azure-pipelines.yml | 2 +- azure-pipelines/publish-deployables.yml | 13 +--- azure-pipelines/release.yml | 90 +++++++++++-------------- 3 files changed, 41 insertions(+), 64 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a1435d91..fe8363a2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -22,7 +22,7 @@ variables: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BuildConfiguration: Release codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ - ci_feed: CI # Azure Artifacts feed name + ci_feed: https://pkgs.dev.azure.com/andrewarnott/_packaging/CI/nuget/v3/index.json # Azure Artifacts feed URL NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages jobs: diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index a4f8e593..f8c1dfc9 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -3,17 +3,6 @@ steps: displayName: Download deployables artifact: deployables-Windows -- task: NuGetToolInstaller@1 - displayName: Use NuGet 5.x - inputs: - versionSpec: 5.x - -- task: NuGetCommand@2 +- script: dotnet nuget push $(Pipeline.Workspace)/deployables-Windows/*.nupkg -s $(ci_feed) -k azdo --skip-duplicate displayName: Push packages to CI feed - inputs: - command: push - packagesToPush: $(Pipeline.Workspace)/deployables-Windows/*.nupkg - nuGetFeedType: internal - publishVstsFeed: $(ci_feed) - allowPackageConflicts: true condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 029b654d..205c514b 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -9,55 +9,43 @@ resources: tags: - auto-release -stages: -- stage: GitHubRelease - displayName: GitHub Release - jobs: - - job: create - pool: - vmImage: ubuntu-latest - steps: - - powershell: | - Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" - displayName: Set pipeline name - - task: GitHubRelease@1 - displayName: GitHub release (create) - inputs: - gitHubConnection: # TODO: fill in service connection here - repositoryName: $(Build.Repository.Name) - target: $(resources.pipeline.CI.sourceCommit) - tagSource: userSpecifiedTag - tag: v$(resources.pipeline.CI.runName) - title: v$(resources.pipeline.CI.runName) - isDraft: true # After running this step, visit the new draft release, edit, and publish. - changeLogCompareToRelease: lastNonDraftRelease - changeLogType: issueBased - changeLogLabels: | - [ - { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, - { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } - ] +variables: +- group: Publishing secrets -- stage: nuget_org - displayName: nuget.org - dependsOn: GitHubRelease - jobs: - - job: push - pool: - vmImage: ubuntu-latest - steps: - - download: CI - artifact: deployables-Windows - displayName: Download deployables-Windows artifact - patterns: 'deployables-Windows/*' - - task: NuGetToolInstaller@1 - displayName: Use NuGet 5.x - inputs: - versionSpec: 5.x - - task: NuGetCommand@2 - displayName: NuGet push - inputs: - command: push - packagesToPush: $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg - nuGetFeedType: external - publishFeedCredentials: # TODO: fill in service connection here +jobs: +- job: release + pool: + vmImage: ubuntu-latest + steps: + - checkout: none + - powershell: Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" + displayName: Set pipeline name + - task: UseDotNet@2 + displayName: Install .NET SDK + inputs: + packageType: sdk + version: 6.x + - task: GitHubRelease@1 + displayName: GitHub release (create) + inputs: + gitHubConnection: # TODO: fill in service connection here + repositoryName: $(Build.Repository.Name) + target: $(resources.pipeline.CI.sourceCommit) + tagSource: userSpecifiedTag + tag: v$(resources.pipeline.CI.runName) + title: v$(resources.pipeline.CI.runName) + isDraft: true # After running this step, visit the new draft release, edit, and publish. + changeLogCompareToRelease: lastNonDraftRelease + changeLogType: issueBased + changeLogLabels: | + [ + { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, + { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } + ] + - download: CI + artifact: deployables-Windows + displayName: Download deployables-Windows artifact + patterns: 'deployables-Windows/*' + - script: dotnet nuget push $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg -s https://api.nuget.org/v3/index.json --api-key $(NuGetOrgApiKey) --skip-duplicate + displayName: Push nuget packages + condition: and(succeeded(), ne(variables['NuGetOrgApiKey'], '')) From 52dcdc720bd044be13fa99e29d6d94b94d120559 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 31 Mar 2022 09:28:40 -0600 Subject: [PATCH 437/704] GitHub release enhancements - Set GitHub release prerelease flag - Include deployables as release artifacts --- azure-pipelines/release.yml | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 205c514b..437ee65b 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -18,13 +18,23 @@ jobs: vmImage: ubuntu-latest steps: - checkout: none - - powershell: Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" - displayName: Set pipeline name + - powershell: | + Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" + if ('$(resources.pipeline.CI.runName)'.Contains('-')) { + Write-Host "##vso[task.setvariable variable=IsPrerelease]true" + } else { + Write-Host "##vso[task.setvariable variable=IsPrerelease]false" + } + displayName: Set up pipeline - task: UseDotNet@2 displayName: Install .NET SDK inputs: packageType: sdk version: 6.x + - download: CI + artifact: deployables-Windows + displayName: Download deployables-Windows artifact + patterns: 'deployables-Windows/*' - task: GitHubRelease@1 displayName: GitHub release (create) inputs: @@ -35,6 +45,8 @@ jobs: tag: v$(resources.pipeline.CI.runName) title: v$(resources.pipeline.CI.runName) isDraft: true # After running this step, visit the new draft release, edit, and publish. + isPreRelease: $(IsPrerelease) + assets: $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg changeLogCompareToRelease: lastNonDraftRelease changeLogType: issueBased changeLogLabels: | @@ -42,10 +54,6 @@ jobs: { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } ] - - download: CI - artifact: deployables-Windows - displayName: Download deployables-Windows artifact - patterns: 'deployables-Windows/*' - script: dotnet nuget push $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg -s https://api.nuget.org/v3/index.json --api-key $(NuGetOrgApiKey) --skip-duplicate displayName: Push nuget packages condition: and(succeeded(), ne(variables['NuGetOrgApiKey'], '')) From 05b8a491c03a9acb4268477a3e187a4c8ec9769e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 31 Mar 2022 10:37:02 -0600 Subject: [PATCH 438/704] Increase test timeout to 60s --- azure-pipelines/dotnet-test-cloud.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index 440bd890..08cd4d1f 100755 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -14,7 +14,7 @@ dotnet test $RepoRoot ` -c $Configuration ` --filter "TestCategory!=FailsInCloudTest" ` -p:CollectCoverage=true ` - --blame-hang-timeout 30s ` + --blame-hang-timeout 60s ` --blame-crash ` -bl:"$ArtifactStagingFolder/build_logs/test.binlog" ` --diag "$ArtifactStagingFolder/test_logs/diag.log;TraceLevel=info" ` From 34262db00810c6f0e48dfe12efbea0a69b1acf89 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 31 Mar 2022 13:34:19 -0600 Subject: [PATCH 439/704] Add recognition for RIDs in test paths --- azure-pipelines/dotnet-test-cloud.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index 08cd4d1f..7d5a4350 100755 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -27,8 +27,12 @@ Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { if ($PublishResults) { $x = [xml](Get-Content -Path $_) $storage = $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')[0].storage -replace '\\','/' - if ($storage -match '/(?[^/]+)/(?[^/]+)\.dll$') { - $runTitle = "$($matches.lib) ($($matches.tfm), $Agent)" + if ($storage -match '/(?net[^/]+)/(?:(?[^/]+)/)?(?[^/]+)\.dll$') { + if ($matches.rid) { + $runTitle = "$($matches.lib) ($($matches.tfm), $($matches.rid), $Agent)" + } else { + $runTitle = "$($matches.lib) ($($matches.tfm), $Agent)" + } } else { $unknownCounter += 1; $runTitle = "unknown$unknownCounter ($Agent)"; From 9d0b31316dbb66265441a80686c63dc7b1d45351 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 10 Apr 2022 09:19:59 -0600 Subject: [PATCH 440/704] Use appropriate slash for the agent OS Fixes #150 --- azure-pipelines/publish-deployables.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index f8c1dfc9..9ccdc29e 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -3,6 +3,6 @@ steps: displayName: Download deployables artifact: deployables-Windows -- script: dotnet nuget push $(Pipeline.Workspace)/deployables-Windows/*.nupkg -s $(ci_feed) -k azdo --skip-duplicate +- powershell: dotnet nuget push "$(Resolve-Path '$(Pipeline.Workspace)\deployables-Windows\')*.nupkg" -s $(ci_feed) -k azdo --skip-duplicate displayName: Push packages to CI feed condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) From 55d14a51bf6c74e102a9a189cc950032ce92a514 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 10 Apr 2022 16:28:54 +0000 Subject: [PATCH 441/704] Bump minimist from 1.2.5 to 1.2.6 in /src/nerdbank-gitversioning.npm Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6. - [Release notes](https://github.com/substack/minimist/releases) - [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6) --- updated-dependencies: - dependency-name: minimist dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index c66da78b..07f11447 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -1762,9 +1762,9 @@ minimatch@^3.0.4: brace-expansion "^1.1.7" minimist@^1.1.0: - version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" - integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== + version "1.2.6" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" + integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== mixin-deep@^1.2.0: version "1.3.2" From 3f11fb5dce7ba03f3753099c1314f15c9bc47b72 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 11 Apr 2022 13:46:40 -0600 Subject: [PATCH 442/704] Update devcontainer Dockerfile to match global.json --- .devcontainer/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index c47acfaa..234db6d1 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0.100-focal +FROM mcr.microsoft.com/dotnet/sdk:6.0.200-focal # Installing mono makes `dotnet test` work without errors even for net472. # But installing it takes a long time, so it's excluded by default. From dd60e837b038dc6964181712275085332f5dfd83 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 11 Apr 2022 17:41:52 -0600 Subject: [PATCH 443/704] Remove explicit Microsoft.NETFramework.ReferenceAssemblies PackageReference --- Directory.Build.props | 1 - 1 file changed, 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index e70a74bb..ecb971a7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -36,7 +36,6 @@ - From 09516ca14922aadc4474d3f2e05cdef8a168dd75 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 12 Apr 2022 06:18:04 -0600 Subject: [PATCH 444/704] Tolerate trx files with test run failures --- azure-pipelines/dotnet-test-cloud.ps1 | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index 7d5a4350..877f11ed 100755 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -26,16 +26,20 @@ Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { if ($PublishResults) { $x = [xml](Get-Content -Path $_) - $storage = $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')[0].storage -replace '\\','/' - if ($storage -match '/(?net[^/]+)/(?:(?[^/]+)/)?(?[^/]+)\.dll$') { + $runTitle = $null + if ($x.TestRun.TestDefinitions -and $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')) { + $storage = $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')[0].storage -replace '\\','/' + if ($storage -match '/(?net[^/]+)/(?:(?[^/]+)/)?(?[^/]+)\.dll$') { if ($matches.rid) { $runTitle = "$($matches.lib) ($($matches.tfm), $($matches.rid), $Agent)" } else { $runTitle = "$($matches.lib) ($($matches.tfm), $Agent)" } - } else { - $unknownCounter += 1; - $runTitle = "unknown$unknownCounter ($Agent)"; + } + } + if (!$runTitle) { + $unknownCounter += 1; + $runTitle = "unknown$unknownCounter ($Agent)"; } Write-Host "##vso[results.publish type=VSTest;runTitle=$runTitle;publishRunAttachments=true;resultFiles=$_;failTaskOnFailedTests=true;testRunSystem=VSTS - PTR;]" From e21c1c1653f89510c77fc4f077d4fb4c2acc333a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 12 Apr 2022 08:30:10 -0600 Subject: [PATCH 445/704] Improve pipeline verbosity --- azure-pipelines/artifacts/_stage_all.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index 87421d56..e4954c13 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -1,7 +1,7 @@ # This script links all the artifacts described by _all.ps1 # into a staging directory, reading for uploading to a cloud build artifact store. # It returns a sequence of objects with Name and Path properties. - +[CmdletBinding()] param ( [string]$ArtifactNameSuffix ) @@ -21,7 +21,6 @@ function Create-SymbolicLink { if (Test-Path $Link) { Remove-Item $Link } $LinkContainer = Split-Path $Link -Parent if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer } - Write-Verbose "Linking $Link to $Target" if ($IsMacOS -or $IsLinux) { ln $Target $Link | Out-Null } else { From 0ac22f889f6d001ba5e2e9b6a2ccecb6f393bc84 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 14 Apr 2022 07:01:18 -0600 Subject: [PATCH 446/704] Document how to create a merge commit in a Library.Template based repo --- README.md | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/README.md b/README.md index 22d1091e..0f9715f3 100644 --- a/README.md +++ b/README.md @@ -36,3 +36,48 @@ Further customize your repo by: 1. Verify the license is suitable for your goal as it appears in the LICENSE and stylecop.json files and the Directory.Build.props file's `PackageLicenseExpression` property. 1. Reset or replace the badges at the top of this file. + +### Maintaining your repo based on this template + +The best way to keep your repo in sync with this template's evolving features and best practices is to periodically merge the template into your repo: + +```ps1 +git checkout main # your default branch +git pull # make sure you're at tip +git fetch libtemplate # fetch latest Library.Template +git merge libtemplate/main +``` + +There will frequently be merge conflicts to work out, but they will be easier to resolve than running the `Apply-Template.ps1` script every time, which simply blows away all your local changes with the latest from the template. + +If you do not already have Library.Template history in your repo or have never completed a merge before, the above steps may produce errors. +To get it working the first time, follow these steps: + +```ps1 +git remote add libtemplate https://github.com/AArnott/Library.Template.git +git fetch libtemplate +``` + +If the `git merge` step described earlier still fails for you, you may need to artificially create your first merge. +First, you must have a local clone of Library.Template on your box: + +```ps1 +git clone https://github.com/AArnott/Library.Template.git +``` + +Make sure you have either `main` checked out in that clone, as appropriate to match. +Use `git rev-parse HEAD` within the Library.Template repo and record the resulting commit as we'll use it later. + +Run the `Apply-Template.ps1` script, passing in the path to your own Library.Template-based repo. This will blow away most customizations you may have made to your repo's build authoring. You should *carefully* review all changes to your repo, staging those changes that you want to keep and reverting those that remove customizations you made. + +Now it's time to commit your changes. We do this in a very low-level way in order to have git record this as a *merge* commit even though it didn't start as a merge. +By doing this, git will allow future merges from `libtemplate/main` and only new changes will be brought down, which will be much easier than the `Apply-Template.ps1` script you just ran. +We create the merge commit with these commands: + +1. Be sure to have staged or reverted all the changes in your repo. +1. Run `git write-tree` within your repo. This will print out a git tree hash. +1. Run `git commit-tree -p HEAD -p A B -m "Merged latest Library.Template"`, where `A` is the output from `git rev-parse HEAD` that you recorded earlier, and `B` is the output from your prior `git write-tree` command. +1. Run `git merge X` where `X` is the output of the `git commit-tree` command. + +Congratulations. You're all done. +Next time you want to sync to latest from Library.Template, you can the simple `git merge` steps given at the start of this section. From 19515d7ca90ca669fa4c874af46977b7a3ebd6aa Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 14 Apr 2022 09:36:30 -0600 Subject: [PATCH 447/704] Protect against misapplication of the Apply-Template script --- Apply-Template.ps1 | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Apply-Template.ps1 b/Apply-Template.ps1 index 0d3f3d8e..d659670b 100644 --- a/Apply-Template.ps1 +++ b/Apply-Template.ps1 @@ -15,6 +15,20 @@ Param( [string]$Path ) +Push-Location $Path +try { + # Look for our own initial commit in the target repo's history. + # If it's there, they've already switched to using git merge to freshen up. + # Using Apply-Template would just complicate future merges, so block it. + git log 05f49ce799c1f9cc696d53eea89699d80f59f833 ^HEAD | Out-Null + if ($LASTEXITCODE -eq 0) { + Write-Error 'The target repo already has Library.Template history merged into it. Use `git merge` instead of this script to freshen your repo. See the README.md file for details.' + exit 1 + } +} finally { + Pop-Location +} + Write-Host "Updating $Path" robocopy /mir $PSScriptRoot/azure-pipelines $Path/azure-pipelines robocopy /mir $PSScriptRoot/.devcontainer $Path/.devcontainer From 86a18ec2dd3772eefd6ef5d35ad2520382fe8d9c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 23 Apr 2022 10:02:34 -0600 Subject: [PATCH 448/704] Ignore .lutconfig files --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 71645608..65f94776 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ *.user *.userosscache *.sln.docstates +*.lutconfig launchSettings.json # User-specific files (MonoDevelop/Xamarin Studio) From b656d1058f82d10de8e43e1c49f151f7ff4e3f88 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 26 Apr 2022 15:57:11 -0600 Subject: [PATCH 449/704] Clarify nuget push task --- azure-pipelines/release.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 437ee65b..6690cccf 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -55,5 +55,5 @@ jobs: { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } ] - script: dotnet nuget push $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg -s https://api.nuget.org/v3/index.json --api-key $(NuGetOrgApiKey) --skip-duplicate - displayName: Push nuget packages + displayName: Push packages to nuget.org condition: and(succeeded(), ne(variables['NuGetOrgApiKey'], '')) From 89eb31fe635d2b6ea1a2eddbd2411d4779cf4940 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 07:45:35 -0600 Subject: [PATCH 450/704] Update NPM package dependencies --- src/nerdbank-gitversioning.npm/package.json | 16 +- src/nerdbank-gitversioning.npm/ts/asyncio.ts | 2 +- src/nerdbank-gitversioning.npm/yarn.lock | 353 ++++++++++++------- 3 files changed, 233 insertions(+), 138 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/package.json b/src/nerdbank-gitversioning.npm/package.json index 05ae84d1..29aca42b 100644 --- a/src/nerdbank-gitversioning.npm/package.json +++ b/src/nerdbank-gitversioning.npm/package.json @@ -25,19 +25,19 @@ ], "devDependencies": { "@types/camel-case": "^1.2.1", - "@types/node": "^13.11.0", - "del": "^5.1.0", + "@types/node": "^17.0.30", + "del": "^6.0.0", "gulp": "^4.0.2", - "gulp-cli": "^2.2.0", - "gulp-sourcemaps": "2.6.5", - "gulp-typescript": "^5.0.0", + "gulp-cli": "^2.3.0", + "gulp-sourcemaps": "3.0.0", + "gulp-typescript": "^5.0.1", "gulp-util": "^3.0.8", - "merge2": "^1.3.0", + "merge2": "^1.4.1", "path": "^0.12.7", - "typescript": "^3.3.1" + "typescript": "^4.6.4" }, "dependencies": { - "camel-case": "^4.1.1" + "camel-case": "^4.1.2" }, "scripts": { "build": "gulp" diff --git a/src/nerdbank-gitversioning.npm/ts/asyncio.ts b/src/nerdbank-gitversioning.npm/ts/asyncio.ts index 7ade8dd4..b560c96c 100644 --- a/src/nerdbank-gitversioning.npm/ts/asyncio.ts +++ b/src/nerdbank-gitversioning.npm/ts/asyncio.ts @@ -8,7 +8,7 @@ export function existsAsync(path: string) { export function mkdirAsync(path: string) { return new Promise((resolve, reject) => fs.mkdir(path, err => { - if (err) { reject(err); } else { resolve() } + if (err) { reject(err); } else { resolve(null) } })); } diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index 07f11447..637e08d0 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -2,18 +2,18 @@ # yarn lockfile v1 -"@gulp-sourcemaps/identity-map@1.X": - version "1.0.2" - resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-1.0.2.tgz#1e6fe5d8027b1f285dc0d31762f566bccd73d5a9" - integrity sha512-ciiioYMLdo16ShmfHBXJBOFm3xPC4AuwO4xeRpFeHz7WK9PYsWCmigagG2XyzZpubK4a3qNKoUBDhbzHfa50LQ== +"@gulp-sourcemaps/identity-map@^2.0.1": + version "2.0.1" + resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/identity-map/-/identity-map-2.0.1.tgz#a6e8b1abec8f790ec6be2b8c500e6e68037c0019" + integrity sha512-Tb+nSISZku+eQ4X1lAkevcQa+jknn/OVUgZ3XCxEKIsLsqYuPoJwJOPQeaOk75X3WPftb29GWY1eqE7GLsXb1Q== dependencies: - acorn "^5.0.3" - css "^2.2.1" - normalize-path "^2.1.1" + acorn "^6.4.1" + normalize-path "^3.0.0" + postcss "^7.0.16" source-map "^0.6.0" - through2 "^2.0.3" + through2 "^3.0.1" -"@gulp-sourcemaps/map-sources@1.X": +"@gulp-sourcemaps/map-sources@^1.0.0": version "1.0.0" resolved "https://registry.yarnpkg.com/@gulp-sourcemaps/map-sources/-/map-sources-1.0.0.tgz#890ae7c5d8c877f6d384860215ace9d7ec945bda" integrity sha1-iQrnxdjId/bThIYCFazp1+yUW9o= @@ -49,34 +49,15 @@ dependencies: camel-case "*" -"@types/events@*": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" - integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== - -"@types/glob@^7.1.1": - version "7.1.1" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" - integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== - dependencies: - "@types/events" "*" - "@types/minimatch" "*" - "@types/node" "*" - -"@types/minimatch@*": - version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" - integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== - -"@types/node@*", "@types/node@^13.11.0": - version "13.11.0" - resolved "https://registry.yarnpkg.com/@types/node/-/node-13.11.0.tgz#390ea202539c61c8fa6ba4428b57e05bc36dc47b" - integrity sha512-uM4mnmsIIPK/yeO+42F2RQhGUIs39K2RFmugcJANppXe6J1nvH87PvzPZYpza7Xhhs8Yn9yIAVdLZ84z61+0xQ== +"@types/node@^17.0.30": + version "17.0.30" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.30.tgz#2c6e8512acac70815e8176aa30c38025067880ef" + integrity sha512-oNBIZjIqyHYP8VCNAV9uEytXVeXG2oR0w9lgAXro20eugRQfY002qr3CUl6BAe+Yf/z3CRjPdz27Pu6WWtuSRw== -acorn@5.X, acorn@^5.0.3: - version "5.7.4" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.4.tgz#3e8d8a9947d0599a1796d10225d7432f4a4acf5e" - integrity sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg== +acorn@^6.4.1: + version "6.4.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" + integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== aggregate-error@^3.0.0: version "3.0.1" @@ -329,7 +310,7 @@ braces@^2.3.1, braces@^2.3.2: split-string "^3.0.2" to-regex "^3.0.1" -braces@^3.0.1: +braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -361,7 +342,7 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -camel-case@*, camel-case@^4.1.1: +camel-case@*: version "4.1.1" resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.1.tgz#1fc41c854f00e2f7d0139dfeba1542d6896fe547" integrity sha512-7fa2WcG4fYFkclIvEmxBbTvmibwF2/agfEBc6q3lOpVu0A13ltLsA+Hr/8Hp6kp5f+G7hKi6t8lys6XxP+1K6Q== @@ -369,6 +350,14 @@ camel-case@*, camel-case@^4.1.1: pascal-case "^3.1.1" tslib "^1.10.0" +camel-case@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-4.1.2.tgz#9728072a954f805228225a6deea6b38461e1bd5a" + integrity sha512-gxGWBrTT1JuMx6R+o5PTXMmUnhnVzLQ9SNutD4YqKtI6ap897t3tKECYla6gCWEkplXnlNybEkZg9GEGxKFCgw== + dependencies: + pascal-case "^3.1.2" + tslib "^2.0.3" + camelcase@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" @@ -509,7 +498,14 @@ concat-stream@^1.6.0: readable-stream "^2.2.2" typedarray "^0.0.6" -convert-source-map@1.X, convert-source-map@^1.5.0: +convert-source-map@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.8.0.tgz#f3373c32d21b4d780dd8004514684fb791ca4369" + integrity sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA== + dependencies: + safe-buffer "~5.1.1" + +convert-source-map@^1.5.0: version "1.7.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== @@ -534,15 +530,14 @@ core-util-is@~1.0.0: resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -css@2.X, css@^2.2.1: - version "2.2.4" - resolved "https://registry.yarnpkg.com/css/-/css-2.2.4.tgz#c646755c73971f2bba6a601e2cf2fd71b1298929" - integrity sha512-oUnjmWpy0niI3x/mPL8dVEI1l7MnG3+HHyRPHf+YFSbK+svOhXpmSOcDURUh2aOCgl2grzrOPt1nHLuCVFULLw== +css@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/css/-/css-3.0.0.tgz#4447a4d58fdd03367c516ca9f64ae365cee4aa5d" + integrity sha512-DG9pFfwOrzc+hawpmqX/dHYHJG+Bsdb0klhyi1sDneOgGOXy9wQIC8hzyVp1e4NRYDBdxcylvywPkkXCHAzTyQ== dependencies: - inherits "^2.0.3" + inherits "^2.0.4" source-map "^0.6.1" - source-map-resolve "^0.5.2" - urix "^0.1.0" + source-map-resolve "^0.6.0" d@1, d@^1.0.1: version "1.0.1" @@ -557,7 +552,7 @@ dateformat@^2.0.0: resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-2.2.0.tgz#4065e2013cf9fb916ddfd82efb506ad4c6769062" integrity sha1-QGXiATz5+5Ft39gu+1Bq1MZ2kGI= -debug-fabulous@1.X: +debug-fabulous@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/debug-fabulous/-/debug-fabulous-1.1.0.tgz#af8a08632465224ef4174a9f06308c3c2a1ebc8e" integrity sha512-GZqvGIgKNlUnHUPQhepnUZFIMoi3dgZKQBzKDeL2g7oJF9SNAji/AAu36dusFUas0O+pae74lNeoIPHqXWDkLg== @@ -631,18 +626,18 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -del@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/del/-/del-5.1.0.tgz#d9487c94e367410e6eff2925ee58c0c84a75b3a7" - integrity sha512-wH9xOVHnczo9jN2IW68BabcecVPxacIA3g/7z6vhSU/4stOKQzeCRK0yD0A24WiAAUJmmVpWqrERcTxnLo3AnA== +del@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952" + integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ== dependencies: - globby "^10.0.1" - graceful-fs "^4.2.2" + globby "^11.0.1" + graceful-fs "^4.2.4" is-glob "^4.0.1" is-path-cwd "^2.2.0" - is-path-inside "^3.0.1" - p-map "^3.0.0" - rimraf "^3.0.0" + is-path-inside "^3.0.2" + p-map "^4.0.0" + rimraf "^3.0.2" slash "^3.0.0" detect-file@^1.0.0: @@ -650,7 +645,7 @@ detect-file@^1.0.0: resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7" integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc= -detect-newline@2.X: +detect-newline@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= @@ -821,17 +816,16 @@ fancy-log@^1.1.0, fancy-log@^1.3.2: parse-node-version "^1.0.0" time-stamp "^1.0.0" -fast-glob@^3.0.3: - version "3.2.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.2.tgz#ade1a9d91148965d4bf7c51f72e1ca662d32e63d" - integrity sha512-UDV82o4uQyljznxwMxyVRJgZZt3O5wENYojjzbaGEGZgeOxkLFf+V4cnUD+krzb2F72E18RhamkMZ7AdeggF7A== +fast-glob@^3.2.9: + version "3.2.11" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" + integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.0" + glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.2" - picomatch "^2.2.1" + micromatch "^4.0.4" fastq@^1.6.0: version "1.7.0" @@ -977,10 +971,10 @@ glob-parent@^3.1.0: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.1.0: - version "5.1.1" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.1.tgz#b6c1ef417c4e5663ea498f1c45afac6916bbc229" - integrity sha512-FnI+VGOpnlGHWZxthPGR+QhR78fuiK0sNLkHQv+bL9fQi57lNNdquIbna/WrfROrolq8GK5Ek6BiMwqL/voRYQ== +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" @@ -1044,18 +1038,16 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globby@^10.0.1: - version "10.0.2" - resolved "https://registry.yarnpkg.com/globby/-/globby-10.0.2.tgz#277593e745acaa4646c3ab411289ec47a0392543" - integrity sha512-7dUi7RvCoT/xast/o/dLN53oqND4yk0nsHkhRgn9w65C4PofCLOoJ39iSOg+qVDdWQPIEj+eszMHQ+aLVwwQSg== +globby@^11.0.1: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== dependencies: - "@types/glob" "^7.1.1" array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.0.3" - glob "^7.1.3" - ignore "^5.1.1" - merge2 "^1.2.3" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" slash "^3.0.0" glogg@^1.0.0: @@ -1065,11 +1057,16 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" -graceful-fs@4.X, graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.2: +graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: version "4.2.3" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== +graceful-fs@^4.2.4: + version "4.2.10" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" + integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== + gulp-cli@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.2.0.tgz#5533126eeb7fe415a7e3e84a297d334d5cf70ebc" @@ -1094,24 +1091,48 @@ gulp-cli@^2.2.0: v8flags "^3.0.1" yargs "^7.1.0" -gulp-sourcemaps@2.6.5: - version "2.6.5" - resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-2.6.5.tgz#a3f002d87346d2c0f3aec36af7eb873f23de8ae6" - integrity sha512-SYLBRzPTew8T5Suh2U8jCSDKY+4NARua4aqjj8HOysBh2tSgT9u4jc1FYirAdPx1akUxxDeK++fqw6Jg0LkQRg== - dependencies: - "@gulp-sourcemaps/identity-map" "1.X" - "@gulp-sourcemaps/map-sources" "1.X" - acorn "5.X" - convert-source-map "1.X" - css "2.X" - debug-fabulous "1.X" - detect-newline "2.X" - graceful-fs "4.X" - source-map "~0.6.0" - strip-bom-string "1.X" - through2 "2.X" - -gulp-typescript@^5.0.0: +gulp-cli@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.3.0.tgz#ec0d380e29e52aa45e47977f0d32e18fd161122f" + integrity sha512-zzGBl5fHo0EKSXsHzjspp3y5CONegCm8ErO5Qh0UzFzk2y4tMvzLWhoDokADbarfZRL2pGpRp7yt6gfJX4ph7A== + dependencies: + ansi-colors "^1.0.1" + archy "^1.0.0" + array-sort "^1.0.0" + color-support "^1.1.3" + concat-stream "^1.6.0" + copy-props "^2.0.1" + fancy-log "^1.3.2" + gulplog "^1.0.0" + interpret "^1.4.0" + isobject "^3.0.1" + liftoff "^3.1.0" + matchdep "^2.0.0" + mute-stdout "^1.0.0" + pretty-hrtime "^1.0.0" + replace-homedir "^1.0.0" + semver-greatest-satisfied-range "^1.1.0" + v8flags "^3.2.0" + yargs "^7.1.0" + +gulp-sourcemaps@3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/gulp-sourcemaps/-/gulp-sourcemaps-3.0.0.tgz#2e154e1a2efed033c0e48013969e6f30337b2743" + integrity sha512-RqvUckJkuYqy4VaIH60RMal4ZtG0IbQ6PXMNkNsshEGJ9cldUPRb/YCgboYae+CLAs1HQNb4ADTKCx65HInquQ== + dependencies: + "@gulp-sourcemaps/identity-map" "^2.0.1" + "@gulp-sourcemaps/map-sources" "^1.0.0" + acorn "^6.4.1" + convert-source-map "^1.0.0" + css "^3.0.0" + debug-fabulous "^1.0.0" + detect-newline "^2.0.0" + graceful-fs "^4.0.0" + source-map "^0.6.0" + strip-bom-string "^1.0.0" + through2 "^2.0.0" + +gulp-typescript@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/gulp-typescript/-/gulp-typescript-5.0.1.tgz#96c6565a6eb31e08c2aae1c857b1a079e6226d94" integrity sha512-YuMMlylyJtUSHG1/wuSVTrZp60k1dMEFKYOvDf7OvbAJWrDtxxD4oZon4ancdWwzjj30ztiidhe4VXJniF0pIQ== @@ -1226,10 +1247,10 @@ hosted-git-info@^2.1.4: resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -ignore@^5.1.1: - version "5.1.4" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf" - integrity sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A== +ignore@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" + integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== indent-string@^4.0.0: version "4.0.0" @@ -1244,7 +1265,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1264,6 +1285,11 @@ interpret@^1.1.0: resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== +interpret@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.4.0.tgz#665ab8bc4da27a774a40584e812e3e0fa45b1a1e" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + invert-kv@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" @@ -1405,10 +1431,10 @@ is-path-cwd@^2.2.0: resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== -is-path-inside@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.2.tgz#f5220fc82a3e233757291dddc9c5877f2a1f3017" - integrity sha512-/2UGPSgmtqwo1ktx8NDHjuPwZWmHhO+gj0f93EkhLB5RgW9RZevWYYlIkS6zePc6U2WpOdQYIwHe9YC4DWEBVg== +is-path-inside@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" @@ -1672,6 +1698,13 @@ lower-case@^2.0.1: dependencies: tslib "^1.10.0" +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + lru-queue@0.1: version "0.1.0" resolved "https://registry.yarnpkg.com/lru-queue/-/lru-queue-0.1.0.tgz#2738bd9f0d3cf4f84490c5736c48699ac632cda3" @@ -1722,11 +1755,16 @@ memoizee@0.4.X: next-tick "1" timers-ext "^0.1.5" -merge2@^1.2.3, merge2@^1.3.0: +merge2@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81" integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw== +merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" @@ -1746,13 +1784,13 @@ micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4: snapdragon "^0.8.1" to-regex "^3.0.2" -micromatch@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.2.tgz#4fcb0999bf9fbc2fcbdd212f6d629b9a56c39259" - integrity sha512-y7FpHSbMUMoyPbYUSzO6PaZ6FyRnQOpHuKwbo1G+Knck95XVU4QAiKdGEnj5wwoS7PlOgthX/09u5iFJ+aYf5Q== +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== dependencies: - braces "^3.0.1" - picomatch "^2.0.5" + braces "^3.0.2" + picomatch "^2.3.1" minimatch@^3.0.4: version "3.0.4" @@ -1836,6 +1874,14 @@ no-case@^3.0.3: lower-case "^2.0.1" tslib "^1.10.0" +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + normalize-package-data@^2.3.2: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -1965,10 +2011,10 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -p-map@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" - integrity sha512-d3qXVTF/s+W+CdJ5A29wywV2n8CQQYahlgz2bFiA+4eVNJbHJodPZ+/gXwPGh0bOqA+j8S+6+ckmvLGPk1QpxQ== +p-map@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: aggregate-error "^3.0.0" @@ -2006,6 +2052,14 @@ pascal-case@^3.1.1: no-case "^3.0.3" tslib "^1.10.0" +pascal-case@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-3.1.2.tgz#b48e0ef2b98e205e7c1dae747d0b1508237660eb" + integrity sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + pascalcase@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" @@ -2067,10 +2121,15 @@ path@^0.12.7: process "^0.11.1" util "^0.10.3" -picomatch@^2.0.5, picomatch@^2.2.1: - version "2.2.2" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.2.tgz#21f333e9b6b8eaff02468f5146ea406d345f4dad" - integrity sha512-q0M/9eZHzmr0AulXyPwNfZjtwZ/RBZlbN3K3CErVrk50T2ASYI7Bye0EvekFY3IP1Nt2DHu0re+V2ZHIpMkuWg== +picocolors@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-0.2.1.tgz#570670f793646851d1ba135996962abad587859f" + integrity sha512-cMlDqaLEqfSaW8Z7N5Jw+lyIW869EzT73/F5lhtY9cLGoVxSXznfgfXMO0Z5K0o0Q2TkTXq+0KFsdnSe3jDViA== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== pify@^2.0.0: version "2.3.0" @@ -2104,6 +2163,14 @@ posix-character-classes@^0.1.0: resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= +postcss@^7.0.16: + version "7.0.39" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.39.tgz#9624375d965630e2e1f2c02a935c82a59cb48309" + integrity sha512-yioayjNbHn6z1/Bywyb2Y4s3yvDAeXGOyxqD+LnVOinq6Mdmd++SW2wUNVzavyyHxd6+DxzWGIuosg6P1Rj8uA== + dependencies: + picocolors "^0.2.1" + source-map "^0.6.1" + pretty-hrtime@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz#b7e3ea42435a4c9b2759d99e0f201eb195802ee1" @@ -2307,7 +2374,7 @@ reusify@^1.0.4: resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@^3.0.0: +rimraf@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== @@ -2398,7 +2465,7 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: +source-map-resolve@^0.5.0: version "0.5.3" resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== @@ -2409,6 +2476,14 @@ source-map-resolve@^0.5.0, source-map-resolve@^0.5.2: source-map-url "^0.4.0" urix "^0.1.0" +source-map-resolve@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.6.0.tgz#3d9df87e236b53f16d01e58150fc7711138e5ed2" + integrity sha512-KXBr9d/fO/bWo97NXsPIAW1bFSBOuCnjbNTBMO7N59hsv5i9yzRDfcYwwt0l04+VqnKC+EwzvJZIP/qkuMgR/w== + dependencies: + atob "^2.1.2" + decode-uri-component "^0.2.0" + source-map-url@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" @@ -2419,7 +2494,7 @@ source-map@^0.5.6: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= -source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0: +source-map@^0.6.0, source-map@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== @@ -2525,7 +2600,7 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" -strip-bom-string@1.X: +strip-bom-string@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/strip-bom-string/-/strip-bom-string-1.0.0.tgz#e5211e9224369fbb81d633a2f00044dc8cedad92" integrity sha1-5SEekiQ2n7uB1jOi8ABE3IztrZI= @@ -2558,7 +2633,7 @@ through2-filter@^3.0.0: through2 "~2.0.0" xtend "~4.0.0" -through2@2.X, through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: +through2@^2.0.0, through2@^2.0.3, through2@~2.0.0: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -2573,6 +2648,14 @@ through2@^3.0.0: dependencies: readable-stream "2 || 3" +through2@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" + integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== + dependencies: + inherits "^2.0.4" + readable-stream "2 || 3" + time-stamp@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/time-stamp/-/time-stamp-1.1.0.tgz#764a5a11af50561921b133f3b44e618687e0f5c3" @@ -2638,6 +2721,11 @@ tslib@^1.10.0: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== +tslib@^2.0.3: + version "2.4.0" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" + integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== + type@^1.0.1: version "1.2.0" resolved "https://registry.yarnpkg.com/type/-/type-1.2.0.tgz#848dd7698dafa3e54a6c479e759c4bc3f18847a0" @@ -2653,10 +2741,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^3.3.1: - version "3.8.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" - integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== +typescript@^4.6.4: + version "4.6.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9" + integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg== unc-path-regex@^0.1.2: version "0.1.2" @@ -2743,6 +2831,13 @@ v8flags@^3.0.1: dependencies: homedir-polyfill "^1.0.1" +v8flags@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-3.2.0.tgz#b243e3b4dfd731fa774e7492128109a0fe66d656" + integrity sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg== + dependencies: + homedir-polyfill "^1.0.1" + validate-npm-package-license@^3.0.1: version "3.0.4" resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" From c388132668c4a15ffbb1934e89f309f5fa349619 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 07:49:51 -0600 Subject: [PATCH 451/704] Enable dependabot --- .github/dependabot.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..f4b57a23 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: +- package-ecosystem: nuget + directory: / + schedule: + interval: monthly +- package-ecosystem: npm + directory: /src/nerdbank-gitversioning.npm + schedule: + interval: monthly From 554f442346457963f55405c5904825e564eb264a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 14:16:07 +0000 Subject: [PATCH 452/704] Bump copy-props from 2.0.4 to 2.0.5 in /src/nerdbank-gitversioning.npm Bumps [copy-props](https://github.com/gulpjs/copy-props) from 2.0.4 to 2.0.5. - [Release notes](https://github.com/gulpjs/copy-props/releases) - [Changelog](https://github.com/gulpjs/copy-props/blob/master/CHANGELOG.md) - [Commits](https://github.com/gulpjs/copy-props/compare/2.0.4...2.0.5) --- updated-dependencies: - dependency-name: copy-props dependency-type: indirect ... Signed-off-by: dependabot[bot] --- src/nerdbank-gitversioning.npm/yarn.lock | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index 637e08d0..fc7e348c 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -518,12 +518,12 @@ copy-descriptor@^0.1.0: integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= copy-props@^2.0.1: - version "2.0.4" - resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.4.tgz#93bb1cadfafd31da5bb8a9d4b41f471ec3a72dfe" - integrity sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A== + version "2.0.5" + resolved "https://registry.yarnpkg.com/copy-props/-/copy-props-2.0.5.tgz#03cf9ae328d4ebb36f8f1d804448a6af9ee3f2d2" + integrity sha512-XBlx8HSqrT0ObQwmSzM7WE5k8FxTV75h1DX1Z3n6NhQ/UYYAvInWYmG06vFt7hQZArE2fuO62aihiWIVQwh1sw== dependencies: - each-props "^1.3.0" - is-plain-object "^2.0.1" + each-props "^1.3.2" + is-plain-object "^5.0.0" core-util-is@~1.0.0: version "1.0.2" @@ -674,7 +674,7 @@ duplexify@^3.6.0: readable-stream "^2.0.0" stream-shift "^1.0.0" -each-props@^1.3.0: +each-props@^1.3.2: version "1.3.2" resolved "https://registry.yarnpkg.com/each-props/-/each-props-1.3.2.tgz#ea45a414d16dd5cfa419b1a81720d5ca06892333" integrity sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA== @@ -1443,6 +1443,11 @@ is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: dependencies: isobject "^3.0.1" +is-plain-object@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" + integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== + is-promise@^2.1: version "2.1.0" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" From 91b9849b0121f9ab62810219e21a83e69fd4701c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 14:56:32 +0000 Subject: [PATCH 453/704] Bump Microsoft.DotNet.PlatformAbstractions from 2.1.0 to 3.1.6 (#741) --- src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index 6f004727..21263f62 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -11,7 +11,7 @@ - + From ecfad1063d450ad12900f5dab549125f6a6d82fb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 15:30:15 +0000 Subject: [PATCH 454/704] Bump Validation from 2.5.5-beta to 2.5.51 (#742) --- src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj | 2 +- src/Shared/SemanticVersionExtensions.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index 21263f62..753800e5 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/Shared/SemanticVersionExtensions.cs b/src/Shared/SemanticVersionExtensions.cs index 4cabbf30..4f58a58b 100644 --- a/src/Shared/SemanticVersionExtensions.cs +++ b/src/Shared/SemanticVersionExtensions.cs @@ -24,7 +24,7 @@ internal static class SemanticVersionExtensions internal static SemanticVersion Increment(this SemanticVersion currentVersion, VersionOptions.ReleaseVersionIncrement increment) { Requires.NotNull(currentVersion, nameof(currentVersion)); - Requires.That(increment != VersionOptions.ReleaseVersionIncrement.Build || currentVersion.Version.Build >= 0, nameof(increment), + Requires.Argument(increment != VersionOptions.ReleaseVersionIncrement.Build || currentVersion.Version.Build >= 0, nameof(increment), "Cannot apply version increment '{0}' to version '{1}'", increment, currentVersion); var major = currentVersion.Version.Major; From 68ebcd6c1bf73bb17d0950f5775bf7ebefc0be1b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 15:31:09 +0000 Subject: [PATCH 455/704] Bump Microsoft.CodeAnalysis.CSharp from 2.10.0 to 4.1.0 (#743) --- .../NerdBank.GitVersioning.Tests.csproj | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index e4a6fb16..2b8be69c 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -33,7 +33,6 @@ - @@ -41,7 +40,7 @@ - + all From f90a2fee3692f70dec234283c72cff976267e59d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 13:33:08 -0600 Subject: [PATCH 456/704] Stabilize tests against different default branch names --- src/NerdBank.GitVersioning.Tests/RepoTestBase.cs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs b/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs index 5cc81647..473f0bd9 100644 --- a/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs +++ b/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs @@ -103,6 +103,13 @@ protected virtual GitContext InitializeSourceControl(string repoPath, bool withI { Repository.Init(repoPath); var repo = new Repository(repoPath); + + // Our tests assume the default branch is master, so retain that regardless of global git configuration on the the machine running the tests. + if (repo.Head.FriendlyName != "master") + { + File.WriteAllText(Path.Combine(repoPath, ".git", "HEAD"), "ref: refs/heads/master\n"); + } + repo.Config.Set("user.name", this.Signer.Name, ConfigurationLevel.Local); repo.Config.Set("user.email", this.Signer.Email, ConfigurationLevel.Local); foreach (var file in repo.RetrieveStatus().Untracked) From 81993d220f41f0cf304f0650fd2d3e0a13461c7c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 19:38:05 +0000 Subject: [PATCH 457/704] Bump DotNetMDDocs from 0.111.0 to 0.112.39 (#744) --- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 2 +- src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 49b38e6a..ed37946b 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -30,7 +30,7 @@ - + diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index 753800e5..465913af 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -9,7 +9,7 @@ Nerdbank.GitVersioning - + From 82fa4ff6e182bd141eff879402473b1d6fd528ed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 13:54:41 -0600 Subject: [PATCH 458/704] Bump coverlet.collector from 1.3.0 to 3.1.2 (#745) Bumps [coverlet.collector](https://github.com/coverlet-coverage/coverlet) from 1.3.0 to 3.1.2. - [Release notes](https://github.com/coverlet-coverage/coverlet/releases) - [Commits](https://github.com/coverlet-coverage/coverlet/commits) --- updated-dependencies: - dependency-name: coverlet.collector dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- .../NerdBank.GitVersioning.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 819813ea..2c23f331 100644 --- a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -22,7 +22,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive all - + diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 2b8be69c..5bdf891c 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -39,7 +39,7 @@ - + From 61c6d71eec3d8fbe6c8f79ccdbfc793400cdd6f5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 19:59:41 +0000 Subject: [PATCH 459/704] Bump Xunit.SkippableFact from 1.3.12 to 1.4.13 (#746) --- .../NerdBank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 5bdf891c..8eb4888f 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -46,7 +46,7 @@ all runtime; build; native; contentfiles; analyzers - + From 4815235782b3d80e981bd70042a13785e4ce363c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 20:00:05 +0000 Subject: [PATCH 460/704] Bump Microsoft.NET.Test.Sdk from 17.0.0 to 17.1.0 (#747) --- src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 2c23f331..cbf2dcd2 100644 --- a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -15,7 +15,7 @@ - + From 92e9b58caadbf0511e6d2342f6b53bebc098d729 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 1 May 2022 20:18:53 +0000 Subject: [PATCH 461/704] Bump System.Threading.Tasks.Dataflow from 4.9.0 to 6.0.0 (#749) --- .../NerdBank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 8eb4888f..f75399d7 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -36,7 +36,7 @@ - + From 2186ad413bf6c5a2094ced11dec7f5944c082820 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 13:45:40 -0600 Subject: [PATCH 462/704] Move .NET 5 tests to .NET 6 .NET 5 is just a few days from falling out of official Microsoft support, so testing on it at this point makes no sense. --- azure-pipelines.yml | 19 +++---------------- global.json | 2 +- .../Cake.GitVersioning.Tests.csproj | 2 +- .../ManagedGit/GitPackTests.cs | 1 + .../ManagedGit/ZLibStreamTest.cs | 1 + .../NerdBank.GitVersioning.Tests.csproj | 2 +- 6 files changed, 8 insertions(+), 19 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 914908dd..17ec4ed6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -36,7 +36,7 @@ stages: matrix: linux: imageName: 'ubuntu-20.04' - testModifier: -f net5.0 + testModifier: -f net6.0 windows: imageName: 'windows-2019' testModifier: @@ -60,24 +60,16 @@ stages: packageType: runtime version: 3.1.x - - task: UseDotNet@2 - displayName: Install .NET 5.0 SDK - inputs: - packageType: sdk # necessary for msbuild tests to run on .NET 5 runtime - version: 5.0.x - - task: UseDotNet@2 displayName: Install .NET 6.0 SDK inputs: packageType: sdk - version: 6.0.100 - + version: 6.0.202 - pwsh: | Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose -Runtime dotnet - & .\dotnet-install.ps1 -Architecture x86 -Channel 5.0 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose - & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.100 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.202 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose displayName: Install 32-bit .NET SDK and runtimes condition: ne(variables['dotnet32'], '') @@ -334,11 +326,6 @@ stages: inputs: packageType: runtime version: 3.1.x - - task: UseDotNet@2 - displayName: Install .NET 5.0 runtime - inputs: - packageType: runtime - version: 5.0.x - task: UseDotNet@2 displayName: Install .NET 6.0.100 SDK inputs: diff --git a/global.json b/global.json index e2af429b..9425292c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.100", + "version": "6.0.202", "rollForward": "patch", "allowPrerelease": false } diff --git a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 819813ea..12d772f1 100644 --- a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -1,7 +1,7 @@ - net5.0;net461 + net6.0;net461 false true false diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs index 0c14a314..e904dd09 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs @@ -5,6 +5,7 @@ using Nerdbank.GitVersioning; using Nerdbank.GitVersioning.ManagedGit; using Xunit; +using ZLibStream = Nerdbank.GitVersioning.ManagedGit.ZLibStream; namespace ManagedGit { diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs b/src/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs index f71827d9..e75ef3ca 100644 --- a/src/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs +++ b/src/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs @@ -5,6 +5,7 @@ using System.Text; using Nerdbank.GitVersioning.ManagedGit; using Xunit; +using ZLibStream = Nerdbank.GitVersioning.ManagedGit.ZLibStream; namespace ManagedGit { diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 2b8be69c..77e52925 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -1,6 +1,6 @@  - net5.0;net461 + net6.0;net461 true true full From f39d7fc74bcd8b2625670bd68e0053b37b400d74 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 14:35:13 -0600 Subject: [PATCH 463/704] Test on .NET 6 instead of .NET 5 .NET 5 falls out of Microsoft support in just a few days, so folks should focus testing on the currently supported platforms. --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 077d8d8f..20108645 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -1,7 +1,7 @@ - net5.0;netcoreapp3.1;net472 + net6.0;netcoreapp3.1;net472 From 3c38b4d178ff5ef5a6a7ace778560ec3f8b4cb43 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 15:56:02 -0600 Subject: [PATCH 464/704] Apply Library.Template Version f39d7fc74bcd8b2625670bd68e0053b37b400d74 specifically. --- .devcontainer/Dockerfile | 13 + .devcontainer/devcontainer.json | 20 ++ .editorconfig | 116 +++++++- .gitattributes | 5 +- .gitignore | 230 +++++++++++++--- .vscode/extensions.json | 17 +- .vscode/settings.json | 10 +- Directory.Build.props | 94 +++++++ Directory.Build.targets | 8 + ...rsioning.sln => Nerdbank.GitVersioning.sln | 16 +- azure-pipelines.yml | 258 +----------------- .../Get-ArtifactsStagingDirectory.ps1 | 15 + azure-pipelines/Get-NuGetTool.ps1 | 22 ++ azure-pipelines/Get-ProcDump.ps1 | 14 + azure-pipelines/Get-SymbolFiles.ps1 | 56 ++++ azure-pipelines/Get-TempToolsPath.ps1 | 13 + azure-pipelines/Get-nbgv.ps1 | 24 ++ azure-pipelines/artifacts/Variables.ps1 | 43 +++ azure-pipelines/artifacts/_all.ps1 | 70 +++++ azure-pipelines/artifacts/_pipelines.ps1 | 15 + azure-pipelines/artifacts/_stage_all.ps1 | 50 ++++ azure-pipelines/artifacts/build_logs.ps1 | 7 + azure-pipelines/artifacts/coverageResults.ps1 | 22 ++ azure-pipelines/artifacts/deployables-LKG.ps1 | 13 + azure-pipelines/artifacts/deployables.ps1 | 13 + .../artifacts/projectAssetsJson.ps1 | 9 + azure-pipelines/artifacts/symbols.ps1 | 7 + azure-pipelines/artifacts/testResults.ps1 | 20 ++ azure-pipelines/artifacts/test_symbols.ps1 | 7 + azure-pipelines/build.yml | 59 ++++ azure-pipelines/dotnet-test-cloud.ps1 | 68 +++++ azure-pipelines/dotnet.yml | 73 +++++ azure-pipelines/install-dependencies.yml | 25 ++ azure-pipelines/justnugetorg.nuget.config | 7 + azure-pipelines/publish-codecoverage.yml | 35 +++ azure-pipelines/publish-deployables.yml | 17 ++ azure-pipelines/release.yml | 152 +++++------ azure-pipelines/variables/_all.ps1 | 13 + azure-pipelines/variables/_pipelines.ps1 | 24 ++ global.json | 2 +- init.cmd | 16 ++ init.ps1 | 101 ++++--- src/nuget.config => nuget.config | 4 + src/.editorconfig | 0 src/AssemblyInfo.cs | 6 + .../Cake.GitVersioning.csproj | 1 - src/Directory.Build.props | 42 +-- src/Directory.Build.targets | 7 + src/strongname.snk => strongname.snk | Bin stylecop.json | 15 + test/.editorconfig | 52 ++++ .../Cake.GitVersioning.Tests.csproj | 0 .../GitVersioningCloudProviderTests.cs | 0 test/Directory.Build.props | 9 + test/Directory.Build.targets | 10 + .../GetVersionBenchmarks.cs | 0 .../Nerdbank.GitVersioning.Benchmarks.csproj | 0 .../Program.cs | 0 .../AssemblyInfoTest.cs | 0 .../BuildIntegrationTests.cs | 0 .../FilterPathTests.cs | 0 .../GitContextTests.cs | 0 .../Keys/keypair.snk | Bin .../Keys/protectedPair.pfx | Bin .../Keys/public.snk | Bin .../LibGit2GitExtensionsTests.cs | 0 .../MSBuildExtensions.cs | 0 .../MSBuildFixture.cs | 0 .../ManagedGit/.gitattributes | 0 ...596ffe59898103a2675547d4597e742e1f2389c.gz | Bin .../ManagedGit/DeltaStreamReaderTests.cs | 0 .../ManagedGit/GitCommitReaderTests.cs | 0 .../ManagedGit/GitCommitTests.cs | 0 .../ManagedGit/GitObjectIdTests.cs | 0 .../ManagedGit/GitObjectStreamTests.cs | 0 .../ManagedGit/GitPackDeltafiedStreamTests.cs | 0 .../GitPackIndexMappedReaderTests.cs | 0 .../ManagedGit/GitPackMemoryCacheTests.cs | 0 .../ManagedGit/GitPackTests.cs | 0 .../ManagedGit/GitRepositoryTests.cs | 0 .../ManagedGit/GitTreeStreamingReaderTests.cs | 0 .../ManagedGit/StreamExtensionsTests.cs | 0 .../ManagedGit/ZLibStreamTest.cs | 0 ...t-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 | 0 ...t-ab39e8acac105fa0db88514f259341c9f0201b22 | 0 ...t-d56dc3ed179053abef2097d1120b4507769bcf1a | 0 .../ManagedGit/commit.delta | 0 ...b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt | 0 ...6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx | Bin ...b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack | Bin ...e-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 | 0 ...e-f914b48023c7c804a4f3be780d451f31aef74ac1 | 0 .../ManagedGit/tree.bin | Bin .../ManagedGit/tree.delta | 0 .../NerdBank.GitVersioning.Tests.csproj | 0 .../ReleaseManagerTests.cs | 0 .../RepoTestBase.Helpers.cs | 0 .../RepoTestBase.cs | 0 .../SemanticVersionExtensionsTests.cs | 0 .../SemanticVersionTests.cs | 0 .../TestUtilities.cs | 0 .../VersionExtensionsTests.cs | 0 .../VersionFileTests.cs | 0 .../VersionOptionsTests.cs | 0 .../VersionOracleTests.cs | 0 .../VersionSchemaTests.cs | 0 .../WindowsTheoryAttribute.cs | 0 .../repos/PackedHeadRef.zip | Bin .../repos/submodules.zip | Bin .../NerdBank.GitVersioning.Tests/test.prj | 0 .../NerdBank.GitVersioning.Tests/test.vcprj | 0 tools/Check-DotNetRuntime.ps1 | 41 +++ tools/Check-DotNetSdk.ps1 | 37 +++ tools/Install-DotNetSdk.ps1 | 58 +++- tools/Install-NuGetCredProvider.ps1 | 76 ++++++ {azure-pipelines => tools}/Set-EnvVars.ps1 | 24 +- version.json | 11 +- 117 files changed, 1699 insertions(+), 493 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 Directory.Build.props create mode 100644 Directory.Build.targets rename src/Nerdbank.GitVersioning.sln => Nerdbank.GitVersioning.sln (80%) create mode 100644 azure-pipelines/Get-ArtifactsStagingDirectory.ps1 create mode 100644 azure-pipelines/Get-NuGetTool.ps1 create mode 100644 azure-pipelines/Get-ProcDump.ps1 create mode 100644 azure-pipelines/Get-SymbolFiles.ps1 create mode 100644 azure-pipelines/Get-TempToolsPath.ps1 create mode 100644 azure-pipelines/Get-nbgv.ps1 create mode 100644 azure-pipelines/artifacts/Variables.ps1 create mode 100644 azure-pipelines/artifacts/_all.ps1 create mode 100644 azure-pipelines/artifacts/_pipelines.ps1 create mode 100644 azure-pipelines/artifacts/_stage_all.ps1 create mode 100644 azure-pipelines/artifacts/build_logs.ps1 create mode 100644 azure-pipelines/artifacts/coverageResults.ps1 create mode 100644 azure-pipelines/artifacts/deployables-LKG.ps1 create mode 100644 azure-pipelines/artifacts/deployables.ps1 create mode 100644 azure-pipelines/artifacts/projectAssetsJson.ps1 create mode 100644 azure-pipelines/artifacts/symbols.ps1 create mode 100644 azure-pipelines/artifacts/testResults.ps1 create mode 100644 azure-pipelines/artifacts/test_symbols.ps1 create mode 100644 azure-pipelines/build.yml create mode 100644 azure-pipelines/dotnet-test-cloud.ps1 create mode 100644 azure-pipelines/dotnet.yml create mode 100644 azure-pipelines/install-dependencies.yml create mode 100644 azure-pipelines/justnugetorg.nuget.config create mode 100644 azure-pipelines/publish-codecoverage.yml create mode 100644 azure-pipelines/publish-deployables.yml create mode 100644 azure-pipelines/variables/_all.ps1 create mode 100644 azure-pipelines/variables/_pipelines.ps1 rename src/nuget.config => nuget.config (90%) create mode 100644 src/.editorconfig create mode 100644 src/AssemblyInfo.cs create mode 100644 src/Directory.Build.targets rename src/strongname.snk => strongname.snk (100%) create mode 100644 stylecop.json create mode 100644 test/.editorconfig rename {src => test}/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj (100%) rename {src => test}/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs (100%) create mode 100644 test/Directory.Build.props create mode 100644 test/Directory.Build.targets rename {src => test}/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs (100%) rename {src => test}/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj (100%) rename {src => test}/NerdBank.GitVersioning.Benchmarks/Program.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/FilterPathTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/GitContextTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/Keys/keypair.snk (100%) rename {src => test}/NerdBank.GitVersioning.Tests/Keys/protectedPair.pfx (100%) rename {src => test}/NerdBank.GitVersioning.Tests/Keys/public.snk (100%) rename {src => test}/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/MSBuildFixture.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/.gitattributes (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/commit.delta (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/tree.bin (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ManagedGit/tree.delta (100%) rename {src => test}/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj (100%) rename {src => test}/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/RepoTestBase.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/TestUtilities.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/VersionFileTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/VersionOracleTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs (100%) rename {src => test}/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip (100%) rename {src => test}/NerdBank.GitVersioning.Tests/repos/submodules.zip (100%) rename {src => test}/NerdBank.GitVersioning.Tests/test.prj (100%) rename {src => test}/NerdBank.GitVersioning.Tests/test.vcprj (100%) create mode 100644 tools/Check-DotNetRuntime.ps1 create mode 100644 tools/Check-DotNetSdk.ps1 create mode 100644 tools/Install-NuGetCredProvider.ps1 rename {azure-pipelines => tools}/Set-EnvVars.ps1 (67%) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 00000000..234db6d1 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,13 @@ +FROM mcr.microsoft.com/dotnet/sdk:6.0.200-focal + +# Installing mono makes `dotnet test` work without errors even for net472. +# But installing it takes a long time, so it's excluded by default. +#RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF +#RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | tee /etc/apt/sources.list.d/mono-official-stable.list +#RUN apt-get update +#RUN DEBIAN_FRONTEND=noninteractive apt-get install -y mono-devel + +# Clear the NUGET_XMLDOC_MODE env var so xml api doc files get unpacked, allowing a rich experience in Intellisense. +# See https://github.com/dotnet/dotnet-docker/issues/2790 for a discussion on this, where the prioritized use case +# was *not* devcontainers, sadly. +ENV NUGET_XMLDOC_MODE= diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 00000000..f4e3b31a --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,20 @@ +{ + "name": "Dev space", + "dockerFile": "Dockerfile", + "settings": { + "terminal.integrated.shell.linux": "/usr/bin/pwsh" + }, + "postCreateCommand": "./init.ps1 -InstallLocality machine", + "extensions": [ + "ms-azure-devops.azure-pipelines", + "ms-dotnettools.csharp", + "k--kato.docomment", + "editorconfig.editorconfig", + "pflannery.vscode-versionlens", + "davidanson.vscode-markdownlint", + "dotjoshjohnson.xml", + "ms-vscode-remote.remote-containers", + "ms-azuretools.vscode-docker", + "ms-vscode.powershell" + ] +} diff --git a/.editorconfig b/.editorconfig index fb31b8c2..e0fb1121 100644 --- a/.editorconfig +++ b/.editorconfig @@ -6,32 +6,36 @@ root = true # Don't use tabs for indentation. [*] indent_style = space + # (Please don't specify an indent_size here; that has too many unintended consequences.) [*.yml] indent_size = 2 +indent_style = space # Code files -[*.{cs,csx,vb,vbx}] +[*.{cs,csx,vb,vbx,h,cpp,idl}] indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true # Xml project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj}] +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj}] indent_size = 2 # Xml config files -[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct}] +[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}] indent_size = 2 # JSON files [*.json] indent_size = 2 +indent_style = space # Dotnet code style settings: [*.{cs,vb}] # Sort using and Import directives with System.* appearing first dotnet_sort_system_directives_first = true -# Use "this." and "Me." everywhere dotnet_style_qualification_for_field = true:warning dotnet_style_qualification_for_property = true:warning dotnet_style_qualification_for_method = true:warning @@ -48,22 +52,96 @@ dotnet_style_coalesce_expression = true:suggestion dotnet_style_null_propagation = true:suggestion dotnet_style_explicit_tuple_names = true:suggestion +# Non-private static fields are PascalCase +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields +dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style + +dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field +dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected +dotnet_naming_symbols.non_private_static_fields.required_modifiers = static + +dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case + +# Constants are PascalCase +dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants +dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style + +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.required_modifiers = const + +dotnet_naming_style.constant_style.capitalization = pascal_case + +# Static fields are camelCase +dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields +dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style + +dotnet_naming_symbols.static_fields.applicable_kinds = field +dotnet_naming_symbols.static_fields.required_modifiers = static + +dotnet_naming_style.static_field_style.capitalization = camel_case + +# Instance fields are camelCase +dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion +dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields +dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style + +dotnet_naming_symbols.instance_fields.applicable_kinds = field + +dotnet_naming_style.instance_field_style.capitalization = camel_case + +# Locals and parameters are camelCase +dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion +dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters +dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style + +dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local + +dotnet_naming_style.camel_case_style.capitalization = camel_case + +# Local functions are PascalCase +dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions +dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style + +dotnet_naming_symbols.local_functions.applicable_kinds = local_function + +dotnet_naming_style.local_function_style.capitalization = pascal_case + +# By default, name items with PascalCase +dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion +dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members +dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style + +dotnet_naming_symbols.all_members.applicable_kinds = * + +dotnet_naming_style.pascal_case_style.capitalization = pascal_case + # CSharp code style settings: [*.cs] +# Indentation preferences +csharp_indent_block_contents = true +csharp_indent_braces = false +csharp_indent_case_contents = true +csharp_indent_switch_labels = true +csharp_indent_labels = flush_left + # Prefer "var" everywhere -csharp_style_var_for_built_in_types = false:none -csharp_style_var_when_type_is_apparent = true:none -csharp_style_var_elsewhere = false:none +csharp_style_var_for_built_in_types = false +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = false:warning # Prefer method-like constructs to have a block body -csharp_style_expression_bodied_methods = true:suggestion -csharp_style_expression_bodied_constructors = true:suggestion -csharp_style_expression_bodied_operators = true:suggestion +csharp_style_expression_bodied_methods = false:none +csharp_style_expression_bodied_constructors = false:none +csharp_style_expression_bodied_operators = false:none # Prefer property-like constructs to have an expression-body -csharp_style_expression_bodied_properties = true:suggestion -csharp_style_expression_bodied_indexers = true:suggestion -csharp_style_expression_bodied_accessors = true:suggestion +csharp_style_expression_bodied_properties = true:none +csharp_style_expression_bodied_indexers = true:none +csharp_style_expression_bodied_accessors = true:none # Suggest more modern language features when available csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion @@ -85,3 +163,15 @@ dotnet_diagnostic.CSIsNull001.severity = warning # CSIsNull002: Use `is object` for non-null checks dotnet_diagnostic.CSIsNull002.severity = warning + +# Blocks are allowed +csharp_prefer_braces = true:silent + +# SA1130: Use lambda syntax +dotnet_diagnostic.SA1130.severity = silent + +# IDE1006: Naming Styles - StyleCop handles these for us +dotnet_diagnostic.IDE1006.severity = none + +[*.sln] +indent_style = tab diff --git a/.gitattributes b/.gitattributes index e9ae1b43..c22a129e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -2,7 +2,10 @@ # Set default behavior to automatically normalize line endings. ############################################################################### * text=auto -*.sh text eol=lf + +# Ensure shell scripts use LF line endings (linux only accepts LF) +*.sh eol=lf +*.ps1 eol=lf ############################################################################### # Set default behavior for command prompt diff. diff --git a/.gitignore b/.gitignore index 41470811..65f94776 100644 --- a/.gitignore +++ b/.gitignore @@ -1,57 +1,88 @@ ## Ignore Visual Studio temporary files, build results, and ## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore # User-specific files +*.rsuser *.suo *.user +*.userosscache *.sln.docstates -.vs/ +*.lutconfig launchSettings.json +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + # Build results [Dd]ebug/ [Dd]ebugPublic/ [Rr]elease/ +[Rr]eleases/ x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ bld/ [Bb]in/ [Oo]bj/ +[Ll]og/ -# Roslyn cache directories -*.ide/ +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ # MSTest test Results [Tt]est[Rr]esult*/ [Bb]uild[Ll]og.* -#NUNIT +# NUnit *.VisualState.xml TestResult.xml +nunit-*.xml # Build Results of an ATL Project [Dd]ebugPS/ [Rr]eleasePS/ dlldata.c +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio *_i.c *_p.c -*_i.h +*_h.h *.ilk *.meta *.obj +*.iobj *.pch *.pdb +*.ipdb *.pgc *.pgd *.rsp +!Directory.Build.rsp *.sbr *.tlb *.tli *.tlh *.tmp *.tmp_proj +*_wpftmp.csproj *.log -*.binlog *.vspscc *.vssscc .builds @@ -66,14 +97,21 @@ _Chutzpah* ipch/ *.aps *.ncb +*.opendb *.opensdf *.sdf *.cachefile +*.VC.db +*.VC.VC.opendb # Visual Studio profiler *.psess *.vsp *.vspx +*.sap + +# Visual Studio Trace Files +*.e2e # TFS 2012 Local Workspace $tf/ @@ -86,7 +124,7 @@ _ReSharper*/ *.[Rr]e[Ss]harper *.DotSettings.user -# JustCode is a .NET coding addin-in +# JustCode is a .NET coding add-in .JustCode # TeamCity is a build add-in @@ -95,9 +133,18 @@ _TeamCity* # DotCover is a Code Coverage Tool *.dotCover +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + # NCrunch _NCrunch_* .*crunch*.local.xml +nCrunchTemp_* # MightyMoose *.mm.* @@ -125,49 +172,71 @@ publish/ # Publish Web Output *.[Pp]ublish.xml *.azurePubxml -## TODO: Comment the next line if you want to checkin your -## web deploy settings but do note that will include unencrypted -## passwords -#*.pubxml - -# NuGet Packages Directory -packages +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files *.nuget.props *.nuget.targets -project.lock.json - -# NPM -package-lock.json - -## TODO: If the tool you use requires repositories.config -## uncomment the next line -#!packages/repositories.config -# Enable "build/" folder in the NuGet Packages folder since -# NuGet packages use it for MSBuild targets. -# This line needs to be after the ignore of the build folder -# (and the packages folder if the line above has been uncommented) -!packages/build/ - -# Windows Azure Build Output +# Microsoft Azure Build Output csx/ *.build.csdef -# Windows Store app package directory +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ # Others -sql/ -*.Cache ClientBin/ -[Ss]tyle[Cc]op.* ~$* *~ *.dbmdl *.dbproj.schemaview +*.jfm +*.pfx *.publishsettings -node_modules/ -bower_components/ +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ # RIA/Silverlight projects Generated_Code/ @@ -179,20 +248,103 @@ _UpgradeReport_Files/ Backup*/ UpgradeLog*.XML UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak # SQL Server files *.mdf *.ldf +*.ndf # Business Intelligence projects *.rdl.data *.bim.layout *.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl # Microsoft Fakes FakesAssemblies/ -# LightSwitch generated files -GeneratedArtifacts/ -_Pvt_Extensions/ -ModelManifest.xml \ No newline at end of file +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# dotnet tool local install directory +.store/ diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 9335c88f..853a3d45 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,19 @@ { + // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. + // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp + // List of extensions which should be recommended for users of this workspace. "recommendations": [ - "formulahendry.dotnet-test-explorer", + "ms-azure-devops.azure-pipelines", "ms-dotnettools.csharp", - ] + "k--kato.docomment", + "editorconfig.editorconfig", + "formulahendry.dotnet-test-explorer", + "pflannery.vscode-versionlens", + "davidanson.vscode-markdownlint", + "dotjoshjohnson.xml", + "ms-vscode-remote.remote-containers", + "ms-azuretools.vscode-docker" + ], + // List of extensions recommended by VS Code that should not be recommended for users of this workspace. + "unwantedRecommendations": [] } diff --git a/.vscode/settings.json b/.vscode/settings.json index 83730d6f..9d58e437 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,9 @@ { - "dotnet-test-explorer.testProjectPath": "src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj" -} \ No newline at end of file + "dotnet-test-explorer.testProjectPath": "src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj", + "files.trimTrailingWhitespace": true, + "files.insertFinalNewline": true, + "files.trimFinalNewlines": true, + "omnisharp.enableEditorConfigSupport": true, + "omnisharp.enableImportCompletion": true, + "omnisharp.enableRoslynAnalyzers": true +} diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..4530c93f --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,94 @@ + + + Debug + $(MSBuildThisFileDirectory) + $(RepoRootPath)obj\$([MSBuild]::MakeRelative($(RepoRootPath), $(MSBuildProjectDirectory)))\ + $(RepoRootPath)bin\$(MSBuildProjectName)\ + $(RepoRootPath)bin\Packages\$(Configuration)\ + $(MSBuildThisFileDirectory)..\wiki\api + 10.0 + enable + enable + latest + true + true + true + + + true + + + $(MSBuildThisFileDirectory) + + embedded + + true + $(MSBuildThisFileDirectory)\strongname.snk + + Andrew Arnott + aarnott + git commit versioning version assemblyinfo + Copyright (c) .NET Foundation and Contributors + https://github.com/dotnet/Nerdbank.GitVersioning + MIT + true + true + + + + + 2.0.315-alpha.0.9 + + + + + + + + + + + + + + + + + + + + + + + + https://github.com/dotnet/Nerdbank.GitVersioning/releases/tag/v$(Version) + + + + + false + true + + + + + <_WpfTempProjectNuGetFilePathNoExt>$(RepoRootPath)obj\$(_TargetAssemblyProjectName)\$(_TargetAssemblyProjectName)$(MSBuildProjectExtension).nuget.g + + false + false + false + false + + + + + diff --git a/Directory.Build.targets b/Directory.Build.targets new file mode 100644 index 00000000..65a15bfc --- /dev/null +++ b/Directory.Build.targets @@ -0,0 +1,8 @@ + + + + false + + + + diff --git a/src/Nerdbank.GitVersioning.sln b/Nerdbank.GitVersioning.sln similarity index 80% rename from src/Nerdbank.GitVersioning.sln rename to Nerdbank.GitVersioning.sln index 9077863c..32a4b547 100644 --- a/src/Nerdbank.GitVersioning.sln +++ b/Nerdbank.GitVersioning.sln @@ -18,21 +18,21 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\version.json = ..\version.json EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NerdBank.GitVersioning.Tests", "NerdBank.GitVersioning.Tests\NerdBank.GitVersioning.Tests.csproj", "{C54F9EC8-FDA7-4D22-BCB2-7D97523BD91E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NerdBank.GitVersioning.Tests", "test\NerdBank.GitVersioning.Tests\NerdBank.GitVersioning.Tests.csproj", "{C54F9EC8-FDA7-4D22-BCB2-7D97523BD91E}" EndProject -Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "nb-gv", "nerdbank-gitversioning.npm\nb-gv.njsproj", "{F79DD916-27B3-4CD0-97FF-5021B3CF9934}" +Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "nb-gv", "src\nerdbank-gitversioning.npm\nb-gv.njsproj", "{F79DD916-27B3-4CD0-97FF-5021B3CF9934}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NerdBank.GitVersioning", "NerdBank.GitVersioning\NerdBank.GitVersioning.csproj", "{C7FA7B7A-0469-4B1C-8657-E274C4CD8ABB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NerdBank.GitVersioning", "src\NerdBank.GitVersioning\NerdBank.GitVersioning.csproj", "{C7FA7B7A-0469-4B1C-8657-E274C4CD8ABB}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Tasks", "Nerdbank.GitVersioning.Tasks\Nerdbank.GitVersioning.Tasks.csproj", "{B2454569-6EDC-4FD4-9936-D2B2F2E10409}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Tasks", "src\Nerdbank.GitVersioning.Tasks\Nerdbank.GitVersioning.Tasks.csproj", "{B2454569-6EDC-4FD4-9936-D2B2F2E10409}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "nbgv", "nbgv\nbgv.csproj", "{EF4DAF23-6CE9-48C5-84C5-80AC80D3D07D}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "nbgv", "src\nbgv\nbgv.csproj", "{EF4DAF23-6CE9-48C5-84C5-80AC80D3D07D}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.GitVersioning", "Cake.GitVersioning\Cake.GitVersioning.csproj", "{1F267A97-DFE3-4166-83B1-9D236B7A09BD}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.GitVersioning", "src\Cake.GitVersioning\Cake.GitVersioning.csproj", "{1F267A97-DFE3-4166-83B1-9D236B7A09BD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Benchmarks", "NerdBank.GitVersioning.Benchmarks\Nerdbank.GitVersioning.Benchmarks.csproj", "{B0B7955D-E51F-4091-BF7F-55D07D381D15}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Benchmarks", "test\NerdBank.GitVersioning.Benchmarks\Nerdbank.GitVersioning.Benchmarks.csproj", "{B0B7955D-E51F-4091-BF7F-55D07D381D15}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.GitVersioning.Tests", "Cake.GitVersioning.Tests\Cake.GitVersioning.Tests.csproj", "{D68829FE-24D8-4ADD-8525-17F47C6FE257}" +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.GitVersioning.Tests", "test\Cake.GitVersioning.Tests\Cake.GitVersioning.Tests.csproj", "{D68829FE-24D8-4ADD-8525-17F47C6FE257}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 17ec4ed6..11a4d988 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -2,13 +2,15 @@ trigger: batch: true branches: include: - - master - - 'v*.*' - - 'validate/*' + - main + - 'v*.*' + - 'validate/*' paths: exclude: - - doc + - doc/ - '*.md' + - .vscode/ + - .github/ - azure-pipelines/release.yml resources: @@ -26,250 +28,14 @@ variables: TreatWarningsAsErrors: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BuildConfiguration: Release - BuildPlatform: Any CPU + codecov_token: 92266a45-648d-454e-8fec-beffae2e6553 + ci_feed: https://pkgs.dev.azure.com/andrewarnott/OSS/_packaging/PublicCI/nuget/v3/index.json + NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages stages: - stage: Build jobs: - - job: Build - strategy: - matrix: - linux: - imageName: 'ubuntu-20.04' - testModifier: -f net6.0 - windows: - imageName: 'windows-2019' - testModifier: - dotnet32: "\"C:\\Program Files (x86)\\dotnet\\dotnet.exe\"" - variables: - - ${{ if eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/') }}: - - group: dotnetfoundation code signing - pool: - vmImage: $(imageName) - steps: - - checkout: self - clean: true - submodules: true # keep the warnings quiet about the wiki not being enlisted - - script: | - git config --global user.name ci - git config --global user.email me@ci.com - displayName: Configure git commit author for testing - - task: UseDotNet@2 - displayName: Install .NET Core 3.1 runtime - inputs: - packageType: runtime - version: 3.1.x - - - task: UseDotNet@2 - displayName: Install .NET 6.0 SDK - inputs: - packageType: sdk - version: 6.0.202 - - - pwsh: | - Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 - & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose -Runtime dotnet - & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.202 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose - displayName: Install 32-bit .NET SDK and runtimes - condition: ne(variables['dotnet32'], '') - - - script: dotnet --info - displayName: Show dotnet SDK info - - - pwsh: | - dotnet tool install --tool-path . nbgv - ./nbgv cloud -a - displayName: Set build number - - - task: DotNetCoreCLI@2 - displayName: Restore NuGet packages - inputs: - command: restore - verbosityRestore: normal # detailed, normal, minimal - projects: src/**/*.sln - feedsToUse: config - nugetConfigPath: src/nuget.config - workingDirectory: src - - - script: npm i -g yarn@">=1.22 <2.0" - displayName: Installing yarn - - - script: yarn --cwd src/nerdbank-gitversioning.npm - displayName: Installing NPM packages - - - script: dotnet build -c $(BuildConfiguration) --no-restore /t:build,pack /bl:"$(Build.ArtifactStagingDirectory)/build_logs/msbuild.binlog" - displayName: Build NuGet package and tests - workingDirectory: src - - - script: dotnet pack -c $(BuildConfiguration) --no-build -p:PackLKG=true /bl:"$(Build.ArtifactStagingDirectory)/build_logs/msbuild_lkg.binlog" - displayName: Build LKG package - workingDirectory: src/Nerdbank.GitVersioning.Tasks - - - script: dotnet publish -c $(BuildConfiguration) -o ../nerdbank-gitversioning.npm/out/nbgv.cli/tools/netcoreapp3.1/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog" - displayName: Publish nbgv tool - workingDirectory: src/nbgv - - - task: gulp@0 - displayName: Build nerdbank-gitversioning NPM package - inputs: - gulpfile: src/nerdbank-gitversioning.npm/gulpfile.js - - - script: > - dotnet test NerdBank.GitVersioning.Tests - --no-build $(testModifier) - -c $(BuildConfiguration) - --filter "TestCategory!=FailsOnAzurePipelines" - --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.x64.trx" - --results-directory $(Build.ArtifactStagingDirectory)/CodeCoverage/ - --collect:"XPlat Code Coverage" - -- - RunConfiguration.DisableAppDomain=true - displayName: Run x64 tests - workingDirectory: src - - - script: > - $(dotnet32) test NerdBank.GitVersioning.Tests - --no-build $(testModifier) - -c $(BuildConfiguration) - --filter "TestCategory!=FailsOnAzurePipelines" - --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.x86.trx" - --results-directory $(Build.ArtifactStagingDirectory)/CodeCoverage/ - --collect:"XPlat Code Coverage" - -- - RunConfiguration.DisableAppDomain=true - displayName: Run x86 tests - workingDirectory: src - condition: ne(variables['dotnet32'], '') - - - script: > - dotnet test Cake.GitVersioning.Tests - --no-build $(testModifier) - -c $(BuildConfiguration) - --filter "TestCategory!=FailsOnAzurePipelines" - --logger "trx;LogFileName=$(Build.ArtifactStagingDirectory)/TestLogs/TestResults.cake.trx" - --results-directory $(Build.ArtifactStagingDirectory)/CodeCoverage/ - --collect:"XPlat Code Coverage" - -- - RunConfiguration.DisableAppDomain=true - displayName: Run cake tests - workingDirectory: src - - - task: PublishCodeCoverageResults@1 - displayName: Publish code coverage results - inputs: - codeCoverageTool: 'cobertura' - summaryFileLocation: $(Build.ArtifactStagingDirectory)/CodeCoverage/**/coverage.cobertura.xml - - - task: PublishTestResults@2 - displayName: Publish test results - inputs: - testResultsFormat: VSTest - testResultsFiles: '*.trx' - searchFolder: $(Build.ArtifactStagingDirectory)/TestLogs - buildPlatform: $(BuildPlatform) - buildConfiguration: $(BuildConfiguration) - publishRunAttachments: false - condition: always() - - - task: CopyFiles@1 - inputs: - sourceFolder: $(System.DefaultWorkingDirectory)/bin - Contents: | - **\*.nupkg - !**\*.LKG* - js\*.tgz - TargetFolder: $(Build.ArtifactStagingDirectory)/deployables - flattenFolders: true - displayName: Collecting deployable artifacts - - - task: CopyFiles@1 - inputs: - sourceFolder: $(System.DefaultWorkingDirectory)/bin - Contents: | - **\*.LKG*.nupkg - TargetFolder: $(Build.ArtifactStagingDirectory)/deployables-lkg - flattenFolders: true - displayName: Collecting LKG artifacts - - - pwsh: > - dotnet tool install --tool-path obj SignClient - - obj/SignClient sign - --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables' - --input '**/*' - --config '$(System.DefaultWorkingDirectory)/azure-pipelines/SignClient.json' - --filelist '$(System.DefaultWorkingDirectory)/azure-pipelines/signfiles.txt' - --user '$(codesign_username)' - --secret '$(codesign_secret)' - --name 'Nerdbank.GitVersioning' - --descriptionUrl 'https://github.com/dotnet/Nerdbank.GitVersioning' - displayName: Code sign - condition: and(succeeded(), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['Build.Reason'], 'PullRequest')) - - - pwsh: > - obj/SignClient sign - --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables-lkg' - --input '**/*' - --config '$(System.DefaultWorkingDirectory)/azure-pipelines/SignClient.json' - --filelist '$(System.DefaultWorkingDirectory)/azure-pipelines/signfiles.txt' - --user '$(codesign_username)' - --secret '$(codesign_secret)' - --name 'Nerdbank.GitVersioning' - --descriptionUrl 'https://github.com/dotnet/Nerdbank.GitVersioning' - displayName: Code sign LKG - condition: and(succeeded(), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['Build.Reason'], 'PullRequest')) - - - task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/deployables - ArtifactName: deployables - ArtifactType: Container - displayName: Publish deployables artifacts - # Only deploy when from a single build in the build matrix - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - - - task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/deployables-lkg - ArtifactName: deployables-lkg - ArtifactType: Container - displayName: Publish deployables-lkg artifact - # Only deploy when from a single build in the build matrix - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - - - task: PublishBuildArtifacts@1 - inputs: - PathtoPublish: $(Build.ArtifactStagingDirectory)/build_logs - ArtifactName: build_logs - ArtifactType: Container - displayName: Publish build_logs artifacts - condition: succeededOrFailed() - - task: NuGetCommand@2 - displayName: Pushing package to PublicCI feed - inputs: - command: push - packagesToPush: $(Build.ArtifactStagingDirectory)/deployables/*.*nupkg - nuGetFeedType: internal - publishVstsFeed: OSS/PublicCI - allowPackageConflicts: true - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest')) - - - pwsh: Set-Content -Path "$(Agent.TempDirectory)/.npmrc" -Value "registry=https://pkgs.dev.azure.com/andrewarnott/OSS/_packaging/PublicCI/npm/registry/`nalways-auth=true" - displayName: Prepare to push to PublicCI - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest')) - - task: npmAuthenticate@0 - displayName: Authenticate to PublicCI - inputs: - workingFile: $(Agent.TempDirectory)/.npmrc - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest')) - - pwsh: | - $tgz = (Get-ChildItem "$(Build.ArtifactStagingDirectory)/deployables/*.tgz")[0].FullName - Write-Host "Will publish $tgz" - npm publish $tgz - workingDirectory: $(Agent.TempDirectory) - displayName: npm publish to PublicCI feed - condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest')) - continueOnError: true + - template: azure-pipelines/build.yml - stage: Test displayName: Functional testing @@ -327,10 +93,10 @@ stages: packageType: runtime version: 3.1.x - task: UseDotNet@2 - displayName: Install .NET 6.0.100 SDK + displayName: Install .NET 6.0.200 SDK inputs: packageType: sdk - version: 6.0.100 + version: 6.0.200 - script: dotnet --info displayName: Show dotnet SDK info - bash: | diff --git a/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 new file mode 100644 index 00000000..391e5713 --- /dev/null +++ b/azure-pipelines/Get-ArtifactsStagingDirectory.ps1 @@ -0,0 +1,15 @@ +Param( + [switch]$CleanIfLocal +) +if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { + $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY +} elseif ($env:RUNNER_TEMP) { + $ArtifactStagingFolder = "$env:RUNNER_TEMP\_artifacts" +} else { + $ArtifactStagingFolder = [System.IO.Path]::GetFullPath("$PSScriptRoot/../obj/_artifacts") + if ($CleanIfLocal -and (Test-Path $ArtifactStagingFolder)) { + Remove-Item $ArtifactStagingFolder -Recurse -Force + } +} + +$ArtifactStagingFolder diff --git a/azure-pipelines/Get-NuGetTool.ps1 b/azure-pipelines/Get-NuGetTool.ps1 new file mode 100644 index 00000000..4431adb9 --- /dev/null +++ b/azure-pipelines/Get-NuGetTool.ps1 @@ -0,0 +1,22 @@ +<# +.SYNOPSIS + Downloads the NuGet.exe tool and returns the path to it. +.PARAMETER NuGetVersion + The version of the NuGet tool to acquire. +#> +Param( + [Parameter()] + [string]$NuGetVersion='5.2.0' +) + +$toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" +$binaryToolsPath = Join-Path $toolsPath $NuGetVersion +if (!(Test-Path $binaryToolsPath)) { $null = mkdir $binaryToolsPath } +$nugetPath = Join-Path $binaryToolsPath nuget.exe + +if (!(Test-Path $nugetPath)) { + Write-Host "Downloading nuget.exe $NuGetVersion..." -ForegroundColor Yellow + (New-Object System.Net.WebClient).DownloadFile("https://dist.nuget.org/win-x86-commandline/v$NuGetVersion/NuGet.exe", $nugetPath) +} + +return (Resolve-Path $nugetPath).Path diff --git a/azure-pipelines/Get-ProcDump.ps1 b/azure-pipelines/Get-ProcDump.ps1 new file mode 100644 index 00000000..1493fe4b --- /dev/null +++ b/azure-pipelines/Get-ProcDump.ps1 @@ -0,0 +1,14 @@ +<# +.SYNOPSIS +Downloads 32-bit and 64-bit procdump executables and returns the path to where they were installed. +#> +$version = '0.0.1' +$baseDir = "$PSScriptRoot\..\obj\tools" +$procDumpToolPath = "$baseDir\procdump.$version\bin" +if (-not (Test-Path $procDumpToolPath)) { + if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } + $baseDir = (Resolve-Path $baseDir).Path # Normalize it + & (& $PSScriptRoot\Get-NuGetTool.ps1) install procdump -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://api.nuget.org/v3/index.json | Out-Null +} + +(Resolve-Path $procDumpToolPath).Path diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1 new file mode 100644 index 00000000..fccb1bb1 --- /dev/null +++ b/azure-pipelines/Get-SymbolFiles.ps1 @@ -0,0 +1,56 @@ +<# +.SYNOPSIS + Collect the list of PDBs built in this repo. +.PARAMETER Path + The directory to recursively search for PDBs. +.PARAMETER Tests + A switch indicating to find PDBs only for test binaries instead of only for shipping shipping binaries. +#> +[CmdletBinding()] +param ( + [parameter(Mandatory=$true)] + [string]$Path, + [switch]$Tests +) + +$ActivityName = "Collecting symbols from $Path" +Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" +$PDBs = Get-ChildItem -rec "$Path/*.pdb" + +# Filter PDBs to product OR test related. +$testregex = "unittest|tests" + +Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" +$PDBsByHash = @{} +$i = 0 +$PDBs |% { + Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length) + $hash = Get-FileHash $_ + $i++ + Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash + Write-Output $_ +} | Sort-Object CreationTime |% { + # De-dupe based on hash. Prefer the first match so we take the first built copy. + if (-not $PDBsByHash.ContainsKey($_.Hash)) { + $PDBsByHash.Add($_.Hash, $_.FullName) + Write-Output $_ + } +} |? { + if ($Tests) { + $_.FullName -match $testregex + } else { + $_.FullName -notmatch $testregex + } +} |% { + # Collect the DLLs/EXEs as well. + $dllPath = "$($_.Directory)/$($_.BaseName).dll" + $exePath = "$($_.Directory)/$($_.BaseName).exe" + if (Test-Path $dllPath) { + $BinaryImagePath = $dllPath + } elseif (Test-Path $exePath) { + $BinaryImagePath = $exePath + } + + Write-Output $BinaryImagePath + Write-Output $_.FullName +} diff --git a/azure-pipelines/Get-TempToolsPath.ps1 b/azure-pipelines/Get-TempToolsPath.ps1 new file mode 100644 index 00000000..bb3da8e3 --- /dev/null +++ b/azure-pipelines/Get-TempToolsPath.ps1 @@ -0,0 +1,13 @@ +if ($env:AGENT_TEMPDIRECTORY) { + $path = "$env:AGENT_TEMPDIRECTORY\$env:BUILD_BUILDID" +} elseif ($env:localappdata) { + $path = "$env:localappdata\gitrepos\tools" +} else { + $path = "$PSScriptRoot\..\obj\tools" +} + +if (!(Test-Path $path)) { + New-Item -ItemType Directory -Path $Path | Out-Null +} + +(Resolve-Path $path).Path diff --git a/azure-pipelines/Get-nbgv.ps1 b/azure-pipelines/Get-nbgv.ps1 new file mode 100644 index 00000000..a5be2cf7 --- /dev/null +++ b/azure-pipelines/Get-nbgv.ps1 @@ -0,0 +1,24 @@ +<# +.SYNOPSIS + Gets the path to the nbgv CLI tool, installing it if necessary. +#> +Param( +) + +$existingTool = Get-Command "nbgv" -ErrorAction SilentlyContinue +if ($existingTool) { + return $existingTool.Path +} + +$toolInstallDir = & "$PSScriptRoot/Get-TempToolsPath.ps1" + +$toolPath = "$toolInstallDir/nbgv" +if (!(Test-Path $toolInstallDir)) { New-Item -Path $toolInstallDir -ItemType Directory | Out-Null } + +if (!(Get-Command $toolPath -ErrorAction SilentlyContinue)) { + Write-Host "Installing nbgv to $toolInstallDir" + dotnet tool install --tool-path "$toolInstallDir" nbgv --configfile "$PSScriptRoot/justnugetorg.nuget.config" | Out-Null +} + +# Normalize the path on the way out. +return (Get-Command $toolPath).Path diff --git a/azure-pipelines/artifacts/Variables.ps1 b/azure-pipelines/artifacts/Variables.ps1 new file mode 100644 index 00000000..4bc6d216 --- /dev/null +++ b/azure-pipelines/artifacts/Variables.ps1 @@ -0,0 +1,43 @@ +# This artifact captures all variables defined in the ..\variables folder. +# It "snaps" the values of these variables where we can compute them during the build, +# and otherwise captures the scripts to run later during an Azure Pipelines environment release. + +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot/../..") +$ArtifactBasePath = "$RepoRoot/obj/_artifacts" +$VariablesArtifactPath = Join-Path $ArtifactBasePath variables +if (-not (Test-Path $VariablesArtifactPath)) { New-Item -ItemType Directory -Path $VariablesArtifactPath | Out-Null } + +# Copy variables, either by value if the value is calculable now, or by script +Get-ChildItem "$PSScriptRoot/../variables" |% { + $value = $null + if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts + # First check the environment variables in case the variable was set in a queued build + # Always use all caps for env var access because Azure Pipelines converts variables to upper-case for env vars, + # and on non-Windows env vars are case sensitive. + $envVarName = $_.BaseName.ToUpper() + if (Test-Path env:$envVarName) { + $value = Get-Content "env:$envVarName" + } + + # If that didn't give us anything, try executing the script right now from its original position + if (-not $value) { + $value = & $_.FullName + } + + if ($value) { + # We got something, so wrap it with quotes so it's treated like a literal value. + $value = "'$value'" + } + } + + # If that didn't get us anything, just copy the script itself + if (-not $value) { + $value = Get-Content -Path $_.FullName + } + + Set-Content -Path "$VariablesArtifactPath/$($_.Name)" -Value $value +} + +@{ + "$VariablesArtifactPath" = (Get-ChildItem $VariablesArtifactPath -Recurse); +} diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 new file mode 100644 index 00000000..afe42be3 --- /dev/null +++ b/azure-pipelines/artifacts/_all.ps1 @@ -0,0 +1,70 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + This script returns all the artifacts that should be collected after a build. + Each powershell artifact is expressed as an object with these properties: + Source - the full path to the source file + ArtifactName - the name of the artifact to upload to + ContainerFolder - the relative path within the artifact in which the file should appear + Each artifact aggregating .ps1 script should return a hashtable: + Key = path to the directory from which relative paths within the artifact should be calculated + Value = an array of paths (absolute or relative to the BaseDirectory) to files to include in the artifact. + FileInfo objects are also allowed. +.PARAMETER Force + Executes artifact scripts even if they have already been uploaded. +#> + +param ( + [string]$ArtifactNameSuffix, + [switch]$Force +) + +Function EnsureTrailingSlash($path) { + if ($path.length -gt 0 -and !$path.EndsWith('\') -and !$path.EndsWith('/')) { + $path = $path + [IO.Path]::DirectorySeparatorChar + } + + $path.Replace('\', [IO.Path]::DirectorySeparatorChar) +} + +Function Test-ArtifactUploaded($artifactName) { + $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" + Test-Path "env:$varName" +} + +Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { + $ArtifactName = $_.BaseName + if ($Force -or !(Test-ArtifactUploaded($ArtifactName + $ArtifactNameSuffix))) { + $totalFileCount = 0 + $fileGroups = & $_ + if ($fileGroups) { + $fileGroups.GetEnumerator() | % { + $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key.ToString()), [UriKind]::Absolute) + $_.Value | ? { $_ } | % { + if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { + $_ = $_.FullName + } + + $artifact = New-Object -TypeName PSObject + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ArtifactName -Value $ArtifactName + + $SourceFullPath = New-Object Uri ($BaseDirectory, $_) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Source -Value $SourceFullPath.LocalPath + + $RelativePath = [Uri]::UnescapeDataString($BaseDirectory.MakeRelative($SourceFullPath)) + Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) + + Write-Output $artifact + $totalFileCount += 1 + } + } + } + + if ($totalFileCount -eq 0) { + Write-Warning "No files found for the `"$ArtifactName`" artifact." + } + } else { + Write-Host "Skipping $ArtifactName because it has already been uploaded." -ForegroundColor DarkGray + } +} diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 new file mode 100644 index 00000000..73a3af0a --- /dev/null +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -0,0 +1,15 @@ +# This script translates all the artifacts described by _all.ps1 +# into commands that instruct Azure Pipelines to actually collect those artifacts. + +param ( + [string]$ArtifactNameSuffix +) + +& "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% { + Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" + + # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts + # will skip this one from a check in the _all.ps1 script. + $varName = "ARTIFACTUPLOADED_$($_.Name.ToUpper())" + Write-Host "##vso[task.setvariable variable=$varName]true" +} diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 new file mode 100644 index 00000000..e4954c13 --- /dev/null +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -0,0 +1,50 @@ +# This script links all the artifacts described by _all.ps1 +# into a staging directory, reading for uploading to a cloud build artifact store. +# It returns a sequence of objects with Name and Path properties. +[CmdletBinding()] +param ( + [string]$ArtifactNameSuffix +) + +$ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" -CleanIfLocal + +function Create-SymbolicLink { + param ( + $Link, + $Target + ) + + if ($Link -eq $Target) { + return + } + + if (Test-Path $Link) { Remove-Item $Link } + $LinkContainer = Split-Path $Link -Parent + if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer } + if ($IsMacOS -or $IsLinux) { + ln $Target $Link | Out-Null + } else { + cmd /c "mklink `"$Link`" `"$Target`"" | Out-Null + } +} + +# Stage all artifacts +$Artifacts = & "$PSScriptRoot\_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix +$Artifacts |% { + $DestinationFolder = [System.IO.Path]::GetFullPath("$ArtifactStagingFolder/$($_.ArtifactName)$ArtifactNameSuffix/$($_.ContainerFolder)").TrimEnd('\') + $Name = "$(Split-Path $_.Source -Leaf)" + + #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow + + if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null } + if (Test-Path -PathType Leaf $_.Source) { # skip folders + Create-SymbolicLink -Link (Join-Path $DestinationFolder $Name) -Target $_.Source + } +} + +$Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } | Get-Unique |% { + $artifact = New-Object -TypeName PSObject + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Name -Value $_ + Add-Member -InputObject $artifact -MemberType NoteProperty -Name Path -Value (Join-Path $ArtifactStagingFolder $_) + Write-Output $artifact +} diff --git a/azure-pipelines/artifacts/build_logs.ps1 b/azure-pipelines/artifacts/build_logs.ps1 new file mode 100644 index 00000000..f05358e0 --- /dev/null +++ b/azure-pipelines/artifacts/build_logs.ps1 @@ -0,0 +1,7 @@ +$ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" + +if (!(Test-Path $ArtifactStagingFolder/build_logs)) { return } + +@{ + "$ArtifactStagingFolder/build_logs" = (Get-ChildItem -Recurse "$ArtifactStagingFolder/build_logs") +} diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 new file mode 100644 index 00000000..8fdb3f72 --- /dev/null +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -0,0 +1,22 @@ +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") + +# Prepare code coverage reports for merging on another machine +if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) { + Write-Host "Substituting $env:SYSTEM_DEFAULTWORKINGDIRECTORY with `"{reporoot}`"" + $reports = Get-ChildItem "$RepoRoot/bin/coverage.*cobertura.xml" -Recurse + $reports |% { + $content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape($env:SYSTEM_DEFAULTWORKINGDIRECTORY), "{reporoot}" } + Set-Content -Path $_ -Value $content -Encoding UTF8 + } +} else { + Write-Warning "coverageResults: Azure Pipelines not detected. Machine-neutral token replacement skipped." +} + +if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } + +@{ + $RepoRoot = ( + @(Get-ChildItem "$RepoRoot\bin\coverage.*cobertura.xml" -Recurse) + + (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) + ); +} diff --git a/azure-pipelines/artifacts/deployables-LKG.ps1 b/azure-pipelines/artifacts/deployables-LKG.ps1 new file mode 100644 index 00000000..94c48cdd --- /dev/null +++ b/azure-pipelines/artifacts/deployables-LKG.ps1 @@ -0,0 +1,13 @@ +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +$BuildConfiguration = $env:BUILDCONFIGURATION +if (!$BuildConfiguration) { + $BuildConfiguration = 'Debug' +} + +$PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" + +if (!(Test-Path $PackagesRoot)) { return } + +@{ + "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) +} diff --git a/azure-pipelines/artifacts/deployables.ps1 b/azure-pipelines/artifacts/deployables.ps1 new file mode 100644 index 00000000..94c48cdd --- /dev/null +++ b/azure-pipelines/artifacts/deployables.ps1 @@ -0,0 +1,13 @@ +$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +$BuildConfiguration = $env:BUILDCONFIGURATION +if (!$BuildConfiguration) { + $BuildConfiguration = 'Debug' +} + +$PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" + +if (!(Test-Path $PackagesRoot)) { return } + +@{ + "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) +} diff --git a/azure-pipelines/artifacts/projectAssetsJson.ps1 b/azure-pipelines/artifacts/projectAssetsJson.ps1 new file mode 100644 index 00000000..d2e85ffb --- /dev/null +++ b/azure-pipelines/artifacts/projectAssetsJson.ps1 @@ -0,0 +1,9 @@ +$ObjRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\obj") + +if (!(Test-Path $ObjRoot)) { return } + +@{ + "$ObjRoot" = ( + (Get-ChildItem "$ObjRoot\project.assets.json" -Recurse) + ); +} diff --git a/azure-pipelines/artifacts/symbols.ps1 b/azure-pipelines/artifacts/symbols.ps1 new file mode 100644 index 00000000..9e2c7bd5 --- /dev/null +++ b/azure-pipelines/artifacts/symbols.ps1 @@ -0,0 +1,7 @@ +$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") +if (!(Test-Path $BinPath)) { return } +$symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique + +@{ + "$BinPath" = $SymbolFiles; +} diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 new file mode 100644 index 00000000..2f894c97 --- /dev/null +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -0,0 +1,20 @@ +$result = @{} + +if ($env:AGENT_TEMPDIRECTORY) { + # The DotNetCoreCLI uses an alternate location to publish these files + $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' + $result[$env:AGENT_TEMPDIRECTORY] = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { + Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\*_crashdump.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse + }); +} +else { + $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" + $result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File) +} + +$testlogsPath = "$env:BUILD_ARTIFACTSTAGINGDIRECTORY\test_logs" +if (Test-Path $testlogsPath) { + $result[$testlogsPath] = Get-ChildItem "$testlogsPath\*"; +} + +$result diff --git a/azure-pipelines/artifacts/test_symbols.ps1 b/azure-pipelines/artifacts/test_symbols.ps1 new file mode 100644 index 00000000..ce2b6481 --- /dev/null +++ b/azure-pipelines/artifacts/test_symbols.ps1 @@ -0,0 +1,7 @@ +$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") +if (!(Test-Path $BinPath)) { return } +$symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath -Tests | Get-Unique + +@{ + "$BinPath" = $SymbolFiles; +} diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml new file mode 100644 index 00000000..4ed7cee7 --- /dev/null +++ b/azure-pipelines/build.yml @@ -0,0 +1,59 @@ +parameters: +- name: windowsPool + type: object + default: + vmImage: windows-2022 +- name: includeMacOS + +jobs: +- job: Windows + pool: ${{ parameters.windowsPool }} + variables: + testModifier: + dotnet32: "\"C:\\Program Files (x86)\\dotnet\\dotnet.exe\"" + - ${{ if eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/') }}: + - group: dotnetfoundation code signing + steps: + - checkout: self + clean: true + submodules: true # keep the warnings quiet about the wiki not being enlisted + - template: install-dependencies.yml + - pwsh: | + Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 + & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose -Runtime dotnet + & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.202 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + displayName: Install 32-bit .NET SDK and runtimes + + - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' + displayName: Set build number + + - template: dotnet.yml + +- job: Linux + pool: + vmImage: Ubuntu 20.04 + variables: + testModifier: -f net6.0 + steps: + - checkout: self + clean: true + submodules: true # keep the warnings quiet about the wiki not being enlisted + - template: install-dependencies.yml + - template: dotnet.yml + +- job: WrapUp + dependsOn: + - Windows + - Linux + pool: ${{ parameters.windowsPool }} # Use Windows agent because PublishSymbols task requires it (https://github.com/microsoft/azure-pipelines-tasks/issues/13821). + condition: succeededOrFailed() + steps: + - checkout: self + clean: true + - template: install-dependencies.yml + parameters: + initArgs: -NoRestore + - template: publish-codecoverage.yml + parameters: + includeMacOS: ${{ parameters.includeMacOS }} + - template: publish-deployables.yml diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 new file mode 100644 index 00000000..588fe871 --- /dev/null +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -0,0 +1,68 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + Runs tests as they are run in cloud test runs. +.PARAMETER Configuration + The configuration within which to run tests +.PARAMETER Agent + The name of the agent. This is used in preparing test run titles. +.PARAMETER PublishResults + A switch to publish results to Azure Pipelines. +.PARAMETER dotnet32 + The path to the 32-bit dotnet.exe to use to run tests. If not specified, the default (typically 64-bit) dotnet process will be used. +#> +Param( + [string]$Configuration='Debug', + [string]$Agent='Local', + [switch]$PublishResults, + [string]$dotnet32 +) + +$RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path +$ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" + +$dotnet = 'dotnet' +if ($dotnet32) { + $dotnet = $dotnet32 + $x86RunTitle = ", x86" +} + +& $dotnet test $RepoRoot ` + --no-build ` + -c $Configuration ` + --filter "TestCategory!=FailsInCloudTest" ` + -p:CollectCoverage=true ` + --blame-hang-timeout 60s ` + --blame-crash ` + -bl:"$ArtifactStagingFolder/build_logs/test.binlog" ` + --diag "$ArtifactStagingFolder/test_logs/diag.log;TraceLevel=info" ` + --logger trx ` + -- ` + RunConfiguration.DisableAppDomain=true + +$unknownCounter = 0 +Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { + Copy-Item $_ -Destination $ArtifactStagingFolder/test_logs/ + + if ($PublishResults) { + $x = [xml](Get-Content -Path $_) + $runTitle = $null + if ($x.TestRun.TestDefinitions -and $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')) { + $storage = $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')[0].storage -replace '\\','/' + if ($storage -match '/(?net[^/]+)/(?:(?[^/]+)/)?(?[^/]+)\.dll$') { + if ($matches.rid) { + $runTitle = "$($matches.lib) ($($matches.tfm), $($matches.rid), $Agent$x86RunTitle)" + } else { + $runTitle = "$($matches.lib) ($($matches.tfm), $Agent$x86RunTitle)" + } + } + } + if (!$runTitle) { + $unknownCounter += 1; + $runTitle = "unknown$unknownCounter ($Agent$x86RunTitle)"; + } + + Write-Host "##vso[results.publish type=VSTest;runTitle=$runTitle;publishRunAttachments=true;resultFiles=$_;failTaskOnFailedTests=true;testRunSystem=VSTS - PTR;]" + } +} diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml new file mode 100644 index 00000000..1ad1b039 --- /dev/null +++ b/azure-pipelines/dotnet.yml @@ -0,0 +1,73 @@ +steps: + +- script: | + git config --global user.name ci + git config --global user.email me@ci.com + displayName: Configure git commit author for testing + +- script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" + displayName: dotnet build + +- script: dotnet pack -c $(BuildConfiguration) --no-build -p:PackLKG=true /bl:"$(Build.ArtifactStagingDirectory)/build_logs/msbuild_lkg.binlog" + displayName: Build LKG package + workingDirectory: src/Nerdbank.GitVersioning.Tasks + +- script: dotnet publish -c $(BuildConfiguration) -o ../nerdbank-gitversioning.npm/out/nbgv.cli/tools/netcoreapp3.1/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog" + displayName: Publish nbgv tool + workingDirectory: src/nbgv + +- task: gulp@0 + displayName: Build nerdbank-gitversioning NPM package + inputs: + gulpfile: src/nerdbank-gitversioning.npm/gulpfile.js + +- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults + displayName: dotnet test x64 + +- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults -dotnet32 '$(dotnet32)' + displayName: dotnet test x86 + condition: ne(variables['dotnet32'], '') + +- pwsh: > + dotnet tool install --tool-path obj SignClient + + obj/SignClient sign + --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables' + --input '**/*' + --config '$(System.DefaultWorkingDirectory)/azure-pipelines/SignClient.json' + --filelist '$(System.DefaultWorkingDirectory)/azure-pipelines/signfiles.txt' + --user '$(codesign_username)' + --secret '$(codesign_secret)' + --name 'Nerdbank.GitVersioning' + --descriptionUrl 'https://github.com/dotnet/Nerdbank.GitVersioning' + displayName: Code sign + condition: and(succeeded(), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['Build.Reason'], 'PullRequest')) + +- pwsh: > + obj/SignClient sign + --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables-lkg' + --input '**/*' + --config '$(System.DefaultWorkingDirectory)/azure-pipelines/SignClient.json' + --filelist '$(System.DefaultWorkingDirectory)/azure-pipelines/signfiles.txt' + --user '$(codesign_username)' + --secret '$(codesign_secret)' + --name 'Nerdbank.GitVersioning' + --descriptionUrl 'https://github.com/dotnet/Nerdbank.GitVersioning' + displayName: Code sign LKG + condition: and(succeeded(), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), eq(variables['Agent.OS'], 'Windows_NT'), ne(variables['Build.Reason'], 'PullRequest')) + +- powershell: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true + displayName: Update pipeline variables based on build outputs + condition: succeededOrFailed() + +- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" + failOnStderr: true + displayName: Publish artifacts + condition: succeededOrFailed() + +- bash: bash <(curl -s https://codecov.io/bash) + displayName: Publish code coverage results to codecov.io + condition: ne(variables['codecov_token'], '') + timeoutInMinutes: 3 + continueOnError: true diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml new file mode 100644 index 00000000..4f848b09 --- /dev/null +++ b/azure-pipelines/install-dependencies.yml @@ -0,0 +1,25 @@ +parameters: + initArgs: + +steps: + +- task: NuGetAuthenticate@0 + displayName: Authenticate NuGet feeds + inputs: + forceReinstallCredentialProvider: true + +- powershell: | + $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors + .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites -NoNuGetCredProvider + dotnet --info + + # Print mono version if it is present. + if (Get-Command mono -ErrorAction SilentlyContinue) { + mono --version + } + displayName: Install prerequisites + +- powershell: azure-pipelines/variables/_pipelines.ps1 + failOnStderr: true + displayName: Set pipeline variables based on source + name: SetPipelineVariables diff --git a/azure-pipelines/justnugetorg.nuget.config b/azure-pipelines/justnugetorg.nuget.config new file mode 100644 index 00000000..765346e5 --- /dev/null +++ b/azure-pipelines/justnugetorg.nuget.config @@ -0,0 +1,7 @@ + + + + + + + diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml new file mode 100644 index 00000000..a0862be3 --- /dev/null +++ b/azure-pipelines/publish-codecoverage.yml @@ -0,0 +1,35 @@ +parameters: + includeMacOS: + +steps: +- download: current + artifact: coverageResults-Windows + displayName: Download Windows code coverage results + continueOnError: true +- download: current + artifact: coverageResults-Linux + displayName: Download Linux code coverage results + continueOnError: true +- download: current + artifact: coverageResults-macOS + displayName: Download macOS code coverage results + continueOnError: true + condition: ${{ parameters.includeMacOS }} +- powershell: | + dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.8.5 --configfile azure-pipelines/justnugetorg.nuget.config + Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj + Write-Host 'Substituting {reporoot} with $(System.DefaultWorkingDirectory)' + $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/coverage.*cobertura.xml' + $reports |% { + $content = Get-Content -Path $_ |% { $_.Replace('{reporoot}', '$(System.DefaultWorkingDirectory)') } + Set-Content -Path $_ -Value $content -Encoding UTF8 + } + $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ })) + obj/reportgenerator -reports:"$Inputs" -targetdir:coveragereport -reporttypes:Cobertura + displayName: Merge coverage +- task: PublishCodeCoverageResults@1 + displayName: Publish code coverage results to Azure DevOps + inputs: + codeCoverageTool: cobertura + summaryFileLocation: 'coveragereport/Cobertura.xml' + failIfCoverageEmpty: true diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml new file mode 100644 index 00000000..14c3f78f --- /dev/null +++ b/azure-pipelines/publish-deployables.yml @@ -0,0 +1,17 @@ +steps: +- download: current + displayName: Download deployables + artifact: deployables-Windows + +- powershell: dotnet nuget push "$(Resolve-Path '$(Pipeline.Workspace)\deployables-Windows\')*.nupkg" -s $(ci_feed) -k azdo --skip-duplicate + displayName: Push packages to CI feed + condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) + +- pwsh: | + $tgz = (Get-ChildItem "$(Pipeline.Workspace)/deployables-Windows/*.tgz")[0].FullName + Write-Host "Will publish $tgz" + npm publish $tgz + workingDirectory: $(Agent.TempDirectory) + displayName: npm publish to PublicCI feed + continueOnError: true + condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 613b925c..ed95d940 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -9,96 +9,66 @@ resources: tags: - auto-release -stages: -- stage: GitHubRelease - displayName: GitHub Release - jobs: - - deployment: create - pool: - vmImage: ubuntu-latest - environment: No-Approval # Approval is already granted in the release stage. - strategy: - runOnce: - deploy: - steps: - - download: none - - powershell: | - Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" - displayName: Set pipeline name - - task: GitHubRelease@1 - displayName: GitHub release (create) - inputs: - gitHubConnection: github.com_AArnott_OAuth - repositoryName: $(Build.Repository.Name) - target: $(resources.pipeline.CI.sourceCommit) - tagSource: userSpecifiedTag - tag: v$(resources.pipeline.CI.runName) - title: v$(resources.pipeline.CI.runName) - isDraft: true - changeLogCompareToRelease: lastNonDraftRelease - changeLogType: issueBased - changeLogLabels: | - [ - { "label" : "breaking changes", "displayName" : "Breaking changes", "state" : "closed" }, - { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, - { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } - ] +variables: +- group: Publishing secrets -- stage: nuget_org - displayName: nuget.org - dependsOn: GitHubRelease - jobs: - - deployment: push - pool: - vmImage: ubuntu-latest - environment: No-Approval # Approval is already granted in the release stage. - strategy: - runOnce: - deploy: - steps: - - download: CI - artifact: deployables - displayName: Download deployables artifact - patterns: '**/*.*nupkg' - - task: NuGetToolInstaller@1 - displayName: Use NuGet 5.x - inputs: - versionSpec: 5.x - - task: NuGetCommand@2 - displayName: NuGet push - inputs: - command: push - packagesToPush: $(Pipeline.Workspace)/CI/deployables/*.nupkg - nuGetFeedType: external - publishFeedCredentials: nuget.org +jobs: +- job: release + pool: + vmImage: ubuntu-latest + steps: + - checkout: none + - powershell: | + Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" + if ('$(resources.pipeline.CI.runName)'.Contains('-')) { + Write-Host "##vso[task.setvariable variable=IsPrerelease]true" + } else { + Write-Host "##vso[task.setvariable variable=IsPrerelease]false" + } + displayName: Set up pipeline + - task: UseDotNet@2 + displayName: Install .NET SDK + inputs: + packageType: sdk + version: 6.x + - download: CI + artifact: deployables-Windows + displayName: Download deployables-Windows artifact + patterns: 'deployables-Windows/*' + - task: GitHubRelease@1 + displayName: GitHub release (create) + inputs: + gitHubConnection: github.com_AArnott_OAuth + repositoryName: $(Build.Repository.Name) + target: $(resources.pipeline.CI.sourceCommit) + tagSource: userSpecifiedTag + tag: v$(resources.pipeline.CI.runName) + title: v$(resources.pipeline.CI.runName) + isDraft: true # After running this step, visit the new draft release, edit, and publish. + isPreRelease: $(IsPrerelease) + assets: $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg + changeLogCompareToRelease: lastNonDraftRelease + changeLogType: issueBased + changeLogLabels: | + [ + { "label" : "breaking changes", "displayName" : "Breaking changes", "state" : "closed" }, + { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, + { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } + ] + - script: dotnet nuget push $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg -s https://api.nuget.org/v3/index.json --api-key $(NuGetOrgApiKey) --skip-duplicate + displayName: Push packages to nuget.org + condition: and(succeeded(), ne(variables['NuGetOrgApiKey'], '')) + - powershell: | + $tgz = (Get-ChildItem "$(Pipeline.Workspace)/CI/deployables-Windows/*.tgz")[0].FullName -- stage: npmjs_org - displayName: npmjs.org - dependsOn: GitHubRelease - jobs: - - deployment: push - pool: - vmImage: ubuntu-latest - environment: No-Approval # Approval is already granted in the release stage. - strategy: - runOnce: - deploy: - steps: - - download: CI - artifact: deployables - displayName: Download deployables artifact - patterns: '**/*.tgz' - - powershell: | - $tgz = (Get-ChildItem "$(Pipeline.Workspace)/CI/deployables/*.tgz")[0].FullName - - npm init -y - npm install $tgz - workingDirectory: $(Agent.TempDirectory) - displayName: Prepare to publish NPM package - - task: Npm@1 - displayName: npm publish - inputs: - command: publish - workingDir: $(Agent.TempDirectory)/node_modules/nerdbank-gitversioning - verbose: false - publishEndpoint: npmjs.org + npm init -y + npm install $tgz + workingDirectory: $(Agent.TempDirectory) + displayName: Prepare to publish NPM package + - task: Npm@1 + displayName: npm publish + inputs: + command: publish + workingDir: $(Agent.TempDirectory)/node_modules/nerdbank-gitversioning + verbose: false + publishEndpoint: npmjs.org diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1 new file mode 100644 index 00000000..0407d307 --- /dev/null +++ b/azure-pipelines/variables/_all.ps1 @@ -0,0 +1,13 @@ +#!/usr/bin/env pwsh + +# This script returns a hashtable of build variables that should be set +# at the start of a build or release definition's execution. + +$vars = @{} + +Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" |% { + Write-Host "Computing $($_.BaseName) variable" + $vars[$_.BaseName] = & $_ +} + +$vars diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 new file mode 100644 index 00000000..867b7fc8 --- /dev/null +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -0,0 +1,24 @@ +# This script translates the variables returned by the _all.ps1 script +# into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume. + +# The build or release definition may have set these variables to override +# what the build would do. So only set them if they have not already been set. + +(& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { + # Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive. + $keyCaps = $_.Key.ToUpper() + if (Test-Path -Path "env:$keyCaps") { + Write-Host "Skipping setting $keyCaps because variable is already set to '$(Get-Content env:$keyCaps)'." -ForegroundColor Cyan + } else { + Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow + if ($env:TF_BUILD) { + # Create two variables: the first that can be used by its simple name and accessible only within this job. + Write-Host "##vso[task.setvariable variable=$keyCaps]$($_.Value)" + # and the second that works across jobs and stages but must be fully qualified when referenced. + Write-Host "##vso[task.setvariable variable=$keyCaps;isOutput=true]$($_.Value)" + } elseif ($env:GITHUB_ACTIONS) { + Add-Content -Path $env:GITHUB_ENV -Value "$keyCaps=$($_.Value)" + } + Set-Item -Path "env:$keyCaps" -Value $_.Value + } +} diff --git a/global.json b/global.json index 9425292c..6bfbd177 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.202", + "version": "6.0.200", "rollForward": "patch", "allowPrerelease": false } diff --git a/init.cmd b/init.cmd index 970285c2..667efabb 100644 --- a/init.cmd +++ b/init.cmd @@ -1,4 +1,20 @@ @echo off SETLOCAL set PS1UnderCmd=1 + +:: Get the datetime in a format that can go in a filename. +set _my_datetime=%date%_%time% +set _my_datetime=%_my_datetime: =_% +set _my_datetime=%_my_datetime::=% +set _my_datetime=%_my_datetime:/=_% +set _my_datetime=%_my_datetime:.=_% +set CmdEnvScriptPath=%temp%\envvarscript_%_my_datetime%.cmd + powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }" + +:: Set environment variables in the parent cmd.exe process. +IF EXIST "%CmdEnvScriptPath%" ( + ENDLOCAL + CALL "%CmdEnvScriptPath%" + DEL "%CmdEnvScriptPath%" +) diff --git a/init.ps1 b/init.ps1 index 8b11d60b..71f4261d 100755 --- a/init.ps1 +++ b/init.ps1 @@ -2,40 +2,74 @@ <# .SYNOPSIS -Installs dependencies required to build and test the projects in this repository. + Installs dependencies required to build and test the projects in this repository. .DESCRIPTION -This MAY not require elevation, as the SDK and runtimes are installed to a per-user location, -unless the `-InstallLocality` switch is specified directing to a per-repo or per-machine location. -See detailed help on that switch for more information. + This MAY not require elevation, as the SDK and runtimes are installed to a per-user location, + unless the `-InstallLocality` switch is specified directing to a per-repo or per-machine location. + See detailed help on that switch for more information. + + The CmdEnvScriptPath environment variable may be optionally set to a path to a cmd shell script to be created (or appended to if it already exists) that will set the environment variables in cmd.exe that are set within the PowerShell environment. + This is used by init.cmd in order to reapply any new environment variables to the parent cmd.exe process that were set in the powershell child process. .PARAMETER InstallLocality -A value indicating whether dependencies should be installed locally to the repo or at a per-user location. -Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. -Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. -Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. -When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. -Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. -Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. + A value indicating whether dependencies should be installed locally to the repo or at a per-user location. + Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache. + Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script. + Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build. + When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. + Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. + Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. .PARAMETER NoPrerequisites -Skips the installation of prerequisite software (e.g. SDKs, tools). + Skips the installation of prerequisite software (e.g. SDKs, tools). +.PARAMETER NoNuGetCredProvider + Skips the installation of the NuGet credential provider. Useful in pipelines with the `NuGetAuthenticate` task, as a workaround for https://github.com/microsoft/artifacts-credprovider/issues/244. + This switch is ignored and installation is skipped when -NoPrerequisites is specified. +.PARAMETER UpgradePrerequisites + Takes time to install prerequisites even if they are already present in case they need to be upgraded. + No effect if -NoPrerequisites is specified. .PARAMETER NoRestore -Skips the package restore step. + Skips the package restore step. +.PARAMETER AccessToken + An optional access token for authenticating to Azure Artifacts authenticated feeds. #> -[CmdletBinding(SupportsShouldProcess=$true)] -Param( - [ValidateSet('repo','user','machine')] - [string]$InstallLocality='user', +[CmdletBinding(SupportsShouldProcess = $true)] +Param ( + [ValidateSet('repo', 'user', 'machine')] + [string]$InstallLocality = 'user', [Parameter()] [switch]$NoPrerequisites, [Parameter()] - [switch]$NoRestore + [switch]$NoNuGetCredProvider, + [Parameter()] + [switch]$UpgradePrerequisites, + [Parameter()] + [switch]$NoRestore, + [Parameter()] + [string]$AccessToken ) +$EnvVars = @{} +$PrependPath = @() + if (!$NoPrerequisites) { + if (!$NoNuGetCredProvider) { + & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites + } + & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality + if ($LASTEXITCODE -eq 3010) { + Exit 3010 + } + + # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests. + # But it only works on Windows. + if ($env:OS -eq 'Windows_NT') { + $EnvVars['PROCDUMP_PATH'] = & "$PSScriptRoot\azure-pipelines\Get-ProcDump.ps1" + } } -$oldPlatform=$env:Platform -$env:Platform='Any CPU' # Some people wander in here from a platform-specific build window. +# Workaround nuget credential provider bug that causes very unreliable package restores on Azure Pipelines +$env:NUGET_PLUGIN_HANDSHAKE_TIMEOUT_IN_SECONDS = 20 +$env:NUGET_PLUGIN_REQUEST_TIMEOUT_IN_SECONDS = 20 Push-Location $PSScriptRoot try { @@ -43,27 +77,30 @@ try { if (!$NoRestore -and $PSCmdlet.ShouldProcess("NuGet packages", "Restore")) { Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor - dotnet restore "$PSScriptRoot\src" + dotnet restore if ($lastexitcode -ne 0) { throw "Failure while restoring packages." } } - Write-Host "Restoring NPM packages..." -ForegroundColor Yellow - Push-Location "$PSScriptRoot\src\nerdbank-gitversioning.npm" - try { - if ($PSCmdlet.ShouldProcess("$PSScriptRoot\src\nerdbank-gitversioning.npm", "yarn install")) { - yarn install --loglevel error + if (!$NoRestore -and $PSCmdlet.ShouldProcess("NPM packages", "Restore")) { + Write-Host "Restoring NPM packages..." -ForegroundColor Yellow + Push-Location "$PSScriptRoot\src\nerdbank-gitversioning.npm" + try { + if ($PSCmdlet.ShouldProcess("$PSScriptRoot\src\nerdbank-gitversioning.npm", "yarn install")) { + yarn install --loglevel error + } + } finally { + Pop-Location } - } finally { - Pop-Location } - Write-Host "Successfully restored all dependencies" -ForegroundColor Yellow -} catch { + & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars -PrependPath $PrependPath | Out-Null +} +catch { Write-Error $error[0] exit $lastexitcode -} finally { - $env:Platform=$oldPlatform +} +finally { Pop-Location } diff --git a/src/nuget.config b/nuget.config similarity index 90% rename from src/nuget.config rename to nuget.config index ede70863..f1b5445d 100644 --- a/src/nuget.config +++ b/nuget.config @@ -9,6 +9,10 @@ + + + + Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer diff --git a/src/.editorconfig b/src/.editorconfig new file mode 100644 index 00000000..e69de29b diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs new file mode 100644 index 00000000..f98fa527 --- /dev/null +++ b/src/AssemblyInfo.cs @@ -0,0 +1,6 @@ +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; + +[assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 49b38e6a..779786c0 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -6,7 +6,6 @@ Chris Crutchfield, Andrew Arnott andarno Cake wrapper for Nerdbank.GitVersioning. Stamps your assemblies with semver 2.0 compliant git commit specific version information and provides NuGet versioning information as well. - Copyright (c) .NET Foundation and Contributors git commit versioning version assemblyinfo cake-addin https://cdn.jsdelivr.net/gh/cake-contrib/graphics/png/addin/cake-contrib-addin-medium.png cake-contrib-addin-medium.png diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 105676df..77d94765 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,43 +1,3 @@ - - Debug - $(MSBuildThisFileDirectory)..\obj\$(MSBuildProjectName)\ - $(MSBuildThisFileDirectory)..\bin\$(MSBuildProjectName)\$(Configuration)\ - $(MSBuildThisFileDirectory)..\wiki\api - 9.0 - - true - $(MSBuildThisFileDirectory)strongname.snk - - Andrew Arnott - aarnott - git commit versioning version assemblyinfo - https://github.com/dotnet/Nerdbank.GitVersioning - MIT - - true - true - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - - - - 2.0.315-alpha.0.9 - - - - - - all - runtime; build; native; contentfiles; analyzers - - - - - - - - - https://github.com/dotnet/Nerdbank.GitVersioning/releases/tag/v$(Version) - - + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets new file mode 100644 index 00000000..566ab4fc --- /dev/null +++ b/src/Directory.Build.targets @@ -0,0 +1,7 @@ + + + + + + + diff --git a/src/strongname.snk b/strongname.snk similarity index 100% rename from src/strongname.snk rename to strongname.snk diff --git a/stylecop.json b/stylecop.json new file mode 100644 index 00000000..4d2f211b --- /dev/null +++ b/stylecop.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", + "settings": { + "documentationRules": { + "companyName": ".NET Foundation and Contributors", + "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.", + "variables": { + "licenseName": "MIT", + "licenseFile": "LICENSE" + }, + "fileNamingConvention": "metadata", + "xmlHeader": false + } + } +} diff --git a/test/.editorconfig b/test/.editorconfig new file mode 100644 index 00000000..8aa791be --- /dev/null +++ b/test/.editorconfig @@ -0,0 +1,52 @@ +[*.cs] + +# SA1600: Elements should be documented +dotnet_diagnostic.SA1600.severity = silent + +# SA1601: Partial elements should be documented +dotnet_diagnostic.SA1601.severity = silent + +# SA1602: Enumeration items should be documented +dotnet_diagnostic.SA1602.severity = silent + +# SA1615: Element return value should be documented +dotnet_diagnostic.SA1615.severity = silent + +# VSTHRD103: Call async methods when in an async method +dotnet_diagnostic.VSTHRD103.severity = silent + +# VSTHRD111: Use .ConfigureAwait(bool) +dotnet_diagnostic.VSTHRD111.severity = none + +# VSTHRD200: Use Async suffix for async methods +dotnet_diagnostic.VSTHRD200.severity = silent + +# CA1014: Mark assemblies with CLSCompliant +dotnet_diagnostic.CA1014.severity = none + +# CA1050: Declare types in namespaces +dotnet_diagnostic.CA1050.severity = none + +# CA1303: Do not pass literals as localized parameters +dotnet_diagnostic.CA1303.severity = none + +# CS1591: Missing XML comment for publicly visible type or member +dotnet_diagnostic.CS1591.severity = silent + +# CA1707: Identifiers should not contain underscores +dotnet_diagnostic.CA1707.severity = silent + +# CA1062: Validate arguments of public methods +dotnet_diagnostic.CA1062.severity = suggestion + +# CA1063: Implement IDisposable Correctly +dotnet_diagnostic.CA1063.severity = silent + +# CA1816: Dispose methods should call SuppressFinalize +dotnet_diagnostic.CA1816.severity = silent + +# CA2007: Consider calling ConfigureAwait on the awaited task +dotnet_diagnostic.CA2007.severity = none + +# SA1401: Fields should be private +dotnet_diagnostic.SA1401.severity = silent diff --git a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj similarity index 100% rename from src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj rename to test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj diff --git a/src/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs b/test/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs similarity index 100% rename from src/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs rename to test/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs diff --git a/test/Directory.Build.props b/test/Directory.Build.props new file mode 100644 index 00000000..449a06e4 --- /dev/null +++ b/test/Directory.Build.props @@ -0,0 +1,9 @@ + + + + + false + true + + + diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets new file mode 100644 index 00000000..2faab375 --- /dev/null +++ b/test/Directory.Build.targets @@ -0,0 +1,10 @@ + + + cobertura + [xunit.*]* + + $(OutputPath)/ + + + + diff --git a/src/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs b/test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs similarity index 100% rename from src/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs rename to test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs diff --git a/src/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj similarity index 100% rename from src/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj rename to test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj diff --git a/src/NerdBank.GitVersioning.Benchmarks/Program.cs b/test/NerdBank.GitVersioning.Benchmarks/Program.cs similarity index 100% rename from src/NerdBank.GitVersioning.Benchmarks/Program.cs rename to test/NerdBank.GitVersioning.Benchmarks/Program.cs diff --git a/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs b/test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs rename to test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs rename to test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/FilterPathTests.cs b/test/NerdBank.GitVersioning.Tests/FilterPathTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/FilterPathTests.cs rename to test/NerdBank.GitVersioning.Tests/FilterPathTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/GitContextTests.cs b/test/NerdBank.GitVersioning.Tests/GitContextTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/GitContextTests.cs rename to test/NerdBank.GitVersioning.Tests/GitContextTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/Keys/keypair.snk b/test/NerdBank.GitVersioning.Tests/Keys/keypair.snk similarity index 100% rename from src/NerdBank.GitVersioning.Tests/Keys/keypair.snk rename to test/NerdBank.GitVersioning.Tests/Keys/keypair.snk diff --git a/src/NerdBank.GitVersioning.Tests/Keys/protectedPair.pfx b/test/NerdBank.GitVersioning.Tests/Keys/protectedPair.pfx similarity index 100% rename from src/NerdBank.GitVersioning.Tests/Keys/protectedPair.pfx rename to test/NerdBank.GitVersioning.Tests/Keys/protectedPair.pfx diff --git a/src/NerdBank.GitVersioning.Tests/Keys/public.snk b/test/NerdBank.GitVersioning.Tests/Keys/public.snk similarity index 100% rename from src/NerdBank.GitVersioning.Tests/Keys/public.snk rename to test/NerdBank.GitVersioning.Tests/Keys/public.snk diff --git a/src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs rename to test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs b/test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs rename to test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs diff --git a/src/NerdBank.GitVersioning.Tests/MSBuildFixture.cs b/test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/MSBuildFixture.cs rename to test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/.gitattributes b/test/NerdBank.GitVersioning.Tests/ManagedGit/.gitattributes similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/.gitattributes rename to test/NerdBank.GitVersioning.Tests/ManagedGit/.gitattributes diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz b/test/NerdBank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz rename to test/NerdBank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs rename to test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 b/test/NerdBank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 rename to test/NerdBank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 b/test/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 rename to test/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a b/test/NerdBank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a rename to test/NerdBank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/commit.delta b/test/NerdBank.GitVersioning.Tests/ManagedGit/commit.delta similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/commit.delta rename to test/NerdBank.GitVersioning.Tests/ManagedGit/commit.delta diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt b/test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt rename to test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx b/test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx rename to test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack b/test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack rename to test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 b/test/NerdBank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 rename to test/NerdBank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 b/test/NerdBank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 rename to test/NerdBank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/tree.bin b/test/NerdBank.GitVersioning.Tests/ManagedGit/tree.bin similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/tree.bin rename to test/NerdBank.GitVersioning.Tests/ManagedGit/tree.bin diff --git a/src/NerdBank.GitVersioning.Tests/ManagedGit/tree.delta b/test/NerdBank.GitVersioning.Tests/ManagedGit/tree.delta similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ManagedGit/tree.delta rename to test/NerdBank.GitVersioning.Tests/ManagedGit/tree.delta diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj similarity index 100% rename from src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj rename to test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj diff --git a/src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs b/test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs rename to test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs b/test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs rename to test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs diff --git a/src/NerdBank.GitVersioning.Tests/RepoTestBase.cs b/test/NerdBank.GitVersioning.Tests/RepoTestBase.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/RepoTestBase.cs rename to test/NerdBank.GitVersioning.Tests/RepoTestBase.cs diff --git a/src/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs rename to test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs b/test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs rename to test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/TestUtilities.cs b/test/NerdBank.GitVersioning.Tests/TestUtilities.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/TestUtilities.cs rename to test/NerdBank.GitVersioning.Tests/TestUtilities.cs diff --git a/src/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs rename to test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/VersionFileTests.cs b/test/NerdBank.GitVersioning.Tests/VersionFileTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/VersionFileTests.cs rename to test/NerdBank.GitVersioning.Tests/VersionFileTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs b/test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs rename to test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/VersionOracleTests.cs rename to test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs b/test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs rename to test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs diff --git a/src/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs b/test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs similarity index 100% rename from src/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs rename to test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs diff --git a/src/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip b/test/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip similarity index 100% rename from src/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip rename to test/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip diff --git a/src/NerdBank.GitVersioning.Tests/repos/submodules.zip b/test/NerdBank.GitVersioning.Tests/repos/submodules.zip similarity index 100% rename from src/NerdBank.GitVersioning.Tests/repos/submodules.zip rename to test/NerdBank.GitVersioning.Tests/repos/submodules.zip diff --git a/src/NerdBank.GitVersioning.Tests/test.prj b/test/NerdBank.GitVersioning.Tests/test.prj similarity index 100% rename from src/NerdBank.GitVersioning.Tests/test.prj rename to test/NerdBank.GitVersioning.Tests/test.prj diff --git a/src/NerdBank.GitVersioning.Tests/test.vcprj b/test/NerdBank.GitVersioning.Tests/test.vcprj similarity index 100% rename from src/NerdBank.GitVersioning.Tests/test.vcprj rename to test/NerdBank.GitVersioning.Tests/test.vcprj diff --git a/tools/Check-DotNetRuntime.ps1 b/tools/Check-DotNetRuntime.ps1 new file mode 100644 index 00000000..9d012109 --- /dev/null +++ b/tools/Check-DotNetRuntime.ps1 @@ -0,0 +1,41 @@ +<# +.SYNOPSIS + Checks whether a given .NET Core runtime is installed. +#> +[CmdletBinding()] +Param ( + [Parameter()] + [ValidateSet('Microsoft.AspNetCore.App','Microsoft.NETCore.App')] + [string]$Runtime='Microsoft.NETCore.App', + [Parameter(Mandatory=$true)] + [Version]$Version +) + +$dotnet = Get-Command dotnet -ErrorAction SilentlyContinue +if (!$dotnet) { + # Nothing is installed. + Write-Output $false + exit 1 +} + +Function IsVersionMatch { + Param( + [Parameter()] + $actualVersion + ) + return $actualVersion -and + $Version.Major -eq $actualVersion.Major -and + $Version.Minor -eq $actualVersion.Minor -and + (($Version.Build -eq -1) -or ($Version.Build -eq $actualVersion.Build)) -and + (($Version.Revision -eq -1) -or ($Version.Revision -eq $actualVersion.Revision)) +} + +$installedRuntimes = dotnet --list-runtimes |? { $_.Split()[0] -ieq $Runtime } |% { $v = $null; [Version]::tryparse($_.Split()[1], [ref] $v); $v } +$matchingRuntimes = $installedRuntimes |? { IsVersionMatch -actualVersion $_ } +if (!$matchingRuntimes) { + Write-Output $false + exit 1 +} + +Write-Output $true +exit 0 diff --git a/tools/Check-DotNetSdk.ps1 b/tools/Check-DotNetSdk.ps1 new file mode 100644 index 00000000..6c9fa772 --- /dev/null +++ b/tools/Check-DotNetSdk.ps1 @@ -0,0 +1,37 @@ +<# +.SYNOPSIS + Checks whether the .NET Core SDK required by this repo is installed. +#> +[CmdletBinding()] +Param ( +) + +$dotnet = Get-Command dotnet -ErrorAction SilentlyContinue +if (!$dotnet) { + # Nothing is installed. + Write-Output $false + exit 1 +} + +# We need to set the current directory so dotnet considers the SDK required by our global.json file. +Push-Location "$PSScriptRoot\.." +try { + dotnet -h 2>&1 | Out-Null + if (($LASTEXITCODE -eq 129) -or # On Linux + ($LASTEXITCODE -eq -2147450751) # On Windows + ) { + # These exit codes indicate no matching SDK exists. + Write-Output $false + exit 2 + } + + # The required SDK is already installed! + Write-Output $true + exit 0 +} catch { + # I don't know why, but on some build agents (e.g. MicroBuild), an exception is thrown from the `dotnet` invocation when a match is not found. + Write-Output $false + exit 3 +} finally { + Pop-Location +} diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 2300d752..7dcddc78 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -38,16 +38,16 @@ if (!$arch) { # Windows Powershell leaves this blank # Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() $windowsDesktopRuntimeVersions = @() -Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { +Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { $projXml = [xml](Get-Content -Path $_) $pg = $projXml.Project.PropertyGroup if ($pg) { - $targetFrameworks = $pg.TargetFramework - if (!$targetFrameworks) { - $targetFrameworks = $pg.TargetFrameworks - if ($targetFrameworks) { - $targetFrameworks = $targetFrameworks -Split ';' - } + $targetFrameworks = @() + $tf = $pg.TargetFramework + $targetFrameworks += $tf + $tfs = $pg.TargetFrameworks + if ($tfs) { + $targetFrameworks = $tfs -Split ';' } } $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% { @@ -72,6 +72,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile = Join-Path $OutDir $Uri.Segments[-1] if (!(Test-Path $OutFile)) { Write-Verbose "Downloading $Uri..." + if (!(Test-Path $OutDir)) { mkdir $OutDir } try { (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) } finally { @@ -87,12 +88,51 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { if ($Runtime) { $sdkOrRuntime = 'Runtime' } # Get the latest/actual version for the specified one - if (([Version]$Version).Build -eq -1) { + $TypedVersion = [Version]$Version + if ($TypedVersion.Build -eq -1) { $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/latest.version" -UseBasicParsing) $Version = $versionInfo[-1] } - Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/dotnet-$($sdkOrRuntime.ToLowerInvariant())-$Version-win-$arch.exe" -OutDir "$DotNetInstallScriptRoot" + $majorMinor = "$($TypedVersion.Major).$($TypedVersion.Minor)" + $ReleasesFile = Join-Path $DotNetInstallScriptRoot "$majorMinor\releases.json" + if (!(Test-Path $ReleasesFile)) { + Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile) + } + + $releases = Get-Content $ReleasesFile | ConvertFrom-Json + $url = $null + foreach ($release in $releases.releases) { + $filesElement = $null + if ($Runtime) { + if ($release.runtime.version -eq $Version) { + $filesElement = $release.runtime.files + } + } else { + if ($release.sdk.version -eq $Version) { + $filesElement = $release.sdk.files + } + } + + if ($filesElement) { + foreach ($file in $filesElement) { + if ($file.rid -eq "win-$arch") { + $url = $file.url + Break + } + } + + if ($url) { + Break + } + } + } + + if ($url) { + Get-FileFromWeb -Uri $url -OutDir $DotNetInstallScriptRoot + } else { + Write-Error "Unable to find release of $sdkOrRuntime v$Version" + } } Function Install-DotNet($Version, [switch]$Runtime) { diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 new file mode 100644 index 00000000..6d310034 --- /dev/null +++ b/tools/Install-NuGetCredProvider.ps1 @@ -0,0 +1,76 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + Downloads and installs the Microsoft Artifacts Credential Provider + from https://github.com/microsoft/artifacts-credprovider + to assist in authenticating to Azure Artifact feeds in interactive development + or unattended build agents. +.PARAMETER Force + Forces install of the CredProvider plugin even if one already exists. This is useful to upgrade an older version. +.PARAMETER AccessToken + An optional access token for authenticating to Azure Artifacts authenticated feeds. +#> +[CmdletBinding()] +Param ( + [Parameter()] + [switch]$Force, + [Parameter()] + [string]$AccessToken +) + +$envVars = @{} + +$toolsPath = & "$PSScriptRoot\..\azure-pipelines\Get-TempToolsPath.ps1" + +if ($IsMacOS -or $IsLinux) { + $installerScript = "installcredprovider.sh" + $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh" +} else { + $installerScript = "installcredprovider.ps1" + $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1" +} + +$installerScript = Join-Path $toolsPath $installerScript + +if (!(Test-Path $installerScript)) { + Invoke-WebRequest $sourceUrl -OutFile $installerScript +} + +$installerScript = (Resolve-Path $installerScript).Path + +if ($IsMacOS -or $IsLinux) { + chmod u+x $installerScript +} + +& $installerScript -Force:$Force + +if ($AccessToken) { + $endpoints = @() + + $endpointURIs = @() + Get-ChildItem "$PSScriptRoot\..\nuget.config" -Recurse |% { + $nugetConfig = [xml](Get-Content -Path $_) + + $nugetConfig.configuration.packageSources.add |? { ($_.value -match '^https://pkgs\.dev\.azure\.com/') -or ($_.value -match '^https://[\w\-]+\.pkgs\.visualstudio\.com/') } |% { + if ($endpointURIs -notcontains $_.Value) { + $endpointURIs += $_.Value + $endpoint = New-Object -TypeName PSObject + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name endpoint -Value $_.value + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name username -Value ado + Add-Member -InputObject $endpoint -MemberType NoteProperty -Name password -Value $AccessToken + $endpoints += $endpoint + } + } + } + + $auth = New-Object -TypeName PSObject + Add-Member -InputObject $auth -MemberType NoteProperty -Name endpointCredentials -Value $endpoints + + $authJson = ConvertTo-Json -InputObject $auth + $envVars += @{ + 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'=$authJson; + } +} + +& "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars | Out-Null diff --git a/azure-pipelines/Set-EnvVars.ps1 b/tools/Set-EnvVars.ps1 similarity index 67% rename from azure-pipelines/Set-EnvVars.ps1 rename to tools/Set-EnvVars.ps1 index 9d14d9aa..3f6f86ba 100644 --- a/azure-pipelines/Set-EnvVars.ps1 +++ b/tools/Set-EnvVars.ps1 @@ -4,8 +4,13 @@ Azure Pipeline and CMD environments are considered. .PARAMETER Variables A hashtable of variables to be set. +.PARAMETER PrependPath + A set of paths to prepend to the PATH environment variable. .OUTPUTS A boolean indicating whether the environment variables can be expected to propagate to the caller's environment. +.DESCRIPTION + The CmdEnvScriptPath environment variable may be optionally set to a path to a cmd shell script to be created (or appended to if it already exists) that will set the environment variables in cmd.exe that are set within the PowerShell environment. + This is used by init.cmd in order to reapply any new environment variables to the parent cmd.exe process that were set in the powershell child process. #> [CmdletBinding(SupportsShouldProcess=$true)] Param( @@ -18,7 +23,7 @@ if ($Variables.Count -eq 0) { return $true } -$cmdInstructions = !$env:TF_BUILD -and !$env:GITHUB_ACTIONS -and $env:PS1UnderCmd -eq '1' +$cmdInstructions = !$env:TF_BUILD -and !$env:GITHUB_ACTIONS -and !$env:CmdEnvScriptPath -and ($env:PS1UnderCmd -eq '1') if ($cmdInstructions) { Write-Warning "Environment variables have been set that will be lost because you're running under cmd.exe" Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue @@ -38,6 +43,7 @@ if ($env:GITHUB_ACTIONS) { Write-Host "GitHub Actions detected. Logging commands will be used to propagate environment variables and prepend path." } +$CmdEnvScript = '' $Variables.GetEnumerator() |% { Set-Item -Path env:$($_.Key) -Value $_.Value @@ -46,12 +52,14 @@ $Variables.GetEnumerator() |% { Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" } if ($env:GITHUB_ACTIONS) { - Write-Host "::set-env name=$($_.Key)::$($_.Value)" + Add-Content -Path $env:GITHUB_ENV -Value "$($_.Key)=$($_.Value)" } if ($cmdInstructions) { Write-Host "SET $($_.Key)=$($_.Value)" } + + $CmdEnvScript += "SET $($_.Key)=$($_.Value)`r`n" } $pathDelimiter = ';' @@ -71,9 +79,19 @@ if ($PrependPath) { Write-Host "##vso[task.prependpath]$_" } if ($env:GITHUB_ACTIONS) { - Write-Host "::add-path::$_" + Add-Content -Path $env:GITHUB_PATH -Value $_ } + + $CmdEnvScript += "SET PATH=$_$pathDelimiter%PATH%" + } +} + +if ($env:CmdEnvScriptPath) { + if (Test-Path $env:CmdEnvScriptPath) { + $CmdEnvScript = (Get-Content -Path $env:CmdEnvScriptPath) + $CmdEnvScript } + + Set-Content -Path $env:CmdEnvScriptPath -Value $CmdEnvScript } return !$cmdInstructions diff --git a/version.json b/version.json index f0167361..c5f9c4d5 100644 --- a/version.json +++ b/version.json @@ -1,12 +1,15 @@ { - "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", "version": "3.5-alpha", "assemblyVersion": { "precision": "revision" }, "publicReleaseRefSpec": [ - "^refs/heads/master$", + "^refs/heads/main$", "^refs/heads/develop$", "^refs/heads/v\\d+\\.\\d+$" - ] -} \ No newline at end of file + ], + "cloudBuild": { + "setVersionVariables": false + } +} From 16d65511f7f92d18eb9dfb19fd40388e86e7a514 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 15:59:52 -0600 Subject: [PATCH 465/704] Skip CI for release pipeline changes Also remove extra slash in snk path --- Directory.Build.props | 2 +- azure-pipelines.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index ecb971a7..834e7457 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -23,7 +23,7 @@ embedded true - $(MSBuildThisFileDirectory)\strongname.snk + $(MSBuildThisFileDirectory)strongname.snk COMPANY-PLACEHOLDER COMPANY-PLACEHOLDER diff --git a/azure-pipelines.yml b/azure-pipelines.yml index fe8363a2..b7d86b45 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -10,6 +10,7 @@ trigger: - '*.md' - .vscode/ - .github/ + - azure-pipelines/release.yml parameters: - name: includeMacOS From 1b6163ea0ba38a6404fa6f6d757e671d615b3b1c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 16:25:30 -0600 Subject: [PATCH 466/704] Set version to '3.6-alpha' --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index f0167361..3ec49b3a 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "3.5-alpha", + "version": "3.6-alpha", "assemblyVersion": { "precision": "revision" }, From 351d94e36c886bb2eed0d75cc3b1953f19040c7b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 16:25:30 -0600 Subject: [PATCH 467/704] Set version to '3.5' --- version.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/version.json b/version.json index f0167361..6c6b3a59 100644 --- a/version.json +++ b/version.json @@ -1,6 +1,6 @@ { "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "3.5-alpha", + "version": "3.5", "assemblyVersion": { "precision": "revision" }, From e0d4ad51a33eacceb0ef1c20a43f7a8b75c79c9d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 1 May 2022 21:35:19 -0600 Subject: [PATCH 468/704] Add support for running 32-bit tests --- azure-pipelines/dotnet-test-cloud.ps1 | 45 ++++++++-- tools/Install-DotNetSdk.ps1 | 124 ++++++++++++++++++++------ 2 files changed, 138 insertions(+), 31 deletions(-) diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index 877f11ed..43cdc3e0 100755 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -1,15 +1,50 @@ #!/usr/bin/env pwsh +<# +.SYNOPSIS + Runs tests as they are run in cloud test runs. +.PARAMETER Configuration + The configuration within which to run tests +.PARAMETER Agent + The name of the agent. This is used in preparing test run titles. +.PARAMETER PublishResults + A switch to publish results to Azure Pipelines. +.PARAMETER x86 + A switch to run the tests in an x86 process. +.PARAMETER dotnet32 + The path to a 32-bit dotnet executable to use. +#> +[CmdletBinding()] Param( [string]$Configuration='Debug', [string]$Agent='Local', - [switch]$PublishResults + [switch]$PublishResults, + [switch]$x86, + [string]$dotnet32 ) $RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path $ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" -dotnet test $RepoRoot ` +$dotnet = 'dotnet' +if ($x86) { + $x86RunTitleSuffix = ", x86" + if ($dotnet32) { + $dotnet = $dotnet32 + } else { + $dotnet32Possibilities = "$PSScriptRoot\../obj/tools/x86/.dotnet/dotnet.exe", "$env:AGENT_TOOLSDIRECTORY/x86/dotnet/dotnet.exe", "${env:ProgramFiles(x86)}\dotnet\dotnet.exe" + $dotnet32Matches = $dotnet32Possibilities |? { Test-Path $_ } + if ($dotnet32Matches) { + $dotnet = Resolve-Path @($dotnet32Matches)[0] + Write-Host "Running tests using `"$dotnet`"" -ForegroundColor DarkGray + } else { + Write-Error "Unable to find 32-bit dotnet.exe" + return 1 + } + } +} + +& $dotnet test $RepoRoot ` --no-build ` -c $Configuration ` --filter "TestCategory!=FailsInCloudTest" ` @@ -18,7 +53,7 @@ dotnet test $RepoRoot ` --blame-crash ` -bl:"$ArtifactStagingFolder/build_logs/test.binlog" ` --diag "$ArtifactStagingFolder/test_logs/diag.log;TraceLevel=info" ` - --logger trx + --logger trx ` $unknownCounter = 0 Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { @@ -33,13 +68,13 @@ Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { if ($matches.rid) { $runTitle = "$($matches.lib) ($($matches.tfm), $($matches.rid), $Agent)" } else { - $runTitle = "$($matches.lib) ($($matches.tfm), $Agent)" + $runTitle = "$($matches.lib) ($($matches.tfm)$x86RunTitleSuffix, $Agent)" } } } if (!$runTitle) { $unknownCounter += 1; - $runTitle = "unknown$unknownCounter ($Agent)"; + $runTitle = "unknown$unknownCounter ($Agent$x86RunTitleSuffix)"; } Write-Host "##vso[results.publish type=VSTest;runTitle=$runTitle;publishRunAttachments=true;resultFiles=$_;failTaskOnFailedTests=true;testRunSystem=VSTS - PTR;]" diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 7dcddc78..76a397f0 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -15,20 +15,28 @@ When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. +.PARAMETER IncludeX86 + Installs a x86 SDK and runtimes in addition to the x64 ones. Only supported on Windows. Ignored on others. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( [ValidateSet('repo','user','machine')] - [string]$InstallLocality='user' + [string]$InstallLocality='user', + [switch]$IncludeX86 ) $DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools" if (!(Test-Path $DotNetInstallScriptRoot)) { New-Item -ItemType Directory -Path $DotNetInstallScriptRoot -WhatIf:$false | Out-Null } $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot -# Look up actual required .NET Core SDK version from global.json +# Look up actual required .NET SDK version from global.json $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" +If ($IncludeX86 -and ($IsMacOS -or $IsLinux)) { + Write-Verbose "Ignoring -IncludeX86 switch because 32-bit runtimes are only supported on Windows." + $IncludeX86 = $false +} + $arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture if (!$arch) { # Windows Powershell leaves this blank $arch = 'x64' @@ -72,7 +80,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile = Join-Path $OutDir $Uri.Segments[-1] if (!(Test-Path $OutFile)) { Write-Verbose "Downloading $Uri..." - if (!(Test-Path $OutDir)) { mkdir $OutDir } + if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir } try { (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) } finally { @@ -83,7 +91,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile } -Function Get-InstallerExe($Version, [switch]$Runtime) { +Function Get-InstallerExe($Version, $Architecture, [switch]$Runtime) { $sdkOrRuntime = 'Sdk' if ($Runtime) { $sdkOrRuntime = 'Runtime' } @@ -116,7 +124,7 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { if ($filesElement) { foreach ($file in $filesElement) { - if ($file.rid -eq "win-$arch") { + if ($file.rid -eq "win-$Architecture") { $url = $file.url Break } @@ -135,22 +143,20 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { } } -Function Install-DotNet($Version, [switch]$Runtime) { +Function Install-DotNet($Version, $Architecture, [switch]$Runtime) { if ($Runtime) { $sdkSubstring = '' } else { $sdkSubstring = 'SDK ' } Write-Host "Downloading .NET Core $sdkSubstring$Version..." - $Installer = Get-InstallerExe -Version $Version -Runtime:$Runtime + $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -Runtime:$Runtime Write-Host "Installing .NET Core $sdkSubstring$Version..." cmd /c start /wait $Installer /install /passive /norestart if ($LASTEXITCODE -eq 3010) { Write-Verbose "Restart required" } elseif ($LASTEXITCODE -ne 0) { - throw "Failure to install .NET Core SDK" + throw "Failure to install .NET SDK" } } -$switches = @( - '-Architecture',$arch -) +$switches = @() $envVars = @{ # For locally installed dotnet, skip first time experience which takes a long time 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' = 'true'; @@ -161,15 +167,25 @@ if ($InstallLocality -eq 'machine') { $DotNetInstallDir = '/usr/share/dotnet' } else { $restartRequired = $false - if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - Install-DotNet -Version $sdkVersion + 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 + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } } $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - Install-DotNet -Version $_ -Runtime + Install-DotNet -Version $_ -Architecture $arch -Runtime $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + + if ($IncludeX86) { + Install-DotNet -Version $_ -Architecture x86 -Runtime + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } } } @@ -182,20 +198,34 @@ if ($InstallLocality -eq 'machine') { } } elseif ($InstallLocality -eq 'repo') { $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet" + $DotNetX86InstallDir = "$DotNetInstallScriptRoot/x86/.dotnet" } elseif ($env:AGENT_TOOLSDIRECTORY) { $DotNetInstallDir = "$env:AGENT_TOOLSDIRECTORY/dotnet" + $DotNetX86InstallDir = "$env:AGENT_TOOLSDIRECTORY/x86/dotnet" } else { $DotNetInstallDir = Join-Path $HOME .dotnet } -Write-Host "Installing .NET Core SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue - if ($DotNetInstallDir) { - $switches += '-InstallDir',"`"$DotNetInstallDir`"" + if (!(Test-Path $DotNetInstallDir)) { New-Item -ItemType Directory -Path $DotNetInstallDir } + $DotNetInstallDir = Resolve-Path $DotNetInstallDir + Write-Host "Installing .NET SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue $envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0' $envVars['DOTNET_ROOT'] = $DotNetInstallDir } +if ($IncludeX86) { + if ($DotNetX86InstallDir) { + if (!(Test-Path $DotNetX86InstallDir)) { New-Item -ItemType Directory -Path $DotNetX86InstallDir } + $DotNetX86InstallDir = Resolve-Path $DotNetX86InstallDir + Write-Host "Installing x86 .NET SDK and runtimes to $DotNetX86InstallDir" -ForegroundColor Blue + } else { + # Only machine-wide or repo-wide installations can handle two unique dotnet.exe architectures. + Write-Error "The installation location or OS isn't supported for x86 installation. Try a different -InstallLocality value." + return 1 + } +} + if ($IsMacOS -or $IsLinux) { $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" @@ -219,47 +249,89 @@ $DotNetInstallScriptPathExpression = "& '$DotNetInstallScriptPathExpression'" $anythingInstalled = $false $global:LASTEXITCODE = 0 -if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { +if ($PSCmdlet.ShouldProcess(".NET SDK $sdkVersion", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches -DryRun" +} + +if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET x86 SDK $sdkVersion", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET x86 SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches -DryRun" + } } $dotnetRuntimeSwitches = $switches + '-Runtime','dotnet' $runtimeVersions | Sort-Object -Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET Core $Arch runtime $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $dotnetRuntimeSwitches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $dotnetRuntimeSwitches -DryRun" + } + + if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET Core x86 runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $dotnetRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $dotnetRuntimeSwitches -DryRun" + } } } $windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop' $windowsDesktopRuntimeVersions | Sort-Object -Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop $arch runtime $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $windowsDesktopRuntimeSwitches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $windowsDesktopRuntimeSwitches -DryRun" + } + + if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop x86 runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $windowsDesktopRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $windowsDesktopRuntimeSwitches -DryRun" + } } } From 88f4c2d70905ac5980759daed5392279d263b59a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 3 May 2022 09:04:16 -0600 Subject: [PATCH 469/704] Fix all compiler warnings --- Directory.Build.props | 4 +- Nerdbank.GitVersioning.sln | 22 +- azure-pipelines/artifacts/deployables-LKG.ps1 | 2 +- azure-pipelines/artifacts/deployables.ps1 | 2 +- azure-pipelines/build.yml | 1 - azure-pipelines/dotnet-test-cloud.ps1 | 32 +- azure-pipelines/dotnet.yml | 11 +- init.ps1 | 13 +- src/.editorconfig | 16 + .../Cake.GitVersioning.csproj | 17 +- .../GitVersioningAliases.cs | 55 +- .../GitVersioningCloudProvider.cs | 5 +- .../GitVersioningCloudSettings.cs | 22 +- .../AssemblyVersionOptionsConverter.cs | 111 +- src/NerdBank.GitVersioning/CloudBuild.cs | 95 +- .../CloudBuildServices/AppVeyor.cs | 112 +- .../CloudBuildServices/AtlassianBamboo.cs | 60 +- .../CloudBuildServices/GitHubActions.cs | 68 +- .../CloudBuildServices/GitLab.cs | 68 +- .../CloudBuildServices/Jenkins.cs | 100 +- .../CloudBuildServices/SpaceAutomation.cs | 62 +- .../CloudBuildServices/TeamCity.cs | 66 +- .../CloudBuildServices/Travis.cs | 61 +- .../VisualStudioTeamServices.cs | 82 +- .../Commands/CloudCommand.cs | 271 +- src/NerdBank.GitVersioning/FilterPath.cs | 513 ++-- .../FilterPathJsonConverter.cs | 68 +- src/NerdBank.GitVersioning/GitContext.cs | 520 ++-- src/NerdBank.GitVersioning/GitException.cs | 138 +- src/NerdBank.GitVersioning/ICloudBuild.cs | 101 +- .../LibGit2/LibGit2Context.cs | 274 +- .../LibGit2/LibGit2GitExtensions.cs | 932 +++--- .../LibGit2/LibGit2VersionFile.cs | 217 +- .../Managed/GitExtensions.cs | 345 +++ .../Managed/ManagedGitContext.cs | 287 +- .../Managed/ManagedGitExtensions.cs | 348 --- .../Managed/ManagedVersionFile.cs | 270 +- .../ManagedGit/DeltaInstruction.cs | 42 +- .../ManagedGit/DeltaInstructionType.cs | 32 +- .../ManagedGit/DeltaStreamReader.cs | 273 +- .../ManagedGit/FileHelpers.cs | 152 +- .../ManagedGit/GitCommit.cs | 260 +- .../ManagedGit/GitCommitReader.cs | 284 +- .../ManagedGit/GitObjectId.cs | 383 ++- .../ManagedGit/GitObjectStream.cs | 105 +- .../ManagedGit/GitPack.cs | 502 ++-- .../ManagedGit/GitPackCache.cs | 116 +- .../ManagedGit/GitPackDeltafiedStream.cs | 322 +-- .../ManagedGit/GitPackIndexMappedReader.cs | 241 +- .../ManagedGit/GitPackIndexReader.cs | 86 +- .../ManagedGit/GitPackMemoryCache.cs | 117 +- .../ManagedGit/GitPackMemoryCacheStream.cs | 185 +- .../GitPackMemoryCacheViewStream.cs | 110 +- .../ManagedGit/GitPackNullCache.cs | 51 +- .../ManagedGit/GitPackObjectType.cs | 53 +- .../ManagedGit/GitPackPooledStream.cs | 181 +- .../ManagedGit/GitPackReader.cs | 163 +- .../ManagedGit/GitReferenceReader.cs | 49 +- .../ManagedGit/GitRepository.cs | 1245 ++++---- .../ManagedGit/GitSignature.cs | 38 +- .../ManagedGit/GitTree.cs | 46 +- .../ManagedGit/GitTreeEntry.cs | 80 +- .../ManagedGit/GitTreeReader.cs | 78 +- .../ManagedGit/GitTreeStreamingReader.cs | 92 +- .../ManagedGit/MemoryMappedStream.cs | 234 +- .../ManagedGit/StreamExtensions.cs | 244 +- .../ManagedGit/ZLibStream.cs | 315 +- .../NerdBank.GitVersioning.csproj | 1 - .../NoGit/NoGitContext.cs | 65 +- .../NoGit/NoGitVersionFile.cs | 23 +- .../Properties/AssemblyInfo.cs | 7 - src/NerdBank.GitVersioning/ReleaseManager.cs | 792 ++--- src/NerdBank.GitVersioning/SemanticVersion.cs | 623 ++-- .../SemanticVersionJsonConverter.cs | 68 +- .../VersionExtensions.cs | 153 +- src/NerdBank.GitVersioning/VersionFile.cs | 389 ++- src/NerdBank.GitVersioning/VersionOptions.cs | 2565 +++++++++-------- .../VersionOptionsContractResolver.cs | 239 +- src/NerdBank.GitVersioning/VersionOracle.cs | 923 +++--- .../AssemblyLoader.cs | 15 +- .../AssemblyVersionInfo.cs | 524 ++-- .../CompareFiles.cs | 119 +- .../ContextAwareTask.cs | 30 +- .../CryptoBlobParser+BlobHeader.cs | 17 +- .../CryptoBlobParser+RsaPubKey.cs | 17 +- .../CryptoBlobParser+SnPublicKeyBlob.cs | 23 +- .../CryptoBlobParser.cs | 136 +- .../GetBuildVersion.cs | 45 +- .../GitLoaderContext.cs | 10 +- .../NativeVersionInfo.cs | 74 +- .../Nerdbank.GitVersioning.Tasks.csproj | 13 +- .../Properties/AssemblyInfo.cs | 7 - .../SetCloudBuildVariables.cs | 38 +- src/Shared/SemanticVersionExtensions.cs | 251 +- src/Shared/Utilities.cs | 40 +- src/nbgv/Program.cs | 141 +- src/nbgv/nbgv.csproj | 2 +- stylecop.json | 3 + test/.editorconfig | 6 + .../Cake.GitVersioning.Tests.csproj | 13 +- .../GitVersioningCloudProviderTests.cs | 21 +- .../GetVersionBenchmarks.cs | 5 +- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- .../Program.cs | 9 +- .../AssemblyInfoTest.cs | 43 +- .../BuildIntegrationTests.cs | 369 +-- .../FilterPathTests.cs | 13 +- .../GitContextTests.cs | 17 +- .../LibGit2GitExtensionsTests.cs | 58 +- .../MSBuildExtensions.cs | 16 +- .../MSBuildFixture.cs | 5 +- .../ManagedGit/DeltaStreamReaderTests.cs | 224 +- .../ManagedGit/GitCommitReaderTests.cs | 70 +- .../ManagedGit/GitCommitTests.cs | 174 +- .../ManagedGit/GitObjectIdTests.cs | 250 +- .../ManagedGit/GitObjectStreamTests.cs | 38 +- .../ManagedGit/GitPackDeltafiedStreamTests.cs | 56 +- .../GitPackIndexMappedReaderTests.cs | 132 +- .../ManagedGit/GitPackMemoryCacheTests.cs | 56 +- .../ManagedGit/GitPackTests.cs | 255 +- .../ManagedGit/GitRepositoryTests.cs | 527 ++-- .../ManagedGit/GitTreeStreamingReaderTests.cs | 36 +- .../ManagedGit/StreamExtensionsTests.cs | 26 +- .../ManagedGit/ZLibStreamTest.cs | 11 +- .../NerdBank.GitVersioning.Tests.csproj | 30 +- .../ReleaseManagerTests.cs | 119 +- .../RepoTestBase.Helpers.cs | 9 +- .../RepoTestBase.cs | 19 +- .../SemanticVersionExtensionsTests.cs | 14 +- .../SemanticVersionTests.cs | 7 +- .../TestUtilities.cs | 9 +- .../VersionExtensionsTests.cs | 13 +- .../VersionFileTests.cs | 132 +- .../VersionOptionsTests.cs | 20 +- .../VersionOracleTests.cs | 144 +- .../VersionSchemaTests.cs | 13 +- .../WindowsTheoryAttribute.cs | 7 +- tools/Install-DotNetSdk.ps1 | 124 +- 138 files changed, 11179 insertions(+), 10716 deletions(-) create mode 100644 src/NerdBank.GitVersioning/Managed/GitExtensions.cs delete mode 100644 src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs delete mode 100644 src/NerdBank.GitVersioning/Properties/AssemblyInfo.cs delete mode 100644 src/Nerdbank.GitVersioning.Tasks/Properties/AssemblyInfo.cs diff --git a/Directory.Build.props b/Directory.Build.props index 4530c93f..50865cda 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -7,7 +7,7 @@ $(RepoRootPath)bin\Packages\$(Configuration)\ $(MSBuildThisFileDirectory)..\wiki\api 10.0 - enable + enable latest true @@ -47,7 +47,7 @@ - + diff --git a/Nerdbank.GitVersioning.sln b/Nerdbank.GitVersioning.sln index 32a4b547..b4c7f06c 100644 --- a/Nerdbank.GitVersioning.sln +++ b/Nerdbank.GitVersioning.sln @@ -18,11 +18,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution ..\version.json = ..\version.json EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NerdBank.GitVersioning.Tests", "test\NerdBank.GitVersioning.Tests\NerdBank.GitVersioning.Tests.csproj", "{C54F9EC8-FDA7-4D22-BCB2-7D97523BD91E}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Tests", "test\Nerdbank.GitVersioning.Tests\Nerdbank.GitVersioning.Tests.csproj", "{C54F9EC8-FDA7-4D22-BCB2-7D97523BD91E}" EndProject Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "nb-gv", "src\nerdbank-gitversioning.npm\nb-gv.njsproj", "{F79DD916-27B3-4CD0-97FF-5021B3CF9934}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NerdBank.GitVersioning", "src\NerdBank.GitVersioning\NerdBank.GitVersioning.csproj", "{C7FA7B7A-0469-4B1C-8657-E274C4CD8ABB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning", "src\Nerdbank.GitVersioning\Nerdbank.GitVersioning.csproj", "{C7FA7B7A-0469-4B1C-8657-E274C4CD8ABB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Tasks", "src\Nerdbank.GitVersioning.Tasks\Nerdbank.GitVersioning.Tasks.csproj", "{B2454569-6EDC-4FD4-9936-D2B2F2E10409}" EndProject @@ -30,9 +30,23 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "nbgv", "src\nbgv\nbgv.cspro EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.GitVersioning", "src\Cake.GitVersioning\Cake.GitVersioning.csproj", "{1F267A97-DFE3-4166-83B1-9D236B7A09BD}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Benchmarks", "test\NerdBank.GitVersioning.Benchmarks\Nerdbank.GitVersioning.Benchmarks.csproj", "{B0B7955D-E51F-4091-BF7F-55D07D381D15}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Benchmarks", "test\Nerdbank.GitVersioning.Benchmarks\Nerdbank.GitVersioning.Benchmarks.csproj", "{B0B7955D-E51F-4091-BF7F-55D07D381D15}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Cake.GitVersioning.Tests", "test\Cake.GitVersioning.Tests\Cake.GitVersioning.Tests.csproj", "{D68829FE-24D8-4ADD-8525-17F47C6FE257}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Cake.GitVersioning.Tests", "test\Cake.GitVersioning.Tests\Cake.GitVersioning.Tests.csproj", "{D68829FE-24D8-4ADD-8525-17F47C6FE257}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{0A4BEA3B-268B-464F-9C0F-6DC2EFA884F8}" + ProjectSection(SolutionItems) = preProject + src\.editorconfig = src\.editorconfig + src\Directory.Build.props = src\Directory.Build.props + src\Directory.Build.targets = src\Directory.Build.targets + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{A603FD3B-1A40-4605-B044-5DDAFDEDCD90}" + ProjectSection(SolutionItems) = preProject + test\.editorconfig = test\.editorconfig + test\Directory.Build.props = test\Directory.Build.props + test\Directory.Build.targets = test\Directory.Build.targets + EndProjectSection EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/azure-pipelines/artifacts/deployables-LKG.ps1 b/azure-pipelines/artifacts/deployables-LKG.ps1 index 94c48cdd..8d47a2a6 100644 --- a/azure-pipelines/artifacts/deployables-LKG.ps1 +++ b/azure-pipelines/artifacts/deployables-LKG.ps1 @@ -9,5 +9,5 @@ $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" if (!(Test-Path $PackagesRoot)) { return } @{ - "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) + "$PackagesRoot" = (Get-ChildItem $PackagesRoot *.LKG.*.nupkg) } diff --git a/azure-pipelines/artifacts/deployables.ps1 b/azure-pipelines/artifacts/deployables.ps1 index 94c48cdd..c860a6d4 100644 --- a/azure-pipelines/artifacts/deployables.ps1 +++ b/azure-pipelines/artifacts/deployables.ps1 @@ -9,5 +9,5 @@ $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" if (!(Test-Path $PackagesRoot)) { return } @{ - "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) + "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse -Exclude *.LKG.*.nupkg) } diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 4ed7cee7..cf345336 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -10,7 +10,6 @@ jobs: pool: ${{ parameters.windowsPool }} variables: testModifier: - dotnet32: "\"C:\\Program Files (x86)\\dotnet\\dotnet.exe\"" - ${{ if eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/') }}: - group: dotnetfoundation code signing steps: diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index 588fe871..43cdc3e0 100644 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -9,13 +9,17 @@ The name of the agent. This is used in preparing test run titles. .PARAMETER PublishResults A switch to publish results to Azure Pipelines. +.PARAMETER x86 + A switch to run the tests in an x86 process. .PARAMETER dotnet32 - The path to the 32-bit dotnet.exe to use to run tests. If not specified, the default (typically 64-bit) dotnet process will be used. + The path to a 32-bit dotnet executable to use. #> +[CmdletBinding()] Param( [string]$Configuration='Debug', [string]$Agent='Local', [switch]$PublishResults, + [switch]$x86, [string]$dotnet32 ) @@ -23,9 +27,21 @@ $RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path $ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" $dotnet = 'dotnet' -if ($dotnet32) { - $dotnet = $dotnet32 - $x86RunTitle = ", x86" +if ($x86) { + $x86RunTitleSuffix = ", x86" + if ($dotnet32) { + $dotnet = $dotnet32 + } else { + $dotnet32Possibilities = "$PSScriptRoot\../obj/tools/x86/.dotnet/dotnet.exe", "$env:AGENT_TOOLSDIRECTORY/x86/dotnet/dotnet.exe", "${env:ProgramFiles(x86)}\dotnet\dotnet.exe" + $dotnet32Matches = $dotnet32Possibilities |? { Test-Path $_ } + if ($dotnet32Matches) { + $dotnet = Resolve-Path @($dotnet32Matches)[0] + Write-Host "Running tests using `"$dotnet`"" -ForegroundColor DarkGray + } else { + Write-Error "Unable to find 32-bit dotnet.exe" + return 1 + } + } } & $dotnet test $RepoRoot ` @@ -38,8 +54,6 @@ if ($dotnet32) { -bl:"$ArtifactStagingFolder/build_logs/test.binlog" ` --diag "$ArtifactStagingFolder/test_logs/diag.log;TraceLevel=info" ` --logger trx ` - -- ` - RunConfiguration.DisableAppDomain=true $unknownCounter = 0 Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { @@ -52,15 +66,15 @@ Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx |% { $storage = $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')[0].storage -replace '\\','/' if ($storage -match '/(?net[^/]+)/(?:(?[^/]+)/)?(?[^/]+)\.dll$') { if ($matches.rid) { - $runTitle = "$($matches.lib) ($($matches.tfm), $($matches.rid), $Agent$x86RunTitle)" + $runTitle = "$($matches.lib) ($($matches.tfm), $($matches.rid), $Agent)" } else { - $runTitle = "$($matches.lib) ($($matches.tfm), $Agent$x86RunTitle)" + $runTitle = "$($matches.lib) ($($matches.tfm)$x86RunTitleSuffix, $Agent)" } } } if (!$runTitle) { $unknownCounter += 1; - $runTitle = "unknown$unknownCounter ($Agent$x86RunTitle)"; + $runTitle = "unknown$unknownCounter ($Agent$x86RunTitleSuffix)"; } Write-Host "##vso[results.publish type=VSTest;runTitle=$runTitle;publishRunAttachments=true;resultFiles=$_;failTaskOnFailedTests=true;testRunSystem=VSTS - PTR;]" diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 1ad1b039..7a8082f0 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -16,17 +16,16 @@ steps: displayName: Publish nbgv tool workingDirectory: src/nbgv -- task: gulp@0 +- script: yarn build displayName: Build nerdbank-gitversioning NPM package - inputs: - gulpfile: src/nerdbank-gitversioning.npm/gulpfile.js + workingDirectory: src/nerdbank-gitversioning.npm - powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults - displayName: dotnet test x64 + displayName: dotnet test -- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults -dotnet32 '$(dotnet32)' +- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults -X86 displayName: dotnet test x86 - condition: ne(variables['dotnet32'], '') + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) - pwsh: > dotnet tool install --tool-path obj SignClient diff --git a/init.ps1 b/init.ps1 index 71f4261d..aef7240a 100755 --- a/init.ps1 +++ b/init.ps1 @@ -55,7 +55,7 @@ if (!$NoPrerequisites) { & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites } - & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality + & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality -IncludeX86 if ($LASTEXITCODE -eq 3010) { Exit 3010 } @@ -84,14 +84,11 @@ try { } if (!$NoRestore -and $PSCmdlet.ShouldProcess("NPM packages", "Restore")) { + Write-Host "Installing yarn" -ForegroundColor Yellow + npm i -g yarn@">=1.22 <2.0" Write-Host "Restoring NPM packages..." -ForegroundColor Yellow - Push-Location "$PSScriptRoot\src\nerdbank-gitversioning.npm" - try { - if ($PSCmdlet.ShouldProcess("$PSScriptRoot\src\nerdbank-gitversioning.npm", "yarn install")) { - yarn install --loglevel error - } - } finally { - Pop-Location + if ($PSCmdlet.ShouldProcess("$PSScriptRoot\src\nerdbank-gitversioning.npm", "yarn install")) { + yarn --cwd src/nerdbank-gitversioning.npm --loglevel error } } diff --git a/src/.editorconfig b/src/.editorconfig index e69de29b..b12e588d 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -0,0 +1,16 @@ +[*.cs] + +# CS1591: Missing XML comment for publicly visible type or member +dotnet_diagnostic.CS1591.severity = suggestion + +# SA1600: Elements should be documented +dotnet_diagnostic.SA1600.severity = suggestion + +# SA1405: Debug.Assert should provide message text +dotnet_diagnostic.SA1405.severity = suggestion + +# SA1601: Partial elements should be documented +dotnet_diagnostic.SA1601.severity = suggestion + +# SA1605: Partial element documentation should have summary +dotnet_diagnostic.SA1605.severity = suggestion diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 779786c0..40b965fb 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -48,25 +48,12 @@ - + - + lib\$(TargetFramework) diff --git a/src/Cake.GitVersioning/GitVersioningAliases.cs b/src/Cake.GitVersioning/GitVersioningAliases.cs index aff32240..02303b15 100644 --- a/src/Cake.GitVersioning/GitVersioningAliases.cs +++ b/src/Cake.GitVersioning/GitVersioningAliases.cs @@ -1,13 +1,16 @@ -namespace Cake.GitVersioning -{ - using System; - using System.IO; - using System.Reflection; - using Cake.Core; - using Cake.Core.Annotations; - using Nerdbank.GitVersioning; - using Nerdbank.GitVersioning.Commands; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO; +using System.Reflection; +using Cake.Core; +using Cake.Core.Annotations; +using Nerdbank.GitVersioning; +using Nerdbank.GitVersioning.Commands; +namespace Cake.GitVersioning +{ /// /// Contains functionality for using Nerdbank.GitVersioning. /// @@ -17,20 +20,23 @@ public static class GitVersioningAliases /// /// Gets the Git Versioning version from the current repo. /// - /// + /// The context. + /// Directory to start the search for version.json. + /// The version information from Git Versioning. + /// + /// Example: + /// /// { /// Information(GetVersioningGetVersion().SemVer2) /// }); - /// - /// The context. - /// Directory to start the search for version.json. - /// The version information from Git Versioning. + /// ]]> + /// [CakeMethodAlias] public static VersionOracle GitVersioningGetVersion(this ICakeContext cakeContext, string projectDirectory = ".") { - var fullProjectDirectory = (new DirectoryInfo(projectDirectory)).FullName; + string fullProjectDirectory = new DirectoryInfo(projectDirectory).FullName; string directoryName = Path.GetDirectoryName(Assembly.GetAssembly(typeof(GitVersioningAliases)).Location); @@ -46,20 +52,23 @@ public static VersionOracle GitVersioningGetVersion(this ICakeContext cakeContex /// /// Adds versioning information to the current build environment's variables. /// - /// + /// The context. + /// Directory to start the search for version.json. + /// The settings to use for updating variables. + /// + /// Example: + /// /// { /// GitVersioningCloud() /// }); - /// - /// The context. - /// Directory to start the search for version.json. - /// The settings to use for updating variables. + /// ]]> + /// [CakeMethodAlias] public static void GitVersioningCloud(this ICakeContext cakeContext, string projectDirectory = ".", GitVersioningCloudSettings settings = null) { - var fullProjectDirectory = (new DirectoryInfo(projectDirectory)).FullName; + string fullProjectDirectory = new DirectoryInfo(projectDirectory).FullName; string directoryName = Path.GetDirectoryName(Assembly.GetAssembly(typeof(GitVersioningAliases)).Location); @@ -79,9 +88,7 @@ public static void GitVersioningCloud(this ICakeContext cakeContext, string proj settings.AllVariables, settings.CommonVariables, settings.AdditionalVariables, - false - ); + false); } - } } diff --git a/src/Cake.GitVersioning/GitVersioningCloudProvider.cs b/src/Cake.GitVersioning/GitVersioningCloudProvider.cs index 5a658028..f5c29163 100644 --- a/src/Cake.GitVersioning/GitVersioningCloudProvider.cs +++ b/src/Cake.GitVersioning/GitVersioningCloudProvider.cs @@ -1,4 +1,7 @@ -namespace Cake.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Cake.GitVersioning { /// /// Defines the supported cloud build providers for the alias. diff --git a/src/Cake.GitVersioning/GitVersioningCloudSettings.cs b/src/Cake.GitVersioning/GitVersioningCloudSettings.cs index 1082373b..9ccf5d32 100644 --- a/src/Cake.GitVersioning/GitVersioningCloudSettings.cs +++ b/src/Cake.GitVersioning/GitVersioningCloudSettings.cs @@ -1,44 +1,44 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable namespace Cake.GitVersioning { - using System; - using System.Collections.Generic; - /// /// Defines settings for the alias. /// public class GitVersioningCloudSettings { /// - /// The string to use for the cloud build number. + /// Gets or sets the string to use for the cloud build number. /// If no value is specified, the computed version will be used. /// public string? Version { get; set; } /// - /// Adds an identifier to the build metadata part of a semantic version. + /// Gets a list of identifiers to include with the build metadata part of a semantic version. /// public List Metadata { get; } = new(); /// - /// Force activation for a particular CI system. If not specified, - /// auto-detection will be used. + /// Gets or sets a a particular CI system to force usage of. + /// If not specified, auto-detection will be used. /// public GitVersioningCloudProvider? CISystem { get; set; } /// - /// Defines ALL version variables as cloud build variables, with a "NBGV_" prefix. + /// Gets or sets a value indicating whether to define ALL version variables as cloud build variables, with a "NBGV_" prefix. /// public bool AllVariables { get; set; } /// - /// Defines a few common version variables as cloud build variables, with a "Git" prefix. + /// Gets or sets a value indicating whether to define a few common version variables as cloud build variables, with a "Git" prefix. /// public bool CommonVariables { get; set; } /// - /// Additional cloud build variables to define. + /// Gets additional cloud build variables to define. /// public Dictionary AdditionalVariables { get; } = new(StringComparer.OrdinalIgnoreCase); } diff --git a/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs b/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs index 0e88f638..01efeeb5 100644 --- a/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs +++ b/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs @@ -1,74 +1,73 @@ -namespace Nerdbank.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using Newtonsoft.Json; + +namespace Nerdbank.GitVersioning; + +internal class AssemblyVersionOptionsConverter : JsonConverter { - using System; - using System.Collections.Generic; - using System.Linq; - using System.Reflection; - using System.Text; - using System.Threading.Tasks; - using Newtonsoft.Json; - using Newtonsoft.Json.Linq; + private readonly bool includeDefaults; - internal class AssemblyVersionOptionsConverter : JsonConverter + internal AssemblyVersionOptionsConverter(bool includeDefaults) { - private readonly bool includeDefaults; - - internal AssemblyVersionOptionsConverter(bool includeDefaults) - { - this.includeDefaults = includeDefaults; - } + this.includeDefaults = includeDefaults; + } - public override bool CanConvert(Type objectType) - { - return typeof(VersionOptions.AssemblyVersionOptions).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); - } + /// + public override bool CanConvert(Type objectType) + { + return typeof(VersionOptions.AssemblyVersionOptions).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (objectType.Equals(typeof(VersionOptions.AssemblyVersionOptions))) { - if (objectType.Equals(typeof(VersionOptions.AssemblyVersionOptions))) + if (reader.Value is string) { - if (reader.Value is string) - { - Version value; - if (Version.TryParse((string)reader.Value, out value)) - { - return new VersionOptions.AssemblyVersionOptions(value); - } - } - else if (reader.TokenType == JsonToken.StartObject) + Version value; + if (Version.TryParse((string)reader.Value, out value)) { - // Temporarily remove ourselves from the serializer so we don't recurse infinitely. - serializer.Converters.Remove(this); - var result = serializer.Deserialize(reader); - serializer.Converters.Add(this); - return result; + return new VersionOptions.AssemblyVersionOptions(value); } } - - throw new NotSupportedException(); + else if (reader.TokenType == JsonToken.StartObject) + { + // Temporarily remove ourselves from the serializer so we don't recurse infinitely. + serializer.Converters.Remove(this); + VersionOptions.AssemblyVersionOptions result = serializer.Deserialize(reader); + serializer.Converters.Add(this); + return result; + } } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + throw new NotSupportedException(); + } + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var data = value as VersionOptions.AssemblyVersionOptions; + if (data is not null) { - var data = value as VersionOptions.AssemblyVersionOptions; - if (data is not null) + if (data.PrecisionOrDefault == VersionOptions.DefaultVersionPrecision && !this.includeDefaults) { - if (data.PrecisionOrDefault == VersionOptions.DefaultVersionPrecision && !this.includeDefaults) - { - serializer.Serialize(writer, data.Version); - return; - } - else - { - // Temporarily remove ourselves from the serializer so we don't recurse infinitely. - serializer.Converters.Remove(this); - serializer.Serialize(writer, data); - serializer.Converters.Add(this); - return; - } + serializer.Serialize(writer, data.Version); + return; + } + else + { + // Temporarily remove ourselves from the serializer so we don't recurse infinitely. + serializer.Converters.Remove(this); + serializer.Serialize(writer, data); + serializer.Converters.Add(this); + return; } - - throw new NotSupportedException(); } + + throw new NotSupportedException(); } } diff --git a/src/NerdBank.GitVersioning/CloudBuild.cs b/src/NerdBank.GitVersioning/CloudBuild.cs index e5417145..b57ac48f 100644 --- a/src/NerdBank.GitVersioning/CloudBuild.cs +++ b/src/NerdBank.GitVersioning/CloudBuild.cs @@ -1,55 +1,56 @@ -namespace Nerdbank.GitVersioning -{ - using System; - using System.Linq; - using CloudBuildServices; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Nerdbank.GitVersioning.CloudBuildServices; +namespace Nerdbank.GitVersioning; + +/// +/// Provides access to cloud build providers. +/// +public static class CloudBuild +{ /// - /// Provides access to cloud build providers. + /// An array of cloud build systems we support. /// - public static class CloudBuild + public static readonly ICloudBuild[] SupportedCloudBuilds = new ICloudBuild[] { - /// - /// An array of cloud build systems we support. - /// - public static readonly ICloudBuild[] SupportedCloudBuilds = new ICloudBuild[] { - new AppVeyor(), - new VisualStudioTeamServices(), - new GitHubActions(), - new TeamCity(), - new AtlassianBamboo(), - new Jenkins(), - new GitLab(), - new Travis(), - new SpaceAutomation(), - }; + new AppVeyor(), + new VisualStudioTeamServices(), + new GitHubActions(), + new TeamCity(), + new AtlassianBamboo(), + new Jenkins(), + new GitLab(), + new Travis(), + new SpaceAutomation(), + }; - /// - /// Gets the cloud build provider that applies to this build, if any. - /// - public static ICloudBuild Active => SupportedCloudBuilds.FirstOrDefault(cb => cb.IsApplicable); - - /// - /// Gets the specified string, prefixing it with some value if it is non-empty and lacks the prefix. - /// - /// The prefix that should be included in the returned value. - /// The value to prefix. - /// The provided, with prepended - /// if the value doesn't already start with that string and the value is non-empty. - internal static string ShouldStartWith(string value, string prefix) - { - return - string.IsNullOrEmpty(value) ? value : - value.StartsWith(prefix, StringComparison.Ordinal) ? value : - prefix + value; - } + /// + /// Gets the cloud build provider that applies to this build, if any. + /// + public static ICloudBuild Active => SupportedCloudBuilds.FirstOrDefault(cb => cb.IsApplicable); - /// - /// Gets the specified string if it starts with a given prefix; otherwise null. - /// - /// The value to return. - /// The prefix to check for. - /// if it starts with ; otherwise null. - internal static string IfStartsWith(string value, string prefix) => value is object && value.StartsWith(prefix, StringComparison.Ordinal) ? value : null; + /// + /// Gets the specified string, prefixing it with some value if it is non-empty and lacks the prefix. + /// + /// The value to prefix. + /// The prefix that should be included in the returned value. + /// The provided, with prepended + /// if the value doesn't already start with that string and the value is non-empty. + internal static string ShouldStartWith(string value, string prefix) + { + return + string.IsNullOrEmpty(value) ? value : + value.StartsWith(prefix, StringComparison.Ordinal) ? value : + prefix + value; } + + /// + /// Gets the specified string if it starts with a given prefix; otherwise null. + /// + /// The value to return. + /// The prefix to check for. + /// if it starts with ; otherwise null. + internal static string IfStartsWith(string value, string prefix) => value is object && value.StartsWith(prefix, StringComparison.Ordinal) ? value : null; } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs b/src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs index 08ac7147..24bee227 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs @@ -1,72 +1,74 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices -{ - using System; - using System.Collections.Generic; - using System.ComponentModel; - using System.Diagnostics; - using System.IO; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.ComponentModel; +using System.Diagnostics; + +namespace Nerdbank.GitVersioning.CloudBuildServices; - /// - /// - /// +/// +/// Cloud build handling for AppVeyor. +/// +/// +/// The AppVeyor-specific properties referenced here are documented here. +/// +internal class AppVeyor : ICloudBuild +{ + /// /// - /// The AppVeyor-specific properties referenced here are documented here: - /// http://www.appveyor.com/docs/environment-variables + /// AppVeyor's branch variable is the target branch of a PR, which is *NOT* to be misinterpreted + /// as building the target branch itself. So only set the branch built property if it's not a PR. /// - internal class AppVeyor : ICloudBuild - { - /// - /// - /// - /// - /// AppVeyor's branch variable is the target branch of a PR, which is *NOT* to be misinterpreted - /// as building the target branch itself. So only set the branch built property if it's not a PR. - /// - public string BuildingBranch => !this.IsPullRequest && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH")) - ? $"refs/heads/{Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH")}" - : null; + public string BuildingBranch => !this.IsPullRequest && !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH")) + ? $"refs/heads/{Environment.GetEnvironmentVariable("APPVEYOR_REPO_BRANCH")}" + : null; - public string BuildingRef => null; + public string BuildingRef => null; - public string BuildingTag => string.Equals("true", Environment.GetEnvironmentVariable("APPVEYOR_REPO_TAG"), StringComparison.OrdinalIgnoreCase) - ? $"refs/tags/{Environment.GetEnvironmentVariable("APPVEYOR_REPO_TAG_NAME")}" - : null; + /// + public string BuildingTag => string.Equals("true", Environment.GetEnvironmentVariable("APPVEYOR_REPO_TAG"), StringComparison.OrdinalIgnoreCase) + ? $"refs/tags/{Environment.GetEnvironmentVariable("APPVEYOR_REPO_TAG_NAME")}" + : null; - public string GitCommitId => null; + /// + public string GitCommitId => null; - public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPVEYOR")); + /// + public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPVEYOR")); - public bool IsPullRequest => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER")); + /// + public bool IsPullRequest => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("APPVEYOR_PULL_REQUEST_NUMBER")); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - // We ignore exit code so as to not fail the build when the cloud build number is not unique. - RunAppveyor($"UpdateBuild -Version \"{buildNumber}\"", stdout, stderr); - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + // We ignore exit code so as to not fail the build when the cloud build number is not unique. + RunAppveyor($"UpdateBuild -Version \"{buildNumber}\"", stdout, stderr); + return new Dictionary(); + } - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - RunAppveyor($"SetVariable -Name {name} -Value \"{value}\"", stdout, stderr); - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + RunAppveyor($"SetVariable -Name {name} -Value \"{value}\"", stdout, stderr); + return new Dictionary(); + } - private static void RunAppveyor(string args, TextWriter stdout, TextWriter stderr) + private static void RunAppveyor(string args, TextWriter stdout, TextWriter stderr) + { + try { - try + // Skip this if this build is running in our own unit tests, since that can + // mess with AppVeyor's actual build information. + if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("_NBGV_UnitTest"))) { - // Skip this if this build is running in our own unit tests, since that can - // mess with AppVeyor's actual build information. - if (string.IsNullOrEmpty(Environment.GetEnvironmentVariable("_NBGV_UnitTest"))) - { - Process.Start("appveyor", args) - .WaitForExit(); - } - } - catch (Win32Exception ex) when ((uint)ex.HResult == 0x80004005) - { - (stderr ?? Console.Error).WriteLine("Could not find appveyor tool to set cloud build variable."); + Process.Start("appveyor", args) + .WaitForExit(); } } + catch (Win32Exception ex) when ((uint)ex.HResult == 0x80004005) + { + (stderr ?? Console.Error).WriteLine("Could not find appveyor tool to set cloud build variable."); + } } } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs b/src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs index fe418113..72a395ee 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs @@ -1,38 +1,42 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Nerdbank.GitVersioning.CloudBuildServices; + +/// +/// Cloud build handling for Atlassian Bamboo. +/// +/// +/// The Bamboo-specific properties referenced here are documented here. +/// +internal class AtlassianBamboo : ICloudBuild { - using System; - using System.Collections.Generic; - using System.IO; - - /// - /// - /// - /// - /// The Bamboo-specific properties referenced here are documented here: - /// https://confluence.atlassian.com/bamboo/bamboo-variables-289277087.html - /// - internal class AtlassianBamboo : ICloudBuild - { - public bool IsPullRequest => false; + /// + public bool IsPullRequest => false; - public string BuildingTag => null; + /// + public string BuildingTag => null; - public string BuildingBranch => CloudBuild.ShouldStartWith(Environment.GetEnvironmentVariable("bamboo.planRepository.branch"), "refs/heads/"); + /// + public string BuildingBranch => CloudBuild.ShouldStartWith(Environment.GetEnvironmentVariable("bamboo.planRepository.branch"), "refs/heads/"); - public string BuildingRef => this.BuildingBranch; + public string BuildingRef => this.BuildingBranch; - public string GitCommitId => Environment.GetEnvironmentVariable("bamboo.planRepository.revision"); + /// + public string GitCommitId => Environment.GetEnvironmentVariable("bamboo.planRepository.revision"); - public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("bamboo.buildKey")); + /// + public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("bamboo.buildKey")); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); } } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs b/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs index f3931042..e278fc01 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs @@ -1,45 +1,49 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices -{ - using System; - using System.Collections.Generic; - using System.IO; - using Nerdbank.GitVersioning; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. - internal class GitHubActions : ICloudBuild - { - public bool IsApplicable => Environment.GetEnvironmentVariable("GITHUB_ACTIONS") == "true"; +namespace Nerdbank.GitVersioning.CloudBuildServices; - public bool IsPullRequest => Environment.GetEnvironmentVariable("GITHUB_EVENT_NAME") == "PullRequestEvent"; +internal class GitHubActions : ICloudBuild +{ + /// + public bool IsApplicable => Environment.GetEnvironmentVariable("GITHUB_ACTIONS") == "true"; - public string BuildingBranch => (BuildingRef?.StartsWith("refs/heads/") ?? false) ? BuildingRef : null; + /// + public bool IsPullRequest => Environment.GetEnvironmentVariable("GITHUB_EVENT_NAME") == "PullRequestEvent"; - public string BuildingTag => (BuildingRef?.StartsWith("refs/tags/") ?? false) ? BuildingRef : null; + /// + public string BuildingBranch => (BuildingRef?.StartsWith("refs/heads/") ?? false) ? BuildingRef : null; - public string GitCommitId => Environment.GetEnvironmentVariable("GITHUB_SHA"); + /// + public string BuildingTag => (BuildingRef?.StartsWith("refs/tags/") ?? false) ? BuildingRef : null; - private static string BuildingRef => Environment.GetEnvironmentVariable("GITHUB_REF"); + /// + public string GitCommitId => Environment.GetEnvironmentVariable("GITHUB_SHA"); - private static string EnvironmentFile => Environment.GetEnvironmentVariable("GITHUB_ENV"); + private static string BuildingRef => Environment.GetEnvironmentVariable("GITHUB_REF"); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + private static string EnvironmentFile => Environment.GetEnvironmentVariable("GITHUB_ENV"); - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - Utilities.FileOperationWithRetry(() => File.AppendAllLines(EnvironmentFile, new [] {$"{name}={value}"})); - return GetDictionaryFor(name, value); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } - private static IReadOnlyDictionary GetDictionaryFor(string variableName, string value) - { - return new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { GetEnvironmentVariableNameForVariable(variableName), value }, - }; - } + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + Utilities.FileOperationWithRetry(() => File.AppendAllLines(EnvironmentFile, new[] { $"{name}={value}" })); + return GetDictionaryFor(name, value); + } - private static string GetEnvironmentVariableNameForVariable(string name) => name.ToUpperInvariant().Replace('.', '_'); + private static IReadOnlyDictionary GetDictionaryFor(string variableName, string value) + { + return new Dictionary(StringComparer.OrdinalIgnoreCase) + { + { GetEnvironmentVariableNameForVariable(variableName), value }, + }; } + + private static string GetEnvironmentVariableNameForVariable(string name) => name.ToUpperInvariant().Replace('.', '_'); } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs b/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs index 21abebd2..f02e4e17 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs @@ -1,42 +1,46 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Nerdbank.GitVersioning.CloudBuildServices; + +/// +/// Cloud build handling for GitLab. +/// +/// +/// The GitLab-specific properties referenced here are documented here. +/// +internal class GitLab : ICloudBuild { - using System; - using System.Collections.Generic; - using System.IO; - - /// - /// - /// - /// - /// The GitLab-specific properties referenced here are documented here: - /// https://docs.gitlab.com/ce/ci/variables/README.html - /// - internal class GitLab : ICloudBuild - { - public string BuildingBranch => - Environment.GetEnvironmentVariable("CI_COMMIT_TAG") is null ? - $"refs/heads/{Environment.GetEnvironmentVariable("CI_COMMIT_REF_NAME")}" : null; + /// + public string BuildingBranch => + Environment.GetEnvironmentVariable("CI_COMMIT_TAG") is null ? + $"refs/heads/{Environment.GetEnvironmentVariable("CI_COMMIT_REF_NAME")}" : null; - public string BuildingRef => this.BuildingBranch ?? this.BuildingTag; + public string BuildingRef => this.BuildingBranch ?? this.BuildingTag; - public string BuildingTag => - Environment.GetEnvironmentVariable("CI_COMMIT_TAG") is not null ? - $"refs/tags/{Environment.GetEnvironmentVariable("CI_COMMIT_TAG")}" : null; + /// + public string BuildingTag => + Environment.GetEnvironmentVariable("CI_COMMIT_TAG") is not null ? + $"refs/tags/{Environment.GetEnvironmentVariable("CI_COMMIT_TAG")}" : null; - public string GitCommitId => Environment.GetEnvironmentVariable("CI_COMMIT_SHA"); + /// + public string GitCommitId => Environment.GetEnvironmentVariable("CI_COMMIT_SHA"); - public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITLAB_CI")); + /// + public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("GITLAB_CI")); - public bool IsPullRequest => false; + /// + public bool IsPullRequest => false; - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); } } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs b/src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs index 688e6b65..e5534c55 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs @@ -1,64 +1,72 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - - /// - /// The Jenkins-specific properties referenced here are documented here: - /// https://wiki.jenkins-ci.org/display/JENKINS/Git+Plugin#GitPlugin-Environmentvariables - /// - internal class Jenkins : ICloudBuild - { - private static readonly Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. - public string BuildingTag => null; +using System.Text; - public bool IsPullRequest => false; +namespace Nerdbank.GitVersioning.CloudBuildServices; - public string BuildingBranch => CloudBuild.ShouldStartWith(Branch, "refs/heads/"); +/// +/// Cloud build handling for Jenkins. +/// +/// +/// The Jenkins-specific properties referenced here are documented here. +/// +internal class Jenkins : ICloudBuild +{ + private static readonly Encoding UTF8NoBOM = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false); - public string GitCommitId => Environment.GetEnvironmentVariable("GIT_COMMIT"); + /// + public string BuildingTag => null; - public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("JENKINS_URL")); + /// + public bool IsPullRequest => false; - private static string Branch => - Environment.GetEnvironmentVariable("GIT_LOCAL_BRANCH") - ?? Environment.GetEnvironmentVariable("GIT_BRANCH"); + /// + public string BuildingBranch => CloudBuild.ShouldStartWith(Branch, "refs/heads/"); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - WriteVersionFile(buildNumber); + /// + public string GitCommitId => Environment.GetEnvironmentVariable("GIT_COMMIT"); - stdout.WriteLine($"## GIT_VERSION: {buildNumber}"); + /// + public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("JENKINS_URL")); - return new Dictionary - { - { "GIT_VERSION", buildNumber } - }; - } + private static string Branch => + Environment.GetEnvironmentVariable("GIT_LOCAL_BRANCH") + ?? Environment.GetEnvironmentVariable("GIT_BRANCH"); - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - return new Dictionary - { - { name, value } - }; - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + WriteVersionFile(buildNumber); + + stdout.WriteLine($"## GIT_VERSION: {buildNumber}"); - private static void WriteVersionFile(string buildNumber) + return new Dictionary { - var workspacePath = Environment.GetEnvironmentVariable("WORKSPACE"); + { "GIT_VERSION", buildNumber }, + }; + } - if (string.IsNullOrEmpty(workspacePath)) - { - return; - } + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + return new Dictionary + { + { name, value }, + }; + } - var versionFilePath = Path.Combine(workspacePath, "jenkins_build_number.txt"); + private static void WriteVersionFile(string buildNumber) + { + string workspacePath = Environment.GetEnvironmentVariable("WORKSPACE"); - Utilities.FileOperationWithRetry(() => File.WriteAllText(versionFilePath, buildNumber, UTF8NoBOM)); + if (string.IsNullOrEmpty(workspacePath)) + { + return; } + + string versionFilePath = Path.Combine(workspacePath, "jenkins_build_number.txt"); + + Utilities.FileOperationWithRetry(() => File.WriteAllText(versionFilePath, buildNumber, UTF8NoBOM)); } } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs b/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs index b3d11a0d..7df2ab28 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs @@ -1,38 +1,42 @@ -using System; -using System.Collections.Generic; -using System.IO; - -namespace Nerdbank.GitVersioning.CloudBuildServices +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Nerdbank.GitVersioning.CloudBuildServices; + +/// +/// SpaceAutomation CI build support. +/// +/// +/// The SpaceAutomation-specific properties referenced here are documented here. +/// +internal class SpaceAutomation : ICloudBuild { - /// - /// SpaceAutomation CI build support. - /// - /// - /// The SpaceAutomation-specific properties referenced here are documented here: - /// https://www.jetbrains.com/help/space/automation-environment-variables.html - /// - internal class SpaceAutomation : ICloudBuild - { - public string BuildingBranch => CloudBuild.IfStartsWith(BuildingRef, "refs/heads/"); + /// + public string BuildingBranch => CloudBuild.IfStartsWith(BuildingRef, "refs/heads/"); - public string BuildingTag => CloudBuild.IfStartsWith(BuildingRef, "refs/tags/"); + /// + public string BuildingTag => CloudBuild.IfStartsWith(BuildingRef, "refs/tags/"); - public string GitCommitId => Environment.GetEnvironmentVariable("JB_SPACE_GIT_REVISION"); + /// + public string GitCommitId => Environment.GetEnvironmentVariable("JB_SPACE_GIT_REVISION"); - public bool IsApplicable => this.GitCommitId is not null; + /// + public bool IsApplicable => this.GitCommitId is not null; - public bool IsPullRequest => false; + /// + public bool IsPullRequest => false; - private static string BuildingRef => Environment.GetEnvironmentVariable("JB_SPACE_GIT_BRANCH"); + private static string BuildingRef => Environment.GetEnvironmentVariable("JB_SPACE_GIT_BRANCH"); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); } -} \ No newline at end of file +} diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs b/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs index 828798ee..89f5b243 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs @@ -1,42 +1,46 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Nerdbank.GitVersioning.CloudBuildServices; + +/// +/// TeamCity CI build support. +/// +/// +/// The TeamCity-specific properties referenced here are documented here. +/// +internal class TeamCity : ICloudBuild { - using System; - using System.Collections.Generic; - using System.IO; - - /// - /// TeamCity CI build support. - /// - /// - /// The TeamCity-specific properties referenced here are documented here: - /// https://www.jetbrains.com/help/teamcity/predefined-build-parameters.html - /// - internal class TeamCity : ICloudBuild - { - public string BuildingBranch => CloudBuild.IfStartsWith(BuildingRef, "refs/heads/"); + /// + public string BuildingBranch => CloudBuild.IfStartsWith(BuildingRef, "refs/heads/"); - public string BuildingTag => CloudBuild.IfStartsWith(BuildingRef, "refs/tags/"); + /// + public string BuildingTag => CloudBuild.IfStartsWith(BuildingRef, "refs/tags/"); - public string GitCommitId => Environment.GetEnvironmentVariable("BUILD_VCS_NUMBER"); + /// + public string GitCommitId => Environment.GetEnvironmentVariable("BUILD_VCS_NUMBER"); - public bool IsApplicable => this.GitCommitId is not null; + /// + public bool IsApplicable => this.GitCommitId is not null; - public bool IsPullRequest => false; + /// + public bool IsPullRequest => false; - private static string BuildingRef => Environment.GetEnvironmentVariable("BUILD_GIT_BRANCH"); + private static string BuildingRef => Environment.GetEnvironmentVariable("BUILD_GIT_BRANCH"); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - (stdout ?? Console.Out).WriteLine($"##teamcity[buildNumber '{buildNumber}']"); - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + (stdout ?? Console.Out).WriteLine($"##teamcity[buildNumber '{buildNumber}']"); + return new Dictionary(); + } - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - (stdout ?? Console.Out).WriteLine($"##teamcity[setParameter name='{name}' value='{value}']"); - (stdout ?? Console.Out).WriteLine($"##teamcity[setParameter name='system.{name}' value='{value}']"); + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + (stdout ?? Console.Out).WriteLine($"##teamcity[setParameter name='{name}' value='{value}']"); + (stdout ?? Console.Out).WriteLine($"##teamcity[setParameter name='system.{name}' value='{value}']"); - return new Dictionary(); - } + return new Dictionary(); } } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs b/src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs index 1c57a4c8..21e6ed0b 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs @@ -1,37 +1,42 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Nerdbank.GitVersioning.CloudBuildServices; + +/// +/// Travis CI build support. +/// +/// +/// The Travis CI environment variables referenced here are documented here. +/// +internal class Travis : ICloudBuild { - using System; - using System.Collections.Generic; - using System.IO; - - /// - /// Travis CI build support. - /// - /// - /// The Travis CI environment variables referenced here are documented here: - /// https://docs.travis-ci.com/user/environment-variables/#default-environment-variables - /// - internal class Travis: ICloudBuild - { - // TRAVIS_BRANCH can reference a branch or a tag, so make sure it starts with refs/heads - public string BuildingBranch => CloudBuild.ShouldStartWith(Environment.GetEnvironmentVariable("TRAVIS_BRANCH"), "refs/heads/"); + // TRAVIS_BRANCH can reference a branch or a tag, so make sure it starts with refs/heads - public string BuildingTag => Environment.GetEnvironmentVariable("TRAVIS_TAG"); + /// + public string BuildingBranch => CloudBuild.ShouldStartWith(Environment.GetEnvironmentVariable("TRAVIS_BRANCH"), "refs/heads/"); - public string GitCommitId => Environment.GetEnvironmentVariable("TRAVIS_COMMIT"); + /// + public string BuildingTag => Environment.GetEnvironmentVariable("TRAVIS_TAG"); - public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TRAVIS")); + /// + public string GitCommitId => Environment.GetEnvironmentVariable("TRAVIS_COMMIT"); - public bool IsPullRequest => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TRAVIS_PULL_REQUEST_BRANCH")); + /// + public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TRAVIS")); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public bool IsPullRequest => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("TRAVIS_PULL_REQUEST_BRANCH")); - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - return new Dictionary(); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } + + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); } } diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs b/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs index fcaf7f1d..f94bb8ea 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs @@ -1,51 +1,55 @@ -namespace Nerdbank.GitVersioning.CloudBuildServices +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Nerdbank.GitVersioning.CloudBuildServices; + +/// +/// Cloud build handling for Azure DevOps. +/// +/// +/// The VSTS-specific properties referenced here are documented here. +/// +internal class VisualStudioTeamServices : ICloudBuild { - using System; - using System.Collections.Generic; - using System.IO; - - /// - /// - /// - /// - /// The VSTS-specific properties referenced here are documented here: - /// https://msdn.microsoft.com/en-us/Library/vs/alm/Build/scripts/variables - /// - internal class VisualStudioTeamServices : ICloudBuild - { - public bool IsPullRequest => BuildingRef?.StartsWith("refs/pull/") ?? false; + /// + public bool IsPullRequest => BuildingRef?.StartsWith("refs/pull/") ?? false; - public string BuildingTag => CloudBuild.IfStartsWith(BuildingRef, "refs/tags/"); + /// + public string BuildingTag => CloudBuild.IfStartsWith(BuildingRef, "refs/tags/"); - public string BuildingBranch => CloudBuild.IfStartsWith(BuildingRef, "refs/heads/"); + /// + public string BuildingBranch => CloudBuild.IfStartsWith(BuildingRef, "refs/heads/"); - public string GitCommitId => null; + /// + public string GitCommitId => null; - public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECTID")); + /// + public bool IsApplicable => !string.IsNullOrEmpty(Environment.GetEnvironmentVariable("SYSTEM_TEAMPROJECTID")); - private static string BuildingRef => Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH"); + private static string BuildingRef => Environment.GetEnvironmentVariable("BUILD_SOURCEBRANCH"); - public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) - { - (stdout ?? Console.Out).WriteLine($"##vso[build.updatebuildnumber]{buildNumber}"); - return GetDictionaryFor("Build.BuildNumber", buildNumber); - } + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + (stdout ?? Console.Out).WriteLine($"##vso[build.updatebuildnumber]{buildNumber}"); + return GetDictionaryFor("Build.BuildNumber", buildNumber); + } - public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) - { - Utilities.FileOperationWithRetry(() => - (stdout ?? Console.Out).WriteLine($"##vso[task.setvariable variable={name};]{value}")); - return GetDictionaryFor(name, value); - } + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + Utilities.FileOperationWithRetry(() => + (stdout ?? Console.Out).WriteLine($"##vso[task.setvariable variable={name};]{value}")); + return GetDictionaryFor(name, value); + } - private static IReadOnlyDictionary GetDictionaryFor(string variableName, string value) + private static IReadOnlyDictionary GetDictionaryFor(string variableName, string value) + { + return new Dictionary(StringComparer.OrdinalIgnoreCase) { - return new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { GetEnvironmentVariableNameForVariable(variableName), value }, - }; - } - - private static string GetEnvironmentVariableNameForVariable(string name) => name.ToUpperInvariant().Replace('.', '_'); + { GetEnvironmentVariableNameForVariable(variableName), value }, + }; } + + private static string GetEnvironmentVariableNameForVariable(string name) => name.ToUpperInvariant().Replace('.', '_'); } diff --git a/src/NerdBank.GitVersioning/Commands/CloudCommand.cs b/src/NerdBank.GitVersioning/Commands/CloudCommand.cs index 8a78fa7f..42890eaa 100644 --- a/src/NerdBank.GitVersioning/Commands/CloudCommand.cs +++ b/src/NerdBank.GitVersioning/Commands/CloudCommand.cs @@ -1,176 +1,173 @@ -namespace Nerdbank.GitVersioning.Commands +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Validation; + +namespace Nerdbank.GitVersioning.Commands; + +/// +/// Implementation of the "nbgv cloud" command that updates the build environments variables with version variables. +/// +public class CloudCommand { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using Validation; + private readonly TextWriter stdout; + private readonly TextWriter stderr; /// - /// Implementation of the "nbgv cloud" command that updates the build environments variables with version variables. + /// Initializes a new instance of the class. /// - public class CloudCommand + /// The to write output to (e.g. ). + /// The to write error messages to (e.g. ). + public CloudCommand(TextWriter outputWriter = null, TextWriter errorWriter = null) + { + this.stdout = outputWriter ?? TextWriter.Null; + this.stderr = errorWriter ?? TextWriter.Null; + } + + /// + /// Defines the possible errors of the "cloud" command. + /// + public enum CloudCommandError { /// - /// Defines the possible errors of the "cloud" command + /// The specified CI system was not found. /// - public enum CloudCommandError - { - /// - /// The specified CI system was not found. - /// - NoCloudBuildProviderMatch, - - /// - /// A cloud variable was defined multiple times. - /// - DuplicateCloudVariable, - - /// - /// No supported cloud build environment could be detected. - /// - NoCloudBuildEnvDetected, - } + NoCloudBuildProviderMatch, /// - /// Exception indicating an error while setting build variables. + /// A cloud variable was defined multiple times. /// - public class CloudCommandException : Exception - { - /// - /// Gets the error that occurred. - /// - public CloudCommandError Error { get; } - - /// - /// Initializes a new instance of class. - /// - /// The message that describes the error. - /// The error that occurred. - public CloudCommandException(string message, CloudCommandError error) : base(message) => this.Error = error; - } - - private readonly TextWriter stdout; - private readonly TextWriter stderr; + DuplicateCloudVariable, /// - /// Initializes a new instance of . + /// No supported cloud build environment could be detected. /// - /// The to write output to (e.g. ). - /// The to write error messages to (e.g. ). - public CloudCommand(TextWriter outputWriter = null, TextWriter errorWriter = null) - { - this.stdout = outputWriter ?? TextWriter.Null; - this.stderr = errorWriter ?? TextWriter.Null; - } + NoCloudBuildEnvDetected, + } + private static string[] CloudProviderNames => CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name).ToArray(); - /// - /// Adds version variables to the the current cloud build environment. - /// - /// Thrown when the build environment could not be updated. - /// - /// The path to the directory which may (or its ancestors may) define the version file. - /// - /// - /// Optionally adds an identifier to the build metadata part of a semantic version. - /// - /// - /// The string to use for the cloud build number. If not specified, the computed version will be used. - /// - /// - /// The CI system to activate. If not specified, auto-detection will be used. - /// - /// - /// Controls whether to define all version variables as cloud build variables. - /// - /// - /// Controls whether to define common version variables as cloud build variables. - /// - /// - /// Additional cloud build variables to define. - /// - /// - /// Force usage of LibGit2 for accessing the git repository. - /// - public void SetBuildVariables(string projectDirectory, IEnumerable metadata, string version, string ciSystem, bool allVars, bool commonVars, IEnumerable> additionalVariables, bool alwaysUseLibGit2) - { - Requires.NotNull(projectDirectory, nameof(projectDirectory)); - Requires.NotNull(additionalVariables, nameof(additionalVariables)); + /// + /// Adds version variables to the the current cloud build environment. + /// + /// Thrown when the build environment could not be updated. + /// + /// The path to the directory which may (or its ancestors may) define the version file. + /// + /// + /// Optionally adds an identifier to the build metadata part of a semantic version. + /// + /// + /// The string to use for the cloud build number. If not specified, the computed version will be used. + /// + /// + /// The CI system to activate. If not specified, auto-detection will be used. + /// + /// + /// Controls whether to define all version variables as cloud build variables. + /// + /// + /// Controls whether to define common version variables as cloud build variables. + /// + /// + /// Additional cloud build variables to define. + /// + /// + /// Force usage of LibGit2 for accessing the git repository. + /// + public void SetBuildVariables(string projectDirectory, IEnumerable metadata, string version, string ciSystem, bool allVars, bool commonVars, IEnumerable> additionalVariables, bool alwaysUseLibGit2) + { + Requires.NotNull(projectDirectory, nameof(projectDirectory)); + Requires.NotNull(additionalVariables, nameof(additionalVariables)); - ICloudBuild activeCloudBuild = CloudBuild.Active; - if (!string.IsNullOrEmpty(ciSystem)) + ICloudBuild activeCloudBuild = CloudBuild.Active; + if (!string.IsNullOrEmpty(ciSystem)) + { + int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, ciSystem, StringComparison.OrdinalIgnoreCase)); + if (matchingIndex == -1) { - int matchingIndex = Array.FindIndex(CloudProviderNames, m => string.Equals(m, ciSystem, StringComparison.OrdinalIgnoreCase)); - if (matchingIndex == -1) - { - throw new CloudCommandException( - $"No cloud provider found by the name: \"{ciSystem}\"", - CloudCommandError.NoCloudBuildProviderMatch); - } - - activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex]; + throw new CloudCommandException( + $"No cloud provider found by the name: \"{ciSystem}\"", + CloudCommandError.NoCloudBuildProviderMatch); } - using var context = GitContext.Create(projectDirectory, writable: alwaysUseLibGit2); - var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild); - if (metadata is not null) - { - oracle.BuildMetadata.AddRange(metadata); - } + activeCloudBuild = CloudBuild.SupportedCloudBuilds[matchingIndex]; + } + + using var context = GitContext.Create(projectDirectory, writable: alwaysUseLibGit2); + var oracle = new VersionOracle(context, cloudBuild: activeCloudBuild); + if (metadata is not null) + { + oracle.BuildMetadata.AddRange(metadata); + } - var variables = new Dictionary(); - if (allVars) + var variables = new Dictionary(); + if (allVars) + { + foreach (KeyValuePair pair in oracle.CloudBuildAllVars) { - foreach (var pair in oracle.CloudBuildAllVars) - { - variables.Add(pair.Key, pair.Value); - } + variables.Add(pair.Key, pair.Value); } + } - if (commonVars) + if (commonVars) + { + foreach (KeyValuePair pair in oracle.CloudBuildVersionVars) { - foreach (var pair in oracle.CloudBuildVersionVars) - { - variables.Add(pair.Key, pair.Value); - } + variables.Add(pair.Key, pair.Value); } + } - foreach (var kvp in additionalVariables) + foreach (KeyValuePair kvp in additionalVariables) + { + if (variables.ContainsKey(kvp.Key)) { - if (variables.ContainsKey(kvp.Key)) - { - throw new CloudCommandException( - $"Cloud build variable \"{kvp.Key}\" specified more than once.", - CloudCommandError.DuplicateCloudVariable); - } - - variables[kvp.Key] = kvp.Value; + throw new CloudCommandException( + $"Cloud build variable \"{kvp.Key}\" specified more than once.", + CloudCommandError.DuplicateCloudVariable); } - if (activeCloudBuild is not null) + variables[kvp.Key] = kvp.Value; + } + + if (activeCloudBuild is not null) + { + if (string.IsNullOrEmpty(version)) { - if (string.IsNullOrEmpty(version)) - { - version = oracle.CloudBuildNumber; - } + version = oracle.CloudBuildNumber; + } - activeCloudBuild.SetCloudBuildNumber(version, this.stdout, this.stderr); + activeCloudBuild.SetCloudBuildNumber(version, this.stdout, this.stderr); - foreach (var pair in variables) - { - activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, this.stdout, this.stderr); - } - } - else + foreach (KeyValuePair pair in variables) { - throw new CloudCommandException( - "No cloud build detected.", - CloudCommandError.NoCloudBuildEnvDetected); + activeCloudBuild.SetCloudBuildVariable(pair.Key, pair.Value, this.stdout, this.stderr); } } + else + { + throw new CloudCommandException( + "No cloud build detected.", + CloudCommandError.NoCloudBuildEnvDetected); + } + } + /// + /// Exception indicating an error while setting build variables. + /// + public class CloudCommandException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The message that describes the error. + /// The error that occurred. + public CloudCommandException(string message, CloudCommandError error) + : base(message) => this.Error = error; - private static string[] CloudProviderNames => CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name).ToArray(); + /// + /// Gets the error that occurred. + /// + public CloudCommandError Error { get; } } } diff --git a/src/NerdBank.GitVersioning/FilterPath.cs b/src/NerdBank.GitVersioning/FilterPath.cs index 72322045..60029c27 100644 --- a/src/NerdBank.GitVersioning/FilterPath.cs +++ b/src/NerdBank.GitVersioning/FilterPath.cs @@ -1,290 +1,319 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System.Text; using Validation; -namespace Nerdbank.GitVersioning +namespace Nerdbank.GitVersioning; + +/// +/// A filter (include or exclude) representing a repo relative path. +/// +public class FilterPath { /// - /// A filter (include or exclude) representing a repo relative path. + /// Initializes a new instance of the class + /// from a pathspec-like string and a relative path within the repository. /// - public class FilterPath + /// + /// A string that supports some pathspec features. + /// This path is relative to . + /// + /// Examples: + /// + /// ../relative/inclusion.txt + /// :/absolute/inclusion.txt + /// :!relative/exclusion.txt + /// :^relative/exclusion.txt + /// :^/absolute/exclusion.txt + /// + /// + /// + /// Path (relative to the root of the repository) that is relative to. + /// Can be empty - which indicates is + /// relative to the root of the repository. + /// + /// Invalid path spec. + public FilterPath(string pathSpec, string relativeTo) { - /// - /// True if this represents an exclude filter. - /// - public bool IsExclude { get; } - - /// - /// if this represents an include filter. - /// - public bool IsInclude => !this.IsExclude; - - /// - /// Path relative to the repository root that this represents. - /// Directories are delimited with forward slashes. - /// - public string RepoRelativePath { get; } - - /// - /// True if this represents the root of the repository. - /// - public bool IsRoot => this.RepoRelativePath == ""; - - /// - /// Was the original pathspec parsed as a relative path? - /// - internal bool IsRelative { get; } - - /// - /// Normalizes a pathspec-like string into a root-relative path. - /// - /// - /// See for supported - /// formats of pathspecs. - /// - /// - /// Path that is relative to. - /// Can be empty - which indicates is - /// relative to the root of the repository. - /// - /// - /// Forward slash delimited string representing the root-relative path. - /// - private static (bool isRelative, string normalized) Normalize(string path, string relativeTo) + Requires.NotNullOrEmpty(pathSpec, nameof(pathSpec)); + Requires.NotNull(relativeTo, nameof(relativeTo)); + + if (pathSpec[0] == ':') { - // Path is absolute, nothing to do here - if (path[0] == '/' || path[0] == '\\') + if (pathSpec.Length > 1 && (pathSpec[1] == '^' || pathSpec[1] == '!')) { - return (false, path.Substring(1)); + this.IsExclude = true; + (this.IsRelative, this.RepoRelativePath) = Normalize(pathSpec.Substring(2), relativeTo); } - - var combined = relativeTo == "" ? path : relativeTo + '/' + path; - - return (true, string.Join("/", - combined - .Split(new[] {Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar}, - StringSplitOptions.RemoveEmptyEntries) - // Loop through each path segment... - .Aggregate(new Stack(), (parts, segment) => - { - switch (segment) - { - // If it refers to the current directory, skip it - case ".": - return parts; - - // If it refers to the parent directory, pop the most recent directory - case "..": - if (parts.Count == 0) - throw new FormatException($"Too many '..' in path '{combined}' - would escape the root of the repository."); - - parts.Pop(); - return parts; - - // Otherwise it's a directory/file name - add it to the stack - default: - parts.Push(segment); - return parts; - } - }) - // Reverse the stack, so it iterates root -> leaf - .Reverse() - )); - } - - /// - /// Construct a from a pathspec-like string and a - /// relative path within the repository. - /// - /// - /// A string that supports some pathspec features. - /// This path is relative to . - /// - /// Examples: - /// - ../relative/inclusion.txt - /// - :/absolute/inclusion.txt - /// - :!relative/exclusion.txt - /// - :^relative/exclusion.txt - /// - :^/absolute/exclusion.txt - /// - /// - /// Path (relative to the root of the repository) that is relative to. - /// Can be empty - which indicates is - /// relative to the root of the repository. - /// - /// Invalid path spec. - public FilterPath(string pathSpec, string relativeTo) - { - Requires.NotNullOrEmpty(pathSpec, nameof(pathSpec)); - Requires.NotNull(relativeTo, nameof(relativeTo)); - - if (pathSpec[0] == ':') + else if ((pathSpec.Length > 1 && pathSpec[1] == '/') || pathSpec[1] == '\\') { - if (pathSpec.Length > 1 && (pathSpec[1] == '^' || pathSpec[1] == '!')) - { - this.IsExclude = true; - (this.IsRelative, this.RepoRelativePath) = Normalize(pathSpec.Substring(2), relativeTo); - } - else if (pathSpec.Length > 1 && pathSpec[1] == '/' || pathSpec[1] == '\\') - { - this.RepoRelativePath = pathSpec.Substring(2); - } - else - { - throw new FormatException($"Unrecognized path spec '{pathSpec}'"); - } + this.RepoRelativePath = pathSpec.Substring(2); } else { - (this.IsRelative, this.RepoRelativePath) = Normalize(pathSpec, relativeTo); + throw new FormatException($"Unrecognized path spec '{pathSpec}'"); } + } + else + { + (this.IsRelative, this.RepoRelativePath) = Normalize(pathSpec, relativeTo); + } + + this.RepoRelativePath = + this.RepoRelativePath + .Replace('\\', '/') + .TrimEnd('/'); + } + + /// + /// Gets a value indicating whether represents an exclude filter. + /// + public bool IsExclude { get; } + + /// + /// Gets a value indicating whether represents an include filter. + /// + public bool IsInclude => !this.IsExclude; + + /// + /// Gets the path that this represents, relative to the repository root. + /// Directories are delimited with forward slashes. + /// + public string RepoRelativePath { get; } + + /// + /// Gets a value indicating whether represents the root of the repository. + /// + public bool IsRoot => this.RepoRelativePath == string.Empty; + + /// + /// Gets a value indicating whether the original pathspec was parsed as a relative path. + /// + internal bool IsRelative { get; } - this.RepoRelativePath = - this.RepoRelativePath - .Replace('\\', '/') - .TrimEnd('/'); + /// + /// Determines if should be excluded by this . + /// + /// Forward-slash delimited path (repo relative). + /// + /// Whether paths should be compared case insensitively. + /// Should be the 'core.ignorecase' config value for the repository. + /// + /// + /// True if this is an excluding filter that matches + /// , otherwise false. + /// + public bool Excludes(string repoRelativePath, bool ignoreCase) + { + if (repoRelativePath is null) + { + throw new ArgumentNullException(nameof(repoRelativePath)); } - /// - /// Determines if should be excluded by this . - /// - /// Forward-slash delimited path (repo relative). - /// - /// Whether paths should be compared case insensitively. - /// Should be the 'core.ignorecase' config value for the repository. - /// - /// - /// True if this is an excluding filter that matches - /// , otherwise false. - /// - public bool Excludes(string repoRelativePath, bool ignoreCase) + if (!this.IsExclude) { - if (repoRelativePath is null) - throw new ArgumentNullException(nameof(repoRelativePath)); + return false; + } - if (!this.IsExclude) return false; + StringComparison stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + return this.RepoRelativePath.Equals(repoRelativePath, stringComparison) || + repoRelativePath.StartsWith(this.RepoRelativePath + "/", stringComparison); + } + + /// + /// Determines if should be included by this . + /// + /// Forward-slash delimited path (repo relative). + /// + /// Whether paths should be compared case insensitively. + /// Should be the 'core.ignorecase' config value for the repository. + /// + /// + /// True if this is an including filter that matches + /// , otherwise false. + /// + public bool Includes(string repoRelativePath, bool ignoreCase) + { + if (repoRelativePath is null) + { + throw new ArgumentNullException(nameof(repoRelativePath)); + } - var stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - return this.RepoRelativePath.Equals(repoRelativePath, stringComparison) || - repoRelativePath.StartsWith(this.RepoRelativePath + "/", - stringComparison); + if (!this.IsInclude) + { + return false; } - /// - /// Determines if should be included by this . - /// - /// Forward-slash delimited path (repo relative). - /// - /// Whether paths should be compared case insensitively. - /// Should be the 'core.ignorecase' config value for the repository. - /// - /// - /// True if this is an including filter that matches - /// , otherwise false. - /// - public bool Includes(string repoRelativePath, bool ignoreCase) + if (this.IsRoot) { - if (repoRelativePath is null) - throw new ArgumentNullException(nameof(repoRelativePath)); + return true; + } - if (!this.IsInclude) return false; - if (this.IsRoot) return true; + StringComparison stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + return this.RepoRelativePath.Equals(repoRelativePath, stringComparison) || + repoRelativePath.StartsWith(this.RepoRelativePath + "/", stringComparison); + } - var stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - return this.RepoRelativePath.Equals(repoRelativePath, stringComparison) || - repoRelativePath.StartsWith(this.RepoRelativePath + "/", - stringComparison); + /// + /// Determines if children of may be included + /// by this . + /// + /// Forward-slash delimited path (repo relative). + /// + /// Whether paths should be compared case insensitively. + /// Should be the 'core.ignorecase' config value for the repository. + /// + /// + /// if this is an including filter that may match + /// children of , otherwise . + /// + public bool IncludesChildren(string repoRelativePath, bool ignoreCase) + { + if (repoRelativePath is null) + { + throw new ArgumentNullException(nameof(repoRelativePath)); + } + + if (!this.IsInclude) + { + return false; } - /// - /// Determines if children of may be included - /// by this . - /// - /// Forward-slash delimited path (repo relative). - /// - /// Whether paths should be compared case insensitively. - /// Should be the 'core.ignorecase' config value for the repository. - /// - /// - /// if this is an including filter that may match - /// children of , otherwise . - /// - public bool IncludesChildren(string repoRelativePath, bool ignoreCase) + if (this.IsRoot) { - if (repoRelativePath is null) - throw new ArgumentNullException(nameof(repoRelativePath)); + return true; + } + + StringComparison stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; + return this.RepoRelativePath.StartsWith(repoRelativePath + "/", stringComparison); + } - if (!this.IsInclude) return false; - if (this.IsRoot) return true; + /// + /// Convert this path filter to a pathspec. + /// + /// + /// Repo-relative directory that relative pathspecs should be relative to. + /// Can be empty - which indicates this FilterPath is + /// relative to the root of the repository. + /// + /// String representation of a path filter (a pathspec). + public string ToPathSpec(string repoRelativeBaseDirectory) + { + Requires.NotNull(repoRelativeBaseDirectory, nameof(repoRelativeBaseDirectory)); - var stringComparison = ignoreCase ? StringComparison.OrdinalIgnoreCase : StringComparison.Ordinal; - return this.RepoRelativePath.StartsWith(repoRelativePath + "/", stringComparison); + var pathSpec = new StringBuilder(this.RepoRelativePath.Length + 2); + (bool _, string normalizedBaseDirectory) = + Normalize(repoRelativeBaseDirectory == string.Empty ? "." : repoRelativeBaseDirectory, null); + + if (this.IsExclude) + { + pathSpec.Append(":!"); } - private static (int dirsToAscend, StringBuilder result) GetRelativePath(string path, string relativeTo) + if (this.IsRelative) { - var pathParts = path.Split('/'); - var baseDirParts = relativeTo.Split(new[] {'/'}, StringSplitOptions.RemoveEmptyEntries); - - int commonParts; - for (commonParts = 0; - commonParts < Math.Min(pathParts.Length, baseDirParts.Length) && - pathParts[commonParts].Equals(baseDirParts[commonParts], StringComparison.OrdinalIgnoreCase); - ++commonParts) + (int dirsAscended, StringBuilder relativePath) = GetRelativePath(this.RepoRelativePath, normalizedBaseDirectory); + if (dirsAscended == 0 && !this.IsExclude) { + pathSpec.Append("./"); } - int dirsToAscend = baseDirParts.Length - commonParts; - - var result = new StringBuilder(path.Length + dirsToAscend * 3); - result.Insert(0, "../", dirsToAscend); - result.Append(string.Join("/", pathParts.Skip(commonParts))); - return (dirsToAscend, result); + pathSpec.Append(relativePath); } - - /// - /// Convert this path filter to a pathspec. - /// - /// - /// Repo-relative directory that relative pathspecs should be relative to. - /// Can be empty - which indicates this FilterPath is - /// relative to the root of the repository. - /// - /// String representation of a path filter (a pathspec) - public string ToPathSpec(string repoRelativeBaseDirectory) + else { - Requires.NotNull(repoRelativeBaseDirectory, nameof(repoRelativeBaseDirectory)); - - var pathSpec = new StringBuilder(this.RepoRelativePath.Length + 2); - var (_, normalizedBaseDirectory) = - Normalize(repoRelativeBaseDirectory == "" ? "." : repoRelativeBaseDirectory, null); + pathSpec.Append('/'); + pathSpec.Append(this.RepoRelativePath); + } - if (this.IsExclude) - pathSpec.Append(":!"); + return pathSpec.ToString(); + } - if (this.IsRelative) - { - var (dirsAscended, relativePath) = GetRelativePath(this.RepoRelativePath, normalizedBaseDirectory); - if (dirsAscended == 0 && !this.IsExclude) - pathSpec.Append("./"); - pathSpec.Append(relativePath); - } - else - { - pathSpec.Append('/'); - pathSpec.Append(this.RepoRelativePath); - } + /// + public override string ToString() + { + return this.RepoRelativePath; + } - return pathSpec.ToString(); + /// + /// Normalizes a pathspec-like string into a root-relative path. + /// + /// + /// See for supported + /// formats of pathspecs. + /// + /// + /// Path that is relative to. + /// Can be empty - which indicates is + /// relative to the root of the repository. + /// + /// + /// Forward slash delimited string representing the root-relative path. + /// + private static (bool IsRelative, string Normalized) Normalize(string path, string relativeTo) + { + // Path is absolute, nothing to do here + if (path[0] == '/' || path[0] == '\\') + { + return (false, path.Substring(1)); } - /// - public override string ToString() + string combined = relativeTo == string.Empty ? path : relativeTo + '/' + path; + + return (true, string.Join( + "/", + combined + .Split(new[] { Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar }, StringSplitOptions.RemoveEmptyEntries) + + // Loop through each path segment... + .Aggregate(new Stack(), (parts, segment) => + { + switch (segment) + { + // If it refers to the current directory, skip it + case ".": + return parts; + + // If it refers to the parent directory, pop the most recent directory + case "..": + if (parts.Count == 0) + { + throw new FormatException($"Too many '..' in path '{combined}' - would escape the root of the repository."); + } + + parts.Pop(); + return parts; + + // Otherwise it's a directory/file name - add it to the stack + default: + parts.Push(segment); + return parts; + } + }) + + // Reverse the stack, so it iterates root -> leaf + .Reverse())); + } + + private static (int DirsToAscend, StringBuilder Result) GetRelativePath(string path, string relativeTo) + { + string[] pathParts = path.Split('/'); + string[] baseDirParts = relativeTo.Split(new[] { '/' }, StringSplitOptions.RemoveEmptyEntries); + + int commonParts; + for (commonParts = 0; + commonParts < Math.Min(pathParts.Length, baseDirParts.Length) && + pathParts[commonParts].Equals(baseDirParts[commonParts], StringComparison.OrdinalIgnoreCase); + ++commonParts) { - return this.RepoRelativePath; } + + int dirsToAscend = baseDirParts.Length - commonParts; + + var result = new StringBuilder(path.Length + (dirsToAscend * 3)); + result.Insert(0, "../", dirsToAscend); + result.Append(string.Join("/", pathParts.Skip(commonParts))); + return (dirsToAscend, result); } } diff --git a/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs b/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs index 304c41f0..06ae8e7a 100644 --- a/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs +++ b/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs @@ -1,48 +1,52 @@ -namespace Nerdbank.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using Newtonsoft.Json; + +namespace Nerdbank.GitVersioning; + +internal class FilterPathJsonConverter : JsonConverter { - using System; - using System.Reflection; - using Newtonsoft.Json; + private readonly string repoRelativeBaseDirectory; - internal class FilterPathJsonConverter : JsonConverter + public FilterPathJsonConverter(string repoRelativeBaseDirectory) { - private readonly string repoRelativeBaseDirectory; + this.repoRelativeBaseDirectory = repoRelativeBaseDirectory; + } - public FilterPathJsonConverter(string repoRelativeBaseDirectory) + /// + public override bool CanConvert(Type objectType) => typeof(FilterPath).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (objectType != typeof(FilterPath) || !(reader.Value is string value)) { - this.repoRelativeBaseDirectory = repoRelativeBaseDirectory; + throw new NotSupportedException(); } - public override bool CanConvert(Type objectType) => typeof(FilterPath).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); - - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + if (this.repoRelativeBaseDirectory is null) { - if (objectType != typeof(FilterPath) || !(reader.Value is string value)) - { - throw new NotSupportedException(); - } + throw new ArgumentNullException(nameof(this.repoRelativeBaseDirectory), $"Base directory must not be null to be able to deserialize filter paths. Ensure that one was passed to {nameof(VersionOptions.GetJsonSettings)}, and that the version.json file is being written to a Git repository."); + } - if (this.repoRelativeBaseDirectory is null) - { - throw new ArgumentNullException(nameof(this.repoRelativeBaseDirectory), $"Base directory must not be null to be able to deserialize filter paths. Ensure that one was passed to {nameof(VersionOptions.GetJsonSettings)}, and that the version.json file is being written to a Git repository."); - } + return new FilterPath(value, this.repoRelativeBaseDirectory); + } - return new FilterPath(value, this.repoRelativeBaseDirectory); + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + if (!(value is FilterPath filterPath)) + { + throw new NotSupportedException(); } - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + if (this.repoRelativeBaseDirectory is null) { - if (!(value is FilterPath filterPath)) - { - throw new NotSupportedException(); - } - - if (this.repoRelativeBaseDirectory is null) - { - throw new ArgumentNullException(nameof(this.repoRelativeBaseDirectory), $"Base directory must not be null to be able to serialize filter paths. Ensure that one was passed to {nameof(VersionOptions.GetJsonSettings)}, and that the version.json file is being written to a Git repository."); - } - - writer.WriteValue(filterPath.ToPathSpec(this.repoRelativeBaseDirectory)); + throw new ArgumentNullException(nameof(this.repoRelativeBaseDirectory), $"Base directory must not be null to be able to serialize filter paths. Ensure that one was passed to {nameof(VersionOptions.GetJsonSettings)}, and that the version.json file is being written to a Git repository."); } + + writer.WriteValue(filterPath.ToPathSpec(this.repoRelativeBaseDirectory)); } } diff --git a/src/NerdBank.GitVersioning/GitContext.cs b/src/NerdBank.GitVersioning/GitContext.cs index b11b7e5d..73df0026 100644 --- a/src/NerdBank.GitVersioning/GitContext.cs +++ b/src/NerdBank.GitVersioning/GitContext.cs @@ -1,313 +1,311 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; using Validation; -namespace Nerdbank.GitVersioning +namespace Nerdbank.GitVersioning; + +/// +/// Represents a location and commit within a git repo and provides access to some version-related git activities. +/// +public abstract class GitContext : IDisposable { /// - /// Represents a location and commit within a git repo and provides access to some version-related git activities. + /// Maximum allowable value for the + /// and components. + /// + private protected const ushort MaximumBuildNumberOrRevisionComponent = 0xfffe; + + /// + /// The 0.0 semver. + /// + private protected static readonly SemanticVersion SemVer0 = SemanticVersion.Parse("0.0"); + + /// + /// The 0.0 version. /// - public abstract class GitContext : IDisposable + private protected static readonly Version Version0 = new Version(0, 0); + + private string repoRelativeProjectDirectory; + + /// Initializes a new instance of the class. + /// The absolute path to the root of the working tree. + /// The path to the .git folder. + protected GitContext(string workingTreePath, string? dotGitPath) { - /// - /// The 0.0 semver. - /// - private protected static readonly SemanticVersion SemVer0 = SemanticVersion.Parse("0.0"); - - /// - /// The 0.0 version. - /// - private protected static readonly Version Version0 = new Version(0, 0); - - /// - /// Maximum allowable value for the - /// and components. - /// - private protected const ushort MaximumBuildNumberOrRevisionComponent = 0xfffe; - - private string repoRelativeProjectDirectory; - - /// Initializes a new instance of the class. - /// The absolute path to the root of the working tree. - /// The path to the .git folder. - protected GitContext(string workingTreePath, string? dotGitPath) - { - this.WorkingTreePath = workingTreePath; - this.repoRelativeProjectDirectory = string.Empty; - this.DotGitPath = dotGitPath; - } + this.WorkingTreePath = workingTreePath; + this.repoRelativeProjectDirectory = string.Empty; + this.DotGitPath = dotGitPath; + } - /// - /// Gets the absolute path to the base directory of the git working tree. - /// - public string WorkingTreePath { get; } + /// + /// Gets the absolute path to the base directory of the git working tree. + /// + public string WorkingTreePath { get; } - /// - /// Gets the path to the directory to read version information from, relative to the . - /// - public string RepoRelativeProjectDirectory + /// + /// Gets or sets the path to the directory to read version information from, relative to the . + /// + public string RepoRelativeProjectDirectory + { + get => this.repoRelativeProjectDirectory; + set { - get => this.repoRelativeProjectDirectory; - set - { - Requires.NotNull(value, nameof(value)); - Requires.Argument(!Path.IsPathRooted(value), nameof(value), "Path must be relative to " + nameof(this.WorkingTreePath) + "."); - this.repoRelativeProjectDirectory = value; - } + Requires.NotNull(value, nameof(value)); + Requires.Argument(!Path.IsPathRooted(value), nameof(value), "Path must be relative to " + nameof(this.WorkingTreePath) + "."); + this.repoRelativeProjectDirectory = value; } + } + + /// + /// Gets the absolute path to the directory to read version information from. + /// + public string AbsoluteProjectDirectory => Path.Combine(this.WorkingTreePath, this.RepoRelativeProjectDirectory); + + /// + /// Gets an instance of that will read version information from the context identified by this instance. + /// + public abstract VersionFile VersionFile { get; } + + /// + /// Gets a value indicating whether a git repository was found at . + /// + public bool IsRepository => this.DotGitPath is object; + + /// + /// Gets the full SHA-1 id of the commit to be read. + /// + public abstract string? GitCommitId { get; } + + /// + /// Gets a value indicating whether refers to the commit at HEAD. + /// + public abstract bool IsHead { get; } + + /// + /// Gets a value indicating whether the repo is a shallow repo. + /// + public bool IsShallow => this.DotGitPath is object && File.Exists(Path.Combine(this.DotGitPath, "shallow")); + + /// + /// Gets the date that the commit identified by was created. + /// + public abstract DateTimeOffset? GitCommitDate { get; } + + /// + /// Gets the canonical name for HEAD's position (e.g. refs/heads/master). + /// + public abstract string? HeadCanonicalName { get; } + + /// + /// Gets the path to the .git folder. + /// + protected string? DotGitPath { get; } - /// - /// Gets the absolute path to the directory to read version information from. - /// - public string AbsoluteProjectDirectory => Path.Combine(this.WorkingTreePath, this.RepoRelativeProjectDirectory); - - /// - /// Gets an instance of that will read version information from the context identified by this instance. - /// - public abstract VersionFile VersionFile { get; } - - /// - /// Gets a value indicating whether a git repository was found at ; - /// - public bool IsRepository => this.DotGitPath is object; - - /// - /// Gets the full SHA-1 id of the commit to be read. - /// - public abstract string? GitCommitId { get; } - - /// - /// Gets a value indicating whether refers to the commit at HEAD. - /// - public abstract bool IsHead { get; } - - /// - /// Gets a value indicating whether the repo is a shallow repo. - /// - public bool IsShallow => this.DotGitPath is object && File.Exists(Path.Combine(this.DotGitPath, "shallow")); - - /// - /// Gets the date that the commit identified by was created. - /// - public abstract DateTimeOffset? GitCommitDate { get; } - - /// - /// Gets the canonical name for HEAD's position (e.g. refs/heads/master) - /// - public abstract string? HeadCanonicalName { get; } - - /// - /// Gets the path to the .git folder. - /// - protected string? DotGitPath { get; } - - /// - public void Dispose() + /// + /// Creates a context for reading/writing version information at a given path and committish. + /// + /// The path to a directory for which version information is required. + /// The SHA-1 or ref for a git commit. + /// if mutating the git repository may be required; otherwise. + /// The newly created . + public static GitContext Create(string path, string? committish = null, bool writable = false) + { + Requires.NotNull(path, nameof(path)); + + if (TryFindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath)) { - this.Dispose(true); - GC.SuppressFinalize(this); + GitContext result = writable + ? new LibGit2.LibGit2Context(workingTreeDirectory, gitDirectory, committish) + : new Managed.ManagedGitContext(workingTreeDirectory, gitDirectory, committish); + result.RepoRelativeProjectDirectory = workingTreeRelativePath; + return result; } - - /// - /// Creates a context for reading/writing version information at a given path and committish. - /// - /// The path to a directory for which version information is required. - /// The SHA-1 or ref for a git commit. - /// if mutating the git repository may be required; otherwise. - /// - public static GitContext Create(string path, string? committish = null, bool writable = false) + else { - Requires.NotNull(path, nameof(path)); - - if (TryFindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath)) + // Consider the working tree to be the entire volume. + string workingTree = path; + string? candidate; + while ((candidate = Path.GetDirectoryName(workingTree)) is object) { - GitContext result = writable - ? (GitContext)new LibGit2.LibGit2Context(workingTreeDirectory, gitDirectory, committish) - : new Managed.ManagedGitContext(workingTreeDirectory, gitDirectory, committish); - result.RepoRelativeProjectDirectory = workingTreeRelativePath; - return result; + workingTree = candidate; } - else - { - // Consider the working tree to be the entire volume. - string workingTree = path; - string? candidate; - while ((candidate = Path.GetDirectoryName(workingTree)) is object) - { - workingTree = candidate; - } - return new NoGitContext(workingTree) - { - RepoRelativeProjectDirectory = path.Substring(workingTree.Length), - }; - } + return new NoGitContext(workingTree) + { + RepoRelativeProjectDirectory = path.Substring(workingTree.Length), + }; } + } - /// - /// Sets the context to represent a particular git commit. - /// - /// Any committish string (e.g. commit id, branch, tag). - /// if the string was successfully parsed into a commit; otherwise. - public abstract bool TrySelectCommit(string committish); - - /// - /// Adds a tag with the given name to the commit identified by . - /// - /// The name of the tag. - /// May be thrown if the context was created without specifying write access was required. - /// Thrown if is . - public abstract void ApplyTag(string name); - - /// - /// Adds the specified path to the stage for the working tree. - /// - /// The path to be staged. - /// May be thrown if the context was created without specifying write access was required. - public abstract void Stage(string path); - - /// - /// Gets the shortest string that uniquely identifies the . - /// - /// A minimum length. - /// A string that is at least in length but may be more as required to uniquely identify the git object identified by . - public abstract string GetShortUniqueCommitId(int minLength); - - internal abstract int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion); - - internal abstract Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight); - - internal string GetRepoRelativePath(string absolutePath) - { - var repoRoot = this.WorkingTreePath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } - if (!absolutePath.StartsWith(repoRoot, StringComparison.OrdinalIgnoreCase)) - { - throw new ArgumentException($"Path '{absolutePath}' is not within repository '{repoRoot}'", nameof(absolutePath)); - } + /// + /// Sets the context to represent a particular git commit. + /// + /// Any committish string (e.g. commit id, branch, tag). + /// if the string was successfully parsed into a commit; otherwise. + public abstract bool TrySelectCommit(string committish); - return absolutePath.Substring(repoRoot.Length) - .TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - } + /// + /// Adds a tag with the given name to the commit identified by . + /// + /// The name of the tag. + /// May be thrown if the context was created without specifying write access was required. + /// Thrown if is . + public abstract void ApplyTag(string name); - /// - /// Gets a value indicating whether the version file has changed in the working tree. - /// - /// - /// The commited . - /// - /// - /// The working version of . - /// - /// if the version file is dirty; otherwise. - protected static bool IsVersionFileChangedInWorkingTree(VersionOptions? committedVersion, VersionOptions? workingVersion) - { - if (workingVersion is object) - { - return !EqualityComparer.Default.Equals(workingVersion, committedVersion); - } + /// + /// Adds the specified path to the stage for the working tree. + /// + /// The path to be staged. + /// May be thrown if the context was created without specifying write access was required. + public abstract void Stage(string path); - // A missing working version is a change only if it was previously committed. - return committedVersion is object; + /// + /// Gets the shortest string that uniquely identifies the . + /// + /// A minimum length. + /// A string that is at least in length but may be more as required to uniquely identify the git object identified by . + public abstract string GetShortUniqueCommitId(int minLength); + + internal static bool TryFindGitPaths(string? path, [NotNullWhen(true)] out string? gitDirectory, [NotNullWhen(true)] out string? workingTreeDirectory, [NotNullWhen(true)] out string? workingTreeRelativePath) + { + if (path is null || path.Length == 0) + { + gitDirectory = null; + workingTreeDirectory = null; + workingTreeRelativePath = null; + return false; } - internal static bool TryFindGitPaths(string? path, [NotNullWhen(true)] out string? gitDirectory, [NotNullWhen(true)] out string? workingTreeDirectory, [NotNullWhen(true)] out string? workingTreeRelativePath) + path = Path.GetFullPath(path); + (string GitDirectory, string WorkingTreeDirectory)? gitDirs = FindGitDir(path); + if (gitDirs is null) { - if (path is null || path.Length == 0) - { - gitDirectory = null; - workingTreeDirectory = null; - workingTreeRelativePath = null; - return false; - } + gitDirectory = null; + workingTreeDirectory = null; + workingTreeRelativePath = null; + return false; + } - path = Path.GetFullPath(path); - var gitDirs = FindGitDir(path); - if (gitDirs is null) - { - gitDirectory = null; - workingTreeDirectory = null; - workingTreeRelativePath = null; - return false; - } + gitDirectory = gitDirs.Value.GitDirectory; + workingTreeDirectory = gitDirs.Value.WorkingTreeDirectory; + workingTreeRelativePath = path.Substring(gitDirs.Value.WorkingTreeDirectory.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + return true; + } + + internal abstract int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion); - gitDirectory = gitDirs.Value.GitDirectory; - workingTreeDirectory = gitDirs.Value.WorkingTreeDirectory; - workingTreeRelativePath = path.Substring(gitDirs.Value.WorkingTreeDirectory.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); - return true; + internal abstract Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight); + + internal string GetRepoRelativePath(string absolutePath) + { + string? repoRoot = this.WorkingTreePath.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + + if (!absolutePath.StartsWith(repoRoot, StringComparison.OrdinalIgnoreCase)) + { + throw new ArgumentException($"Path '{absolutePath}' is not within repository '{repoRoot}'", nameof(absolutePath)); } - private protected static void FindGitPaths(string path, out string gitDirectory, out string workingTreeDirectory, out string workingTreeRelativePath) + return absolutePath.Substring(repoRoot.Length) + .TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + } + + /// + /// Gets a value indicating whether the version file has changed in the working tree. + /// + /// + /// The commited . + /// + /// + /// The working version of . + /// + /// if the version file is dirty; otherwise. + protected static bool IsVersionFileChangedInWorkingTree(VersionOptions? committedVersion, VersionOptions? workingVersion) + { + if (workingVersion is object) { - if (TryFindGitPaths(path, out string? gitDirectoryLocal, out string? workingTreeDirectoryLocal, out string? workingTreeRelativePathLocal)) - { - gitDirectory = gitDirectoryLocal; - workingTreeDirectory = workingTreeDirectoryLocal; - workingTreeRelativePath = workingTreeRelativePathLocal; - } - else - { - throw new ArgumentException("Path is not within a git directory.", nameof(path)); - } + return !EqualityComparer.Default.Equals(workingVersion, committedVersion); } - /// - /// Disposes of native and managed resources associated by this object. - /// - /// to dispose managed and native resources; to only dispose of native resources. - protected virtual void Dispose(bool disposing) + // A missing working version is a change only if it was previously committed. + return committedVersion is object; + } + + /// + /// Disposes of native and managed resources associated by this object. + /// + /// to dispose managed and native resources; to only dispose of native resources. + protected virtual void Dispose(bool disposing) + { + } + + private protected static void FindGitPaths(string path, out string gitDirectory, out string workingTreeDirectory, out string workingTreeRelativePath) + { + if (TryFindGitPaths(path, out string? gitDirectoryLocal, out string? workingTreeDirectoryLocal, out string? workingTreeRelativePathLocal)) + { + gitDirectory = gitDirectoryLocal; + workingTreeDirectory = workingTreeDirectoryLocal; + workingTreeRelativePath = workingTreeRelativePathLocal; + } + else { + throw new ArgumentException("Path is not within a git directory.", nameof(path)); } + } - /// - /// Searches a path and its ancestors for a directory with a .git subdirectory. - /// - /// The absolute path to start the search from. - /// The path to the .git folder and working tree, or if not found. - private static (string GitDirectory, string WorkingTreeDirectory)? FindGitDir(string path) + /// + /// Searches a path and its ancestors for a directory with a .git subdirectory. + /// + /// The absolute path to start the search from. + /// The path to the .git folder and working tree, or if not found. + private static (string GitDirectory, string WorkingTreeDirectory)? FindGitDir(string path) + { + string? startingDir = path; + while (startingDir is object) { - string? startingDir = path; - while (startingDir is object) + string? dirOrFilePath = Path.Combine(startingDir, ".git"); + if (Directory.Exists(dirOrFilePath)) { - var dirOrFilePath = Path.Combine(startingDir, ".git"); - if (Directory.Exists(dirOrFilePath)) - { - return (dirOrFilePath, Path.GetDirectoryName(dirOrFilePath)!); - } - else if (File.Exists(dirOrFilePath)) + return (dirOrFilePath, Path.GetDirectoryName(dirOrFilePath)!); + } + else if (File.Exists(dirOrFilePath)) + { + string? relativeGitDirPath = ReadGitDirFromFile(dirOrFilePath); + if (!string.IsNullOrWhiteSpace(relativeGitDirPath)) { - string? relativeGitDirPath = ReadGitDirFromFile(dirOrFilePath); - if (!string.IsNullOrWhiteSpace(relativeGitDirPath)) + string? fullGitDirPath = Path.GetFullPath(Path.Combine(startingDir, relativeGitDirPath)); + if (Directory.Exists(fullGitDirPath)) { - var fullGitDirPath = Path.GetFullPath(Path.Combine(startingDir, relativeGitDirPath)); - if (Directory.Exists(fullGitDirPath)) - { - return (fullGitDirPath, Path.GetDirectoryName(dirOrFilePath)!); - } + return (fullGitDirPath, Path.GetDirectoryName(dirOrFilePath)!); } } - - startingDir = Path.GetDirectoryName(startingDir); } - return null; + startingDir = Path.GetDirectoryName(startingDir); } - private static string? ReadGitDirFromFile(string fileName) - { - const string expectedPrefix = "gitdir: "; - var firstLineOfFile = File.ReadLines(fileName).FirstOrDefault(); - if (firstLineOfFile?.StartsWith(expectedPrefix) ?? false) - { - return firstLineOfFile.Substring(expectedPrefix.Length); // strip off the prefix, leaving just the path - } + return null; + } - return null; + private static string? ReadGitDirFromFile(string fileName) + { + const string expectedPrefix = "gitdir: "; + string? firstLineOfFile = File.ReadLines(fileName).FirstOrDefault(); + if (firstLineOfFile?.StartsWith(expectedPrefix) ?? false) + { + return firstLineOfFile.Substring(expectedPrefix.Length); // strip off the prefix, leaving just the path } + + return null; } } diff --git a/src/NerdBank.GitVersioning/GitException.cs b/src/NerdBank.GitVersioning/GitException.cs index 72802b6e..2a37dc93 100644 --- a/src/NerdBank.GitVersioning/GitException.cs +++ b/src/NerdBank.GitVersioning/GitException.cs @@ -1,89 +1,91 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Runtime.Serialization; -namespace Nerdbank.GitVersioning +namespace Nerdbank.GitVersioning; + +/// +/// The exception which is thrown by the managed Git layer. +/// +[Serializable] +public class GitException : Exception { /// - /// The exception which is thrown by the managed Git layer. + /// Initializes a new instance of the class. /// - [Serializable] - public class GitException : Exception + public GitException() { - /// - /// Initializes a new instance of the class. - /// - public GitException() - { - } + } - /// - /// Initializes a new instance of the class. - /// - /// - public GitException(string message) - : base(message) - { - } + /// + /// Initializes a new instance of the class. + /// + /// + public GitException(string message) + : base(message) + { + } - /// - /// Initializes a new instance of the with an - /// error message and an inner message. - /// - /// - /// A message which describes the error. - /// - /// - /// The which caused this exception to be thrown. - /// - public GitException(string message, Exception innerException) - : base(message, innerException) - { - } + /// + /// Initializes a new instance of the class + /// with an error message and an inner message. + /// + /// + /// A message which describes the error. + /// + /// + /// The which caused this exception to be thrown. + /// + public GitException(string message, Exception innerException) + : base(message, innerException) + { + } - /// - /// Initializes a new instance of the class. - /// - protected GitException(SerializationInfo info, StreamingContext context) - : base(info, context) - { - this.ErrorCode = (ErrorCodes)info.GetUInt32(nameof(this.ErrorCode)); - this.iSShallowClone = info.GetBoolean(nameof(this.iSShallowClone)); - } + /// + /// Initializes a new instance of the class. + /// + /// + protected GitException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + this.ErrorCode = (ErrorCodes)info.GetUInt32(nameof(this.ErrorCode)); + this.IsShallowClone = info.GetBoolean(nameof(this.IsShallowClone)); + } + /// + /// Describes specific error conditions that may warrant branching code paths. + /// + public enum ErrorCodes + { /// - /// Gets the error code for this exception. + /// No error code was specified. /// - public ErrorCodes ErrorCode { get; set; } + Unspecified = 0, /// - /// Gets a value indicating whether the exception was thrown from a shallow clone. + /// An object could not be found. /// - public bool iSShallowClone { get; set; } + ObjectNotFound, + } - /// - public override void GetObjectData(SerializationInfo info, StreamingContext context) - { - base.GetObjectData(info, context); - info.AddValue(nameof(this.ErrorCode), (int)this.ErrorCode); - info.AddValue(nameof(this.iSShallowClone), this.iSShallowClone); - } + /// + /// Gets or sets the error code for this exception. + /// + public ErrorCodes ErrorCode { get; set; } - /// - /// Describes specific error conditions that may warrant branching code paths. - /// - public enum ErrorCodes - { - /// - /// No error code was specified. - /// - Unspecified = 0, + /// + /// Gets or sets a value indicating whether the exception was thrown from a shallow clone. + /// + public bool IsShallowClone { get; set; } - /// - /// An object could not be found. - /// - ObjectNotFound, - } + /// + public override void GetObjectData(SerializationInfo info, StreamingContext context) + { + base.GetObjectData(info, context); + info.AddValue(nameof(this.ErrorCode), (int)this.ErrorCode); + info.AddValue(nameof(this.IsShallowClone), this.IsShallowClone); } } diff --git a/src/NerdBank.GitVersioning/ICloudBuild.cs b/src/NerdBank.GitVersioning/ICloudBuild.cs index df8a69fa..15b76e42 100644 --- a/src/NerdBank.GitVersioning/ICloudBuild.cs +++ b/src/NerdBank.GitVersioning/ICloudBuild.cs @@ -1,57 +1,56 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning +#nullable enable + +namespace Nerdbank.GitVersioning; + +/// +/// Defines cloud build provider functionality. +/// +public interface ICloudBuild { - using System.Collections.Generic; - using System.IO; + /// + /// Gets a value indicating whether the active cloud build matches what this instance supports. + /// + bool IsApplicable { get; } + + /// + /// Gets a value indicating whether a cloud build is validating a pull request. + /// + bool IsPullRequest { get; } + + /// + /// Gets the branch being built by a cloud build, if applicable. + /// + string? BuildingBranch { get; } + + /// + /// Gets the tag being built by a cloud build, if applicable. + /// + string? BuildingTag { get; } + + /// + /// Gets the git commit ID being built by a cloud build, if applicable. + /// + string? GitCommitId { get; } + + /// + /// Sets the build number for the cloud build, if supported. + /// + /// The build number to set. + /// An optional redirection for what should be written to the standard out stream. + /// An optional redirection for what should be written to the standard error stream. + /// A dictionary of environment/build variables that the caller should set to update the environment to match the new settings. + IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter? stdout, TextWriter? stderr); /// - /// Defines cloud build provider functionality. + /// Sets a cloud build variable, if supported. /// - public interface ICloudBuild - { - /// - /// Gets a value indicating whether the active cloud build matches what this instance supports. - /// - bool IsApplicable { get; } - - /// - /// Gets a value indicating whether a cloud build is validating a pull request. - /// - bool IsPullRequest { get; } - - /// - /// Gets the branch being built by a cloud build, if applicable. - /// - string? BuildingBranch { get; } - - /// - /// Gets the tag being built by a cloud build, if applicable. - /// - string? BuildingTag { get; } - - /// - /// Gets the git commit ID being built by a cloud build, if applicable. - /// - string? GitCommitId { get; } - - /// - /// Sets the build number for the cloud build, if supported. - /// - /// The build number to set. - /// An optional redirection for what should be written to the standard out stream. - /// An optional redirection for what should be written to the standard error stream. - /// A dictionary of environment/build variables that the caller should set to update the environment to match the new settings. - IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter? stdout, TextWriter? stderr); - - /// - /// Sets a cloud build variable, if supported. - /// - /// The name of the variable. - /// The value for the variable. - /// An optional redirection for what should be written to the standard out stream. - /// An optional redirection for what should be written to the standard error stream. - /// A dictionary of environment/build variables that the caller should set to update the environment to match the new settings. - IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter? stdout, TextWriter? stderr); - } + /// The name of the variable. + /// The value for the variable. + /// An optional redirection for what should be written to the standard out stream. + /// An optional redirection for what should be written to the standard error stream. + /// A dictionary of environment/build variables that the caller should set to update the environment to match the new settings. + IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter? stdout, TextWriter? stderr); } diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs index 65cd8bba..583d4cd1 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs @@ -1,177 +1,179 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Diagnostics; using LibGit2Sharp; -using Validation; -namespace Nerdbank.GitVersioning.LibGit2 +namespace Nerdbank.GitVersioning.LibGit2; + +/// +/// A git context implemented in terms of LibGit2Sharp. +/// +[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] +public class LibGit2Context : GitContext { - /// - /// A git context implemented in terms of LibGit2Sharp. - /// - [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] - public class LibGit2Context : GitContext + internal LibGit2Context(string workingTreeDirectory, string dotGitPath, string? committish = null) + : base(workingTreeDirectory, dotGitPath) { - internal LibGit2Context(string workingTreeDirectory, string dotGitPath, string? committish = null) - : base(workingTreeDirectory, dotGitPath) + this.Repository = OpenGitRepo(workingTreeDirectory, useDefaultConfigSearchPaths: true); + if (this.Repository.Info.WorkingDirectory is null) { - this.Repository = OpenGitRepo(workingTreeDirectory, useDefaultConfigSearchPaths: true); - if (this.Repository.Info.WorkingDirectory is null) - { - throw new ArgumentException("Bare repositories not supported.", nameof(workingTreeDirectory)); - } - - this.Commit = committish is null ? this.Repository.Head.Tip : this.Repository.Lookup(committish); - if (this.Commit is null && committish is object) - { - throw new ArgumentException("No matching commit found.", nameof(committish)); - } + throw new ArgumentException("Bare repositories not supported.", nameof(workingTreeDirectory)); + } - this.VersionFile = new LibGit2VersionFile(this); + this.Commit = committish is null ? this.Repository.Head.Tip : this.Repository.Lookup(committish); + if (this.Commit is null && committish is object) + { + throw new ArgumentException("No matching commit found.", nameof(committish)); } - /// - public override VersionFile VersionFile { get; } + this.VersionFile = new LibGit2VersionFile(this); + } - /// - public Repository Repository { get; } + /// + public override VersionFile VersionFile { get; } - /// - public Commit? Commit { get; private set; } + public Repository Repository { get; } - /// - public override string? GitCommitId => this.Commit?.Sha; + public Commit? Commit { get; private set; } - /// - public override bool IsHead => this.Repository.Head?.Tip?.Equals(this.Commit) ?? false; + /// + public override string? GitCommitId => this.Commit?.Sha; - /// - public override DateTimeOffset? GitCommitDate => this.Commit?.Author.When; + /// + public override bool IsHead => this.Repository.Head?.Tip?.Equals(this.Commit) ?? false; - /// - public override string HeadCanonicalName => this.Repository.Head.CanonicalName; + /// + public override DateTimeOffset? GitCommitDate => this.Commit?.Author.When; - private string DebuggerDisplay => $"\"{this.WorkingTreePath}\" (libgit2)"; + /// + public override string HeadCanonicalName => this.Repository.Head.CanonicalName; - /// - public override void ApplyTag(string name) => this.Repository.Tags.Add(name, this.Commit); + private string DebuggerDisplay => $"\"{this.WorkingTreePath}\" (libgit2)"; - /// - public override bool TrySelectCommit(string committish) + /// Initializes a new instance of the class. + /// The path to the .git directory or somewhere in a git working tree. + /// The SHA-1 or ref for a git commit. + /// The new instance. + public static LibGit2Context Create(string path, string? committish = null) + { + FindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath); + return new LibGit2Context(workingTreeDirectory, gitDirectory, committish) { - try - { - this.Repository.RevParse(committish, out Reference? reference, out GitObject obj); - if (obj is Commit commit) - { - this.Commit = commit; - return true; - } - } - catch (NotFoundException) - { - } - - return false; - } - - /// - public override void Stage(string path) => global::LibGit2Sharp.Commands.Stage(this.Repository, path); + RepoRelativeProjectDirectory = workingTreeRelativePath, + }; + } - /// - public override string GetShortUniqueCommitId(int minLength) => this.Repository.ObjectDatabase.ShortenObjectId(this.Commit, minLength); + /// + public override void ApplyTag(string name) => this.Repository.Tags.Add(name, this.Commit); - internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) + /// + public override bool TrySelectCommit(string committish) + { + try { - var headCommitVersion = committedVersion?.Version ?? SemVer0; - - if (IsVersionFileChangedInWorkingTree(committedVersion, workingVersion)) + this.Repository.RevParse(committish, out Reference? reference, out GitObject obj); + if (obj is Commit commit) { - var workingCopyVersion = workingVersion?.Version?.Version; - - if (workingCopyVersion is null || !workingCopyVersion.Equals(headCommitVersion)) - { - // The working copy has changed the major.minor version. - // So by definition the version height is 0, since no commit represents it yet. - return 0; - } + this.Commit = commit; + return true; } - - return LibGit2GitExtensions.GetVersionHeight(this); } - - internal override System.Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) + catch (NotFoundException) { - VersionOptions? version = IsVersionFileChangedInWorkingTree(committedVersion, workingVersion) ? workingVersion : committedVersion; - - return this.Commit.GetIdAsVersionHelper(version, versionHeight); } - /// The path to the .git directory or somewhere in a git working tree. - /// The SHA-1 or ref for a git commit. - public static LibGit2Context Create(string path, string? committish = null) + return false; + } + + /// + public override void Stage(string path) => global::LibGit2Sharp.Commands.Stage(this.Repository, path); + + /// + public override string GetShortUniqueCommitId(int minLength) => this.Repository.ObjectDatabase.ShortenObjectId(this.Commit, minLength); + + /// + /// Opens a found at or above a specified path. + /// + /// The path to the .git directory or the working directory. + /// + /// Specifies whether to use default settings for looking up global and system settings. + /// + /// By default ( == false), the repository will be configured to only + /// use the repository-level configuration ignoring system or user-level configuration (set using git config --global. + /// Thus only settings explicitly set for the repo will be available. + /// + /// + /// For example using Repository.Configuration.Get{string}("user.name") to get the user's name will + /// return the value set in the repository config or null if the user name has not been explicitly set for the repository. + /// + /// + /// When the caller specifies to use the default configuration search paths ( == true) + /// both repository level and global configuration will be available to the repo as well. + /// + /// + /// In this mode, using Repository.Configuration.Get{string}("user.name") will return the + /// value set in the user's global git configuration unless set on the repository level, + /// matching the behavior of the git command. + /// + /// + /// The found for the specified path, or null if no git repo is found. + internal static Repository OpenGitRepo(string path, bool useDefaultConfigSearchPaths = false) + { + if (useDefaultConfigSearchPaths) { - FindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath); - return new LibGit2Context(workingTreeDirectory, gitDirectory, committish) - { - RepoRelativeProjectDirectory = workingTreeRelativePath, - }; + // pass null to reset to defaults + GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); + GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, null); } - - /// - protected override void Dispose(bool disposing) + else { - if (disposing) - { - this.Repository.Dispose(); - } - - base.Dispose(disposing); + // Override Config Search paths to empty path to avoid new Repository instance to lookup for Global\System .gitconfig file + GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, string.Empty); + GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, string.Empty); } - /// - /// Opens a found at or above a specified path. - /// - /// The path to the .git directory or the working directory. - /// - /// Specifies whether to use default settings for looking up global and system settings. - /// - /// By default ( == false), the repository will be configured to only - /// use the repository-level configuration ignoring system or user-level configuration (set using git config --global. - /// Thus only settings explicitly set for the repo will be available. - /// - /// - /// For example using Repository.Configuration.Get{string}("user.name") to get the user's name will - /// return the value set in the repository config or null if the user name has not been explicitly set for the repository. - /// - /// - /// When the caller specifies to use the default configuration search paths ( == true) - /// both repository level and global configuration will be available to the repo as well. - /// - /// - /// In this mode, using Repository.Configuration.Get{string}("user.name") will return the - /// value set in the user's global git configuration unless set on the repository level, - /// matching the behavior of the git command. - /// - /// - /// The found for the specified path, or null if no git repo is found. - internal static Repository OpenGitRepo(string path, bool useDefaultConfigSearchPaths = false) + return new Repository(path); + } + + /// + internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) + { + SemanticVersion? headCommitVersion = committedVersion?.Version ?? SemVer0; + + if (IsVersionFileChangedInWorkingTree(committedVersion, workingVersion)) { - if (useDefaultConfigSearchPaths) - { - // pass null to reset to defaults - GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, null); - GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, null); - } - else + System.Version? workingCopyVersion = workingVersion?.Version?.Version; + + if (workingCopyVersion is null || !workingCopyVersion.Equals(headCommitVersion)) { - // Override Config Search paths to empty path to avoid new Repository instance to lookup for Global\System .gitconfig file - GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.Global, string.Empty); - GlobalSettings.SetConfigSearchPaths(ConfigurationLevel.System, string.Empty); + // The working copy has changed the major.minor version. + // So by definition the version height is 0, since no commit represents it yet. + return 0; } + } - return new Repository(path); + return LibGit2GitExtensions.GetVersionHeight(this); + } + + /// + internal override System.Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) + { + VersionOptions? version = IsVersionFileChangedInWorkingTree(committedVersion, workingVersion) ? workingVersion : committedVersion; + + return this.Commit.GetIdAsVersionHelper(version, versionHeight); + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + this.Repository.Dispose(); } + + base.Dispose(disposing); } } diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 76eff1f3..09b2438b 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -1,580 +1,578 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.LibGit2 +using System.Buffers.Binary; +using System.Runtime.InteropServices; +using System.Text; +using LibGit2Sharp; +using Validation; +using Version = System.Version; + +#nullable enable + +namespace Nerdbank.GitVersioning.LibGit2; + +/// +/// Git extension methods. +/// +public static class LibGit2GitExtensions { - using System; - using System.Buffers.Binary; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Runtime.InteropServices; - using System.Text; - using LibGit2Sharp; - using Validation; - using Version = System.Version; + /// + /// Maximum allowable value for the + /// and components. + /// + private const ushort MaximumBuildNumberOrRevisionComponent = 0xfffe; /// - /// Git extension methods. + /// The 0.0 version. /// - public static class LibGit2GitExtensions - { - /// - /// The 0.0 version. - /// - private static readonly Version Version0 = new Version(0, 0); + private static readonly Version Version0 = new Version(0, 0); - /// - /// The 0.0 semver. - /// - private static readonly SemanticVersion SemVer0 = SemanticVersion.Parse("0.0"); + /// + /// The 0.0 semver. + /// + private static readonly SemanticVersion SemVer0 = SemanticVersion.Parse("0.0"); - private static readonly LibGit2Sharp.CompareOptions DiffOptions = new LibGit2Sharp.CompareOptions() - { - // When calculating the height of a commit, we do not care if a file has been renamed only if it has been added or removed. - // Calculating similarities can consume significant amounts of CPU, so disable it. - Similarity = SimilarityOptions.None, - ContextLines = 0 - }; - - /// - /// Maximum allowable value for the - /// and components. - /// - private const ushort MaximumBuildNumberOrRevisionComponent = 0xfffe; - - /// - /// Gets the number of commits in the longest single path between - /// the specified commit and the most distant ancestor (inclusive) - /// that set the version to the value at . - /// - /// The git context to read from. - /// Optional base version to calculate the height. If not specified, the base version will be calculated by scanning the repository. - /// The height of the commit. Always a positive integer. - internal static int GetVersionHeight(LibGit2Context context, Version? baseVersion = null) - { - if (context.Commit is null) - { - return 0; - } + private static readonly LibGit2Sharp.CompareOptions DiffOptions = new LibGit2Sharp.CompareOptions() + { + // When calculating the height of a commit, we do not care if a file has been renamed only if it has been added or removed. + // Calculating similarities can consume significant amounts of CPU, so disable it. + Similarity = SimilarityOptions.None, + ContextLines = 0, + }; - var tracker = new GitWalkTracker(context); + /// + /// Gets the number of commits in the longest single path between + /// the specified commit and the most distant ancestor (inclusive). + /// + /// The git context to read from. + /// + /// A function that returns false when we reach a commit that + /// should not be included in the height calculation. + /// May be null to count the height to the original commit. + /// + /// The height of the commit. Always a positive integer. + public static int GetHeight(LibGit2Context context, Func? continueStepping = null) + { + Verify.Operation(context.Commit is object, "No commit is selected."); + var tracker = new GitWalkTracker(context); + return GetCommitHeight(context.Commit, tracker, continueStepping); + } - var versionOptions = tracker.GetVersion(context.Commit); - if (versionOptions is null) - { - return 0; - } + /// + /// Takes the first 2 bytes of a commit ID (i.e. first 4 characters of its hex-encoded SHA) + /// and returns them as an 16-bit unsigned integer. + /// + /// The commit to identify with an integer. + /// The unsigned integer which identifies a commit. + public static ushort GetTruncatedCommitIdAsUInt16(this Commit commit) + { + Requires.NotNull(commit, nameof(commit)); + return BinaryPrimitives.ReadUInt16BigEndian(commit.Id.RawId); + } - var baseSemVer = - baseVersion is not null ? SemanticVersion.Parse(baseVersion.ToString()) : - versionOptions.Version ?? SemVer0; + /// + /// Looks up the commit that matches a specified version number. + /// + /// The git context to read from. + /// The version previously obtained from . + /// The matching commit, or null if no match is found. + /// + /// Thrown in the very rare situation that more than one matching commit is found. + /// + public static Commit GetCommitFromVersion(LibGit2Context context, Version version) + { + // Note we'll accept no match, or one match. But we throw if there is more than one match. + return GetCommitsFromVersion(context, version).SingleOrDefault(); + } - var versionHeightPosition = versionOptions.VersionHeightPosition; - if (versionHeightPosition.HasValue) - { - int height = GetHeight(context, c => CommitMatchesVersion(c, baseSemVer, versionHeightPosition.Value, tracker)); - return height; - } + /// + /// Looks up the commits that match a specified version number. + /// + /// The git context to read from. + /// The version previously obtained from . + /// The matching commits, or an empty enumeration if no match is found. + public static IEnumerable GetCommitsFromVersion(LibGit2Context context, Version version) + { + Requires.NotNull(context, nameof(context)); + Requires.NotNull(version, nameof(version)); + + var tracker = new GitWalkTracker(context); + IEnumerable? possibleCommits = from commit in GetCommitsReachableFromRefs(context.Repository) + let commitVersionOptions = tracker.GetVersion(commit) + where commitVersionOptions?.Version?.IsMatchingVersion(version) is true + where !IsCommitIdMismatch(version, commitVersionOptions, commit) + where !IsVersionHeightMismatch(version, commitVersionOptions, commit, tracker) + select commit; + + return possibleCommits; + } - return 0; + /// + /// Finds the directory that contains the appropriate native libgit2 module. + /// + /// The path to the directory that contains the lib folder. + /// Receives the directory that native binaries are expected. + public static string? FindLibGit2NativeBinaries(string basePath) + { + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + return Path.Combine(basePath, "lib", "win32", IntPtr.Size == 4 ? "x86" : "x64"); } - - /// - /// Gets the number of commits in the longest single path between - /// the specified commit and the most distant ancestor (inclusive). - /// - /// The git context to read from. - /// - /// A function that returns false when we reach a commit that - /// should not be included in the height calculation. - /// May be null to count the height to the original commit. - /// - /// The height of the commit. Always a positive integer. - public static int GetHeight(LibGit2Context context, Func? continueStepping = null) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { - Verify.Operation(context.Commit is object, "No commit is selected."); - var tracker = new GitWalkTracker(context); - return GetCommitHeight(context.Commit, tracker, continueStepping); + return Path.Combine(basePath, "lib", "linux", IntPtr.Size == 4 ? "x86" : "x86_64"); } - - /// - /// Takes the first 2 bytes of a commit ID (i.e. first 4 characters of its hex-encoded SHA) - /// and returns them as an 16-bit unsigned integer. - /// - /// The commit to identify with an integer. - /// The unsigned integer which identifies a commit. - public static ushort GetTruncatedCommitIdAsUInt16(this Commit commit) + else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) { - Requires.NotNull(commit, nameof(commit)); - return BinaryPrimitives.ReadUInt16BigEndian(commit.Id.RawId); + return Path.Combine(basePath, "lib", "osx", RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm_64" : "x86_64"); } - /// - /// Returns the repository that belongs to. - /// - /// Member of the repository. - /// Repository that belongs to. - private static IRepository GetRepository(this IBelongToARepository repositoryMember) + return null; + } + + /// + /// Gets the number of commits in the longest single path between + /// the specified commit and the most distant ancestor (inclusive) + /// that set the version to the value at . + /// + /// The git context to read from. + /// Optional base version to calculate the height. If not specified, the base version will be calculated by scanning the repository. + /// The height of the commit. Always a positive integer. + internal static int GetVersionHeight(LibGit2Context context, Version? baseVersion = null) + { + if (context.Commit is null) { - return repositoryMember.Repository; + return 0; } - /// - /// Looks up the commit that matches a specified version number. - /// - /// The git context to read from. - /// The version previously obtained from . - /// The matching commit, or null if no match is found. - /// - /// Thrown in the very rare situation that more than one matching commit is found. - /// - public static Commit GetCommitFromVersion(LibGit2Context context, Version version) + var tracker = new GitWalkTracker(context); + + VersionOptions? versionOptions = tracker.GetVersion(context.Commit); + if (versionOptions is null) { - // Note we'll accept no match, or one match. But we throw if there is more than one match. - return GetCommitsFromVersion(context, version).SingleOrDefault(); + return 0; } - /// - /// Looks up the commits that match a specified version number. - /// - /// The git context to read from. - /// The version previously obtained from . - /// The matching commits, or an empty enumeration if no match is found. - public static IEnumerable GetCommitsFromVersion(LibGit2Context context, Version version) + SemanticVersion? baseSemVer = + baseVersion is not null ? SemanticVersion.Parse(baseVersion.ToString()) : + versionOptions.Version ?? SemVer0; + + SemanticVersion.Position? versionHeightPosition = versionOptions.VersionHeightPosition; + if (versionHeightPosition.HasValue) { - Requires.NotNull(context, nameof(context)); - Requires.NotNull(version, nameof(version)); - - var tracker = new GitWalkTracker(context); - var possibleCommits = from commit in GetCommitsReachableFromRefs(context.Repository) - let commitVersionOptions = tracker.GetVersion(commit) - where commitVersionOptions?.Version?.IsMatchingVersion(version) is true - where !IsCommitIdMismatch(version, commitVersionOptions, commit) - where !IsVersionHeightMismatch(version, commitVersionOptions, commit, tracker) - select commit; - - return possibleCommits; + int height = GetHeight(context, c => CommitMatchesVersion(c, baseSemVer, versionHeightPosition.Value, tracker)); + return height; } - /// - /// Finds the directory that contains the appropriate native libgit2 module. - /// - /// The path to the directory that contains the lib folder. - /// Receives the directory that native binaries are expected. - public static string? FindLibGit2NativeBinaries(string basePath) + return 0; + } + + /// + /// Encodes a commit from history in a + /// so that the original commit can be found later. + /// + /// The commit whose ID and position in history is to be encoded. + /// The version options applicable at this point (either from commit or working copy). + /// The version height, previously calculated by a call to . + /// + /// A version whose and + /// components are calculated based on the commit. + /// + /// + /// In the returned version, the component is + /// the height of the git commit while the + /// component is the first four bytes of the git commit id (forced to be a positive integer). + /// + internal static Version GetIdAsVersionHelper(this Commit? commit, VersionOptions? versionOptions, int versionHeight) + { + Version? baseVersion = versionOptions?.Version?.Version ?? Version0; + int buildNumber = baseVersion.Build; + int revision = baseVersion.Revision; + + // Don't use the ?? coalescing operator here because the position property getters themselves can return null, which should NOT be overridden with our default. + // The default value is only appropriate if versionOptions itself is null. + SemanticVersion.Position? versionHeightPosition = versionOptions is not null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; + SemanticVersion.Position? commitIdPosition = versionOptions is not null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; + + // The compiler (due to WinPE header requirements) only allows 16-bit version components, + // and forbids 0xffff as a value. + if (versionHeightPosition.HasValue) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return Path.Combine(basePath, "lib", "win32", IntPtr.Size == 4 ? "x86" : "x64"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + int adjustedVersionHeight = versionHeight == 0 ? 0 : versionHeight + (versionOptions?.VersionHeightOffset ?? 0); + Verify.Operation(adjustedVersionHeight <= MaximumBuildNumberOrRevisionComponent, "Git height is {0}, which is greater than the maximum allowed {0}.", adjustedVersionHeight, MaximumBuildNumberOrRevisionComponent); + switch (versionHeightPosition.Value) { - return Path.Combine(basePath, "lib", "linux", IntPtr.Size == 4 ? "x86" : "x86_64"); + case SemanticVersion.Position.Build: + buildNumber = adjustedVersionHeight; + break; + case SemanticVersion.Position.Revision: + revision = adjustedVersionHeight; + break; } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) - { - return Path.Combine(basePath, "lib", "osx", RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm_64" : "x86_64"); - } - - return null; } - /// - /// Tests whether a commit is of a specified version, comparing major and minor components - /// with the version.txt file defined by that commit. - /// - /// The commit to test. - /// The version to test for in the commit - /// The last component of the version to include in the comparison. - /// The caching tracker for storing or fetching version information per commit. - /// true if the matches the major and minor components of . - private static bool CommitMatchesVersion(this Commit commit, SemanticVersion expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) + if (commitIdPosition.HasValue) { - Requires.NotNull(commit, nameof(commit)); - Requires.NotNull(expectedVersion, nameof(expectedVersion)); - - var commitVersionData = tracker.GetVersion(commit); - var semVerFromFile = commitVersionData?.Version; - if (semVerFromFile is null) - { - return false; - } - - // If the version height position moved, that's an automatic reset in version height. - if (commitVersionData!.VersionHeightPosition != comparisonPrecision) + switch (commitIdPosition.Value) { - return false; + case SemanticVersion.Position.Revision: + revision = commit is object + ? Math.Min(MaximumBuildNumberOrRevisionComponent, commit.GetTruncatedCommitIdAsUInt16()) + : 0; + break; } - - return !SemanticVersion.WillVersionChangeResetVersionHeight(commitVersionData.Version, expectedVersion, comparisonPrecision); } - /// - /// Tests whether a commit's version-spec matches a given version-spec. - /// - /// The commit to test. - /// The version to test for in the commit - /// The last component of the version to include in the comparison. - /// The caching tracker for storing or fetching version information per commit. - /// true if the matches the major and minor components of . - private static bool CommitMatchesVersion(this Commit commit, Version expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) - { - Requires.NotNull(commit, nameof(commit)); - Requires.NotNull(expectedVersion, nameof(expectedVersion)); + return VersionExtensions.Create(baseVersion.Major, baseVersion.Minor, buildNumber, revision); + } - var commitVersionData = tracker.GetVersion(commit); - var semVerFromFile = commitVersionData?.Version; - if (semVerFromFile is null) - { - return false; - } + /// + /// Returns the repository that belongs to. + /// + /// Member of the repository. + /// Repository that belongs to. + private static IRepository GetRepository(this IBelongToARepository repositoryMember) + { + return repositoryMember.Repository; + } - for (SemanticVersion.Position position = SemanticVersion.Position.Major; position <= comparisonPrecision; position++) - { - int expectedValue = SemanticVersion.ReadVersionPosition(expectedVersion, position); - int actualValue = SemanticVersion.ReadVersionPosition(semVerFromFile.Version, position); - if (expectedValue != actualValue) - { - return false; - } - } + /// + /// Tests whether a commit is of a specified version, comparing major and minor components + /// with the version.txt file defined by that commit. + /// + /// The commit to test. + /// The version to test for in the commit. + /// The last component of the version to include in the comparison. + /// The caching tracker for storing or fetching version information per commit. + /// true if the matches the major and minor components of . + private static bool CommitMatchesVersion(this Commit commit, SemanticVersion expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) + { + Requires.NotNull(commit, nameof(commit)); + Requires.NotNull(expectedVersion, nameof(expectedVersion)); - return true; + VersionOptions? commitVersionData = tracker.GetVersion(commit); + SemanticVersion? semVerFromFile = commitVersionData?.Version; + if (semVerFromFile is null) + { + return false; } - private static bool IsVersionHeightMismatch(Version version, VersionOptions versionOptions, Commit commit, GitWalkTracker tracker) + // If the version height position moved, that's an automatic reset in version height. + if (commitVersionData!.VersionHeightPosition != comparisonPrecision) { - Requires.NotNull(version, nameof(version)); - Requires.NotNull(versionOptions, nameof(versionOptions)); - Requires.NotNull(commit, nameof(commit)); + return false; + } - // The version.Build or version.Revision MAY represent the version height. - var position = versionOptions.VersionHeightPosition; - if (position.HasValue && position.Value <= SemanticVersion.Position.Revision) - { - int expectedVersionHeight = SemanticVersion.ReadVersionPosition(version, position.Value); + return !SemanticVersion.WillVersionChangeResetVersionHeight(commitVersionData.Version, expectedVersion, comparisonPrecision); + } - var actualVersionOffset = versionOptions.VersionHeightOffsetOrDefault; - var actualVersionHeight = GetCommitHeight(commit, tracker, c => CommitMatchesVersion(c, version, position.Value - 1, tracker)); - return expectedVersionHeight != actualVersionHeight + actualVersionOffset; - } + /// + /// Tests whether a commit's version-spec matches a given version-spec. + /// + /// The commit to test. + /// The version to test for in the commit. + /// The last component of the version to include in the comparison. + /// The caching tracker for storing or fetching version information per commit. + /// true if the matches the major and minor components of . + private static bool CommitMatchesVersion(this Commit commit, Version expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) + { + Requires.NotNull(commit, nameof(commit)); + Requires.NotNull(expectedVersion, nameof(expectedVersion)); - // It's not a mismatch, since for this commit, the version height wasn't recorded in the 4-integer version. + VersionOptions? commitVersionData = tracker.GetVersion(commit); + SemanticVersion? semVerFromFile = commitVersionData?.Version; + if (semVerFromFile is null) + { return false; } - private static bool IsCommitIdMismatch(Version version, VersionOptions versionOptions, Commit commit) + for (SemanticVersion.Position position = SemanticVersion.Position.Major; position <= comparisonPrecision; position++) { - Requires.NotNull(version, nameof(version)); - Requires.NotNull(versionOptions, nameof(versionOptions)); - Requires.NotNull(commit, nameof(commit)); - - // The version.Revision MAY represent the first 2 bytes of the git commit ID, but not if 3 integers were specified in version.json, - // since in that case the 4th integer is the version height. But we won't know till we read the version.json file, so for now, - var position = versionOptions.GitCommitIdPosition; - if (position.HasValue && position.Value <= SemanticVersion.Position.Revision) + int expectedValue = SemanticVersion.ReadVersionPosition(expectedVersion, position); + int actualValue = SemanticVersion.ReadVersionPosition(semVerFromFile.Version, position); + if (expectedValue != actualValue) { - // prepare for it to be the commit ID. - // The revision is a 16-bit unsigned integer, but is not allowed to be 0xffff. - // So if the value is 0xfffe, consider that the actual last bit is insignificant - // since the original git commit ID could have been either 0xffff or 0xfffe. - var expectedCommitIdLeadingValue = SemanticVersion.ReadVersionPosition(version, position.Value); - if (expectedCommitIdLeadingValue != -1) - { - ushort objectIdLeadingValue = (ushort)expectedCommitIdLeadingValue; - ushort objectIdMask = (ushort)(objectIdLeadingValue == MaximumBuildNumberOrRevisionComponent ? 0xfffe : 0xffff); - - // Accept a big endian match or a little endian match. - // Nerdbank.GitVersioning up to v3.4 would produce versions based on the endianness of the CPU it ran on (typically little endian). - // Starting with v3.5, it deterministically used big endian. In order for `nbgv get-commits` to match on versions computed before and after the change, - // we match on either endian setting. - return !(commit.Id.StartsWith(objectIdLeadingValue, bigEndian: true, objectIdMask) || commit.Id.StartsWith(objectIdLeadingValue, bigEndian: false, objectIdMask)); - } + return false; } - - // It's not a mismatch, since for this commit, the commit ID wasn't recorded in the 4-integer version. - return false; } - /// - /// Tests whether an object's ID starts with the specified 16-bits, or a subset of them. - /// - /// The object whose ID is to be tested. - /// The leading 16-bits to be tested. - /// The mask that indicates which bits should be compared. - /// to read the first two bytes as big endian (v3.5+ behavior); to use little endian (v3.4 and earlier behavior). - /// True if the object's ID starts with after applying the . - private static bool StartsWith(this ObjectId @object, ushort leadingBytes, bool bigEndian, ushort bitMask = 0xffff) - { - ushort truncatedObjectId = bigEndian ? BinaryPrimitives.ReadUInt16BigEndian(@object.RawId) : BinaryPrimitives.ReadUInt16LittleEndian(@object.RawId); - return (truncatedObjectId & bitMask) == leadingBytes; - } + return true; + } - /// - /// Encodes a byte array as hex. - /// - /// The buffer to encode. - /// A hexidecimal string. - private static string EncodeAsHex(byte[] buffer) - { - Requires.NotNull(buffer, nameof(buffer)); + private static bool IsVersionHeightMismatch(Version version, VersionOptions versionOptions, Commit commit, GitWalkTracker tracker) + { + Requires.NotNull(version, nameof(version)); + Requires.NotNull(versionOptions, nameof(versionOptions)); + Requires.NotNull(commit, nameof(commit)); - var sb = new StringBuilder(); - for (int i = 0; i < buffer.Length; i++) - { - sb.AppendFormat("{0:x2}", buffer[i]); - } + // The version.Build or version.Revision MAY represent the version height. + SemanticVersion.Position? position = versionOptions.VersionHeightPosition; + if (position.HasValue && position.Value <= SemanticVersion.Position.Revision) + { + int expectedVersionHeight = SemanticVersion.ReadVersionPosition(version, position.Value); - return sb.ToString(); + int actualVersionOffset = versionOptions.VersionHeightOffsetOrDefault; + int actualVersionHeight = GetCommitHeight(commit, tracker, c => CommitMatchesVersion(c, version, position.Value - 1, tracker)); + return expectedVersionHeight != actualVersionHeight + actualVersionOffset; } - /// - /// Gets the number of commits in the longest single path between - /// the specified branch's head and the most distant ancestor (inclusive). - /// - /// The commit to measure the height of. - /// The caching tracker for storing or fetching version information per commit. - /// - /// A function that returns false when we reach a commit that - /// should not be included in the height calculation. - /// May be null to count the height to the original commit. - /// - /// The height of the branch. - private static int GetCommitHeight(Commit startingCommit, GitWalkTracker tracker, Func? continueStepping) - { - Requires.NotNull(startingCommit, nameof(startingCommit)); - Requires.NotNull(tracker, nameof(tracker)); + // It's not a mismatch, since for this commit, the version height wasn't recorded in the 4-integer version. + return false; + } - if (continueStepping is object && !continueStepping(startingCommit)) + private static bool IsCommitIdMismatch(Version version, VersionOptions versionOptions, Commit commit) + { + Requires.NotNull(version, nameof(version)); + Requires.NotNull(versionOptions, nameof(versionOptions)); + Requires.NotNull(commit, nameof(commit)); + + // The version.Revision MAY represent the first 2 bytes of the git commit ID, but not if 3 integers were specified in version.json, + // since in that case the 4th integer is the version height. But we won't know till we read the version.json file, so for now, + SemanticVersion.Position? position = versionOptions.GitCommitIdPosition; + if (position.HasValue && position.Value <= SemanticVersion.Position.Revision) + { + // prepare for it to be the commit ID. + // The revision is a 16-bit unsigned integer, but is not allowed to be 0xffff. + // So if the value is 0xfffe, consider that the actual last bit is insignificant + // since the original git commit ID could have been either 0xffff or 0xfffe. + int expectedCommitIdLeadingValue = SemanticVersion.ReadVersionPosition(version, position.Value); + if (expectedCommitIdLeadingValue != -1) { - return 0; + ushort objectIdLeadingValue = (ushort)expectedCommitIdLeadingValue; + ushort objectIdMask = (ushort)(objectIdLeadingValue == MaximumBuildNumberOrRevisionComponent ? 0xfffe : 0xffff); + + // Accept a big endian match or a little endian match. + // Nerdbank.GitVersioning up to v3.4 would produce versions based on the endianness of the CPU it ran on (typically little endian). + // Starting with v3.5, it deterministically used big endian. In order for `nbgv get-commits` to match on versions computed before and after the change, + // we match on either endian setting. + return !(commit.Id.StartsWith(objectIdLeadingValue, bigEndian: true, objectIdMask) || commit.Id.StartsWith(objectIdLeadingValue, bigEndian: false, objectIdMask)); } + } - var commitsToEvaluate = new Stack(); - bool TryCalculateHeight(Commit commit) - { - // Get max height among all parents, or schedule all missing parents for their own evaluation and return false. - int maxHeightAmongParents = 0; - bool parentMissing = false; - foreach (Commit parent in commit.Parents) - { - if (!tracker.TryGetVersionHeight(parent, out int parentHeight)) - { - if (continueStepping is object && !continueStepping(parent)) - { - // This parent isn't supposed to contribute to height. - continue; - } - - commitsToEvaluate.Push(parent); - parentMissing = true; - } - else - { - maxHeightAmongParents = Math.Max(maxHeightAmongParents, parentHeight); - } - } + // It's not a mismatch, since for this commit, the commit ID wasn't recorded in the 4-integer version. + return false; + } - if (parentMissing) - { - return false; - } + /// + /// Tests whether an object's ID starts with the specified 16-bits, or a subset of them. + /// + /// The object whose ID is to be tested. + /// The leading 16-bits to be tested. + /// to read the first two bytes as big endian (v3.5+ behavior); to use little endian (v3.4 and earlier behavior). + /// The mask that indicates which bits should be compared. + /// True if the object's ID starts with after applying the . + private static bool StartsWith(this ObjectId @object, ushort leadingBytes, bool bigEndian, ushort bitMask = 0xffff) + { + ushort truncatedObjectId = bigEndian ? BinaryPrimitives.ReadUInt16BigEndian(@object.RawId) : BinaryPrimitives.ReadUInt16LittleEndian(@object.RawId); + return (truncatedObjectId & bitMask) == leadingBytes; + } - var versionOptions = tracker.GetVersion(commit); - var pathFilters = versionOptions?.PathFilters; + /// + /// Encodes a byte array as hex. + /// + /// The buffer to encode. + /// A hexidecimal string. + private static string EncodeAsHex(byte[] buffer) + { + Requires.NotNull(buffer, nameof(buffer)); - var includePaths = - pathFilters - ?.Where(filter => !filter.IsExclude) - .Select(filter => filter.RepoRelativePath) - .ToList(); + var sb = new StringBuilder(); + for (int i = 0; i < buffer.Length; i++) + { + sb.AppendFormat("{0:x2}", buffer[i]); + } - var excludePaths = pathFilters?.Where(filter => filter.IsExclude).ToList(); + return sb.ToString(); + } - var ignoreCase = commit.GetRepository().Config.Get("core.ignorecase")?.Value ?? false; - bool ContainsRelevantChanges(IEnumerable changes) => - excludePaths?.Count == 0 - ? changes.Any() - // If there is a single change that isn't excluded, - // then this commit is relevant. - : changes.Any(change => !excludePaths.Any(exclude => exclude.Excludes(change.Path, ignoreCase))); + /// + /// Gets the number of commits in the longest single path between + /// the specified branch's head and the most distant ancestor (inclusive). + /// + /// The commit to measure the height of. + /// The caching tracker for storing or fetching version information per commit. + /// + /// A function that returns false when we reach a commit that + /// should not be included in the height calculation. + /// May be null to count the height to the original commit. + /// + /// The height of the branch. + private static int GetCommitHeight(Commit startingCommit, GitWalkTracker tracker, Func? continueStepping) + { + Requires.NotNull(startingCommit, nameof(startingCommit)); + Requires.NotNull(tracker, nameof(tracker)); - int height = 1; + if (continueStepping is object && !continueStepping(startingCommit)) + { + return 0; + } - if (includePaths is not null) + var commitsToEvaluate = new Stack(); + bool TryCalculateHeight(Commit commit) + { + // Get max height among all parents, or schedule all missing parents for their own evaluation and return false. + int maxHeightAmongParents = 0; + bool parentMissing = false; + foreach (Commit parent in commit.Parents) + { + if (!tracker.TryGetVersionHeight(parent, out int parentHeight)) { - // If there are no include paths, or any of the include - // paths refer to the root of the repository, then do not - // filter the diff at all. - var diffInclude = - includePaths.Count == 0 || pathFilters.Any(filter => filter.IsRoot) - ? null - : includePaths; - - // If the diff between this commit and any of its parents - // touches a path that we care about, bump the height. - // A no-parent commit is relevant if it introduces anything in the filtered path. - var relevantCommit = - commit.Parents.Any() - ? commit.Parents.Any(parent => ContainsRelevantChanges(commit.GetRepository().Diff - .Compare(parent.Tree, commit.Tree, diffInclude, DiffOptions))) - : ContainsRelevantChanges(commit.GetRepository().Diff - .Compare(null, commit.Tree, diffInclude, DiffOptions)); - - if (!relevantCommit) + if (continueStepping is object && !continueStepping(parent)) { - height = 0; + // This parent isn't supposed to contribute to height. + continue; } - } - tracker.RecordHeight(commit, height + maxHeightAmongParents); - return true; + commitsToEvaluate.Push(parent); + parentMissing = true; + } + else + { + maxHeightAmongParents = Math.Max(maxHeightAmongParents, parentHeight); + } } - commitsToEvaluate.Push(startingCommit); - while (commitsToEvaluate.Count > 0) + if (parentMissing) { - Commit commit = commitsToEvaluate.Peek(); - if (tracker.TryGetVersionHeight(commit, out _) || TryCalculateHeight(commit)) - { - commitsToEvaluate.Pop(); - } + return false; } - Assumes.True(tracker.TryGetVersionHeight(startingCommit, out int result)); - return result; - } + VersionOptions? versionOptions = tracker.GetVersion(commit); + IReadOnlyList? pathFilters = versionOptions?.PathFilters; - /// - /// Enumerates over the set of commits in the repository that are reachable from any named reference. - /// - /// The repo to search. - /// An enumerate of commits. - private static IEnumerable GetCommitsReachableFromRefs(Repository repo) - { - Requires.NotNull(repo, nameof(repo)); + var includePaths = + pathFilters + ?.Where(filter => !filter.IsExclude) + .Select(filter => filter.RepoRelativePath) + .ToList(); + + var excludePaths = pathFilters?.Where(filter => filter.IsExclude).ToList(); - var visitedCommitIds = new HashSet(); - var breadthFirstQueue = new Queue(); + bool ignoreCase = commit.GetRepository().Config.Get("core.ignorecase")?.Value ?? false; + bool ContainsRelevantChanges(IEnumerable changes) => + excludePaths?.Count == 0 + ? changes.Any() + //// If there is a single change that isn't excluded, + //// then this commit is relevant. + : changes.Any(change => !excludePaths.Any(exclude => exclude.Excludes(change.Path, ignoreCase))); - // Start the discovery with HEAD, and all commits that have refs pointing to them. - breadthFirstQueue.Enqueue(repo.Head.Tip); - foreach (var reference in repo.Refs) + int height = 1; + + if (includePaths is not null) { - var commit = reference.ResolveToDirectReference()?.Target as Commit; - if (commit is object) + // If there are no include paths, or any of the include + // paths refer to the root of the repository, then do not + // filter the diff at all. + List? diffInclude = + includePaths.Count == 0 || pathFilters.Any(filter => filter.IsRoot) + ? null + : includePaths; + + // If the diff between this commit and any of its parents + // touches a path that we care about, bump the height. + // A no-parent commit is relevant if it introduces anything in the filtered path. + bool relevantCommit = + commit.Parents.Any() + ? commit.Parents.Any(parent => ContainsRelevantChanges(commit.GetRepository().Diff + .Compare(parent.Tree, commit.Tree, diffInclude, DiffOptions))) + : ContainsRelevantChanges(commit.GetRepository().Diff + .Compare(null, commit.Tree, diffInclude, DiffOptions)); + + if (!relevantCommit) { - breadthFirstQueue.Enqueue(commit); + height = 0; } } - while (breadthFirstQueue.Count > 0) + tracker.RecordHeight(commit, height + maxHeightAmongParents); + return true; + } + + commitsToEvaluate.Push(startingCommit); + while (commitsToEvaluate.Count > 0) + { + Commit commit = commitsToEvaluate.Peek(); + if (tracker.TryGetVersionHeight(commit, out _) || TryCalculateHeight(commit)) { - Commit head = breadthFirstQueue.Dequeue(); - if (visitedCommitIds.Add(head.Id)) - { - yield return head; - foreach (Commit parent in head.Parents) - { - breadthFirstQueue.Enqueue(parent); - } - } + commitsToEvaluate.Pop(); } } - /// - /// Encodes a commit from history in a - /// so that the original commit can be found later. - /// - /// The commit whose ID and position in history is to be encoded. - /// The version options applicable at this point (either from commit or working copy). - /// The version height, previously calculated by a call to . - /// - /// A version whose and - /// components are calculated based on the commit. - /// - /// - /// In the returned version, the component is - /// the height of the git commit while the - /// component is the first four bytes of the git commit id (forced to be a positive integer). - /// - internal static Version GetIdAsVersionHelper(this Commit? commit, VersionOptions? versionOptions, int versionHeight) + Assumes.True(tracker.TryGetVersionHeight(startingCommit, out int result)); + return result; + } + + /// + /// Enumerates over the set of commits in the repository that are reachable from any named reference. + /// + /// The repo to search. + /// An enumerate of commits. + private static IEnumerable GetCommitsReachableFromRefs(Repository repo) + { + Requires.NotNull(repo, nameof(repo)); + + var visitedCommitIds = new HashSet(); + var breadthFirstQueue = new Queue(); + + // Start the discovery with HEAD, and all commits that have refs pointing to them. + breadthFirstQueue.Enqueue(repo.Head.Tip); + foreach (Reference? reference in repo.Refs) { - var baseVersion = versionOptions?.Version?.Version ?? Version0; - int buildNumber = baseVersion.Build; - int revision = baseVersion.Revision; - - // Don't use the ?? coalescing operator here because the position property getters themselves can return null, which should NOT be overridden with our default. - // The default value is only appropriate if versionOptions itself is null. - var versionHeightPosition = versionOptions is not null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; - var commitIdPosition = versionOptions is not null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; - - // The compiler (due to WinPE header requirements) only allows 16-bit version components, - // and forbids 0xffff as a value. - if (versionHeightPosition.HasValue) + var commit = reference.ResolveToDirectReference()?.Target as Commit; + if (commit is object) { - int adjustedVersionHeight = versionHeight == 0 ? 0 : versionHeight + (versionOptions?.VersionHeightOffset ?? 0); - Verify.Operation(adjustedVersionHeight <= MaximumBuildNumberOrRevisionComponent, "Git height is {0}, which is greater than the maximum allowed {0}.", adjustedVersionHeight, MaximumBuildNumberOrRevisionComponent); - switch (versionHeightPosition.Value) - { - case SemanticVersion.Position.Build: - buildNumber = adjustedVersionHeight; - break; - case SemanticVersion.Position.Revision: - revision = adjustedVersionHeight; - break; - } + breadthFirstQueue.Enqueue(commit); } + } - if (commitIdPosition.HasValue) + while (breadthFirstQueue.Count > 0) + { + Commit head = breadthFirstQueue.Dequeue(); + if (visitedCommitIds.Add(head.Id)) { - switch (commitIdPosition.Value) + yield return head; + foreach (Commit parent in head.Parents) { - case SemanticVersion.Position.Revision: - revision = commit is object - ? Math.Min(MaximumBuildNumberOrRevisionComponent, commit.GetTruncatedCommitIdAsUInt16()) - : 0; - break; + breadthFirstQueue.Enqueue(parent); } } - - return VersionExtensions.Create(baseVersion.Major, baseVersion.Minor, buildNumber, revision); } + } - private class GitWalkTracker - { - private readonly Dictionary commitVersionCache = new Dictionary(); - private readonly Dictionary blobVersionCache = new Dictionary(); - private readonly Dictionary heights = new Dictionary(); - private readonly LibGit2Context context; + private class GitWalkTracker + { + private readonly Dictionary commitVersionCache = new Dictionary(); + private readonly Dictionary blobVersionCache = new Dictionary(); + private readonly Dictionary heights = new Dictionary(); + private readonly LibGit2Context context; - internal GitWalkTracker(LibGit2Context context) - { - this.context = context; - } + internal GitWalkTracker(LibGit2Context context) + { + this.context = context; + } - internal bool TryGetVersionHeight(Commit commit, out int height) => this.heights.TryGetValue(commit.Id, out height); + internal bool TryGetVersionHeight(Commit commit, out int height) => this.heights.TryGetValue(commit.Id, out height); - internal void RecordHeight(Commit commit, int height) => this.heights.Add(commit.Id, height); + internal void RecordHeight(Commit commit, int height) => this.heights.Add(commit.Id, height); - internal VersionOptions? GetVersion(Commit commit) + internal VersionOptions? GetVersion(Commit commit) + { + if (!this.commitVersionCache.TryGetValue(commit.Id, out VersionOptions? options)) { - if (!this.commitVersionCache.TryGetValue(commit.Id, out VersionOptions? options)) + try { - try - { - options = ((LibGit2VersionFile)this.context.VersionFile).GetVersion(commit, this.context.RepoRelativeProjectDirectory, this.blobVersionCache, out string? actualDirectory); - } - catch (Exception ex) - { - throw new InvalidOperationException($"Unable to get version from commit: {commit.Id.Sha}", ex); - } - - this.commitVersionCache.Add(commit.Id, options); + options = ((LibGit2VersionFile)this.context.VersionFile).GetVersion(commit, this.context.RepoRelativeProjectDirectory, this.blobVersionCache, out string? actualDirectory); + } + catch (Exception ex) + { + throw new InvalidOperationException($"Unable to get version from commit: {commit.Id.Sha}", ex); } - return options; + this.commitVersionCache.Add(commit.Id, options); } + + return options; } } } diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs index ae077ec3..c741328e 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs @@ -1,142 +1,141 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.LibGit2 -{ - using System; - using System.Collections.Generic; - using System.IO; - using LibGit2Sharp; - using Newtonsoft.Json; +using LibGit2Sharp; +using Newtonsoft.Json; + +#nullable enable +namespace Nerdbank.GitVersioning.LibGit2; + +/// +/// Exposes queries and mutations on a version.json or version.txt file, +/// implemented in terms of libgit2sharp. +/// +internal class LibGit2VersionFile : VersionFile +{ /// - /// Exposes queries and mutations on a version.json or version.txt file, - /// implemented in terms of libgit2sharp. + /// A sequence of possible filenames for the version file in preferred order. /// - internal class LibGit2VersionFile : VersionFile - { - /// - /// A sequence of possible filenames for the version file in preferred order. - /// - public static readonly IReadOnlyList PreferredFileNames = new[] { JsonFileName, TxtFileName }; + public static readonly IReadOnlyList PreferredFileNames = new[] { JsonFileName, TxtFileName }; - internal LibGit2VersionFile(LibGit2Context context) - : base(context) - { - } - - protected new LibGit2Context Context => (LibGit2Context)base.Context; + internal LibGit2VersionFile(LibGit2Context context) + : base(context) + { + } - protected override VersionOptions? GetVersionCore(out string? actualDirectory) => this.GetVersion(this.Context.Commit!, this.Context.RepoRelativeProjectDirectory, null, out actualDirectory); + protected new LibGit2Context Context => (LibGit2Context)base.Context; - /// - /// Reads the version.json file and returns the deserialized from it. - /// - /// The commit to read from. - /// The directory to consider when searching for the version.txt file. - /// An optional blob cache for storing the raw parse results of a version.txt or version.json file (before any inherit merge operations are applied). - /// Receives the full path to the directory in which the version file was found. - /// The version information read from the file. - internal VersionOptions? GetVersion(Commit commit, string repoRelativeProjectDirectory, Dictionary? blobVersionCache, out string? actualDirectory) + /// + /// Reads the version.json file and returns the deserialized from it. + /// + /// The commit to read from. + /// The directory to consider when searching for the version.txt file. + /// An optional blob cache for storing the raw parse results of a version.txt or version.json file (before any inherit merge operations are applied). + /// Receives the full path to the directory in which the version file was found. + /// The version information read from the file. + internal VersionOptions? GetVersion(Commit commit, string repoRelativeProjectDirectory, Dictionary? blobVersionCache, out string? actualDirectory) + { + string? searchDirectory = repoRelativeProjectDirectory ?? string.Empty; + while (searchDirectory is object) { - string? searchDirectory = repoRelativeProjectDirectory ?? string.Empty; - while (searchDirectory is object) - { - string? parentDirectory = searchDirectory.Length > 0 ? Path.GetDirectoryName(searchDirectory) : null; + string? parentDirectory = searchDirectory.Length > 0 ? Path.GetDirectoryName(searchDirectory) : null; - string candidatePath = Path.Combine(searchDirectory, TxtFileName).Replace('\\', '/'); - var versionTxtBlob = commit.Tree[candidatePath]?.Target as Blob; - if (versionTxtBlob is object) + string candidatePath = Path.Combine(searchDirectory, TxtFileName).Replace('\\', '/'); + var versionTxtBlob = commit.Tree[candidatePath]?.Target as Blob; + if (versionTxtBlob is object) + { + if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionTxtBlob.Id, out VersionOptions? result)) { - if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionTxtBlob.Id, out VersionOptions? result)) + result = TryReadVersionFile(new StreamReader(versionTxtBlob.GetContentStream())); + if (blobVersionCache is object) { - result = TryReadVersionFile(new StreamReader(versionTxtBlob.GetContentStream())); - if (blobVersionCache is object) - { - result?.Freeze(); - blobVersionCache.Add(versionTxtBlob.Id, result); - } + result?.Freeze(); + blobVersionCache.Add(versionTxtBlob.Id, result); } + } - if (result is object) - { - IBelongToARepository commitAsRepoMember = commit; - actualDirectory = Path.Combine(commitAsRepoMember.Repository.Info.WorkingDirectory, searchDirectory); - return result; - } + if (result is object) + { + IBelongToARepository commitAsRepoMember = commit; + actualDirectory = Path.Combine(commitAsRepoMember.Repository.Info.WorkingDirectory, searchDirectory); + return result; } + } - candidatePath = Path.Combine(searchDirectory, JsonFileName).Replace('\\', '/'); - var versionJsonBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; - if (versionJsonBlob is object) + candidatePath = Path.Combine(searchDirectory, JsonFileName).Replace('\\', '/'); + var versionJsonBlob = commit.Tree[candidatePath]?.Target as LibGit2Sharp.Blob; + if (versionJsonBlob is object) + { + string? versionJsonContent = null; + if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionJsonBlob.Id, out VersionOptions? result)) { - string? versionJsonContent = null; - if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionJsonBlob.Id, out VersionOptions? result)) + using (var sr = new StreamReader(versionJsonBlob.GetContentStream())) { - using (var sr = new StreamReader(versionJsonBlob.GetContentStream())) - { - versionJsonContent = sr.ReadToEnd(); - } + versionJsonContent = sr.ReadToEnd(); + } - try - { - result = TryReadVersionJsonContent(versionJsonContent, searchDirectory); - } - catch (FormatException ex) - { - throw new FormatException( - $"Failure while reading {JsonFileName} from commit {this.Context.GitCommitId}. " + - "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + - "https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/migrating.md", ex); - } + try + { + result = TryReadVersionJsonContent(versionJsonContent, searchDirectory); + } + catch (FormatException ex) + { + throw new FormatException( + $"Failure while reading {JsonFileName} from commit {this.Context.GitCommitId}. " + + "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + + "https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/migrating.md", + ex); + } - if (blobVersionCache is object) - { - result?.Freeze(); - blobVersionCache.Add(versionJsonBlob.Id, result); - } + if (blobVersionCache is object) + { + result?.Freeze(); + blobVersionCache.Add(versionJsonBlob.Id, result); } + } - if (result?.Inherit ?? false) + if (result?.Inherit ?? false) + { + if (parentDirectory is object) { - if (parentDirectory is object) + result = this.GetVersion(commit, parentDirectory, blobVersionCache, out actualDirectory); + if (result is object) { - result = this.GetVersion(commit, parentDirectory, blobVersionCache, out actualDirectory); - if (result is object) + if (versionJsonContent is null) { - if (versionJsonContent is null) - { - // We reused a cache VersionOptions, but now we need the actual JSON string. - using (var sr = new StreamReader(versionJsonBlob.GetContentStream())) - { - versionJsonContent = sr.ReadToEnd(); - } - } - - if (result.IsFrozen) - { - result = new VersionOptions(result); - } - - JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: searchDirectory)); - return result; + // We reused a cache VersionOptions, but now we need the actual JSON string. + using var sr = new StreamReader(versionJsonBlob.GetContentStream()); + versionJsonContent = sr.ReadToEnd(); } - } - throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); - } - else if (result is object) - { - IBelongToARepository commitAsRepoMember = commit; - actualDirectory = Path.Combine(commitAsRepoMember.Repository.Info.WorkingDirectory, searchDirectory); - return result; + if (result.IsFrozen) + { + result = new VersionOptions(result); + } + + JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: searchDirectory)); + return result; + } } - } - searchDirectory = parentDirectory; + throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); + } + else if (result is object) + { + IBelongToARepository commitAsRepoMember = commit; + actualDirectory = Path.Combine(commitAsRepoMember.Repository.Info.WorkingDirectory, searchDirectory); + return result; + } } - actualDirectory = null; - return null; + searchDirectory = parentDirectory; } + + actualDirectory = null; + return null; } + + /// + protected override VersionOptions? GetVersionCore(out string? actualDirectory) => this.GetVersion(this.Context.Commit!, this.Context.RepoRelativeProjectDirectory, null, out actualDirectory); } diff --git a/src/NerdBank.GitVersioning/Managed/GitExtensions.cs b/src/NerdBank.GitVersioning/Managed/GitExtensions.cs new file mode 100644 index 00000000..6d97eee0 --- /dev/null +++ b/src/NerdBank.GitVersioning/Managed/GitExtensions.cs @@ -0,0 +1,345 @@ +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable + +using Nerdbank.GitVersioning.ManagedGit; +using Validation; + +namespace Nerdbank.GitVersioning.Managed; + +internal static class GitExtensions +{ + /// + /// The 0.0 semver. + /// + private static readonly SemanticVersion SemVer0 = SemanticVersion.Parse("0.0"); + + /// + /// Gets the number of commits in the longest single path between + /// the specified commit and the most distant ancestor (inclusive). + /// + /// The git context. + /// + /// A function that returns false when we reach a commit that + /// should not be included in the height calculation. + /// May be null to count the height to the original commit. + /// + /// The height of the commit. Always a positive integer. + public static int GetHeight(ManagedGitContext context, Func? continueStepping = null) + { + Verify.Operation(context.Commit.HasValue, "No commit is selected."); + var tracker = new GitWalkTracker(context); + return GetCommitHeight(context.Repository, context.Commit.Value, tracker, continueStepping); + } + + /// + /// Takes the first 2 bytes of a commit ID (i.e. first 4 characters of its hex-encoded SHA) + /// and returns them as an 16-bit unsigned integer. + /// + /// The commit to identify with an integer. + /// The unsigned integer which identifies a commit. + public static ushort GetTruncatedCommitIdAsUInt16(this GitCommit commit) + { + return commit.Sha.AsUInt16(); + } + + /// + /// Gets the number of commits in the longest single path between + /// the specified commit and the most distant ancestor (inclusive) + /// that set the version to the value at . + /// + /// The git context for which to calculate the height. + /// Optional base version to calculate the height. If not specified, the base version will be calculated by scanning the repository. + /// The height of the commit. Always a positive integer. + internal static int GetVersionHeight(ManagedGitContext context, Version? baseVersion = null) + { + if (context.Commit is null) + { + return 0; + } + + var tracker = new GitWalkTracker(context); + + VersionOptions? versionOptions = tracker.GetVersion(context.Commit.Value); + if (versionOptions is null) + { + return 0; + } + + SemanticVersion? baseSemVer = + baseVersion is not null ? SemanticVersion.Parse(baseVersion.ToString()) : + versionOptions.Version ?? SemVer0; + + SemanticVersion.Position? versionHeightPosition = versionOptions.VersionHeightPosition; + if (versionHeightPosition.HasValue) + { + int height = GetHeight(context, c => CommitMatchesVersion(c, baseSemVer, versionHeightPosition.Value, tracker)); + return height; + } + + return 0; + } + + /// + /// Gets the number of commits in the longest single path between + /// the specified branch's head and the most distant ancestor (inclusive). + /// + /// The Git repository. + /// The commit to measure the height of. + /// The caching tracker for storing or fetching version information per commit. + /// + /// A function that returns false when we reach a commit that + /// should not be included in the height calculation. + /// May be null to count the height to the original commit. + /// + /// The height of the branch. + private static int GetCommitHeight(GitRepository repository, GitCommit startingCommit, GitWalkTracker tracker, Func? continueStepping) + { + if (continueStepping is object && !continueStepping(startingCommit)) + { + return 0; + } + + var commitsToEvaluate = new Stack(); + bool TryCalculateHeight(GitCommit commit) + { + // Get max height among all parents, or schedule all missing parents for their own evaluation and return false. + int maxHeightAmongParents = 0; + bool parentMissing = false; + foreach (GitObjectId parentId in commit.Parents) + { + GitCommit parent = repository.GetCommit(parentId); + if (!tracker.TryGetVersionHeight(parent, out int parentHeight)) + { + if (continueStepping is object && !continueStepping(parent)) + { + // This parent isn't supposed to contribute to height. + continue; + } + + commitsToEvaluate.Push(parent); + parentMissing = true; + } + else + { + maxHeightAmongParents = Math.Max(maxHeightAmongParents, parentHeight); + } + } + + if (parentMissing) + { + return false; + } + + VersionOptions? versionOptions = tracker.GetVersion(commit); + IReadOnlyList? pathFilters = versionOptions?.PathFilters; + + var includePaths = + pathFilters + ?.Where(filter => !filter.IsExclude) + .Select(filter => filter.RepoRelativePath) + .ToList(); + + var excludePaths = pathFilters?.Where(filter => filter.IsExclude).ToList(); + + bool ignoreCase = repository.IgnoreCase; + + int height = 1; + + if (pathFilters is not null) + { + // If the diff between this commit and any of its parents + // touches a path that we care about, bump the height. + bool relevantCommit = false, anyParents = false; + foreach (GitObjectId parentId in commit.Parents) + { + anyParents = true; + GitCommit parent = repository.GetCommit(parentId); + if (IsRelevantCommit(repository, commit, parent, pathFilters)) + { + // No need to scan further, as a positive match will never turn negative. + relevantCommit = true; + break; + } + } + + if (!anyParents) + { + // A no-parent commit is relevant if it introduces anything in the filtered path. + relevantCommit = IsRelevantCommit(repository, commit, parent: default(GitCommit), pathFilters); + } + + if (!relevantCommit) + { + height = 0; + } + } + + tracker.RecordHeight(commit, height + maxHeightAmongParents); + return true; + } + + commitsToEvaluate.Push(startingCommit); + while (commitsToEvaluate.Count > 0) + { + GitCommit commit = commitsToEvaluate.Peek(); + if (tracker.TryGetVersionHeight(commit, out _) || TryCalculateHeight(commit)) + { + commitsToEvaluate.Pop(); + } + } + + Assumes.True(tracker.TryGetVersionHeight(startingCommit, out int result)); + return result; + } + + private static bool IsRelevantCommit(GitRepository repository, GitCommit commit, GitCommit parent, IReadOnlyList filters) + { + return IsRelevantCommit( + repository, + repository.GetTree(commit.Tree), + parent != default ? repository.GetTree(parent.Tree) : null, + relativePath: string.Empty, + filters); + } + + private static bool IsRelevantCommit(GitRepository repository, GitTree tree, GitTree? parent, string relativePath, IReadOnlyList filters) + { + // Walk over all child nodes in the current tree. If a child node was found in the parent, + // remove it, so that after the iteration the parent contains all nodes which have been + // deleted. + foreach (KeyValuePair child in tree.Children) + { + GitTreeEntry? entry = child.Value; + GitTreeEntry? parentEntry = null; + + // If the entry is not present in the parent commit, it was added; + // if the Sha does not match, it was modified. + if (parent is null || + !parent.Children.TryGetValue(child.Key, out parentEntry) || + parentEntry.Sha != child.Value.Sha) + { + // Determine whether the change was relevant. + string? fullPath = $"{relativePath}{entry.Name}"; + + bool isRelevant = + //// Either there are no include filters at all (i.e. everything is included), or there's an explicit include filter + (!filters.Any(f => f.IsInclude) || filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)) + || (!entry.IsFile && filters.Any(f => f.IncludesChildren(fullPath, repository.IgnoreCase)))) + //// The path is not excluded by any filters + && !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase)); + + // If the change was relevant, and the item is a directory, we need to recurse. + if (isRelevant && !entry.IsFile) + { + isRelevant = IsRelevantCommit( + repository, + repository.GetTree(entry.Sha), + parentEntry is null ? GitTree.Empty : repository.GetTree(parentEntry.Sha), + $"{fullPath}/", + filters); + } + + // Quit as soon as any relevant change has been detected. + if (isRelevant) + { + return true; + } + } + + if (parentEntry is not null) + { + Assumes.NotNull(parent); + parent.Children.Remove(child.Key); + } + } + + // Inspect removed entries (i.e. present in parent but not in the current tree) + if (parent is not null) + { + foreach (KeyValuePair child in parent.Children) + { + // Determine whether the change was relevant. + string? fullPath = Path.Combine(relativePath, child.Key); + + bool isRelevant = + filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)) + && !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase)); + + if (isRelevant) + { + return true; + } + } + } + + // No relevant changes have been detected + return false; + } + + /// + /// Tests whether a commit is of a specified version, comparing major and minor components + /// with the version.txt file defined by that commit. + /// + /// The commit to test. + /// The version to test for in the commit. + /// The last component of the version to include in the comparison. + /// The caching tracker for storing or fetching version information per commit. + /// true if the matches the major and minor components of . + private static bool CommitMatchesVersion(GitCommit commit, SemanticVersion expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) + { + Requires.NotNull(expectedVersion, nameof(expectedVersion)); + + VersionOptions? commitVersionData = tracker.GetVersion(commit); + SemanticVersion? semVerFromFile = commitVersionData?.Version; + if (commitVersionData is null || semVerFromFile is null) + { + return false; + } + + // If the version height position moved, that's an automatic reset in version height. + if (commitVersionData.VersionHeightPosition != comparisonPrecision) + { + return false; + } + + return !SemanticVersion.WillVersionChangeResetVersionHeight(commitVersionData.Version, expectedVersion, comparisonPrecision); + } + + private class GitWalkTracker + { + private readonly Dictionary commitVersionCache = new Dictionary(); + private readonly Dictionary blobVersionCache = new Dictionary(); + private readonly Dictionary heights = new Dictionary(); + private readonly ManagedGitContext context; + + internal GitWalkTracker(ManagedGitContext context) + { + this.context = context; + } + + internal bool TryGetVersionHeight(GitCommit commit, out int height) => this.heights.TryGetValue(commit.Sha, out height); + + internal void RecordHeight(GitCommit commit, int height) => this.heights.Add(commit.Sha, height); + + internal VersionOptions? GetVersion(GitCommit commit) + { + if (!this.commitVersionCache.TryGetValue(commit.Sha, out VersionOptions? options)) + { + try + { + options = ((ManagedVersionFile)this.context.VersionFile).GetVersion(commit, this.context.RepoRelativeProjectDirectory, this.blobVersionCache, out string? actualDirectory); + } + catch (Exception ex) + { + throw new InvalidOperationException($"Unable to get version from commit: {commit.Sha}", ex); + } + + this.commitVersionCache.Add(commit.Sha, options); + } + + return options; + } + } +} diff --git a/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs b/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs index a6d4fab5..aa4cc107 100644 --- a/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs +++ b/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs @@ -1,191 +1,192 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.Text; using Nerdbank.GitVersioning.ManagedGit; using Validation; -namespace Nerdbank.GitVersioning.Managed +namespace Nerdbank.GitVersioning.Managed; + +/// +/// A git context implemented without any native code dependency. +/// +[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] +public class ManagedGitContext : GitContext { - /// - /// A git context implemented without any native code dependency. - /// - [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] - public class ManagedGitContext : GitContext + internal ManagedGitContext(string workingDirectory, string dotGitPath, string? committish = null) + : base(workingDirectory, dotGitPath) { - internal ManagedGitContext(string workingDirectory, string dotGitPath, string? committish = null) - : base(workingDirectory, dotGitPath) + var repo = GitRepository.Create(workingDirectory); + if (repo is null) { - GitRepository? repo = GitRepository.Create(workingDirectory); - if (repo is null) - { - throw new ArgumentException("No git repo found here.", nameof(workingDirectory)); - } - - this.Commit = committish is null ? repo.GetHeadCommit() : (repo.Lookup(committish) is { } objectId ? (GitCommit?)repo.GetCommit(objectId) : null); - if (this.Commit is null && committish is object) - { - throw new ArgumentException("No matching commit found.", nameof(committish)); - } + throw new ArgumentException("No git repo found here.", nameof(workingDirectory)); + } - this.Repository = repo; - this.VersionFile = new ManagedVersionFile(this); + this.Commit = committish is null ? repo.GetHeadCommit() : (repo.Lookup(committish) is { } objectId ? (GitCommit?)repo.GetCommit(objectId) : null); + if (this.Commit is null && committish is object) + { + throw new ArgumentException("No matching commit found.", nameof(committish)); } - /// - public GitRepository Repository { get; } + this.Repository = repo; + this.VersionFile = new ManagedVersionFile(this); + } - /// - public GitCommit? Commit { get; private set; } + public GitRepository Repository { get; } - /// - public override VersionFile VersionFile { get; } + public GitCommit? Commit { get; private set; } - /// - public override string? GitCommitId => this.Commit?.Sha.ToString(); + /// + public override VersionFile VersionFile { get; } - /// - public override bool IsHead => this.Repository.GetHeadCommit().Equals(this.Commit); + /// + public override string? GitCommitId => this.Commit?.Sha.ToString(); - /// - public override DateTimeOffset? GitCommitDate => this.Commit is { } commit ? (commit.Author?.Date ?? this.Repository.GetCommit(commit.Sha, readAuthor: true).Author?.Date) : null; + /// + public override bool IsHead => this.Repository.GetHeadCommit().Equals(this.Commit); - /// - public override string HeadCanonicalName => this.Repository.GetHeadAsReferenceOrSha().ToString() ?? throw new InvalidOperationException("Unable to determine the HEAD position."); + /// + public override DateTimeOffset? GitCommitDate => this.Commit is { } commit ? (commit.Author?.Date ?? this.Repository.GetCommit(commit.Sha, readAuthor: true).Author?.Date) : null; - private string DebuggerDisplay => $"\"{this.WorkingTreePath}\" (managed)"; + /// + public override string HeadCanonicalName => this.Repository.GetHeadAsReferenceOrSha().ToString() ?? throw new InvalidOperationException("Unable to determine the HEAD position."); - /// - public override void ApplyTag(string name) => throw new NotSupportedException(); + private string DebuggerDisplay => $"\"{this.WorkingTreePath}\" (managed)"; - /// - public override bool TrySelectCommit(string committish) + /// Initializes a new instance of the class. + /// The path to the .git directory or somewhere in a git working tree. + /// The SHA-1 or ref for a git commit. + /// The new instance. + public static ManagedGitContext Create(string path, string? committish = null) + { + FindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath); + return new ManagedGitContext(workingTreeDirectory, gitDirectory, committish) { - if (this.Repository.Lookup(committish) is { } objectId) - { - this.Commit = this.Repository.GetCommit(objectId); - return true; - } - - return false; - } + RepoRelativeProjectDirectory = workingTreeRelativePath, + }; + } - /// - public override void Stage(string path) => throw new NotSupportedException(); + /// + public override void ApplyTag(string name) => throw new NotSupportedException(); - /// The path to the .git directory or somewhere in a git working tree. - /// The SHA-1 or ref for a git commit. - public static ManagedGitContext Create(string path, string? committish = null) + /// + public override bool TrySelectCommit(string committish) + { + if (this.Repository.Lookup(committish) is { } objectId) { - FindGitPaths(path, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath); - return new ManagedGitContext(workingTreeDirectory, gitDirectory, committish) - { - RepoRelativeProjectDirectory = workingTreeRelativePath, - }; + this.Commit = this.Repository.GetCommit(objectId); + return true; } - internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) + return false; + } + + /// + public override void Stage(string path) => throw new NotSupportedException(); + + /// + public override string GetShortUniqueCommitId(int minLength) + { + Verify.Operation(this.Commit is object, "No commit is selected."); + return this.Repository.ShortenObjectId(this.Commit.Value.Sha, minLength); + } + + /// + internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) + { + SemanticVersion? headCommitVersion = committedVersion?.Version ?? SemVer0; + + if (IsVersionFileChangedInWorkingTree(committedVersion, workingVersion)) { - var headCommitVersion = committedVersion?.Version ?? SemVer0; + Version? workingCopyVersion = workingVersion?.Version?.Version; - if (IsVersionFileChangedInWorkingTree(committedVersion, workingVersion)) + if (workingCopyVersion is null || !workingCopyVersion.Equals(headCommitVersion)) { - var workingCopyVersion = workingVersion?.Version?.Version; - - if (workingCopyVersion is null || !workingCopyVersion.Equals(headCommitVersion)) - { - // The working copy has changed the major.minor version. - // So by definition the version height is 0, since no commit represents it yet. - return 0; - } + // The working copy has changed the major.minor version. + // So by definition the version height is 0, since no commit represents it yet. + return 0; } - - return GitExtensions.GetVersionHeight(this); } - internal override Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) - { - var version = IsVersionFileChangedInWorkingTree(committedVersion, workingVersion) ? workingVersion : committedVersion; + return GitExtensions.GetVersionHeight(this); + } - return this.GetIdAsVersionHelper(version, versionHeight); - } + /// + internal override Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) + { + VersionOptions? version = IsVersionFileChangedInWorkingTree(committedVersion, workingVersion) ? workingVersion : committedVersion; - /// - public override string GetShortUniqueCommitId(int minLength) + return this.GetIdAsVersionHelper(version, versionHeight); + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) { - Verify.Operation(this.Commit is object, "No commit is selected."); - return this.Repository.ShortenObjectId(this.Commit.Value.Sha, minLength); + this.Repository.Dispose(); } - /// - protected override void Dispose(bool disposing) + base.Dispose(disposing); + } + + /// + /// Encodes a commit from history in a + /// so that the original commit can be found later. + /// + /// The version options applicable at this point (either from commit or working copy). + /// The version height, previously calculated. + /// + /// A version whose and + /// components are calculated based on the commit. + /// + /// + /// In the returned version, the component is + /// the height of the git commit while the + /// component is the first four bytes of the git commit id (forced to be a positive integer). + /// + private Version GetIdAsVersionHelper(VersionOptions? versionOptions, int versionHeight) + { + Version? baseVersion = versionOptions?.Version?.Version ?? Version0; + int buildNumber = baseVersion.Build; + int revision = baseVersion.Revision; + + // Don't use the ?? coalescing operator here because the position property getters themselves can return null, which should NOT be overridden with our default. + // The default value is only appropriate if versionOptions itself is null. + SemanticVersion.Position? versionHeightPosition = versionOptions is not null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; + SemanticVersion.Position? commitIdPosition = versionOptions is not null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; + + // The compiler (due to WinPE header requirements) only allows 16-bit version components, + // and forbids 0xffff as a value. + if (versionHeightPosition.HasValue) { - if (disposing) + int adjustedVersionHeight = versionHeight == 0 ? 0 : versionHeight + (versionOptions?.VersionHeightOffset ?? 0); + Verify.Operation(adjustedVersionHeight <= MaximumBuildNumberOrRevisionComponent, "Git height is {0}, which is greater than the maximum allowed {0}.", adjustedVersionHeight, MaximumBuildNumberOrRevisionComponent); + switch (versionHeightPosition.Value) { - this.Repository.Dispose(); + case SemanticVersion.Position.Build: + buildNumber = adjustedVersionHeight; + break; + case SemanticVersion.Position.Revision: + revision = adjustedVersionHeight; + break; } - - base.Dispose(disposing); } - /// - /// Encodes a commit from history in a - /// so that the original commit can be found later. - /// - /// The version options applicable at this point (either from commit or working copy). - /// The version height, previously calculated. - /// - /// A version whose and - /// components are calculated based on the commit. - /// - /// - /// In the returned version, the component is - /// the height of the git commit while the - /// component is the first four bytes of the git commit id (forced to be a positive integer). - /// - private Version GetIdAsVersionHelper(VersionOptions? versionOptions, int versionHeight) + if (commitIdPosition.HasValue) { - var baseVersion = versionOptions?.Version?.Version ?? Version0; - int buildNumber = baseVersion.Build; - int revision = baseVersion.Revision; - - // Don't use the ?? coalescing operator here because the position property getters themselves can return null, which should NOT be overridden with our default. - // The default value is only appropriate if versionOptions itself is null. - var versionHeightPosition = versionOptions is not null ? versionOptions.VersionHeightPosition : SemanticVersion.Position.Build; - var commitIdPosition = versionOptions is not null ? versionOptions.GitCommitIdPosition : SemanticVersion.Position.Revision; - - // The compiler (due to WinPE header requirements) only allows 16-bit version components, - // and forbids 0xffff as a value. - if (versionHeightPosition.HasValue) + switch (commitIdPosition.Value) { - int adjustedVersionHeight = versionHeight == 0 ? 0 : versionHeight + (versionOptions?.VersionHeightOffset ?? 0); - Verify.Operation(adjustedVersionHeight <= MaximumBuildNumberOrRevisionComponent, "Git height is {0}, which is greater than the maximum allowed {0}.", adjustedVersionHeight, MaximumBuildNumberOrRevisionComponent); - switch (versionHeightPosition.Value) - { - case SemanticVersion.Position.Build: - buildNumber = adjustedVersionHeight; - break; - case SemanticVersion.Position.Revision: - revision = adjustedVersionHeight; - break; - } + case SemanticVersion.Position.Revision: + revision = this.Commit.HasValue + ? Math.Min(MaximumBuildNumberOrRevisionComponent, this.Commit.Value.GetTruncatedCommitIdAsUInt16()) + : 0; + break; } - - if (commitIdPosition.HasValue) - { - switch (commitIdPosition.Value) - { - case SemanticVersion.Position.Revision: - revision = this.Commit.HasValue - ? Math.Min(MaximumBuildNumberOrRevisionComponent, this.Commit.Value.GetTruncatedCommitIdAsUInt16()) - : 0; - break; - } - } - - return VersionExtensions.Create(baseVersion.Major, baseVersion.Minor, buildNumber, revision); } + + return VersionExtensions.Create(baseVersion.Major, baseVersion.Minor, buildNumber, revision); } } diff --git a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs b/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs deleted file mode 100644 index e51bf4ea..00000000 --- a/src/NerdBank.GitVersioning/Managed/ManagedGitExtensions.cs +++ /dev/null @@ -1,348 +0,0 @@ -#nullable enable - -using System; -using System.Collections.Generic; -using System.IO; -using System.Linq; -using System.Runtime.InteropServices; -using Nerdbank.GitVersioning.ManagedGit; -using Validation; - -namespace Nerdbank.GitVersioning.Managed -{ - internal static class GitExtensions - { - /// - /// The 0.0 semver. - /// - private static readonly SemanticVersion SemVer0 = SemanticVersion.Parse("0.0"); - - /// - /// Gets the number of commits in the longest single path between - /// the specified commit and the most distant ancestor (inclusive) - /// that set the version to the value at . - /// - /// The git context for which to calculate the height. - /// Optional base version to calculate the height. If not specified, the base version will be calculated by scanning the repository. - /// The height of the commit. Always a positive integer. - internal static int GetVersionHeight(ManagedGitContext context, Version? baseVersion = null) - { - if (context.Commit is null) - { - return 0; - } - - var tracker = new GitWalkTracker(context); - - var versionOptions = tracker.GetVersion(context.Commit.Value); - if (versionOptions is null) - { - return 0; - } - - var baseSemVer = - baseVersion is not null ? SemanticVersion.Parse(baseVersion.ToString()) : - versionOptions.Version ?? SemVer0; - - var versionHeightPosition = versionOptions.VersionHeightPosition; - if (versionHeightPosition.HasValue) - { - int height = GetHeight(context, c => CommitMatchesVersion(c, baseSemVer, versionHeightPosition.Value, tracker)); - return height; - } - - return 0; - } - - /// - /// Tests whether a commit is of a specified version, comparing major and minor components - /// with the version.txt file defined by that commit. - /// - /// The commit to test. - /// The version to test for in the commit - /// The last component of the version to include in the comparison. - /// The caching tracker for storing or fetching version information per commit. - /// true if the matches the major and minor components of . - private static bool CommitMatchesVersion(GitCommit commit, SemanticVersion expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) - { - Requires.NotNull(expectedVersion, nameof(expectedVersion)); - - var commitVersionData = tracker.GetVersion(commit); - var semVerFromFile = commitVersionData?.Version; - if (commitVersionData is null || semVerFromFile is null) - { - return false; - } - - // If the version height position moved, that's an automatic reset in version height. - if (commitVersionData.VersionHeightPosition != comparisonPrecision) - { - return false; - } - - return !SemanticVersion.WillVersionChangeResetVersionHeight(commitVersionData.Version, expectedVersion, comparisonPrecision); - } - - /// - /// Gets the number of commits in the longest single path between - /// the specified commit and the most distant ancestor (inclusive). - /// - /// The git context. - /// - /// A function that returns false when we reach a commit that - /// should not be included in the height calculation. - /// May be null to count the height to the original commit. - /// - /// The height of the commit. Always a positive integer. - public static int GetHeight(ManagedGitContext context, Func? continueStepping = null) - { - Verify.Operation(context.Commit.HasValue, "No commit is selected."); - var tracker = new GitWalkTracker(context); - return GetCommitHeight(context.Repository, context.Commit.Value, tracker, continueStepping); - } - - /// - /// Gets the number of commits in the longest single path between - /// the specified branch's head and the most distant ancestor (inclusive). - /// - /// The Git repository. - /// The commit to measure the height of. - /// The caching tracker for storing or fetching version information per commit. - /// - /// A function that returns false when we reach a commit that - /// should not be included in the height calculation. - /// May be null to count the height to the original commit. - /// - /// The height of the branch. - private static int GetCommitHeight(GitRepository repository, GitCommit startingCommit, GitWalkTracker tracker, Func? continueStepping) - { - if (continueStepping is object && !continueStepping(startingCommit)) - { - return 0; - } - - var commitsToEvaluate = new Stack(); - bool TryCalculateHeight(GitCommit commit) - { - // Get max height among all parents, or schedule all missing parents for their own evaluation and return false. - int maxHeightAmongParents = 0; - bool parentMissing = false; - foreach (GitObjectId parentId in commit.Parents) - { - var parent = repository.GetCommit(parentId); - if (!tracker.TryGetVersionHeight(parent, out int parentHeight)) - { - if (continueStepping is object && !continueStepping(parent)) - { - // This parent isn't supposed to contribute to height. - continue; - } - - commitsToEvaluate.Push(parent); - parentMissing = true; - } - else - { - maxHeightAmongParents = Math.Max(maxHeightAmongParents, parentHeight); - } - } - - if (parentMissing) - { - return false; - } - - var versionOptions = tracker.GetVersion(commit); - var pathFilters = versionOptions?.PathFilters; - - var includePaths = - pathFilters - ?.Where(filter => !filter.IsExclude) - .Select(filter => filter.RepoRelativePath) - .ToList(); - - var excludePaths = pathFilters?.Where(filter => filter.IsExclude).ToList(); - - var ignoreCase = repository.IgnoreCase; - - int height = 1; - - if (pathFilters is not null) - { - // If the diff between this commit and any of its parents - // touches a path that we care about, bump the height. - bool relevantCommit = false, anyParents = false; - foreach (GitObjectId parentId in commit.Parents) - { - anyParents = true; - GitCommit parent = repository.GetCommit(parentId); - if (IsRelevantCommit(repository, commit, parent, pathFilters)) - { - // No need to scan further, as a positive match will never turn negative. - relevantCommit = true; - break; - } - } - - if (!anyParents) - { - // A no-parent commit is relevant if it introduces anything in the filtered path. - relevantCommit = IsRelevantCommit(repository, commit, parent: default(GitCommit), pathFilters); - } - - if (!relevantCommit) - { - height = 0; - } - } - - tracker.RecordHeight(commit, height + maxHeightAmongParents); - return true; - } - - commitsToEvaluate.Push(startingCommit); - while (commitsToEvaluate.Count > 0) - { - GitCommit commit = commitsToEvaluate.Peek(); - if (tracker.TryGetVersionHeight(commit, out _) || TryCalculateHeight(commit)) - { - commitsToEvaluate.Pop(); - } - } - - Assumes.True(tracker.TryGetVersionHeight(startingCommit, out int result)); - return result; - } - - private static bool IsRelevantCommit(GitRepository repository, GitCommit commit, GitCommit parent, IReadOnlyList filters) - { - return IsRelevantCommit( - repository, - repository.GetTree(commit.Tree), - parent != default ? repository.GetTree(parent.Tree) : null, - relativePath: string.Empty, - filters); - } - - private static bool IsRelevantCommit(GitRepository repository, GitTree tree, GitTree? parent, string relativePath, IReadOnlyList filters) - { - // Walk over all child nodes in the current tree. If a child node was found in the parent, - // remove it, so that after the iteration the parent contains all nodes which have been - // deleted. - foreach (var child in tree.Children) - { - var entry = child.Value; - GitTreeEntry? parentEntry = null; - - // If the entry is not present in the parent commit, it was added; - // if the Sha does not match, it was modified. - if (parent is null || - !parent.Children.TryGetValue(child.Key, out parentEntry) || - parentEntry.Sha != child.Value.Sha) - { - // Determine whether the change was relevant. - var fullPath = $"{relativePath}{entry.Name}"; - - bool isRelevant = - // Either there are no include filters at all (i.e. everything is included), or there's an explicit include filter - (!filters.Any(f => f.IsInclude) || filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)) - || (!entry.IsFile && filters.Any(f => f.IncludesChildren(fullPath, repository.IgnoreCase)))) - // The path is not excluded by any filters - && !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase)); - - // If the change was relevant, and the item is a directory, we need to recurse. - if (isRelevant && !entry.IsFile) - { - isRelevant = IsRelevantCommit( - repository, - repository.GetTree(entry.Sha), - parentEntry is null ? GitTree.Empty : repository.GetTree(parentEntry.Sha), - $"{fullPath}/", - filters); - } - - // Quit as soon as any relevant change has been detected. - if (isRelevant) - { - return true; - } - } - - if (parentEntry is not null) - { - Assumes.NotNull(parent); - parent.Children.Remove(child.Key); - } - } - - // Inspect removed entries (i.e. present in parent but not in the current tree) - if (parent is not null) - { - foreach (var child in parent.Children) - { - // Determine whether the change was relevant. - var fullPath = Path.Combine(relativePath, child.Key); - - bool isRelevant = - filters.Any(f => f.Includes(fullPath, repository.IgnoreCase)) - && !filters.Any(f => f.Excludes(fullPath, repository.IgnoreCase)); - - if (isRelevant) - { - return true; - } - } - } - - // No relevant changes have been detected - return false; - } - - /// - /// Takes the first 2 bytes of a commit ID (i.e. first 4 characters of its hex-encoded SHA) - /// and returns them as an 16-bit unsigned integer. - /// - /// The commit to identify with an integer. - /// The unsigned integer which identifies a commit. - public static ushort GetTruncatedCommitIdAsUInt16(this GitCommit commit) - { - return commit.Sha.AsUInt16(); - } - - private class GitWalkTracker - { - private readonly Dictionary commitVersionCache = new Dictionary(); - private readonly Dictionary blobVersionCache = new Dictionary(); - private readonly Dictionary heights = new Dictionary(); - private readonly ManagedGitContext context; - - internal GitWalkTracker(ManagedGitContext context) - { - this.context = context; - } - - internal bool TryGetVersionHeight(GitCommit commit, out int height) => this.heights.TryGetValue(commit.Sha, out height); - - internal void RecordHeight(GitCommit commit, int height) => this.heights.Add(commit.Sha, height); - - internal VersionOptions? GetVersion(GitCommit commit) - { - if (!this.commitVersionCache.TryGetValue(commit.Sha, out VersionOptions? options)) - { - try - { - options = ((ManagedVersionFile)this.context.VersionFile).GetVersion(commit, this.context.RepoRelativeProjectDirectory, this.blobVersionCache, out string? actualDirectory); - } - catch (Exception ex) - { - throw new InvalidOperationException($"Unable to get version from commit: {commit.Sha}", ex); - } - - this.commitVersionCache.Add(commit.Sha, options); - } - - return options; - } - } - } -} diff --git a/src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs b/src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs index 06e9e8ee..777a2c18 100644 --- a/src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs +++ b/src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs @@ -1,186 +1,182 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.Managed +using System.Text; +using Nerdbank.GitVersioning.ManagedGit; +using Newtonsoft.Json; + +#nullable enable + +namespace Nerdbank.GitVersioning.Managed; + +/// +/// Exposes queries and mutations on a version.json or version.txt file, +/// implemented in terms of our private managed git implementation. +/// +internal class ManagedVersionFile : VersionFile { - using System; - using System.Collections.Generic; - using System.IO; - using System.Text; - using Nerdbank.GitVersioning; - using Nerdbank.GitVersioning.ManagedGit; - using Newtonsoft.Json; - using Validation; + /// + /// The filename of the version.txt file, as a byte array. + /// + private static readonly byte[] TxtFileNameBytes = Encoding.ASCII.GetBytes(TxtFileName); /// - /// Exposes queries and mutations on a version.json or version.txt file, - /// implemented in terms of our private managed git implementation. + /// The filename of the version.json file, as a byte array. /// - internal class ManagedVersionFile : VersionFile - { - /// - /// The filename of the version.txt file, as a byte array. - /// - private static readonly byte[] TxtFileNameBytes = Encoding.ASCII.GetBytes(TxtFileName); - - /// - /// The filename of the version.json file, as a byte array. - /// - private static readonly byte[] JsonFileNameBytes = Encoding.ASCII.GetBytes(JsonFileName); - - /// - /// Initializes a new instance of the class. - /// - /// - public ManagedVersionFile(GitContext context) - : base(context) - { - } + private static readonly byte[] JsonFileNameBytes = Encoding.ASCII.GetBytes(JsonFileName); - protected new ManagedGitContext Context => (ManagedGitContext)base.Context; + /// + /// Initializes a new instance of the class. + /// + /// + public ManagedVersionFile(GitContext context) + : base(context) + { + } - protected override VersionOptions? GetVersionCore(out string? actualDirectory) => this.GetVersion(this.Context.Commit!.Value, this.Context.RepoRelativeProjectDirectory, null, out actualDirectory); + protected new ManagedGitContext Context => (ManagedGitContext)base.Context; - /// - /// Reads the version.json file and returns the deserialized from it. - /// - /// The commit to read from. - /// The directory to consider when searching for the version.txt file. - /// An optional blob cache for storing the raw parse results of a version.txt or version.json file (before any inherit merge operations are applied). - /// Receives the full path to the directory in which the version file was found. - /// The version information read from the file. - internal VersionOptions? GetVersion(GitCommit commit, string repoRelativeProjectDirectory, Dictionary? blobVersionCache, out string? actualDirectory) - { - Stack directories = new Stack(); + /// + /// Reads the version.json file and returns the deserialized from it. + /// + /// The commit to read from. + /// The directory to consider when searching for the version.txt file. + /// An optional blob cache for storing the raw parse results of a version.txt or version.json file (before any inherit merge operations are applied). + /// Receives the full path to the directory in which the version file was found. + /// The version information read from the file. + internal VersionOptions? GetVersion(GitCommit commit, string repoRelativeProjectDirectory, Dictionary? blobVersionCache, out string? actualDirectory) + { + var directories = new Stack(); - string? currentDirectory = repoRelativeProjectDirectory; + string? currentDirectory = repoRelativeProjectDirectory; - while (!string.IsNullOrEmpty(currentDirectory)) - { - directories.Push(Path.GetFileName(currentDirectory)); - currentDirectory = Path.GetDirectoryName(currentDirectory); - } + while (!string.IsNullOrEmpty(currentDirectory)) + { + directories.Push(Path.GetFileName(currentDirectory)); + currentDirectory = Path.GetDirectoryName(currentDirectory); + } - GitObjectId tree = commit.Tree; - string? searchDirectory = string.Empty; - string? parentDirectory = null; + GitObjectId tree = commit.Tree; + string? searchDirectory = string.Empty; + string? parentDirectory = null; - VersionOptions? finalResult = null; - actualDirectory = null; + VersionOptions? finalResult = null; + actualDirectory = null; - while (tree != GitObjectId.Empty) + while (tree != GitObjectId.Empty) + { + GitObjectId versionTxtBlob = this.Context.Repository.GetTreeEntry(tree, TxtFileNameBytes); + if (versionTxtBlob != GitObjectId.Empty) { - var versionTxtBlob = this.Context.Repository.GetTreeEntry(tree, TxtFileNameBytes); - if (versionTxtBlob != GitObjectId.Empty) + if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionTxtBlob, out VersionOptions? result)) { - if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionTxtBlob, out VersionOptions? result)) + result = TryReadVersionFile(new StreamReader(this.Context.Repository.GetObjectBySha(versionTxtBlob, "blob")!)); + if (blobVersionCache is object) { - result = TryReadVersionFile(new StreamReader(this.Context.Repository.GetObjectBySha(versionTxtBlob, "blob")!)); - if (blobVersionCache is object) - { - result?.Freeze(); - blobVersionCache.Add(versionTxtBlob, result); - } + result?.Freeze(); + blobVersionCache.Add(versionTxtBlob, result); } + } - if (result is object) - { - finalResult = result; - actualDirectory = Path.Combine(this.Context.WorkingTreePath, searchDirectory); - } + if (result is object) + { + finalResult = result; + actualDirectory = Path.Combine(this.Context.WorkingTreePath, searchDirectory); } + } - var versionJsonBlob = this.Context.Repository.GetTreeEntry(tree, JsonFileNameBytes); - if (versionJsonBlob != GitObjectId.Empty) + GitObjectId versionJsonBlob = this.Context.Repository.GetTreeEntry(tree, JsonFileNameBytes); + if (versionJsonBlob != GitObjectId.Empty) + { + string? versionJsonContent = null; + if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionJsonBlob, out VersionOptions? result)) { - string? versionJsonContent = null; - if (blobVersionCache is null || !blobVersionCache.TryGetValue(versionJsonBlob, out VersionOptions? result)) + using (var sr = new StreamReader(this.Context.Repository.GetObjectBySha(versionJsonBlob, "blob")!)) { - using (var sr = new StreamReader(this.Context.Repository.GetObjectBySha(versionJsonBlob, "blob")!)) - { - versionJsonContent = sr.ReadToEnd(); - } + versionJsonContent = sr.ReadToEnd(); + } - try - { - result = TryReadVersionJsonContent(versionJsonContent, searchDirectory); - } - catch (FormatException ex) - { - throw new FormatException( - $"Failure while reading {JsonFileName} from commit {this.Context.GitCommitId}. " + - "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + - "https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/migrating.md", ex); - } + try + { + result = TryReadVersionJsonContent(versionJsonContent, searchDirectory); + } + catch (FormatException ex) + { + throw new FormatException( + $"Failure while reading {JsonFileName} from commit {this.Context.GitCommitId}. " + + "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + + "https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/migrating.md", + ex); + } - if (blobVersionCache is object) - { - result?.Freeze(); - blobVersionCache.Add(versionJsonBlob, result); - } + if (blobVersionCache is object) + { + result?.Freeze(); + blobVersionCache.Add(versionJsonBlob, result); } + } - if (result?.Inherit ?? false) + if (result?.Inherit ?? false) + { + if (parentDirectory is object) { - if (parentDirectory is object) + result = this.GetVersion(commit, parentDirectory, blobVersionCache, out string? resultingDirectory); + if (result is object) { - result = this.GetVersion(commit, parentDirectory, blobVersionCache, out string? resultingDirectory); - if (result is object) + if (versionJsonContent is null) { - if (versionJsonContent is null) - { - // We reused a cache VersionOptions, but now we need the actual JSON string. - using (var sr = new StreamReader(this.Context.Repository.GetObjectBySha(versionJsonBlob, "blob")!)) - { - versionJsonContent = sr.ReadToEnd(); - } - } - - if (result.IsFrozen) - { - result = new VersionOptions(result); - } - - JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: searchDirectory)); - finalResult = result; + // We reused a cache VersionOptions, but now we need the actual JSON string. + using var sr = new StreamReader(this.Context.Repository.GetObjectBySha(versionJsonBlob, "blob")!); + versionJsonContent = sr.ReadToEnd(); } - else + + if (result.IsFrozen) { - var candidatePath = Path.Combine(searchDirectory, JsonFileName); - throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); + result = new VersionOptions(result); } + + JsonConvert.PopulateObject(versionJsonContent, result, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: searchDirectory)); + finalResult = result; } else { - var candidatePath = Path.Combine(searchDirectory, JsonFileName); + string? candidatePath = Path.Combine(searchDirectory, JsonFileName); throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); } } - - if (result is object) + else { - actualDirectory = Path.Combine(this.Context.WorkingTreePath, searchDirectory); - finalResult = result; + string? candidatePath = Path.Combine(searchDirectory, JsonFileName); + throw new InvalidOperationException($"\"{candidatePath}\" inherits from a parent directory version.json file but none exists."); } } - - if (directories.Count > 0) - { - var directoryName = directories.Pop(); - tree = this.Context.Repository.GetTreeEntry(tree, GitRepository.Encoding.GetBytes(directoryName)); - parentDirectory = searchDirectory; - searchDirectory = Path.Combine(searchDirectory, directoryName); - } - else + if (result is object) { - tree = GitObjectId.Empty; - parentDirectory = null; - searchDirectory = null; - break; + actualDirectory = Path.Combine(this.Context.WorkingTreePath, searchDirectory); + finalResult = result; } } - return finalResult; + if (directories.Count > 0) + { + string? directoryName = directories.Pop(); + tree = this.Context.Repository.GetTreeEntry(tree, GitRepository.Encoding.GetBytes(directoryName)); + parentDirectory = searchDirectory; + searchDirectory = Path.Combine(searchDirectory, directoryName); + } + else + { + tree = GitObjectId.Empty; + parentDirectory = null; + searchDirectory = null; + break; + } } + + return finalResult; } + + /// + protected override VersionOptions? GetVersionCore(out string? actualDirectory) => this.GetVersion(this.Context.Commit!.Value, this.Context.RepoRelativeProjectDirectory, null, out actualDirectory); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs b/src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs index 149da05a..d26ec03d 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs @@ -1,27 +1,29 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.ManagedGit +#nullable enable + +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Represents an instruction in a deltified stream. +/// +/// +public struct DeltaInstruction { /// - /// Represents an instruction in a deltified stream. + /// Gets or sets the type of the current instruction. /// - /// - public struct DeltaInstruction - { - /// - /// Gets or sets the type of the current instruction. - /// - public DeltaInstructionType InstructionType; + public DeltaInstructionType InstructionType; - /// - /// If the is , - /// the offset of the base stream to start copying from. - /// - public int Offset; + /// + /// If the is , + /// the offset of the base stream to start copying from. + /// + public int Offset; - /// - /// The number of bytes to copy or insert. - /// - public int Size; - } + /// + /// The number of bytes to copy or insert. + /// + public int Size; } diff --git a/src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs b/src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs index 8373bf82..efabe4d1 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs @@ -1,21 +1,23 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.ManagedGit +#nullable enable + +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Enumerates the various instruction types which can be found in a deltafied stream. +/// +/// +public enum DeltaInstructionType { /// - /// Enumerates the various instruction types which can be found in a deltafied stream. + /// Instructs the caller to insert a new byte range into the object. /// - /// - public enum DeltaInstructionType - { - /// - /// Instructs the caller to insert a new byte range into the object. - /// - Insert = 0, + Insert = 0, - /// - /// Instructs the caller to copy a byte range from the source object. - /// - Copy = 1, - } + /// + /// Instructs the caller to copy a byte range from the source object. + /// + Copy = 1, } diff --git a/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs b/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs index 08ee301e..d16d4a57 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs @@ -1,173 +1,172 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.IO; +#nullable enable -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Reads delta instructions from a . +/// +/// +public static class DeltaStreamReader { /// - /// Reads delta instructions from a . + /// Reads the next instruction from a . /// - /// - public static class DeltaStreamReader + /// + /// The stream from which to read the instruction. + /// + /// + /// The next instruction if found; otherwise, . + /// + public static DeltaInstruction? Read(Stream stream) { - /// - /// Reads the next instruction from a . - /// - /// - /// The stream from which to read the instruction. - /// - /// - /// The next instruction if found; otherwise, . - /// - public static DeltaInstruction? Read(Stream stream) + int next = stream.ReadByte(); + + if (next == -1) { - int next = stream.ReadByte(); + return null; + } + + byte instruction = (byte)next; + + DeltaInstruction value; + value.Offset = 0; + value.Size = 0; + + value.InstructionType = (DeltaInstructionType)((instruction & 0b1000_0000) >> 7); - if (next == -1) + if (value.InstructionType == DeltaInstructionType.Insert) + { + value.Size = instruction & 0b0111_1111; + } + else if (value.InstructionType == DeltaInstructionType.Copy) + { + // offset1 + if ((instruction & 0b0000_0001) != 0) { - return null; + value.Offset |= (byte)stream.ReadByte(); } - byte instruction = (byte)next; + // offset2 + if ((instruction & 0b0000_0010) != 0) + { + value.Offset |= (byte)stream.ReadByte() << 8; + } - DeltaInstruction value; - value.Offset = 0; - value.Size = 0; + // offset3 + if ((instruction & 0b0000_0100) != 0) + { + value.Offset |= (byte)stream.ReadByte() << 16; + } - value.InstructionType = (DeltaInstructionType)((instruction & 0b1000_0000) >> 7); + // offset4 + if ((instruction & 0b0000_1000) != 0) + { + value.Offset |= (byte)stream.ReadByte() << 24; + } - if (value.InstructionType == DeltaInstructionType.Insert) + // size1 + if ((instruction & 0b0001_0000) != 0) { - value.Size = instruction & 0b0111_1111; + value.Size = (byte)stream.ReadByte(); } - else if (value.InstructionType == DeltaInstructionType.Copy) + + // size2 + if ((instruction & 0b0010_0000) != 0) { - // offset1 - if ((instruction & 0b0000_0001) != 0) - { - value.Offset |= (byte)stream.ReadByte(); - } - - // offset2 - if ((instruction & 0b0000_0010) != 0) - { - value.Offset |= ((byte)stream.ReadByte() << 8); - } - - // offset3 - if ((instruction & 0b0000_0100) != 0) - { - value.Offset |= ((byte)stream.ReadByte() << 16); - } - - // offset4 - if ((instruction & 0b0000_1000) != 0) - { - value.Offset |= ((byte)stream.ReadByte() << 24); - } - - // size1 - if ((instruction & 0b0001_0000) != 0) - { - value.Size = (byte)stream.ReadByte(); - } - - // size2 - if ((instruction & 0b0010_0000) != 0) - { - value.Size |= ((byte)stream.ReadByte() << 8); - } - - // size3 - if ((instruction & 0b0100_0000) != 0) - { - value.Size |= ((byte)stream.ReadByte() << 16); - } + value.Size |= (byte)stream.ReadByte() << 8; } - return value; + // size3 + if ((instruction & 0b0100_0000) != 0) + { + value.Size |= (byte)stream.ReadByte() << 16; + } } - /// - /// Reads the next instruction from a . - /// - /// - /// The stream from which to read the instruction. - /// - /// - /// The next instruction if found; otherwise, . - /// - public static DeltaInstruction? Read(ref ReadOnlyMemory stream) + return value; + } + + /// + /// Reads the next instruction from a . + /// + /// + /// The stream from which to read the instruction. + /// + /// + /// The next instruction if found; otherwise, . + /// + public static DeltaInstruction? Read(ref ReadOnlyMemory stream) + { + if (stream.Length == 0) { - if (stream.Length == 0) + return null; + } + + ReadOnlySpan span = stream.Span; + int i = 0; + int next = span[i++]; + + byte instruction = (byte)next; + + DeltaInstruction value; + value.Offset = 0; + value.Size = 0; + + value.InstructionType = (DeltaInstructionType)((instruction & 0b1000_0000) >> 7); + + if (value.InstructionType == DeltaInstructionType.Insert) + { + value.Size = instruction & 0b0111_1111; + } + else if (value.InstructionType == DeltaInstructionType.Copy) + { + // offset1 + if ((instruction & 0b0000_0001) != 0) { - return null; + value.Offset |= span[i++]; } - var span = stream.Span; - int i = 0; - int next = span[i++]; - - byte instruction = (byte)next; + // offset2 + if ((instruction & 0b0000_0010) != 0) + { + value.Offset |= span[i++] << 8; + } - DeltaInstruction value; - value.Offset = 0; - value.Size = 0; + // offset3 + if ((instruction & 0b0000_0100) != 0) + { + value.Offset |= span[i++] << 16; + } - value.InstructionType = (DeltaInstructionType)((instruction & 0b1000_0000) >> 7); + // offset4 + if ((instruction & 0b0000_1000) != 0) + { + value.Offset |= span[i++] << 24; + } - if (value.InstructionType == DeltaInstructionType.Insert) + // size1 + if ((instruction & 0b0001_0000) != 0) { - value.Size = instruction & 0b0111_1111; + value.Size = span[i++]; } - else if (value.InstructionType == DeltaInstructionType.Copy) + + // size2 + if ((instruction & 0b0010_0000) != 0) { - // offset1 - if ((instruction & 0b0000_0001) != 0) - { - value.Offset |= span[i++]; - } - - // offset2 - if ((instruction & 0b0000_0010) != 0) - { - value.Offset |= (span[i++] << 8); - } - - // offset3 - if ((instruction & 0b0000_0100) != 0) - { - value.Offset |= (span[i++] << 16); - } - - // offset4 - if ((instruction & 0b0000_1000) != 0) - { - value.Offset |= (span[i++] << 24); - } - - // size1 - if ((instruction & 0b0001_0000) != 0) - { - value.Size = span[i++]; - } - - // size2 - if ((instruction & 0b0010_0000) != 0) - { - value.Size |= (span[i++] << 8); - } - - // size3 - if ((instruction & 0b0100_0000) != 0) - { - value.Size |= (span[i++] << 16); - } + value.Size |= span[i++] << 8; } - stream = stream.Slice(i); - return value; + // size3 + if ((instruction & 0b0100_0000) != 0) + { + value.Size |= span[i++] << 16; + } } + + stream = stream.Slice(i); + return value; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs index e1d9713b..5d2cf46a 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs @@ -1,108 +1,108 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using Windows.Win32; using Windows.Win32.Storage.FileSystem; using Windows.Win32.System.SystemServices; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +internal static class FileHelpers { - internal static class FileHelpers - { - private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); + private static readonly bool IsWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows); - /// - /// Opens the file with a given path, if it exists. - /// - /// The path to the file. - /// The stream to open to, if the file exists. - /// if the file exists; otherwise . - internal static bool TryOpen(string path, out FileStream? stream) + /// + /// Opens the file with a given path, if it exists. + /// + /// The path to the file. + /// The stream to open to, if the file exists. + /// if the file exists; otherwise . + internal static bool TryOpen(string path, out FileStream? stream) + { + if (IsWindows) { - if (IsWindows) - { - var handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); + SafeFileHandle? handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); - if (!handle.IsInvalid) - { - var fileHandle = new SafeFileHandle(handle.DangerousGetHandle(), ownsHandle: true); - handle.SetHandleAsInvalid(); - stream = new FileStream(fileHandle, System.IO.FileAccess.Read); - return true; - } - else - { - stream = null; - return false; - } + if (!handle.IsInvalid) + { + var fileHandle = new SafeFileHandle(handle.DangerousGetHandle(), ownsHandle: true); + handle.SetHandleAsInvalid(); + stream = new FileStream(fileHandle, System.IO.FileAccess.Read); + return true; } else { - if (!File.Exists(path)) - { - stream = null; - return false; - } - - stream = File.OpenRead(path); - return true; + stream = null; + return false; } } + else + { + if (!File.Exists(path)) + { + stream = null; + return false; + } + + stream = File.OpenRead(path); + return true; + } + } - /// - /// Opens the file with a given path, if it exists. - /// - /// The path to the file, as a null-terminated UTF-16 character array. - /// The stream to open to, if the file exists. - /// if the file exists; otherwise . - internal static unsafe bool TryOpen(ReadOnlySpan path, [NotNullWhen(true)] out FileStream? stream) + /// + /// Opens the file with a given path, if it exists. + /// + /// The path to the file, as a null-terminated UTF-16 character array. + /// The stream to open to, if the file exists. + /// if the file exists; otherwise . + internal static unsafe bool TryOpen(ReadOnlySpan path, [NotNullWhen(true)] out FileStream? stream) + { + if (IsWindows) { - if (IsWindows) + HANDLE handle; + fixed (char* pPath = &path[0]) { - HANDLE handle; - fixed (char* pPath = &path[0]) - { - handle = PInvoke.CreateFile(pPath, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default); - } + handle = PInvoke.CreateFile(pPath, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default); + } - if (!handle.Equals(Constants.INVALID_HANDLE_VALUE)) - { - var fileHandle = new SafeFileHandle(handle, ownsHandle: true); - stream = new FileStream(fileHandle, System.IO.FileAccess.Read); - return true; - } - else - { - stream = null; - return false; - } + if (!handle.Equals(Constants.INVALID_HANDLE_VALUE)) + { + var fileHandle = new SafeFileHandle(handle, ownsHandle: true); + stream = new FileStream(fileHandle, System.IO.FileAccess.Read); + return true; } else { - // Make sure to trim the trailing \0 - string fullPath = GetUtf16String(path.Slice(0, path.Length - 1)); - - if (!File.Exists(fullPath)) - { - stream = null; - return false; - } - - stream = File.OpenRead(fullPath); - return true; + stream = null; + return false; } } - - private static unsafe string GetUtf16String(ReadOnlySpan chars) + else { - fixed (char* pChars = chars) + // Make sure to trim the trailing \0 + string fullPath = GetUtf16String(path.Slice(0, path.Length - 1)); + + if (!File.Exists(fullPath)) { - return new string(pChars, 0, chars.Length); + stream = null; + return false; } + + stream = File.OpenRead(fullPath); + return true; + } + } + + private static unsafe string GetUtf16String(ReadOnlySpan chars) + { + fixed (char* pChars = chars) + { + return new string(pChars, 0, chars.Length); } } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs b/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs index 2e27acd5..2e01be1d 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs @@ -1,175 +1,173 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Collections; -using System.Collections.Generic; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Represents a Git commit, as stored in the Git object database. +/// +public struct GitCommit : IEquatable { /// - /// Represents a Git commit, as stored in the Git object database. + /// Gets or sets the of the file tree which represents directory + /// structure of the repository at the time of the commit. /// - public struct GitCommit : IEquatable - { - /// - /// Gets or sets the of the file tree which represents directory - /// structure of the repository at the time of the commit. - /// - public GitObjectId Tree { get; set; } + public GitObjectId Tree { get; set; } - /// - /// Gets or sets a which uniquely identifies the . - /// - public GitObjectId Sha { get; set; } + /// + /// Gets or sets a which uniquely identifies the . + /// + public GitObjectId Sha { get; set; } - /// - /// Gets or sets the first parent of this commit. - /// - public GitObjectId? FirstParent { get; set; } + /// + /// Gets or sets the first parent of this commit. + /// + public GitObjectId? FirstParent { get; set; } - /// - /// Gets or sets the second parent of this commit. - /// - public GitObjectId? SecondParent { get; set; } + /// + /// Gets or sets the second parent of this commit. + /// + public GitObjectId? SecondParent { get; set; } - /// - /// Gets or sets additional parents (3rd parent and on) of this commit, if any. - /// - public List? AdditionalParents { get; set; } + /// + /// Gets or sets additional parents (3rd parent and on) of this commit, if any. + /// + public List? AdditionalParents { get; set; } - /// - /// Gets an enumerator for parents of this commit. - /// - public ParentEnumerable Parents => new ParentEnumerable(this); + /// + /// Gets an enumerator for parents of this commit. + /// + public ParentEnumerable Parents => new ParentEnumerable(this); - /// - /// Gets or sets the author of this commit. - /// - public GitSignature? Author { get; set; } + /// + /// Gets or sets the author of this commit. + /// + public GitSignature? Author { get; set; } - /// - public override bool Equals(object? obj) - { - if (obj is GitCommit) - { - return this.Equals((GitCommit)obj); - } + public static bool operator ==(GitCommit left, GitCommit right) + { + return Equals(left, right); + } - return false; - } + public static bool operator !=(GitCommit left, GitCommit right) + { + return !Equals(left, right); + } - /// - public bool Equals(GitCommit other) + /// + public override bool Equals(object? obj) + { + if (obj is GitCommit) { - return this.Sha.Equals(other.Sha); + return this.Equals((GitCommit)obj); } - /// - public static bool operator ==(GitCommit left, GitCommit right) - { - return Equals(left, right); - } + return false; + } - /// - public static bool operator !=(GitCommit left, GitCommit right) - { - return !Equals(left, right); - } + /// + public bool Equals(GitCommit other) + { + return this.Sha.Equals(other.Sha); + } - /// - public override int GetHashCode() - { - return this.Sha.GetHashCode(); - } + /// + public override int GetHashCode() + { + return this.Sha.GetHashCode(); + } - /// - public override string ToString() - { - return $"Git Commit: {this.Sha}"; - } + /// + public override string ToString() + { + return $"Git Commit: {this.Sha}"; + } + + /// + /// An enumerable for parents of a commit. + /// + public struct ParentEnumerable : IEnumerable + { + private readonly GitCommit owner; /// - /// An enumerable for parents of a commit. + /// Initializes a new instance of the struct. /// - public struct ParentEnumerable : IEnumerable + /// The commit whose parents are to be enumerated. + public ParentEnumerable(GitCommit owner) { - private readonly GitCommit owner; + this.owner = owner; + } - /// - /// Initializes an instance of the struct. - /// - /// The commit whose parents are to be enumerated. - public ParentEnumerable(GitCommit owner) - { - this.owner = owner; - } + /// + public IEnumerator GetEnumerator() => new ParentEnumerator(this.owner); - /// - public IEnumerator GetEnumerator() => new ParentEnumerator(this.owner); + /// + IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); + } - /// - IEnumerator IEnumerable.GetEnumerator() => this.GetEnumerator(); - } + /// + /// An enumerator for a commit's parents. + /// + public struct ParentEnumerator : IEnumerator + { + private readonly GitCommit owner; + + private int position; /// - /// An enumerator for a commit's parents. + /// Initializes a new instance of the struct. /// - public struct ParentEnumerator : IEnumerator + /// The commit whose parents are to be enumerated. + public ParentEnumerator(GitCommit owner) { - private readonly GitCommit owner; - - private int position; - - /// - /// Initializes an instance of the struct. - /// - /// The commit whose parents are to be enumerated. - public ParentEnumerator(GitCommit owner) - { - this.owner = owner; - this.position = -1; - } + this.owner = owner; + this.position = -1; + } - /// - public GitObjectId Current + /// + public GitObjectId Current + { + get { - get + if (this.position < 0) { - if (this.position < 0) - { - throw new InvalidOperationException("Call MoveNext first."); - } - - return this.position switch - { - 0 => this.owner.FirstParent ?? throw new InvalidOperationException("No more elements."), - 1 => this.owner.SecondParent ?? throw new InvalidOperationException("No more elements."), - _ => this.owner.AdditionalParents?[this.position - 2] ?? throw new InvalidOperationException("No more elements."), - }; + throw new InvalidOperationException("Call MoveNext first."); } - } - - /// - object IEnumerator.Current => this.Current; - /// - public void Dispose() - { - } - - /// - public bool MoveNext() - { - return ++this.position switch + return this.position switch { - 0 => this.owner.FirstParent.HasValue, - 1 => this.owner.SecondParent.HasValue, - _ => this.owner.AdditionalParents?.Count > this.position - 2, + 0 => this.owner.FirstParent ?? throw new InvalidOperationException("No more elements."), + 1 => this.owner.SecondParent ?? throw new InvalidOperationException("No more elements."), + _ => this.owner.AdditionalParents?[this.position - 2] ?? throw new InvalidOperationException("No more elements."), }; } + } + + /// + object IEnumerator.Current => this.Current; + + /// + public void Dispose() + { + } - /// - public void Reset() => this.position = -1; + /// + public bool MoveNext() + { + return ++this.position switch + { + 0 => this.owner.FirstParent.HasValue, + 1 => this.owner.SecondParent.HasValue, + _ => this.owner.AdditionalParents?.Count > this.position - 2, + }; } + + /// + public void Reset() => this.position = -1; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs index 8af84e05..e4629e2a 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs @@ -1,186 +1,184 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers; -using System.Collections.Generic; using System.Diagnostics; -using System.IO; -using System.Linq; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Reads a object. +/// +public static class GitCommitReader { + private const int TreeLineLength = 46; + private const int ParentLineLength = 48; + + private static readonly byte[] TreeStart = GitRepository.Encoding.GetBytes("tree "); + private static readonly byte[] ParentStart = GitRepository.Encoding.GetBytes("parent "); + private static readonly byte[] AuthorStart = GitRepository.Encoding.GetBytes("author "); + /// - /// Reads a object. + /// Reads a object from a . /// - public static class GitCommitReader + /// + /// A which contains the in its text representation. + /// + /// + /// The of the commit. + /// + /// + /// A value indicating whether to populate the field. + /// + /// + /// The . + /// + public static GitCommit Read(Stream stream, GitObjectId sha, bool readAuthor = false) { - private static readonly byte[] TreeStart = GitRepository.Encoding.GetBytes("tree "); - private static readonly byte[] ParentStart = GitRepository.Encoding.GetBytes("parent "); - private static readonly byte[] AuthorStart = GitRepository.Encoding.GetBytes("author "); - - private const int TreeLineLength = 46; - private const int ParentLineLength = 48; - - /// - /// Reads a object from a . - /// - /// - /// A which contains the in its text representation. - /// - /// - /// The of the commit. - /// - /// - /// A value indicating whether to populate the field. - /// - /// - /// The . - /// - public static GitCommit Read(Stream stream, GitObjectId sha, bool readAuthor = false) + if (stream is null) { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } + throw new ArgumentNullException(nameof(stream)); + } - byte[] buffer = ArrayPool.Shared.Rent((int)stream.Length); + byte[] buffer = ArrayPool.Shared.Rent((int)stream.Length); - try - { - Span span = buffer.AsSpan(0, (int)stream.Length); - stream.ReadAll(span); + try + { + Span span = buffer.AsSpan(0, (int)stream.Length); + stream.ReadAll(span); - return Read(span, sha, readAuthor); - } - finally - { - ArrayPool.Shared.Return(buffer); - } + return Read(span, sha, readAuthor); } - - /// - /// Reads a object from a . - /// - /// - /// A which contains the in its text representation. - /// - /// - /// The of the commit. - /// - /// - /// A value indicating whether to populate the field. - /// - /// - /// The . - /// - public static GitCommit Read(ReadOnlySpan commit, GitObjectId sha, bool readAuthor = false) + finally { - var buffer = commit; + ArrayPool.Shared.Return(buffer); + } + } - var tree = ReadTree(buffer.Slice(0, TreeLineLength)); + /// + /// Reads a object from a . + /// + /// + /// A which contains the in its text representation. + /// + /// + /// The of the commit. + /// + /// + /// A value indicating whether to populate the field. + /// + /// + /// The . + /// + public static GitCommit Read(ReadOnlySpan commit, GitObjectId sha, bool readAuthor = false) + { + ReadOnlySpan buffer = commit; - buffer = buffer.Slice(TreeLineLength); + GitObjectId tree = ReadTree(buffer.Slice(0, TreeLineLength)); - GitObjectId? firstParent = null, secondParent = null; - List? additionalParents = null; - List parents = new List(); - while (TryReadParent(buffer, out GitObjectId parent)) + buffer = buffer.Slice(TreeLineLength); + + GitObjectId? firstParent = null, secondParent = null; + List? additionalParents = null; + var parents = new List(); + while (TryReadParent(buffer, out GitObjectId parent)) + { + if (!firstParent.HasValue) { - if (!firstParent.HasValue) - { - firstParent = parent; - } - else if (!secondParent.HasValue) - { - secondParent = parent; - } - else - { - additionalParents ??= new List(); - additionalParents.Add(parent); - } - - buffer = buffer.Slice(ParentLineLength); + firstParent = parent; } - - GitSignature signature = default; - - if (readAuthor && !TryReadAuthor(buffer, out signature)) + else if (!secondParent.HasValue) { - throw new GitException(); + secondParent = parent; } - - return new GitCommit() + else { - Sha = sha, - FirstParent = firstParent, - SecondParent = secondParent, - AdditionalParents = additionalParents, - Tree = tree, - Author = readAuthor ? signature : (GitSignature?)null, - }; + additionalParents ??= new List(); + additionalParents.Add(parent); + } + + buffer = buffer.Slice(ParentLineLength); } - private static GitObjectId ReadTree(ReadOnlySpan line) + GitSignature signature = default; + + if (readAuthor && !TryReadAuthor(buffer, out signature)) { - // Format: tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579\n - // 47 bytes: - // tree: 5 bytes - // space: 1 byte - // hash: 40 bytes - // \n: 1 byte - Debug.Assert(line.Slice(0, TreeStart.Length).SequenceEqual(TreeStart)); - Debug.Assert(line[TreeLineLength - 1] == (byte)'\n'); - - return GitObjectId.ParseHex(line.Slice(TreeStart.Length, 40)); + throw new GitException(); } - private static bool TryReadParent(ReadOnlySpan line, out GitObjectId parent) + return new GitCommit() { - // Format: "parent ef079ebcca375f6fd54aa0cb9f35e3ecc2bb66e7\n" - parent = GitObjectId.Empty; + Sha = sha, + FirstParent = firstParent, + SecondParent = secondParent, + AdditionalParents = additionalParents, + Tree = tree, + Author = readAuthor ? signature : null, + }; + } - if (!line.Slice(0, ParentStart.Length).SequenceEqual(ParentStart)) - { - return false; - } + private static GitObjectId ReadTree(ReadOnlySpan line) + { + // Format: tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579\n + // 47 bytes: + // tree: 5 bytes + // space: 1 byte + // hash: 40 bytes + // \n: 1 byte + Debug.Assert(line.Slice(0, TreeStart.Length).SequenceEqual(TreeStart)); + Debug.Assert(line[TreeLineLength - 1] == (byte)'\n'); + + return GitObjectId.ParseHex(line.Slice(TreeStart.Length, 40)); + } - if (line[ParentLineLength - 1] != (byte)'\n') - { - return false; - } + private static bool TryReadParent(ReadOnlySpan line, out GitObjectId parent) + { + // Format: "parent ef079ebcca375f6fd54aa0cb9f35e3ecc2bb66e7\n" + parent = GitObjectId.Empty; - parent = GitObjectId.ParseHex(line.Slice(ParentStart.Length, 40)); - return true; + if (!line.Slice(0, ParentStart.Length).SequenceEqual(ParentStart)) + { + return false; } - private static bool TryReadAuthor(ReadOnlySpan line, out GitSignature signature) + if (line[ParentLineLength - 1] != (byte)'\n') { - signature = default; + return false; + } - if (!line.Slice(0, AuthorStart.Length).SequenceEqual(AuthorStart)) - { - return false; - } + parent = GitObjectId.ParseHex(line.Slice(ParentStart.Length, 40)); + return true; + } - line = line.Slice(AuthorStart.Length); + private static bool TryReadAuthor(ReadOnlySpan line, out GitSignature signature) + { + signature = default; - int emailStart = line.IndexOf((byte)'<'); - int emailEnd = line.IndexOf((byte)'>'); - var lineEnd = line.IndexOf((byte)'\n'); + if (!line.Slice(0, AuthorStart.Length).SequenceEqual(AuthorStart)) + { + return false; + } - var name = line.Slice(0, emailStart - 1); - var email = line.Slice(emailStart + 1, emailEnd - emailStart - 1); - var time = line.Slice(emailEnd + 2, lineEnd - emailEnd - 2); + line = line.Slice(AuthorStart.Length); - signature.Name = GitRepository.GetString(name); - signature.Email = GitRepository.GetString(email); + int emailStart = line.IndexOf((byte)'<'); + int emailEnd = line.IndexOf((byte)'>'); + int lineEnd = line.IndexOf((byte)'\n'); - var offsetStart = time.IndexOf((byte)' '); - var ticks = long.Parse(GitRepository.GetString(time.Slice(0, offsetStart))); - signature.Date = DateTimeOffset.FromUnixTimeSeconds(ticks); + ReadOnlySpan name = line.Slice(0, emailStart - 1); + ReadOnlySpan email = line.Slice(emailStart + 1, emailEnd - emailStart - 1); + ReadOnlySpan time = line.Slice(emailEnd + 2, lineEnd - emailEnd - 2); - return true; - } + signature.Name = GitRepository.GetString(name); + signature.Email = GitRepository.GetString(email); + + int offsetStart = time.IndexOf((byte)' '); + long ticks = long.Parse(GitRepository.GetString(time.Slice(0, offsetStart))); + signature.Date = DateTimeOffset.FromUnixTimeSeconds(ticks); + + return true; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs b/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs index 3e62f158..9dc03ef0 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs @@ -1,246 +1,245 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers.Binary; using System.Diagnostics; using System.Runtime.InteropServices; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// A identifies an object stored in the Git repository. The +/// of an object is the SHA-1 hash of the contents of that +/// object. +/// +/// . +public unsafe struct GitObjectId : IEquatable { + private const string HexDigits = "0123456789abcdef"; + private const int NativeSize = 20; + private static readonly byte[] HexBytes = new byte[] { (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' }; + private static readonly byte[] ReverseHexDigits = BuildReverseHexDigits(); + private fixed byte value[NativeSize]; + private string? sha; + /// - /// A identifies an object stored in the Git repository. The - /// of an object is the SHA-1 hash of the contents of that - /// object. + /// Gets a which represents an empty . /// - /// . - public unsafe struct GitObjectId : IEquatable + public static GitObjectId Empty => default(GitObjectId); + + /// + /// Gets the 20 byte ID of this object as a span from the field. + /// + private Span Value { - private const string hexDigits = "0123456789abcdef"; - private readonly static byte[] hexBytes = new byte[] { (byte)'0', (byte)'1', (byte)'2', (byte)'3', (byte)'4', (byte)'5', (byte)'6', (byte)'7', (byte)'8', (byte)'9', (byte)'a', (byte)'b', (byte)'c', (byte)'d', (byte)'e', (byte)'f' }; - private const int NativeSize = 20; - private fixed byte value[NativeSize]; - private string? sha; - - /// - /// Gets the 20 byte ID of this object as a span from the field. - /// - private Span Value + get { - get + fixed (byte* value = this.value) { - fixed (byte* value = this.value) - { - return new Span(value, NativeSize); - } + return new Span(value, NativeSize); } } + } - private static readonly byte[] ReverseHexDigits = BuildReverseHexDigits(); - - /// - /// Gets a which represents an empty . - /// - public static GitObjectId Empty => default(GitObjectId); - - /// - /// Parses a which contains the - /// as a sequence of byte values. - /// - /// - /// The as a sequence of byte values. Must be exactly 20 bytes in length. - /// - /// - /// A . - /// - public static GitObjectId Parse(ReadOnlySpan value) - { - Debug.Assert(value.Length == 20); + public static bool operator ==(GitObjectId left, GitObjectId right) => Equals(left, right); - GitObjectId objectId = new GitObjectId(); - value.CopyTo(objectId.Value); - return objectId; - } + public static bool operator !=(GitObjectId left, GitObjectId right) => !Equals(left, right); - /// - /// Parses a which contains the hexadecimal representation of a - /// . - /// - /// - /// A which contains the hexadecimal representation of the - /// . - /// - /// - /// A . - /// - public static GitObjectId Parse(string value) - { - Debug.Assert(value.Length == 40); + /// + /// Parses a which contains the + /// as a sequence of byte values. + /// + /// + /// The as a sequence of byte values. Must be exactly 20 bytes in length. + /// + /// + /// A . + /// + public static GitObjectId Parse(ReadOnlySpan value) + { + Debug.Assert(value.Length == 20); - GitObjectId objectId = new GitObjectId(); - Span bytes = objectId.Value; + var objectId = default(GitObjectId); + value.CopyTo(objectId.Value); + return objectId; + } - for (int i = 0; i < value.Length; i++) - { - int c1 = ReverseHexDigits[value[i++] - '0'] << 4; - int c2 = ReverseHexDigits[value[i] - '0']; + /// + /// Parses a which contains the hexadecimal representation of a + /// . + /// + /// + /// A which contains the hexadecimal representation of the + /// . + /// + /// + /// A . + /// + public static GitObjectId Parse(string value) + { + Debug.Assert(value.Length == 40); - bytes[i >> 1] = (byte)(c1 + c2); - } + var objectId = default(GitObjectId); + Span bytes = objectId.Value; + + for (int i = 0; i < value.Length; i++) + { + int c1 = ReverseHexDigits[value[i++] - '0'] << 4; + int c2 = ReverseHexDigits[value[i] - '0']; - objectId.sha = value.ToLower(); - return objectId; + bytes[i >> 1] = (byte)(c1 + c2); } - /// - /// Parses a which contains the hexadecimal representation of a - /// . - /// - /// - /// A which contains the hexadecimal representation of the - /// encoded in ASCII. - /// - /// - /// A . - /// - public static GitObjectId ParseHex(ReadOnlySpan value) - { - Debug.Assert(value.Length == 40); + objectId.sha = value.ToLower(); + return objectId; + } - GitObjectId objectId = new GitObjectId(); - Span bytes = objectId.Value; + /// + /// Parses a which contains the hexadecimal representation of a + /// . + /// + /// + /// A which contains the hexadecimal representation of the + /// encoded in ASCII. + /// + /// + /// A . + /// + public static GitObjectId ParseHex(ReadOnlySpan value) + { + Debug.Assert(value.Length == 40); - for (int i = 0; i < value.Length; i++) - { - int c1 = ReverseHexDigits[value[i++] - '0'] << 4; - int c2 = ReverseHexDigits[value[i] - '0']; + var objectId = default(GitObjectId); + Span bytes = objectId.Value; - bytes[i >> 1] = (byte)(c1 + c2); - } + for (int i = 0; i < value.Length; i++) + { + int c1 = ReverseHexDigits[value[i++] - '0'] << 4; + int c2 = ReverseHexDigits[value[i] - '0']; - return objectId; + bytes[i >> 1] = (byte)(c1 + c2); } - private static byte[] BuildReverseHexDigits() + return objectId; + } + + /// + public override bool Equals(object? obj) + { + if (obj is GitObjectId) { - var bytes = new byte['f' - '0' + 1]; + return this.Equals((GitObjectId)obj); + } - for (int i = 0; i < 10; i++) - { - bytes[i] = (byte)i; - } + return false; + } - for (int i = 10; i < 16; i++) - { - bytes[i + 'a' - '0' - 0x0a] = (byte)i; - bytes[i + 'A' - '0' - 0x0a] = (byte)i; - } + /// + public bool Equals(GitObjectId other) => this.Value.SequenceEqual(other.Value); - return bytes; - } + /// + public override int GetHashCode() => BinaryPrimitives.ReadInt32LittleEndian(this.Value.Slice(0, 4)); - /// - public override bool Equals(object? obj) - { - if (obj is GitObjectId) - { - return this.Equals((GitObjectId)obj); - } + /// + /// Gets a which represents the first two bytes of this . + /// + /// + /// A which represents the first two bytes of this . + /// + public ushort AsUInt16() => BinaryPrimitives.ReadUInt16BigEndian(this.Value.Slice(0, 2)); - return false; + /// + /// Returns the SHA1 hash of this object. + /// + /// + public override string ToString() + { + if (this.sha is null) + { + this.sha = this.CreateString(0, 20); } - /// - public bool Equals(GitObjectId other) => this.Value.SequenceEqual(other.Value); + return this.sha; + } - /// - public static bool operator ==(GitObjectId left, GitObjectId right) => Equals(left, right); + /// + /// Encodes a portion of this as hex. + /// + /// + /// The index of the first byte of this to start copying. + /// + /// + /// The number of bytes of this to copy. + /// + /// The buffer that receives the hex characters. It must be at least twice as long as . + /// + /// This method is used to populate file paths as byte* objects which are passed to UTF-16-based + /// Windows APIs. + /// + public void CopyAsHex(int start, int length, Span chars) + { + Span bytes = MemoryMarshal.Cast(chars); - /// - public static bool operator !=(GitObjectId left, GitObjectId right) => !Equals(left, right); + // Inspired by http://stackoverflow.com/questions/623104/c-byte-to-hex-string/3974535#3974535 + int lengthInNibbles = length * 2; + + for (int i = 0; i < (lengthInNibbles & -2); i++) + { + int index0 = +i >> 1; + byte b = (byte)(this.value[start + index0] >> 4); + bytes[(2 * i) + 1] = 0; + bytes[2 * i++] = HexBytes[b]; + + b = (byte)(this.value[start + index0] & 0x0F); + bytes[(2 * i) + 1] = 0; + bytes[2 * i] = HexBytes[b]; + } + } - /// - public override int GetHashCode() => BinaryPrimitives.ReadInt32LittleEndian(this.Value.Slice(0, 4)); + /// + /// Copies the byte representation of this to a . + /// + /// + /// The memory to which to copy this . + /// + public void CopyTo(Span value) => this.Value.CopyTo(value); - /// - /// Gets a which represents the first two bytes of this . - /// - /// - /// A which represents the first two bytes of this . - /// - public ushort AsUInt16() => BinaryPrimitives.ReadUInt16BigEndian(this.Value.Slice(0, 2)); + private static byte[] BuildReverseHexDigits() + { + byte[]? bytes = new byte['f' - '0' + 1]; - /// - /// Returns the SHA1 hash of this object. - /// - public override string ToString() + for (int i = 0; i < 10; i++) { - if (this.sha is null) - { - this.sha = this.CreateString(0, 20); - } - - return this.sha; + bytes[i] = (byte)i; } - private string CreateString(int start, int length) + for (int i = 10; i < 16; i++) { - // Inspired byte http://stackoverflow.com/questions/623104/c-byte-to-hex-string/3974535#3974535 - int lengthInNibbles = length * 2; - var c = new char[lengthInNibbles]; - - for (int i = 0; i < (lengthInNibbles & -2); i++) - { - int index0 = +i >> 1; - var b = ((byte)(this.value[start + index0] >> 4)); - c[i++] = hexDigits[b]; + bytes[i + 'a' - '0' - 0x0a] = (byte)i; + bytes[i + 'A' - '0' - 0x0a] = (byte)i; + } - b = ((byte)(this.value[start + index0] & 0x0F)); - c[i] = hexDigits[b]; - } + return bytes; + } - return new string(c); - } + private string CreateString(int start, int length) + { + // Inspired byte http://stackoverflow.com/questions/623104/c-byte-to-hex-string/3974535#3974535 + int lengthInNibbles = length * 2; + char[]? c = new char[lengthInNibbles]; - /// - /// Encodes a portion of this as hex. - /// - /// - /// The index of the first byte of this to start copying. - /// - /// - /// The number of bytes of this to copy. - /// - /// The buffer that receives the hex characters. It must be at least twice as long as . - /// - /// This method is used to populate file paths as byte* objects which are passed to UTF-16-based - /// Windows APIs. - /// - public void CopyAsHex(int start, int length, Span chars) + for (int i = 0; i < (lengthInNibbles & -2); i++) { - Span bytes = MemoryMarshal.Cast(chars); - - // Inspired by http://stackoverflow.com/questions/623104/c-byte-to-hex-string/3974535#3974535 - int lengthInNibbles = length * 2; + int index0 = +i >> 1; + byte b = (byte)(this.value[start + index0] >> 4); + c[i++] = HexDigits[b]; - for (int i = 0; i < (lengthInNibbles & -2); i++) - { - int index0 = +i >> 1; - var b = ((byte)(this.value[start + index0] >> 4)); - bytes[2 * i + 1] = 0; - bytes[2 * i++] = hexBytes[b]; - - b = ((byte)(this.value[start + index0] & 0x0F)); - bytes[2 * i + 1] = 0; - bytes[2 * i] = hexBytes[b]; - } + b = (byte)(this.value[start + index0] & 0x0F); + c[i] = HexDigits[b]; } - /// - /// Copies the byte representation of this to a . - /// - /// - /// The memory to which to copy this . - /// - public void CopyTo(Span value) => this.Value.CopyTo(value); + return new string(c); } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs index da8c5201..7b4749d0 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs @@ -1,74 +1,73 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.IO; +#nullable enable -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// A which reads data stored in the Git object store. The data is stored +/// as a gz-compressed stream, and is prefixed with the object type and data length. +/// +public class GitObjectStream : ZLibStream { /// - /// A which reads data stored in the Git object store. The data is stored - /// as a gz-compressed stream, and is prefixed with the object type and data length. + /// Initializes a new instance of the class. /// - public class GitObjectStream : ZLibStream - { - /// - /// Initializes a new instance of the class. - /// - /// - /// The from which to read data. - /// - /// - /// The expected object type of the git object. - /// + /// + /// The from which to read data. + /// + /// + /// The expected object type of the git object. + /// #pragma warning disable CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. ObjectType is assigned in ReadObjectTypeAndLength. - public GitObjectStream(Stream stream, string objectType) + public GitObjectStream(Stream stream, string objectType) #pragma warning restore CS8618 // Non-nullable field is uninitialized. Consider declaring as nullable. - : base(stream, -1) - { - this.ReadObjectTypeAndLength(objectType); - } - - /// - /// Gets the object type of this Git object. - /// - public string ObjectType { get; private set; } - - /// - public override bool CanRead => true; + : base(stream, -1) + { + this.ReadObjectTypeAndLength(objectType); + } - /// - public override bool CanSeek => true; + /// + /// Gets the object type of this Git object. + /// + public string ObjectType { get; private set; } - /// - public override bool CanWrite => false; + /// + public override bool CanRead => true; - private void ReadObjectTypeAndLength(string objectType) - { - Span buffer = stackalloc byte[128]; - this.Read(buffer.Slice(0, objectType.Length + 1)); + /// + public override bool CanSeek => true; - var actualObjectType = GitRepository.GetString(buffer.Slice(0, objectType.Length)); - this.ObjectType = actualObjectType; + /// + public override bool CanWrite => false; - int headerLength = 0; - long length = 0; + private void ReadObjectTypeAndLength(string objectType) + { + Span buffer = stackalloc byte[128]; + this.Read(buffer.Slice(0, objectType.Length + 1)); - while (headerLength < buffer.Length) - { - this.Read(buffer.Slice(headerLength, 1)); + string? actualObjectType = GitRepository.GetString(buffer.Slice(0, objectType.Length)); + this.ObjectType = actualObjectType; - if (buffer[headerLength] == 0) - { - break; - } + int headerLength = 0; + long length = 0; - // Direct conversion from ASCII to int - length = (10 * length) + (buffer[headerLength] - (byte)'0'); + while (headerLength < buffer.Length) + { + this.Read(buffer.Slice(headerLength, 1)); - headerLength += 1; + if (buffer[headerLength] == 0) + { + break; } - this.Initialize(length); + // Direct conversion from ASCII to int + length = (10 * length) + (buffer[headerLength] - (byte)'0'); + + headerLength += 1; } + + this.Initialize(length); } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs index 995659e6..8b093428 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs @@ -1,299 +1,297 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; -using System.Collections.Generic; -using System.IO; using System.IO.MemoryMappedFiles; -using System.Linq; using System.Text; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Supports retrieving objects from a Git pack file. +/// +public class GitPack : IDisposable { + private readonly Func packStream; + private readonly Lazy indexStream; + private readonly GitPackCache cache; + private readonly MemoryMappedFile? packFile = null; + private readonly MemoryMappedViewAccessor? accessor = null; + + // Maps GitObjectIds to offets in the git pack. + private readonly Dictionary offsets = new Dictionary(); + + // A histogram which tracks the objects which have been retrieved from this GitPack. The key is the offset + // of the object. Used to get some insights in usage patterns. +#if DEBUG + private readonly Dictionary histogram = new Dictionary(); +#endif + + private readonly Lazy indexReader; + + // Operating on git packfiles can potentially open a lot of streams which point to the pack file. For example, + // deltafied objects can have base objects which are in turn delafied. Opening and closing these streams has + // become a performance bottleneck. This is mitigated by pooling streams (i.e. reusing the streams after they + // are closed by the caller). + private readonly Queue pooledStreams = new Queue(); + /// - /// Supports retrieving objects from a Git pack file. + /// Initializes a new instance of the class. /// - public class GitPack : IDisposable + /// + /// A delegate which fetches objects from the Git object store. + /// + /// + /// The full path to the index file. + /// + /// + /// The full path to the pack file. + /// + /// + /// A which is used to cache objects which operate + /// on the pack file. + /// + public GitPack(GetObjectFromRepositoryDelegate getObjectFromRepositoryDelegate, string indexPath, string packPath, GitPackCache? cache = null) + : this(getObjectFromRepositoryDelegate, new Lazy(() => File.OpenRead(indexPath)), () => File.OpenRead(packPath), cache) { - /// - /// A delegate for methods which fetch objects from the Git object store. - /// - /// - /// The Git object ID of the object to fetch. - /// - /// - /// The object type of the object to fetch. - /// - /// - /// A which represents the requested object. - /// - public delegate Stream? GetObjectFromRepositoryDelegate(GitObjectId sha, string objectType); - - private readonly Func packStream; - private readonly Lazy indexStream; - private readonly GitPackCache cache; - private MemoryMappedFile? packFile = null; - private MemoryMappedViewAccessor? accessor = null; - - // Maps GitObjectIds to offets in the git pack. - private readonly Dictionary offsets = new Dictionary(); - - // A histogram which tracks the objects which have been retrieved from this GitPack. The key is the offset - // of the object. Used to get some insights in usage patterns. -#if DEBUG - private readonly Dictionary histogram = new Dictionary(); -#endif + } - private Lazy indexReader; - - // Operating on git packfiles can potentially open a lot of streams which point to the pack file. For example, - // deltafied objects can have base objects which are in turn delafied. Opening and closing these streams has - // become a performance bottleneck. This is mitigated by pooling streams (i.e. reusing the streams after they - // are closed by the caller). - private readonly Queue pooledStreams = new Queue(); - - /// - /// Initializes a new instance of the class. - /// - /// - /// A delegate which fetches objects from the Git object store. - /// - /// - /// The full path to the index file. - /// - /// - /// The full path to the pack file. - /// - /// - /// A which is used to cache objects which operate - /// on the pack file. - /// - public GitPack(GetObjectFromRepositoryDelegate getObjectFromRepositoryDelegate, string indexPath, string packPath, GitPackCache? cache = null) - : this(getObjectFromRepositoryDelegate, new Lazy(() => File.OpenRead(indexPath)), () => File.OpenRead(packPath), cache) + /// + /// Initializes a new instance of the class. + /// + /// + /// A delegate which fetches objects from the Git object store. + /// + /// + /// A function which creates a new which provides read-only + /// access to the index file. + /// + /// + /// A function which creates a new which provides read-only + /// access to the pack file. + /// + /// + /// A which is used to cache objects which operate + /// on the pack file. + /// + public GitPack(GetObjectFromRepositoryDelegate getObjectFromRepositoryDelegate, Lazy indexStream, Func packStream, GitPackCache? cache = null) + { + this.GetObjectFromRepository = getObjectFromRepositoryDelegate ?? throw new ArgumentNullException(nameof(getObjectFromRepositoryDelegate)); + this.indexReader = new Lazy(this.OpenIndex); + this.packStream = packStream ?? throw new ArgumentException(nameof(packStream)); + this.indexStream = indexStream ?? throw new ArgumentNullException(nameof(indexStream)); + this.cache = cache ?? new GitPackMemoryCache(); + + if (IntPtr.Size > 4) { + this.packFile = MemoryMappedFile.CreateFromFile(this.packStream(), mapName: null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); + this.accessor = this.packFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); } + } - /// - /// Initializes a new instance of the class. - /// - /// - /// A delegate which fetches objects from the Git object store. - /// - /// - /// A function which creates a new which provides read-only - /// access to the index file. - /// - /// - /// A function which creates a new which provides read-only - /// access to the pack file. - /// - /// - /// A which is used to cache objects which operate - /// on the pack file. - /// - public GitPack(GetObjectFromRepositoryDelegate getObjectFromRepositoryDelegate, Lazy indexStream, Func packStream, GitPackCache? cache = null) + /// + /// A delegate for methods which fetch objects from the Git object store. + /// + /// + /// The Git object ID of the object to fetch. + /// + /// + /// The object type of the object to fetch. + /// + /// + /// A which represents the requested object. + /// + public delegate Stream? GetObjectFromRepositoryDelegate(GitObjectId sha, string objectType); + + /// + /// Gets a delegate which fetches objects from the Git object store. + /// + public GetObjectFromRepositoryDelegate GetObjectFromRepository { get; private set; } + + /// + /// Finds a git object using a partial object ID. + /// + /// + /// A partial object ID. + /// + /// + /// + /// If found, a full object ID which matches the partial object ID. + /// Otherwise, . + /// + public GitObjectId? Lookup(Span objectId, bool endsWithHalfByte = false) + { + (long? _, GitObjectId? actualObjectId) = this.indexReader.Value.GetOffset(objectId, endsWithHalfByte); + return actualObjectId; + } + + /// + /// Attempts to retrieve a Git object from this Git pack. + /// + /// + /// The Git object Id of the object to retrieve. + /// + /// + /// The object type of the object to retrieve. + /// + /// + /// If found, receives a which represents the object. + /// + /// + /// if the object was found; otherwise, . + /// + public bool TryGetObject(GitObjectId objectId, string objectType, out Stream? value) + { + long? offset = this.GetOffset(objectId); + + if (offset is null) { - this.GetObjectFromRepository = getObjectFromRepositoryDelegate ?? throw new ArgumentNullException(nameof(getObjectFromRepositoryDelegate)); - this.indexReader = new Lazy(this.OpenIndex); - this.packStream = packStream ?? throw new ArgumentException(nameof(packStream)); - this.indexStream = indexStream ?? throw new ArgumentNullException(nameof(indexStream)); - this.cache = cache ?? new GitPackMemoryCache(); - - if (IntPtr.Size > 4) - { - this.packFile = MemoryMappedFile.CreateFromFile(this.packStream(), mapName: null, 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); - this.accessor = this.packFile.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); - } + value = null; + return false; } + else + { + value = this.GetObject(offset.Value, objectType); + return true; + } + } - /// - /// Gets a delegate which fetches objects from the Git object store. - /// - public GetObjectFromRepositoryDelegate GetObjectFromRepository { get; private set; } - - /// - /// Finds a git object using a partial object ID. - /// - /// - /// A partial object ID. - /// - /// - /// - /// If found, a full object ID which matches the partial object ID. - /// Otherwise, . - /// - public GitObjectId? Lookup(Span objectId, bool endsWithHalfByte = false) + /// + /// Gets a Git object at a specific offset. + /// + /// + /// The offset of the Git object, relative to the pack file. + /// + /// + /// The object type of the object to retrieve. + /// + /// + /// A which represents the object. + /// + public Stream GetObject(long offset, string objectType) + { +#if DEBUG + if (!this.histogram.TryAdd(offset, 1)) { - (var _, var actualObjectId) = this.indexReader.Value.GetOffset(objectId, endsWithHalfByte); - return actualObjectId; + this.histogram[offset] += 1; } +#endif - /// - /// Attempts to retrieve a Git object from this Git pack. - /// - /// - /// The Git object Id of the object to retrieve. - /// - /// - /// The object type of the object to retrieve. - /// - /// - /// If found, receives a which represents the object. - /// - /// - /// if the object was found; otherwise, . - /// - public bool TryGetObject(GitObjectId objectId, string objectType, out Stream? value) + if (this.cache.TryOpen(offset, out Stream? stream)) { - var offset = this.GetOffset(objectId); - - if (offset is null) - { - value = null; - return false; - } - else - { - value = this.GetObject(offset.Value, objectType); - return true; - } + return stream!; } - /// - /// Gets a Git object at a specific offset. - /// - /// - /// The offset of the Git object, relative to the pack file. - /// - /// - /// The object type of the object to retrieve. - /// - /// - /// A which represents the object. - /// - public Stream GetObject(long offset, string objectType) + GitPackObjectType packObjectType; + + switch (objectType) { -#if DEBUG - if (!this.histogram.TryAdd(offset, 1)) - { - this.histogram[offset] += 1; - } -#endif + case "commit": + packObjectType = GitPackObjectType.OBJ_COMMIT; + break; + + case "tree": + packObjectType = GitPackObjectType.OBJ_TREE; + break; - if (this.cache.TryOpen(offset, out Stream? stream)) - { - return stream!; - } - - GitPackObjectType packObjectType; - - switch (objectType) - { - case "commit": - packObjectType = GitPackObjectType.OBJ_COMMIT; - break; - - case "tree": - packObjectType = GitPackObjectType.OBJ_TREE; - break; - - case "blob": - packObjectType = GitPackObjectType.OBJ_BLOB; - break; - - default: - throw new GitException($"The object type '{objectType}' is not supported by the {nameof(GitPack)} class."); - } - - var packStream = this.GetPackStream(); - Stream objectStream; - - try - { - objectStream = GitPackReader.GetObject(this, packStream, offset, objectType, packObjectType); - } - catch - { - packStream.Dispose(); - throw; - } - - return this.cache.Add(offset, objectStream); + case "blob": + packObjectType = GitPackObjectType.OBJ_BLOB; + break; + + default: + throw new GitException($"The object type '{objectType}' is not supported by the {nameof(GitPack)} class."); } - /// - /// Writes cache statistics to a . - /// - /// - /// A to which the cache statistics are written. - /// - public void GetCacheStatistics(StringBuilder builder) + Stream? packStream = this.GetPackStream(); + Stream objectStream; + + try { - builder.AppendLine($"Git Pack:"); + objectStream = GitPackReader.GetObject(this, packStream, offset, objectType, packObjectType); + } + catch + { + packStream.Dispose(); + throw; + } + + return this.cache.Add(offset, objectStream); + } + + /// + /// Writes cache statistics to a . + /// + /// + /// A to which the cache statistics are written. + /// + public void GetCacheStatistics(StringBuilder builder) + { + builder.AppendLine($"Git Pack:"); #if DEBUG - int histogramCount = 25; - builder.AppendLine($"Top {histogramCount} / {this.histogram.Count} items:"); + int histogramCount = 25; + builder.AppendLine($"Top {histogramCount} / {this.histogram.Count} items:"); - foreach (var item in this.histogram.OrderByDescending(v => v.Value).Take(25)) - { - builder.AppendLine($" {item.Key}: {item.Value}"); - } + foreach (KeyValuePair item in this.histogram.OrderByDescending(v => v.Value).Take(25)) + { + builder.AppendLine($" {item.Key}: {item.Value}"); + } - builder.AppendLine(); + builder.AppendLine(); #endif - this.cache.GetCacheStatistics(builder); - } + this.cache.GetCacheStatistics(builder); + } - /// - public void Dispose() + /// + public void Dispose() + { + if (this.indexReader.IsValueCreated) { - if (this.indexReader.IsValueCreated) - { - this.indexReader.Value.Dispose(); - } - - this.accessor?.Dispose(); - this.packFile?.Dispose(); - this.cache.Dispose(); + this.indexReader.Value.Dispose(); } - private long? GetOffset(GitObjectId objectId) - { - if (this.offsets.TryGetValue(objectId, out long cachedOffset)) - { - return cachedOffset; - } + this.accessor?.Dispose(); + this.packFile?.Dispose(); + this.cache.Dispose(); + } - var indexReader = this.indexReader.Value; - var offset = indexReader.GetOffset(objectId); + private long? GetOffset(GitObjectId objectId) + { + if (this.offsets.TryGetValue(objectId, out long cachedOffset)) + { + return cachedOffset; + } - if (offset is not null) - { - this.offsets.Add(objectId, offset.Value); - } + GitPackIndexReader? indexReader = this.indexReader.Value; + long? offset = indexReader.GetOffset(objectId); - return offset; + if (offset is not null) + { + this.offsets.Add(objectId, offset.Value); } - private Stream GetPackStream() + return offset; + } + + private Stream GetPackStream() + { + // On 64-bit processes, we can use Memory Mapped Streams (the address space + // will be large enough to map the entire packfile). On 32-bit processes, + // we directly access the underlying stream. + if (IntPtr.Size > 4) { - // On 64-bit processes, we can use Memory Mapped Streams (the address space - // will be large enough to map the entire packfile). On 32-bit processes, - // we directly access the underlying stream. - if (IntPtr.Size > 4) - { - return new MemoryMappedStream(this.accessor); - } - else - { - return this.packStream(); - } + return new MemoryMappedStream(this.accessor); } - - private GitPackIndexReader OpenIndex() + else { - return new GitPackIndexMappedReader(this.indexStream.Value); + return this.packStream(); } } + + private GitPackIndexReader OpenIndex() + { + return new GitPackIndexMappedReader(this.indexStream.Value); + } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs index b817b357..50e054ab 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs @@ -1,71 +1,71 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Text; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Represents a cache in which objects retrieved from a +/// are cached. Caching these objects can be of interest, because retrieving +/// data from a can be potentially expensive: the data is +/// compressed and can be deltified. +/// +public abstract class GitPackCache : IDisposable { /// - /// Represents a cache in which objects retrieved from a - /// are cached. Caching these objects can be of interest, because retrieving - /// data from a can be potentially expensive: the data is - /// compressed and can be deltified. + /// Attempts to retrieve a Git object from cache. /// - public abstract class GitPackCache : IDisposable - { - /// - /// Attempts to retrieve a Git object from cache. - /// - /// - /// The offset of the Git object in the Git pack. - /// - /// - /// A which will be set to the cached Git object. - /// - /// - /// if the object was found in cache; otherwise, - /// . - /// - public abstract bool TryOpen(long offset, [NotNullWhen(true)] out Stream? stream); + /// + /// The offset of the Git object in the Git pack. + /// + /// + /// A which will be set to the cached Git object. + /// + /// + /// if the object was found in cache; otherwise, + /// . + /// + public abstract bool TryOpen(long offset, [NotNullWhen(true)] out Stream? stream); - /// - /// Gets statistics about the cache usage. - /// - /// - /// A to which to write the statistics. - /// - public abstract void GetCacheStatistics(StringBuilder builder); + /// + /// Gets statistics about the cache usage. + /// + /// + /// A to which to write the statistics. + /// + public abstract void GetCacheStatistics(StringBuilder builder); - /// - /// Adds a Git object to this cache. - /// - /// - /// The offset of the Git object in the Git pack. - /// - /// - /// A which represents the object to add. This stream - /// will be copied to the cache. - /// - /// - /// A which represents the cached entry. - /// - public abstract Stream Add(long offset, Stream stream); + /// + /// Adds a Git object to this cache. + /// + /// + /// The offset of the Git object in the Git pack. + /// + /// + /// A which represents the object to add. This stream + /// will be copied to the cache. + /// + /// + /// A which represents the cached entry. + /// + public abstract Stream Add(long offset, Stream stream); - /// - public void Dispose() - { - this.Dispose(true); - GC.SuppressFinalize(this); - } + /// + public void Dispose() + { + this.Dispose(true); + GC.SuppressFinalize(this); + } - /// - /// Disposes of native and managed resources associated by this object. - /// - /// to dispose managed and native resources; to only dispose of native resources. - protected virtual void Dispose(bool disposing) - { - } + /// + /// Disposes of native and managed resources associated by this object. + /// + /// to dispose managed and native resources; to only dispose of native resources. + protected virtual void Dispose(bool disposing) + { } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs index 9b73a7bb..0cd4e039 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs @@ -1,207 +1,207 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers; using System.Diagnostics; -using System.IO; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Reads data from a deltafied object. +/// +/// +public class GitPackDeltafiedStream : Stream { + private readonly long length; + + private readonly Stream baseStream; + private readonly Stream deltaStream; + + private long position; + private DeltaInstruction? current; + private int offset; + /// - /// Reads data from a deltafied object. + /// Initializes a new instance of the class. /// - /// - public class GitPackDeltafiedStream : Stream + /// + /// The base stream to which the deltas are applied. + /// + /// + /// A which contains a sequence of s. + /// + public GitPackDeltafiedStream(Stream baseStream, Stream deltaStream) { - private readonly long length; - private long position; - - private readonly Stream baseStream; - private readonly Stream deltaStream; - - private DeltaInstruction? current; - private int offset; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The base stream to which the deltas are applied. - /// - /// - /// A which contains a sequence of s. - /// - public GitPackDeltafiedStream(Stream baseStream, Stream deltaStream) - { - this.baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); - this.deltaStream = deltaStream ?? throw new ArgumentNullException(nameof(deltaStream)); + this.baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); + this.deltaStream = deltaStream ?? throw new ArgumentNullException(nameof(deltaStream)); - int baseObjectlength = deltaStream.ReadMbsInt(); - this.length = deltaStream.ReadMbsInt(); - } + int baseObjectlength = deltaStream.ReadMbsInt(); + this.length = deltaStream.ReadMbsInt(); + } - /// - /// Gets the base stream to which the deltas are applied. - /// - public Stream BaseStream => this.baseStream; + /// + /// Gets the base stream to which the deltas are applied. + /// + public Stream BaseStream => this.baseStream; - /// - public override bool CanRead => true; + /// + public override bool CanRead => true; - /// - public override bool CanSeek => false; + /// + public override bool CanSeek => false; - /// - public override bool CanWrite => false; + /// + public override bool CanWrite => false; - /// - public override long Length => this.length; + /// + public override long Length => this.length; - /// - public override long Position - { - get => this.position; - set => throw new NotImplementedException(); - } + /// + public override long Position + { + get => this.position; + set => throw new NotImplementedException(); + } #if NETSTANDARD2_0 - /// - /// Reads a sequence of bytes from the current and advances the position - /// within the stream by the number of bytes read. - /// - /// - /// A region of memory. When this method returns, the contents of this region are replaced by the bytes - /// read from the current source. - /// - /// - /// The total number of bytes read into the buffer. This can be less than the number of bytes allocated - /// in the buffer if that many bytes are not currently available, or zero (0) if the end of the stream - /// has been reached. - /// - public int Read(Span span) + /// + /// Reads a sequence of bytes from the current and advances the position + /// within the stream by the number of bytes read. + /// + /// + /// A region of memory. When this method returns, the contents of this region are replaced by the bytes + /// read from the current source. + /// + /// + /// The total number of bytes read into the buffer. This can be less than the number of bytes allocated + /// in the buffer if that many bytes are not currently available, or zero (0) if the end of the stream + /// has been reached. + /// + public int Read(Span span) #else - /// - public override int Read(Span span) + /// + public override int Read(Span span) #endif - { - int read = 0; - int canRead; - int didRead; - - while (read < span.Length && this.TryGetInstruction(out DeltaInstruction instruction)) - { - var source = instruction.InstructionType == DeltaInstructionType.Copy ? this.baseStream : this.deltaStream; - - Debug.Assert(instruction.Size > this.offset); - Debug.Assert(source.Position + instruction.Size - this.offset <= source.Length); - canRead = Math.Min(span.Length - read, instruction.Size - this.offset); - didRead = source.Read(span.Slice(read, canRead)); - - Debug.Assert(didRead != 0); - read += didRead; - this.offset += didRead; - } - - this.position += read; - Debug.Assert(read <= span.Length); - return read; - } + { + int read = 0; + int canRead; + int didRead; - /// - public override int Read(byte[] buffer, int offset, int count) + while (read < span.Length && this.TryGetInstruction(out DeltaInstruction instruction)) { - return this.Read(buffer.AsSpan(offset, count)); - } + Stream? source = instruction.InstructionType == DeltaInstructionType.Copy ? this.baseStream : this.deltaStream; - /// - public override void Flush() - { - throw new NotImplementedException(); + Debug.Assert(instruction.Size > this.offset); + Debug.Assert(source.Position + instruction.Size - this.offset <= source.Length); + canRead = Math.Min(span.Length - read, instruction.Size - this.offset); + didRead = source.Read(span.Slice(read, canRead)); + + Debug.Assert(didRead != 0); + read += didRead; + this.offset += didRead; } - /// - public override long Seek(long offset, SeekOrigin origin) + this.position += read; + Debug.Assert(read <= span.Length); + return read; + } + + /// + public override int Read(byte[] buffer, int offset, int count) + { + return this.Read(buffer.AsSpan(offset, count)); + } + + /// + public override void Flush() + { + throw new NotImplementedException(); + } + + /// + public override long Seek(long offset, SeekOrigin origin) + { + if (origin == SeekOrigin.Begin && offset == this.position) { - if (origin == SeekOrigin.Begin && offset == this.position) - { - return this.position; - } - - if (origin == SeekOrigin.Current && offset == 0) - { - return this.position; - } - - if (origin == SeekOrigin.Begin && offset > this.position) - { - // We can optimise this by skipping over instructions rather than executing them - int length = (int)(offset - this.position); - - byte[] buffer = ArrayPool.Shared.Rent(length); - this.Read(buffer, 0, length); - ArrayPool.Shared.Return(buffer); - return this.position; - } - else - { - throw new NotImplementedException(); - } + return this.position; } - /// - public override void SetLength(long value) + if (origin == SeekOrigin.Current && offset == 0) { - throw new NotImplementedException(); + return this.position; } - /// - public override void Write(byte[] buffer, int offset, int count) + if (origin == SeekOrigin.Begin && offset > this.position) { - throw new NotImplementedException(); - } + // We can optimise this by skipping over instructions rather than executing them + int length = (int)(offset - this.position); - /// - protected override void Dispose(bool disposing) + byte[] buffer = ArrayPool.Shared.Rent(length); + this.Read(buffer, 0, length); + ArrayPool.Shared.Return(buffer); + return this.position; + } + else { - this.deltaStream.Dispose(); - this.baseStream.Dispose(); + throw new NotImplementedException(); } + } - private bool TryGetInstruction(out DeltaInstruction instruction) - { - if (this.current is not null && this.offset < this.current.Value.Size) - { - instruction = this.current.Value; - return true; - } + /// + public override void SetLength(long value) + { + throw new NotImplementedException(); + } - this.current = DeltaStreamReader.Read(this.deltaStream); + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotImplementedException(); + } - if (this.current is null) - { - instruction = default; - return false; - } + /// + protected override void Dispose(bool disposing) + { + this.deltaStream.Dispose(); + this.baseStream.Dispose(); + } + private bool TryGetInstruction(out DeltaInstruction instruction) + { + if (this.current is not null && this.offset < this.current.Value.Size) + { instruction = this.current.Value; + return true; + } - switch (instruction.InstructionType) - { - case DeltaInstructionType.Copy: - this.baseStream.Seek(instruction.Offset, SeekOrigin.Begin); - Debug.Assert(this.baseStream.Position == instruction.Offset); - this.offset = 0; - break; + this.current = DeltaStreamReader.Read(this.deltaStream); - case DeltaInstructionType.Insert: - this.offset = 0; - break; + if (this.current is null) + { + instruction = default; + return false; + } - default: - throw new GitException(); - } + instruction = this.current.Value; - return true; + switch (instruction.InstructionType) + { + case DeltaInstructionType.Copy: + this.baseStream.Seek(instruction.Offset, SeekOrigin.Begin); + Debug.Assert(this.baseStream.Position == instruction.Offset); + this.offset = 0; + break; + + case DeltaInstructionType.Insert: + this.offset = 0; + break; + + default: + throw new GitException(); } + + return true; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs index b3690166..34449d82 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs @@ -1,166 +1,165 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System.Buffers.Binary; using System.Diagnostics; -using System.IO; using System.IO.MemoryMappedFiles; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// A which uses a memory-mapped file to read from the index. +/// +/// +public unsafe class GitPackIndexMappedReader : GitPackIndexReader { + private readonly MemoryMappedFile file; + private readonly MemoryMappedViewAccessor accessor; + + // The fanout table consists of + // 256 4-byte network byte order integers. + // The N-th entry of this table records the number of objects in the corresponding pack, + // the first byte of whose object name is less than or equal to N. + private readonly int[] fanoutTable = new int[257]; + + private readonly byte* ptr; + private bool initialized; + /// - /// A which uses a memory-mapped file to read from the index. + /// Initializes a new instance of the class. /// - /// - public unsafe class GitPackIndexMappedReader : GitPackIndexReader + /// + /// A which points to the index file. + /// + public GitPackIndexMappedReader(FileStream stream) { - private readonly MemoryMappedFile file; - private readonly MemoryMappedViewAccessor accessor; - - // The fanout table consists of - // 256 4-byte network byte order integers. - // The N-th entry of this table records the number of objects in the corresponding pack, - // the first byte of whose object name is less than or equal to N. - private readonly int[] fanoutTable = new int[257]; - - private byte* ptr; - private bool initialized; - - /// - /// Initializes a new instance of the class. - /// - /// - /// A which points to the index file. - /// - public GitPackIndexMappedReader(FileStream stream) + if (stream is null) { - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } - - this.file = MemoryMappedFile.CreateFromFile(stream, mapName: null, capacity: 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); - this.accessor = this.file.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); - this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.ptr); + throw new ArgumentNullException(nameof(stream)); } - private ReadOnlySpan Value + this.file = MemoryMappedFile.CreateFromFile(stream, mapName: null, capacity: 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); + this.accessor = this.file.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); + this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.ptr); + } + + private ReadOnlySpan Value + { + get { - get - { - return new ReadOnlySpan(this.ptr, (int)this.accessor.Capacity); - } + return new ReadOnlySpan(this.ptr, (int)this.accessor.Capacity); } + } - /// - public override (long?, GitObjectId?) GetOffset(Span objectName, bool endsWithHalfByte = false) - { - this.Initialize(); + /// + public override (long? Offset, GitObjectId? ObjectId) GetOffset(Span objectName, bool endsWithHalfByte = false) + { + this.Initialize(); - var packStart = this.fanoutTable[objectName[0]]; - var packEnd = this.fanoutTable[objectName[0] + 1]; - var objectCount = this.fanoutTable[256]; + int packStart = this.fanoutTable[objectName[0]]; + int packEnd = this.fanoutTable[objectName[0] + 1]; + int objectCount = this.fanoutTable[256]; - // The fanout table is followed by a table of sorted 20-byte SHA-1 object names. - // These are packed together without offset values to reduce the cache footprint of the binary search for a specific object name. + // The fanout table is followed by a table of sorted 20-byte SHA-1 object names. + // These are packed together without offset values to reduce the cache footprint of the binary search for a specific object name. - // The object names start at: 4 (header) + 4 (version) + 256 * 4 (fanout table) + 20 * (packStart) - // and end at 4 (header) + 4 (version) + 256 * 4 (fanout table) + 20 * (packEnd) + // The object names start at: 4 (header) + 4 (version) + 256 * 4 (fanout table) + 20 * (packStart) + // and end at 4 (header) + 4 (version) + 256 * 4 (fanout table) + 20 * (packEnd) + int i = 0; + int order = 0; - var i = 0; - var order = 0; + int tableSize = 20 * (packEnd - packStart + 1); + ReadOnlySpan table = this.Value.Slice(4 + 4 + (256 * 4) + (20 * packStart), tableSize); - var tableSize = 20 * (packEnd - packStart + 1); - var table = this.Value.Slice(4 + 4 + 256 * 4 + 20 * packStart, tableSize); + int originalPackStart = packStart; - int originalPackStart = packStart; + packEnd -= originalPackStart; + packStart = 0; - packEnd -= originalPackStart; - packStart = 0; + Span buffer = stackalloc byte[20]; + while (packStart <= packEnd) + { + i = (packStart + packEnd) / 2; - while (packStart <= packEnd) + ReadOnlySpan comparand = table.Slice(20 * i, objectName.Length); + if (endsWithHalfByte) { - i = (packStart + packEnd) / 2; - - ReadOnlySpan comparand = table.Slice(20 * i, objectName.Length); - if (endsWithHalfByte) - { - // Copy out the value to be checked so we can zero out the last four bits, - // so that it matches the last 4 bits of the objectName that isn't supposed to be compared. - Span buffer = stackalloc byte[20]; - comparand.CopyTo(buffer); - buffer[objectName.Length - 1] &= 0xf0; - order = buffer.Slice(0, objectName.Length).SequenceCompareTo(objectName); - } - else - { - order = comparand.SequenceCompareTo(objectName); - } - - if (order < 0) - { - packStart = i + 1; - } - else if (order > 0) - { - packEnd = i - 1; - } - else - { - break; - } + // Copy out the value to be checked so we can zero out the last four bits, + // so that it matches the last 4 bits of the objectName that isn't supposed to be compared. + comparand.CopyTo(buffer); + buffer[objectName.Length - 1] &= 0xf0; + order = buffer.Slice(0, objectName.Length).SequenceCompareTo(objectName); } - - if (order != 0) + else { - return (null, null); + order = comparand.SequenceCompareTo(objectName); } - // Get the offset value. It's located at: - // 4 (header) + 4 (version) + 256 * 4 (fanout table) + 20 * objectCount (SHA1 object name table) + 4 * objectCount (CRC32) + 4 * i (offset values) - int offsetTableStart = 4 + 4 + 256 * 4 + 20 * objectCount + 4 * objectCount; - var offsetBuffer = this.Value.Slice(offsetTableStart + 4 * (i + originalPackStart), 4); - var offset = BinaryPrimitives.ReadUInt32BigEndian(offsetBuffer); - - if (offsetBuffer[0] < 128) + if (order < 0) + { + packStart = i + 1; + } + else if (order > 0) { - return (offset, GitObjectId.Parse(table.Slice(20 * i, 20))); + packEnd = i - 1; } else { - // If the first bit of the offset address is set, the offset is stored as a 64-bit value in the table of 8-byte offset entries, - // which follows the table of 4-byte offset entries: "large offsets are encoded as an index into the next table with the msbit set." - offset = offset & 0x7FFFFFFF; - - offsetBuffer = this.Value.Slice(offsetTableStart + 4 * objectCount + 8 * (int)offset, 8); - var offset64 = BinaryPrimitives.ReadInt64BigEndian(offsetBuffer); - return (offset64, GitObjectId.Parse(table.Slice(20 * i, 20))); + break; } } - /// - public override void Dispose() + if (order != 0) { - this.accessor.Dispose(); - this.file.Dispose(); + return (null, null); } - private void Initialize() + // Get the offset value. It's located at: + // 4 (header) + 4 (version) + 256 * 4 (fanout table) + 20 * objectCount (SHA1 object name table) + 4 * objectCount (CRC32) + 4 * i (offset values) + int offsetTableStart = 4 + 4 + (256 * 4) + (20 * objectCount) + (4 * objectCount); + ReadOnlySpan offsetBuffer = this.Value.Slice(offsetTableStart + (4 * (i + originalPackStart)), 4); + uint offset = BinaryPrimitives.ReadUInt32BigEndian(offsetBuffer); + + if (offsetBuffer[0] < 128) { - if (!this.initialized) - { - var value = this.Value; + return (offset, GitObjectId.Parse(table.Slice(20 * i, 20))); + } + else + { + // If the first bit of the offset address is set, the offset is stored as a 64-bit value in the table of 8-byte offset entries, + // which follows the table of 4-byte offset entries: "large offsets are encoded as an index into the next table with the msbit set." + offset = offset & 0x7FFFFFFF; + + offsetBuffer = this.Value.Slice(offsetTableStart + (4 * objectCount) + (8 * (int)offset), 8); + long offset64 = BinaryPrimitives.ReadInt64BigEndian(offsetBuffer); + return (offset64, GitObjectId.Parse(table.Slice(20 * i, 20))); + } + } - var header = value.Slice(0, 4); - var version = BinaryPrimitives.ReadInt32BigEndian(value.Slice(4, 4)); - Debug.Assert(header.SequenceEqual(Header)); - Debug.Assert(version == 2); + /// + public override void Dispose() + { + this.accessor.Dispose(); + this.file.Dispose(); + } - for (int i = 1; i <= 256; i++) - { - this.fanoutTable[i] = BinaryPrimitives.ReadInt32BigEndian(value.Slice(4 + 4 * i, 4)); - } + private void Initialize() + { + if (!this.initialized) + { + ReadOnlySpan value = this.Value; + + ReadOnlySpan header = value.Slice(0, 4); + int version = BinaryPrimitives.ReadInt32BigEndian(value.Slice(4, 4)); + Debug.Assert(header.SequenceEqual(Header)); + Debug.Assert(version == 2); - this.initialized = true; + for (int i = 1; i <= 256; i++) + { + this.fanoutTable[i] = BinaryPrimitives.ReadInt32BigEndian(value.Slice(4 + (4 * i), 4)); } + + this.initialized = true; } } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs index d11be037..2d9bde35 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs @@ -1,50 +1,50 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Base class for classes which support reading data stored in a Git Pack file. +/// +/// +public abstract class GitPackIndexReader : IDisposable { /// - /// Base class for classes which support reading data stored in a Git Pack file. + /// The header of the index file. /// - /// - public abstract class GitPackIndexReader : IDisposable - { - /// - /// The header of the index file. - /// - protected static readonly byte[] Header = new byte[] { 0xff, 0x74, 0x4f, 0x63 }; + protected static readonly byte[] Header = new byte[] { 0xff, 0x74, 0x4f, 0x63 }; - /// - /// Gets the offset of a Git object in the index file. - /// - /// - /// The Git object Id of the Git object for which to get the offset. - /// - /// - /// If found, the offset of the Git object in the index file; otherwise, - /// . - /// - public long? GetOffset(GitObjectId objectId) - { - Span name = stackalloc byte[20]; - objectId.CopyTo(name); - (var offset, var _) = this.GetOffset(name); - return offset; - } + /// + /// Gets the offset of a Git object in the index file. + /// + /// + /// The Git object Id of the Git object for which to get the offset. + /// + /// + /// If found, the offset of the Git object in the index file; otherwise, + /// . + /// + public long? GetOffset(GitObjectId objectId) + { + Span name = stackalloc byte[20]; + objectId.CopyTo(name); + (long? offset, GitObjectId? _) = this.GetOffset(name); + return offset; + } - /// - /// Gets the offset of a Git object in the index file. - /// - /// - /// A partial or full Git object id, in its binary representation. - /// - /// if ends with a byte whose last 4 bits are all zeros and not intended for inclusion in the search; otherwise. - /// - /// If found, the offset of the Git object in the index file; otherwise, - /// . - /// - public abstract (long?, GitObjectId?) GetOffset(Span objectId, bool endsWithHalfByte = false); + /// + /// Gets the offset of a Git object in the index file. + /// + /// + /// A partial or full Git object id, in its binary representation. + /// + /// if ends with a byte whose last 4 bits are all zeros and not intended for inclusion in the search; otherwise. + /// + /// If found, the offset of the Git object in the index file; otherwise, + /// . + /// + public abstract (long? Offset, GitObjectId? ObjectId) GetOffset(Span objectId, bool endsWithHalfByte = false); - /// - public abstract void Dispose(); - } -} \ No newline at end of file + /// + public abstract void Dispose(); +} diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs index c88abe19..c7f8c6eb 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs @@ -1,77 +1,76 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; -using System.IO; -using System.Linq; using System.Text; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// +/// The implements the abstract class. +/// When a is added to the , it is wrapped in a +/// . This stream allows for just-in-time, random, read-only +/// access to the underlying data (which may deltafied and/or compressed). +/// +/// +/// Whenever data is read from a , the call is forwarded to the +/// underlying and cached in a . If the same data is read +/// twice, it is read from the , rather than the underlying . +/// +/// +/// and return +/// objects which may operate on the same underlying , but independently maintain +/// their state. +/// +/// +public class GitPackMemoryCache : GitPackCache { - /// - /// - /// The implements the abstract class. - /// When a is added to the , it is wrapped in a - /// . This stream allows for just-in-time, random, read-only - /// access to the underlying data (which may deltafied and/or compressed). - /// - /// - /// Whenever data is read from a , the call is forwarded to the - /// underlying and cached in a . If the same data is read - /// twice, it is read from the , rather than the underlying . - /// - /// - /// and return - /// objects which may operate on the same underlying , but independently maintain - /// their state. - /// - /// - public class GitPackMemoryCache : GitPackCache + private readonly Dictionary cache = new Dictionary(); + + /// + public override Stream Add(long offset, Stream stream) { - private readonly Dictionary cache = new Dictionary(); + var cacheStream = new GitPackMemoryCacheStream(stream); + this.cache.Add(offset, cacheStream); + return new GitPackMemoryCacheViewStream(cacheStream); + } - /// - public override Stream Add(long offset, Stream stream) + /// + public override bool TryOpen(long offset, [NotNullWhen(true)] out Stream? stream) + { + if (this.cache.TryGetValue(offset, out GitPackMemoryCacheStream? cacheStream)) { - var cacheStream = new GitPackMemoryCacheStream(stream); - this.cache.Add(offset, cacheStream); - return new GitPackMemoryCacheViewStream(cacheStream); + stream = new GitPackMemoryCacheViewStream(cacheStream!); + return true; } - /// - public override bool TryOpen(long offset, [NotNullWhen(true)] out Stream? stream) - { - if (this.cache.TryGetValue(offset, out GitPackMemoryCacheStream? cacheStream)) - { - stream = new GitPackMemoryCacheViewStream(cacheStream!); - return true; - } - - stream = null; - return false; - } + stream = null; + return false; + } - /// - public override void GetCacheStatistics(StringBuilder builder) - { - builder.AppendLine($"{this.cache.Count} items in cache"); - } + /// + public override void GetCacheStatistics(StringBuilder builder) + { + builder.AppendLine($"{this.cache.Count} items in cache"); + } - /// - protected override void Dispose(bool disposing) + /// + protected override void Dispose(bool disposing) + { + if (disposing) { - if (disposing) + while (this.cache.Count > 0) { - while (this.cache.Count > 0) - { - var key = this.cache.Keys.First(); - var stream = this.cache[key]; - stream.Dispose(); - this.cache.Remove(key); - } + long key = this.cache.Keys.First(); + GitPackMemoryCacheStream? stream = this.cache[key]; + stream.Dispose(); + this.cache.Remove(key); } - - base.Dispose(disposing); } + + base.Dispose(disposing); } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs index 66fa2f04..3574e2e8 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs @@ -1,121 +1,132 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers; -using System.IO; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +internal class GitPackMemoryCacheStream : Stream { - internal class GitPackMemoryCacheStream : Stream - { - private Stream stream; - private readonly MemoryStream cacheStream = new MemoryStream(); - private long length; + private readonly Stream stream; + private readonly MemoryStream cacheStream = new MemoryStream(); + private readonly long length; - public GitPackMemoryCacheStream(Stream stream) - { - this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); - this.length = this.stream.Length; - } + public GitPackMemoryCacheStream(Stream stream) + { + this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); + this.length = this.stream.Length; + } - public override bool CanRead => true; + /// + public override bool CanRead => true; - public override bool CanSeek => true; + /// + public override bool CanSeek => true; - public override bool CanWrite => false; + /// + public override bool CanWrite => false; - public override long Length => this.length; + /// + public override long Length => this.length; - public override long Position - { - get => this.cacheStream.Position; - set => throw new NotSupportedException(); - } + /// + public override long Position + { + get => this.cacheStream.Position; + set => throw new NotSupportedException(); + } - public override void Flush() - { - throw new NotSupportedException(); - } + /// + public override void Flush() + { + throw new NotSupportedException(); + } #if NETSTANDARD2_0 - public int Read(Span buffer) + public int Read(Span buffer) #else - /// - public override int Read(Span buffer) + /// + public override int Read(Span buffer) #endif + { + if (this.cacheStream.Length < this.length + && this.cacheStream.Position + buffer.Length > this.cacheStream.Length) { - if (this.cacheStream.Length < this.length - && this.cacheStream.Position + buffer.Length > this.cacheStream.Length) - { - var currentPosition = this.cacheStream.Position; - var toRead = (int)(buffer.Length - this.cacheStream.Length + this.cacheStream.Position); - int actualRead = this.stream.Read(buffer.Slice(0, toRead)); - this.cacheStream.Seek(0, SeekOrigin.End); - this.cacheStream.Write(buffer.Slice(0, actualRead)); - this.cacheStream.Seek(currentPosition, SeekOrigin.Begin); - this.DisposeStreamIfRead(); - } - - return this.cacheStream.Read(buffer); + long currentPosition = this.cacheStream.Position; + int toRead = (int)(buffer.Length - this.cacheStream.Length + this.cacheStream.Position); + int actualRead = this.stream.Read(buffer.Slice(0, toRead)); + this.cacheStream.Seek(0, SeekOrigin.End); + this.cacheStream.Write(buffer.Slice(0, actualRead)); + this.cacheStream.Seek(currentPosition, SeekOrigin.Begin); + this.DisposeStreamIfRead(); } - public override int Read(byte[] buffer, int offset, int count) - { - return this.Read(buffer.AsSpan(offset, count)); - } + return this.cacheStream.Read(buffer); + } - public override long Seek(long offset, SeekOrigin origin) - { - if (origin != SeekOrigin.Begin) - { - throw new NotSupportedException(); - } - - if (offset > this.cacheStream.Length) - { - var toRead = (int)(offset - this.cacheStream.Length); - byte[] buffer = ArrayPool.Shared.Rent(toRead); - int read = this.stream.Read(buffer, 0, toRead); - this.cacheStream.Seek(0, SeekOrigin.End); - this.cacheStream.Write(buffer, 0, read); - ArrayPool.Shared.Return(buffer); - - this.DisposeStreamIfRead(); - return this.cacheStream.Position; - } - else - { - return this.cacheStream.Seek(offset, origin); - } - } + /// + public override int Read(byte[] buffer, int offset, int count) + { + return this.Read(buffer.AsSpan(offset, count)); + } - public override void SetLength(long value) + /// + public override long Seek(long offset, SeekOrigin origin) + { + if (origin != SeekOrigin.Begin) { throw new NotSupportedException(); } - public override void Write(byte[] buffer, int offset, int count) + if (offset > this.cacheStream.Length) { - throw new NotSupportedException(); + int toRead = (int)(offset - this.cacheStream.Length); + byte[] buffer = ArrayPool.Shared.Rent(toRead); + int read = this.stream.Read(buffer, 0, toRead); + this.cacheStream.Seek(0, SeekOrigin.End); + this.cacheStream.Write(buffer, 0, read); + ArrayPool.Shared.Return(buffer); + + this.DisposeStreamIfRead(); + return this.cacheStream.Position; } - - protected override void Dispose(bool disposing) + else { - if (disposing) - { - this.stream.Dispose(); - this.cacheStream.Dispose(); - } + return this.cacheStream.Seek(offset, origin); + } + } + + /// + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } - base.Dispose(disposing); + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + this.stream.Dispose(); + this.cacheStream.Dispose(); } - private void DisposeStreamIfRead() + base.Dispose(disposing); + } + + private void DisposeStreamIfRead() + { + if (this.cacheStream.Length == this.stream.Length) { - if (this.cacheStream.Length == this.stream.Length) - { - this.stream.Dispose(); - } + this.stream.Dispose(); } } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs index e91b67c1..80f47b33 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs @@ -1,77 +1,85 @@ -using System; -using System.Collections.Generic; -using System.IO; -using System.Text; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +internal class GitPackMemoryCacheViewStream : Stream { - internal class GitPackMemoryCacheViewStream : Stream - { - private readonly GitPackMemoryCacheStream baseStream; + private readonly GitPackMemoryCacheStream baseStream; - public GitPackMemoryCacheViewStream(GitPackMemoryCacheStream baseStream) - { - this.baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); - } + private long position; - public override bool CanRead => true; + public GitPackMemoryCacheViewStream(GitPackMemoryCacheStream baseStream) + { + this.baseStream = baseStream ?? throw new ArgumentNullException(nameof(baseStream)); + } - public override bool CanSeek => true; + /// + public override bool CanRead => true; - public override bool CanWrite => false; + /// + public override bool CanSeek => true; - public override long Length => this.baseStream.Length; + /// + public override bool CanWrite => false; - private long position; + /// + public override long Length => this.baseStream.Length; - public override long Position - { - get => this.position; - set => throw new NotSupportedException(); - } + /// + public override long Position + { + get => this.position; + set => throw new NotSupportedException(); + } - public override void Flush() => throw new NotImplementedException(); + /// + public override void Flush() => throw new NotImplementedException(); - public override int Read(byte[] buffer, int offset, int count) - { - return this.Read(buffer.AsSpan(offset, count)); - } + /// + public override int Read(byte[] buffer, int offset, int count) + { + return this.Read(buffer.AsSpan(offset, count)); + } #if NETSTANDARD2_0 - public int Read(Span buffer) + public int Read(Span buffer) #else - /// - public override int Read(Span buffer) + /// + public override int Read(Span buffer) #endif - { - int read = 0; + { + int read = 0; - lock (this.baseStream) + lock (this.baseStream) + { + if (this.baseStream.Position != this.position) { - if (this.baseStream.Position != this.position) - { - this.baseStream.Seek(this.position, SeekOrigin.Begin); - } - - read = this.baseStream.Read(buffer); + this.baseStream.Seek(this.position, SeekOrigin.Begin); } - this.position += read; - return read; + read = this.baseStream.Read(buffer); } - public override long Seek(long offset, SeekOrigin origin) - { - if (origin != SeekOrigin.Begin) - { - throw new NotSupportedException(); - } + this.position += read; + return read; + } - this.position = Math.Min(offset, this.Length); - return this.position; + /// + public override long Seek(long offset, SeekOrigin origin) + { + if (origin != SeekOrigin.Begin) + { + throw new NotSupportedException(); } - public override void SetLength(long value) => throw new NotSupportedException(); - public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); + this.position = Math.Min(offset, this.Length); + return this.position; } + + /// + public override void SetLength(long value) => throw new NotSupportedException(); + + /// + public override void Write(byte[] buffer, int offset, int count) => throw new NotSupportedException(); } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs index 0050123d..f96e8ba9 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs @@ -1,37 +1,38 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable using System.Diagnostics.CodeAnalysis; -using System.IO; using System.Text; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// A no-op implementation of the class. +/// +public class GitPackNullCache : GitPackCache { /// - /// A no-op implementation of the class. + /// Gets the default instance of the class. /// - public class GitPackNullCache : GitPackCache - { - /// - /// Gets the default instance of the class. - /// - public static GitPackNullCache Instance { get; } = new GitPackNullCache(); + public static GitPackNullCache Instance { get; } = new GitPackNullCache(); - /// - public override Stream Add(long offset, Stream stream) - { - return stream; - } + /// + public override Stream Add(long offset, Stream stream) + { + return stream; + } - /// - public override bool TryOpen(long offset, [NotNullWhen(true)] out Stream? stream) - { - stream = null; - return false; - } + /// + public override bool TryOpen(long offset, [NotNullWhen(true)] out Stream? stream) + { + stream = null; + return false; + } - /// - public override void GetCacheStatistics(StringBuilder builder) - { - } + /// + public override void GetCacheStatistics(StringBuilder builder) + { } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs index e0ff3ef2..5275c9d5 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs @@ -1,15 +1,44 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.ManagedGit +#nullable enable + +namespace Nerdbank.GitVersioning.ManagedGit; + +internal enum GitPackObjectType { - internal enum GitPackObjectType - { - Invalid = 0, - OBJ_COMMIT = 1, - OBJ_TREE = 2, - OBJ_BLOB = 3, - OBJ_TAG = 4, - OBJ_OFS_DELTA = 6, - OBJ_REF_DELTA = 7, - } + /// + /// Invalid. + /// + Invalid = 0, + + /// + /// A commit. + /// + OBJ_COMMIT = 1, + + /// + /// A tree. + /// + OBJ_TREE = 2, + + /// + /// A blob. + /// + OBJ_BLOB = 3, + + /// + /// A tag. + /// + OBJ_TAG = 4, + + /// + /// An OFS_DELTA. + /// + OBJ_OFS_DELTA = 6, + + /// + /// A REF_DELTA. + /// + OBJ_REF_DELTA = 7, } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs index 74cde41e..53ca6769 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs @@ -1,104 +1,103 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; -using System.Collections.Generic; using System.Diagnostics; -using System.IO; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// A pooled , which wraps around a +/// which will be returned to a pool +/// instead of actually being closed when is called. +/// +public class GitPackPooledStream : Stream { + private readonly Stream stream; + private readonly Queue pool; + + /// + /// Initializes a new instance of the class. + /// + /// + /// The which is being pooled. + /// + /// + /// A to which the stream will be returned. + /// + public GitPackPooledStream(Stream stream, Queue pool) + { + this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); + this.pool = pool ?? throw new ArgumentNullException(nameof(pool)); + } + /// - /// A pooled , which wraps around a - /// which will be returned to a pool - /// instead of actually being closed when is called. + /// Gets the underlying for this . /// - public class GitPackPooledStream : Stream + public Stream BaseStream => this.stream; + + /// + public override bool CanRead => this.stream.CanRead; + + /// + public override bool CanSeek => this.stream.CanSeek; + + /// + public override bool CanWrite => this.stream.CanWrite; + + /// + public override long Length => this.stream.Length; + + /// + public override long Position + { + get => this.stream.Position; + set => this.stream.Position = value; + } + + /// + public override void Flush() { - private readonly Stream stream; - private readonly Queue pool; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The which is being pooled. - /// - /// - /// A to which the stream will be returned. - /// - public GitPackPooledStream(Stream stream, Queue pool) - { - this.stream = stream ?? throw new ArgumentNullException(nameof(stream)); - this.pool = pool ?? throw new ArgumentNullException(nameof(pool)); - } - - /// - /// Gets the underlying for this . - /// - public Stream BaseStream => this.stream; - - /// - public override bool CanRead => this.stream.CanRead; - - /// - public override bool CanSeek => this.stream.CanSeek; - - /// - public override bool CanWrite => this.stream.CanWrite; - - /// - public override long Length => this.stream.Length; - - /// - public override long Position - { - get => this.stream.Position; - set => this.stream.Position = value; - } - - /// - public override void Flush() - { - this.stream.Flush(); - } + this.stream.Flush(); + } #if !NETSTANDARD2_0 - /// - public override int Read(Span buffer) - { - return this.stream.Read(buffer); - } + /// + public override int Read(Span buffer) + { + return this.stream.Read(buffer); + } #endif - /// - public override int Read(byte[] buffer, int offset, int count) - { - return this.stream.Read(buffer, offset, count); - } - - /// - public override long Seek(long offset, SeekOrigin origin) - { - return this.stream.Seek(offset, origin); - } - - /// - public override void SetLength(long value) - { - this.stream.SetLength(value); - } - - /// - public override void Write(byte[] buffer, int offset, int count) - { - throw new NotSupportedException(); - } - - /// - protected override void Dispose(bool disposing) - { - this.pool.Enqueue(this); - Debug.WriteLine("Returning stream to pool"); - } + /// + public override int Read(byte[] buffer, int offset, int count) + { + return this.stream.Read(buffer, offset, count); + } + + /// + public override long Seek(long offset, SeekOrigin origin) + { + return this.stream.Seek(offset, origin); + } + + /// + public override void SetLength(long value) + { + this.stream.SetLength(value); + } + + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + /// + protected override void Dispose(bool disposing) + { + this.pool.Enqueue(this); + Debug.WriteLine("Returning stream to pool"); } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs index 354060d4..12ca7865 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs @@ -1,117 +1,118 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers.Binary; using System.Diagnostics; -using System.IO; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +internal static class GitPackReader { - internal static class GitPackReader - { - private static readonly byte[] Signature = GitRepository.Encoding.GetBytes("PACK"); + private static readonly byte[] Signature = GitRepository.Encoding.GetBytes("PACK"); - public static Stream GetObject(GitPack pack, Stream stream, long offset, string objectType, GitPackObjectType packObjectType) + public static Stream GetObject(GitPack pack, Stream stream, long offset, string objectType, GitPackObjectType packObjectType) + { + if (pack is null) { - if (pack is null) - { - throw new ArgumentNullException(nameof(pack)); - } + throw new ArgumentNullException(nameof(pack)); + } - if (stream is null) - { - throw new ArgumentNullException(nameof(stream)); - } + if (stream is null) + { + throw new ArgumentNullException(nameof(stream)); + } - // Read the signature + // Read the signature #if DEBUG - stream.Seek(0, SeekOrigin.Begin); - Span buffer = stackalloc byte[12]; - stream.ReadAll(buffer); + stream.Seek(0, SeekOrigin.Begin); + Span buffer = stackalloc byte[12]; + stream.ReadAll(buffer); - Debug.Assert(buffer.Slice(0, 4).SequenceEqual(Signature)); + Debug.Assert(buffer.Slice(0, 4).SequenceEqual(Signature)); - var versionNumber = BinaryPrimitives.ReadInt32BigEndian(buffer.Slice(4, 4)); - Debug.Assert(versionNumber == 2); + int versionNumber = BinaryPrimitives.ReadInt32BigEndian(buffer.Slice(4, 4)); + Debug.Assert(versionNumber == 2); - var numberOfObjects = BinaryPrimitives.ReadInt32BigEndian(buffer.Slice(8, 4)); + int numberOfObjects = BinaryPrimitives.ReadInt32BigEndian(buffer.Slice(8, 4)); #endif - stream.Seek(offset, SeekOrigin.Begin); + stream.Seek(offset, SeekOrigin.Begin); - var (type, decompressedSize) = ReadObjectHeader(stream); + (GitPackObjectType type, long decompressedSize) = ReadObjectHeader(stream); - if (type == GitPackObjectType.OBJ_OFS_DELTA) - { - var baseObjectRelativeOffset = ReadVariableLengthInteger(stream); - long baseObjectOffset = offset - baseObjectRelativeOffset; - - var deltaStream = new ZLibStream(stream, decompressedSize); - var baseObjectStream = pack.GetObject(baseObjectOffset, objectType); - - return new GitPackDeltafiedStream(baseObjectStream, deltaStream); - } - else if (type == GitPackObjectType.OBJ_REF_DELTA) - { - Span baseObjectId = stackalloc byte[20]; - stream.ReadAll(baseObjectId); + if (type == GitPackObjectType.OBJ_OFS_DELTA) + { + long baseObjectRelativeOffset = ReadVariableLengthInteger(stream); + long baseObjectOffset = offset - baseObjectRelativeOffset; - Stream baseObject = pack.GetObjectFromRepository(GitObjectId.Parse(baseObjectId), objectType)!; - var seekableBaseObject = new GitPackMemoryCacheStream(baseObject); + var deltaStream = new ZLibStream(stream, decompressedSize); + Stream? baseObjectStream = pack.GetObject(baseObjectOffset, objectType); - var deltaStream = new ZLibStream(stream, decompressedSize); + return new GitPackDeltafiedStream(baseObjectStream, deltaStream); + } + else if (type == GitPackObjectType.OBJ_REF_DELTA) + { + Span baseObjectId = stackalloc byte[20]; + stream.ReadAll(baseObjectId); - return new GitPackDeltafiedStream(seekableBaseObject, deltaStream); - } + Stream baseObject = pack.GetObjectFromRepository(GitObjectId.Parse(baseObjectId), objectType)!; + var seekableBaseObject = new GitPackMemoryCacheStream(baseObject); - // Tips for handling deltas: https://github.com/choffmeister/gitnet/blob/4d907623d5ce2d79a8875aee82e718c12a8aad0b/src/GitNet/GitPack.cs - if (type != packObjectType) - { - throw new GitException($"An object of type {objectType} could not be located at offset {offset}.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; - } + var deltaStream = new ZLibStream(stream, decompressedSize); - return new ZLibStream(stream, decompressedSize); + return new GitPackDeltafiedStream(seekableBaseObject, deltaStream); } - private static (GitPackObjectType, long) ReadObjectHeader(Stream stream) + // Tips for handling deltas: https://github.com/choffmeister/gitnet/blob/4d907623d5ce2d79a8875aee82e718c12a8aad0b/src/GitNet/GitPack.cs + if (type != packObjectType) { - Span value = stackalloc byte[1]; - stream.Read(value); - - var type = (GitPackObjectType)((value[0] & 0b0111_0000) >> 4); - long length = value[0] & 0b_1111; + throw new GitException($"An object of type {objectType} could not be located at offset {offset}.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; + } - if ((value[0] & 0b1000_0000) == 0) - { - return (type, length); - } + return new ZLibStream(stream, decompressedSize); + } - int shift = 4; + private static (GitPackObjectType ObjectType, long Length) ReadObjectHeader(Stream stream) + { + Span value = stackalloc byte[1]; + stream.Read(value); - do - { - stream.Read(value); - length = length | ((value[0] & (long)0b0111_1111) << shift); - shift += 7; - } while ((value[0] & 0b1000_0000) != 0); + var type = (GitPackObjectType)((value[0] & 0b0111_0000) >> 4); + long length = value[0] & 0b_1111; + if ((value[0] & 0b1000_0000) == 0) + { return (type, length); } - private static long ReadVariableLengthInteger(Stream stream) + int shift = 4; + + do + { + stream.Read(value); + length = length | ((value[0] & 0b0111_1111L) << shift); + shift += 7; + } + while ((value[0] & 0b1000_0000) != 0); + + return (type, length); + } + + private static long ReadVariableLengthInteger(Stream stream) + { + long offset = -1; + int b; + + do { - long offset = -1; - int b; - - do - { - offset++; - b = stream.ReadByte(); - offset = (offset << 7) + (b & 127); - } - while ((b & (byte)128) != 0); - - return offset; + offset++; + b = stream.ReadByte(); + offset = (offset << 7) + (b & 127); } + while ((b & 128) != 0); + + return offset; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs index e7ce4ae6..942e8ff2 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs @@ -1,39 +1,38 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; -using System.IO; +#nullable enable -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +internal class GitReferenceReader { - internal class GitReferenceReader + private static readonly byte[] RefPrefix = GitRepository.Encoding.GetBytes("ref: "); + + public static object ReadReference(Stream stream) { - private readonly static byte[] RefPrefix = GitRepository.Encoding.GetBytes("ref: "); + Span reference = stackalloc byte[(int)stream.Length]; + stream.ReadAll(reference); - public static object ReadReference(Stream stream) - { - Span reference = stackalloc byte[(int)stream.Length]; - stream.ReadAll(reference); + return ReadReference(reference); + } - return ReadReference(reference); + public static object ReadReference(Span value) + { + if (value.Length == 41 && !value.StartsWith(RefPrefix)) + { + // Skip the trailing \n + return GitObjectId.ParseHex(value.Slice(0, 40)); } - - public static object ReadReference(Span value) + else { - if (value.Length == 41 && !value.StartsWith(RefPrefix)) + if (!value.StartsWith(RefPrefix)) { - // Skip the trailing \n - return GitObjectId.ParseHex(value.Slice(0, 40)); + throw new GitException(); } - else - { - if (!value.StartsWith(RefPrefix)) - { - throw new GitException(); - } - // Skip the terminating \n character - return GitRepository.GetString(value.Slice(RefPrefix.Length, value.Length - RefPrefix.Length - 1)); - } + // Skip the terminating \n character + return GitRepository.GetString(value.Slice(RefPrefix.Length, value.Length - RefPrefix.Length - 1)); } } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index c079b951..d9dfcfee 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -1,774 +1,765 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; -using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Globalization; -using System.IO; -using System.Linq; using System.Runtime.InteropServices; using System.Text; using Validation; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Provides access to a Git repository. +/// +public class GitRepository : IDisposable { + private const string HeadFileName = "HEAD"; + private const string GitDirectoryName = ".git"; + private readonly Lazy> packs; + /// - /// Provides access to a Git repository. + /// UTF-16 encoded string. /// - public class GitRepository : IDisposable - { - private const string HeadFileName = "HEAD"; - private const string GitDirectoryName = ".git"; - private readonly Lazy> packs; - - /// - /// UTF-16 encoded string. - /// - private readonly char[] objectPathBuffer; + private readonly char[] objectPathBuffer; - private readonly List alternates = new List(); + private readonly List alternates = new List(); #if DEBUG - private Dictionary histogram = new Dictionary(); + private readonly Dictionary histogram = new Dictionary(); #endif - /// - /// Creates a new instance of the class. - /// - /// - /// - /// A which represents the git repository, or - /// if no git repository was found. - /// - public static GitRepository? Create(string? workingDirectory) - { - if (!GitContext.TryFindGitPaths(workingDirectory, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath)) - { - return null; + /// + /// Initializes a new instance of the class. + /// + /// + /// The current working directory. This can be a subdirectory of the Git repository. + /// + /// + /// The directory in which the git HEAD file is stored. This is the .git directory unless the working directory is a worktree. + /// + /// + /// The common Git directory, which is parent to the objects, refs, and other directories. + /// + /// + /// The object directory in which Git objects are stored. + /// + public GitRepository(string workingDirectory, string gitDirectory, string commonDirectory, string objectDirectory) + { + this.WorkingDirectory = workingDirectory ?? throw new ArgumentNullException(nameof(workingDirectory)); + this.GitDirectory = gitDirectory ?? throw new ArgumentNullException(nameof(gitDirectory)); + this.CommonDirectory = commonDirectory ?? throw new ArgumentNullException(nameof(commonDirectory)); + this.ObjectDirectory = objectDirectory ?? throw new ArgumentNullException(nameof(objectDirectory)); + + // Normalize paths + this.WorkingDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.WorkingDirectory)); + this.GitDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.GitDirectory)); + this.CommonDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.CommonDirectory)); + this.ObjectDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.ObjectDirectory)); + + if (FileHelpers.TryOpen( + Path.Combine(this.ObjectDirectory, "info", "alternates"), + out FileStream? alternateStream)) + { + // There's not a lot of documentation on git alternates; but this StackOverflow question + // https://stackoverflow.com/questions/36123655/what-is-the-git-alternates-mechanism + // provides a good starting point. + Span alternates = stackalloc byte[4096]; + int length = alternateStream!.Read(alternates); + alternates = alternates.Slice(0, length); + + foreach (string? alternate in ParseAlternates(alternates)) + { + this.alternates.Add( + GitRepository.Create( + workingDirectory, + gitDirectory, + commonDirectory, + objectDirectory: Path.GetFullPath(Path.Combine(this.ObjectDirectory, alternate)))); } + } - string commonDirectory = gitDirectory; - string commonDirFile = Path.Combine(gitDirectory, "commondir"); + int pathLengthInChars = this.ObjectDirectory.Length + + 1 // '/' + + 2 // 'xy' is first byte as 2 hex characters. + + 1 // '/' + + 38 // 19 bytes * 2 hex chars each + + 1; // Trailing null character + this.objectPathBuffer = new char[pathLengthInChars]; + this.ObjectDirectory.CopyTo(0, this.objectPathBuffer, 0, this.ObjectDirectory.Length); - if (File.Exists(commonDirFile)) - { - var commonDirectoryRelativePath = File.ReadAllText(commonDirFile).Trim('\n'); - commonDirectory = Path.Combine(gitDirectory, commonDirectoryRelativePath); - } + this.objectPathBuffer[this.ObjectDirectory.Length] = '/'; + this.objectPathBuffer[this.ObjectDirectory.Length + 3] = '/'; + this.objectPathBuffer[pathLengthInChars - 1] = '\0'; // Make sure to initialize with zeros - string objectDirectory = Path.Combine(commonDirectory, "objects"); - - return new GitRepository(workingDirectory!, gitDirectory, commonDirectory, objectDirectory); - } - - /// - /// Creates a new instance of the class. - /// - /// - /// - /// - /// - public static GitRepository Create(string workingDirectory, string gitDirectory, string commonDirectory, string objectDirectory) - { - return new GitRepository(workingDirectory, gitDirectory, commonDirectory, objectDirectory); - } - - /// - /// Initializes a new instance of the class. - /// - /// - /// The current working directory. This can be a subdirectory of the Git repository. - /// - /// - /// The directory in which the git HEAD file is stored. This is the .git directory unless the working directory is a worktree. - /// - /// - /// The common Git directory, which is parent to the objects, refs, and other directories. - /// - /// - /// The object directory in which Git objects are stored. - /// - public GitRepository(string workingDirectory, string gitDirectory, string commonDirectory, string objectDirectory) - { - this.WorkingDirectory = workingDirectory ?? throw new ArgumentNullException(nameof(workingDirectory)); - this.GitDirectory = gitDirectory ?? throw new ArgumentNullException(nameof(gitDirectory)); - this.CommonDirectory = commonDirectory ?? throw new ArgumentNullException(nameof(commonDirectory)); - this.ObjectDirectory = objectDirectory ?? throw new ArgumentNullException(nameof(objectDirectory)); - - // Normalize paths - this.WorkingDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.WorkingDirectory)); - this.GitDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.GitDirectory)); - this.CommonDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.CommonDirectory)); - this.ObjectDirectory = TrimEndingDirectorySeparator(Path.GetFullPath(this.ObjectDirectory)); - - if (FileHelpers.TryOpen( - Path.Combine(this.ObjectDirectory, "info", "alternates"), - out var alternateStream)) - { - // There's not a lot of documentation on git alternates; but this StackOverflow question - // https://stackoverflow.com/questions/36123655/what-is-the-git-alternates-mechanism - // provides a good starting point. - Span alternates = stackalloc byte[4096]; - var length = alternateStream!.Read(alternates); - alternates = alternates.Slice(0, length); - - foreach (var alternate in ParseAlternates(alternates)) - { - this.alternates.Add( - GitRepository.Create( - workingDirectory, - gitDirectory, - commonDirectory, - objectDirectory: Path.GetFullPath(Path.Combine(this.ObjectDirectory, alternate)))); - } - } + this.packs = new Lazy>(this.LoadPacks); + } + // TODO: read from Git settings - int pathLengthInChars = this.ObjectDirectory.Length - + 1 // '/' - + 2 // 'xy' is first byte as 2 hex characters. - + 1 // '/' - + 38 // 19 bytes * 2 hex chars each - + 1; // Trailing null character - this.objectPathBuffer = new char[pathLengthInChars]; - this.ObjectDirectory.CopyTo(0, this.objectPathBuffer, 0, this.ObjectDirectory.Length); - - this.objectPathBuffer[this.ObjectDirectory.Length] = '/'; - this.objectPathBuffer[this.ObjectDirectory.Length + 3] = '/'; - this.objectPathBuffer[pathLengthInChars - 1] = '\0'; // Make sure to initialize with zeros - - this.packs = new Lazy>(this.LoadPacks); - } - - // TODO: read from Git settings - /// - /// Gets a value indicating whether this Git repository is case-insensitive. - /// - public bool IgnoreCase { get; private set; } = false; - - /// - /// Gets the path to the current working directory. - /// - public string WorkingDirectory { get; private set; } - - /// - /// Gets the path to the Git directory, in which at minimum HEAD is stored. - /// Use for all other metadata (e.g. references, configuration). - /// - public string GitDirectory { get; private set; } - - /// - /// Gets the path to the common directory, in which shared Git data (e.g. objects) are stored. - /// - public string CommonDirectory { get; private set; } - - /// - /// Gets the path to the Git object directory. It is a subdirectory of . - /// - public string ObjectDirectory { get; private set; } - - /// - /// Gets the encoding used by this Git repository. - /// - public static Encoding Encoding => Encoding.UTF8; - - /// - /// Shortens the object id - /// - /// - /// The object Id to shorten. - /// - /// - /// The minimum string length. - /// - /// - /// The short object id. - /// - public string ShortenObjectId(GitObjectId objectId, int minimum) - { - var sha = objectId.ToString(); - - for (int length = minimum; length < sha.Length; length += 2) - { - var objectish = sha.Substring(0, length); + /// + /// Gets the encoding used by this Git repository. + /// + public static Encoding Encoding => Encoding.UTF8; - if (this.Lookup(objectish) is not null) - { - return objectish; - } - } + /// + /// Gets a value indicating whether this Git repository is case-insensitive. + /// + public bool IgnoreCase { get; private set; } = false; - return sha; - } + /// + /// Gets the path to the current working directory. + /// + public string WorkingDirectory { get; private set; } + + /// + /// Gets the path to the Git directory, in which at minimum HEAD is stored. + /// Use for all other metadata (e.g. references, configuration). + /// + public string GitDirectory { get; private set; } + + /// + /// Gets the path to the common directory, in which shared Git data (e.g. objects) are stored. + /// + public string CommonDirectory { get; private set; } + + /// + /// Gets the path to the Git object directory. It is a subdirectory of . + /// + public string ObjectDirectory { get; private set; } - /// - /// Returns the current HEAD as a reference (if available) or a Git object id. - /// - /// - /// The current HEAD as a reference (if available) or a Git object id. - /// - public object GetHeadAsReferenceOrSha() + /// + /// Creates a new instance of the class. + /// + /// + /// + /// A which represents the git repository, or + /// if no git repository was found. + /// + public static GitRepository? Create(string? workingDirectory) + { + if (!GitContext.TryFindGitPaths(workingDirectory, out string? gitDirectory, out string? workingTreeDirectory, out string? workingTreeRelativePath)) { - using (var stream = File.OpenRead(Path.Combine(this.GitDirectory, HeadFileName))) - { - return GitReferenceReader.ReadReference(stream); - } + return null; } - /// - /// Gets the object ID of the current HEAD. - /// - /// - /// The object ID of the current HEAD. - /// - public GitObjectId GetHeadCommitSha() + string commonDirectory = gitDirectory; + string commonDirFile = Path.Combine(gitDirectory, "commondir"); + + if (File.Exists(commonDirFile)) { - return this.Lookup("HEAD") ?? GitObjectId.Empty; + string? commonDirectoryRelativePath = File.ReadAllText(commonDirFile).Trim('\n'); + commonDirectory = Path.Combine(gitDirectory, commonDirectoryRelativePath); } - /// - /// Gets the current HEAD commit, if available. - /// - /// - /// A value indicating whether to populate the field. - /// - /// - /// The current HEAD commit, or if not available. - /// - public GitCommit? GetHeadCommit(bool readAuthor = false) - { - var headCommitId = this.GetHeadCommitSha(); + string objectDirectory = Path.Combine(commonDirectory, "objects"); - if (headCommitId == GitObjectId.Empty) - { - return null; - } + return new GitRepository(workingDirectory!, gitDirectory, commonDirectory, objectDirectory); + } - return this.GetCommit(headCommitId, readAuthor); - } + /// + /// Creates a new instance of the class. + /// + /// + /// + /// + /// + /// A newly created instance. + public static GitRepository Create(string workingDirectory, string gitDirectory, string commonDirectory, string objectDirectory) + { + return new GitRepository(workingDirectory, gitDirectory, commonDirectory, objectDirectory); + } - /// - /// Gets a commit by its Git object Id. - /// - /// - /// The Git object Id of the commit. - /// - /// - /// A value indicating whether to populate the field. - /// - /// - /// The requested commit. - /// - public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) + /// + /// Decodes a sequence of bytes from the specified byte array into a . + /// + /// + /// The span containing the sequence of UTF-8 bytes to decode. + /// + /// + /// A that contains the results of decoding the specified sequence of bytes. + /// + public static unsafe string GetString(ReadOnlySpan bytes) + { + fixed (byte* pBytes = bytes) { - using (Stream? stream = this.GetObjectBySha(sha, "commit")) - { - if (stream is null) - { - throw new GitException($"The commit {sha} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; - } - - return GitCommitReader.Read(stream, sha, readAuthor); - } + return Encoding.GetString(pBytes, bytes.Length); } + } - /// - /// Parses any committish to an object id. - /// - /// Any "objectish" string (e.g. commit ID (partial or full), branch name, tag name, or "HEAD"). - /// The object ID referenced by if found; otherwise . - public GitObjectId? Lookup(string objectish) - { - bool skipObjectIdLookup = false; + /// + /// Parses the contents of the alternates file, and returns a list of (relative) paths to the alternate object directories. + /// + /// + /// The contents of the alternates files. + /// + /// + /// A list of (relative) paths to the alternate object directories. + /// + public static List ParseAlternates(ReadOnlySpan alternates) + => ParseAlternates(alternates, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 2 : 0); - if (objectish == "HEAD") - { - var reference = this.GetHeadAsReferenceOrSha(); - if (reference is GitObjectId headObjectId) - { - return headObjectId; - } + /// + /// Parses the contents of the alternates file, and returns a list of (relative) paths to the alternate object directories. + /// + /// + /// The contents of the alternates files. + /// + /// + /// The number of bytes to skip in the span when looking for a delimiter. + /// + /// + /// A list of (relative) paths to the alternate object directories. + /// + public static List ParseAlternates(ReadOnlySpan alternates, int skipCount) + { + var values = new List(); - objectish = (string)reference; - } + int index; + int length; - var possibleLooseFileMatches = new List(); - if (objectish.StartsWith("refs/", StringComparison.Ordinal)) - { - // Match on loose ref files by their canonical name. - possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, objectish)); - skipObjectIdLookup = true; - } - else - { - // Look for simple names for branch or tag. - possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, "refs", "heads", objectish)); - possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, "refs", "tags", objectish)); - possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, "refs", "remotes", objectish)); - } + // The alternates path is colon (:)-separated. On Windows, there may be full paths, such as + // C:/Users/username/source/repos/nbgv/.git, which also contain a colon. Because the colon + // can only appear at the second position, we skip the first two characters (e.g. C:) on Windows. + while (alternates.Length > skipCount) + { + index = alternates.Slice(skipCount).IndexOfAny((byte)':', (byte)'\n'); + length = index > 0 ? skipCount + index : alternates.Length; - if (possibleLooseFileMatches.FirstOrDefault(File.Exists) is string existingPath) - { - return GitObjectId.Parse(File.ReadAllText(existingPath).TrimEnd()); - } + values.Add(GetString(alternates.Slice(0, length))); + alternates = index > 0 ? alternates.Slice(length + 1) : Span.Empty; + } - // Match in packed-refs file. - string packedRefPath = Path.Combine(this.CommonDirectory, "packed-refs"); - if (File.Exists(packedRefPath)) - { - using var refReader = File.OpenText(packedRefPath); - string? line; - while ((line = refReader.ReadLine()) is object) - { - if (line.StartsWith("#", StringComparison.Ordinal)) - { - continue; - } + return values; + } - string refName = line.Substring(41); - if (string.Equals(refName, objectish, StringComparison.Ordinal)) - { - return GitObjectId.Parse(line.Substring(0, 40)); - } - else if (!objectish.StartsWith("refs/", StringComparison.Ordinal)) - { - // Not a canonical ref, so try heads and tags - if (string.Equals(refName, "refs/heads/" + objectish, StringComparison.Ordinal)) - { - return GitObjectId.Parse(line.Substring(0, 40)); - } - else if (string.Equals(refName, "refs/tags/" + objectish, StringComparison.Ordinal)) - { - return GitObjectId.Parse(line.Substring(0, 40)); - } - else if (string.Equals(refName, "refs/remotes/" + objectish, StringComparison.Ordinal)) - { - return GitObjectId.Parse(line.Substring(0, 40)); - } - } - } - } + /// + /// Shortens the object id. + /// + /// + /// The object Id to shorten. + /// + /// + /// The minimum string length. + /// + /// + /// The short object id. + /// + public string ShortenObjectId(GitObjectId objectId, int minimum) + { + string? sha = objectId.ToString(); - if (skipObjectIdLookup) - { - return null; - } + for (int length = minimum; length < sha.Length; length += 2) + { + string? objectish = sha.Substring(0, length); - if (objectish.Length == 40) + if (this.Lookup(objectish) is not null) { - return GitObjectId.Parse(objectish); + return objectish; } + } - var possibleObjectIds = new List(); - if (objectish.Length > 2 && objectish.Length < 40) - { - // Search for _any_ object whose id starts with objectish in the object database - var directory = Path.Combine(this.ObjectDirectory, objectish.Substring(0, 2)); + return sha; + } - if (Directory.Exists(directory)) - { - var files = Directory.GetFiles(directory, $"{objectish.Substring(2)}*"); + /// + /// Returns the current HEAD as a reference (if available) or a Git object id. + /// + /// + /// The current HEAD as a reference (if available) or a Git object id. + /// + public object GetHeadAsReferenceOrSha() + { + using FileStream? stream = File.OpenRead(Path.Combine(this.GitDirectory, HeadFileName)); + return GitReferenceReader.ReadReference(stream); + } - foreach (var file in files) - { - var objectId = $"{objectish.Substring(0, 2)}{Path.GetFileName(file)}"; - possibleObjectIds.Add(GitObjectId.Parse(objectId)); - } - } + /// + /// Gets the object ID of the current HEAD. + /// + /// + /// The object ID of the current HEAD. + /// + public GitObjectId GetHeadCommitSha() + { + return this.Lookup("HEAD") ?? GitObjectId.Empty; + } - // Search for _any_ object whose id starts with objectish in the packfile - bool endsWithHalfByte = objectish.Length % 2 == 1; - if (endsWithHalfByte) - { - // Add one more character so hex can be converted to bytes. - // The bit length to be compared will not consider the last four bits. - objectish += "0"; - } + /// + /// Gets the current HEAD commit, if available. + /// + /// + /// A value indicating whether to populate the field. + /// + /// + /// The current HEAD commit, or if not available. + /// + public GitCommit? GetHeadCommit(bool readAuthor = false) + { + GitObjectId headCommitId = this.GetHeadCommitSha(); - if (objectish.Length <= 40 && objectish.Length % 2 == 0) - { - Span decodedHex = stackalloc byte[objectish.Length / 2]; - if (TryConvertHexStringToByteArray(objectish, decodedHex)) - { - foreach (var pack in this.packs.Value.Span) - { - var objectId = pack.Lookup(decodedHex, endsWithHalfByte); + if (headCommitId == GitObjectId.Empty) + { + return null; + } - // It's possible for the same object to be present in both the object database and the pack files, - // or in multiple pack files. - if (objectId is not null && !possibleObjectIds.Contains(objectId.Value)) - { - if (possibleObjectIds.Count > 0) - { - // If objectish already resolved to at least one object which is different from the current - // object id, objectish is not well-defined; so stop resolving and return null instead. - return null; - } - else - { - possibleObjectIds.Add(objectId.Value); - } - } - } - } - } - } + return this.GetCommit(headCommitId, readAuthor); + } + + /// + /// Gets a commit by its Git object Id. + /// + /// + /// The Git object Id of the commit. + /// + /// + /// A value indicating whether to populate the field. + /// + /// + /// The requested commit. + /// + public GitCommit GetCommit(GitObjectId sha, bool readAuthor = false) + { + using Stream? stream = this.GetObjectBySha(sha, "commit"); + if (stream is null) + { + throw new GitException($"The commit {sha} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; + } - if (possibleObjectIds.Count == 1) + return GitCommitReader.Read(stream, sha, readAuthor); + } + + /// + /// Parses any committish to an object id. + /// + /// Any "objectish" string (e.g. commit ID (partial or full), branch name, tag name, or "HEAD"). + /// The object ID referenced by if found; otherwise . + public GitObjectId? Lookup(string objectish) + { + bool skipObjectIdLookup = false; + + if (objectish == "HEAD") + { + object? reference = this.GetHeadAsReferenceOrSha(); + if (reference is GitObjectId headObjectId) { - return possibleObjectIds[0]; + return headObjectId; } - return null; + objectish = (string)reference; } - /// - /// Gets a tree object by its Git object Id. - /// - /// - /// The Git object Id of the tree. - /// - /// - /// The requested tree. - /// - public GitTree GetTree(GitObjectId sha) + var possibleLooseFileMatches = new List(); + if (objectish.StartsWith("refs/", StringComparison.Ordinal)) { - using (Stream? stream = this.GetObjectBySha(sha, "tree")) - { - if (stream is null) - { - throw new GitException($"The tree {sha} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; - } + // Match on loose ref files by their canonical name. + possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, objectish)); + skipObjectIdLookup = true; + } + else + { + // Look for simple names for branch or tag. + possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, "refs", "heads", objectish)); + possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, "refs", "tags", objectish)); + possibleLooseFileMatches.Add(Path.Combine(this.CommonDirectory, "refs", "remotes", objectish)); + } - return GitTreeReader.Read(stream, sha); - } + if (possibleLooseFileMatches.FirstOrDefault(File.Exists) is string existingPath) + { + return GitObjectId.Parse(File.ReadAllText(existingPath).TrimEnd()); } - /// - /// Gets an entry in a git tree. - /// - /// - /// The Git object Id of the Git tree. - /// - /// - /// The name of the node in the Git tree. - /// - /// - /// The object Id of the requested entry. Returns if the entry - /// could not be found. - /// - public GitObjectId GetTreeEntry(GitObjectId treeId, ReadOnlySpan nodeName) - { - using (Stream? treeStream = this.GetObjectBySha(treeId, "tree")) + // Match in packed-refs file. + string packedRefPath = Path.Combine(this.CommonDirectory, "packed-refs"); + if (File.Exists(packedRefPath)) + { + using StreamReader? refReader = File.OpenText(packedRefPath); + string? line; + while ((line = refReader.ReadLine()) is object) { - if (treeStream is null) + if (line.StartsWith("#", StringComparison.Ordinal)) { - throw new GitException($"The tree {treeId} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; + continue; } - return GitTreeStreamingReader.FindNode(treeStream, nodeName); + string refName = line.Substring(41); + if (string.Equals(refName, objectish, StringComparison.Ordinal)) + { + return GitObjectId.Parse(line.Substring(0, 40)); + } + else if (!objectish.StartsWith("refs/", StringComparison.Ordinal)) + { + // Not a canonical ref, so try heads and tags + if (string.Equals(refName, "refs/heads/" + objectish, StringComparison.Ordinal)) + { + return GitObjectId.Parse(line.Substring(0, 40)); + } + else if (string.Equals(refName, "refs/tags/" + objectish, StringComparison.Ordinal)) + { + return GitObjectId.Parse(line.Substring(0, 40)); + } + else if (string.Equals(refName, "refs/remotes/" + objectish, StringComparison.Ordinal)) + { + return GitObjectId.Parse(line.Substring(0, 40)); + } + } } } - /// - /// Gets a Git object by its Git object Id. - /// - /// - /// The Git object id of the object to retrieve. - /// - /// - /// The type of object to retrieve. - /// - /// - /// A which represents the requested object. - /// - /// - /// The requested object could not be found. - /// - /// - /// As a special case, a value will be returned for - /// . - /// - public Stream? GetObjectBySha(GitObjectId sha, string objectType) - { - if (sha == GitObjectId.Empty) - { - return null; - } + if (skipObjectIdLookup) + { + return null; + } - if (this.TryGetObjectBySha(sha, objectType, out Stream? value)) - { - return value; - } - else - { - throw new GitException($"An {objectType} object with SHA {sha} could not be found.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; - } + if (objectish.Length == 40) + { + return GitObjectId.Parse(objectish); } - /// - /// Gets a Git object by its Git object Id. - /// - /// - /// The Git object id of the object to retrieve. - /// - /// - /// The type of object to retrieve. - /// - /// - /// An output parameter which retrieves the requested Git object. - /// - /// - /// if the object could be found; otherwise, - /// . - /// - public bool TryGetObjectBySha(GitObjectId sha, string objectType, out Stream? value) + var possibleObjectIds = new List(); + if (objectish.Length > 2 && objectish.Length < 40) { -#if DEBUG - if (!this.histogram.TryAdd(sha, 1)) - { - this.histogram[sha] += 1; - } -#endif + // Search for _any_ object whose id starts with objectish in the object database + string? directory = Path.Combine(this.ObjectDirectory, objectish.Substring(0, 2)); - foreach (var pack in this.packs.Value.Span) + if (Directory.Exists(directory)) { - if (pack.TryGetObject(sha, objectType, out value)) + string[]? files = Directory.GetFiles(directory, $"{objectish.Substring(2)}*"); + + foreach (string? file in files) { - return true; + string? objectId = $"{objectish.Substring(0, 2)}{Path.GetFileName(file)}"; + possibleObjectIds.Add(GitObjectId.Parse(objectId)); } } - if (this.TryGetObjectByPath(sha, objectType, out value)) + // Search for _any_ object whose id starts with objectish in the packfile + bool endsWithHalfByte = objectish.Length % 2 == 1; + if (endsWithHalfByte) { - return true; + // Add one more character so hex can be converted to bytes. + // The bit length to be compared will not consider the last four bits. + objectish += "0"; } - foreach (var alternate in this.alternates) + if (objectish.Length <= 40 && objectish.Length % 2 == 0) { - if (alternate.TryGetObjectBySha(sha, objectType, out value)) + Span decodedHex = stackalloc byte[objectish.Length / 2]; + if (TryConvertHexStringToByteArray(objectish, decodedHex)) { - return true; + foreach (GitPack? pack in this.packs.Value.Span) + { + GitObjectId? objectId = pack.Lookup(decodedHex, endsWithHalfByte); + + // It's possible for the same object to be present in both the object database and the pack files, + // or in multiple pack files. + if (objectId is not null && !possibleObjectIds.Contains(objectId.Value)) + { + if (possibleObjectIds.Count > 0) + { + // If objectish already resolved to at least one object which is different from the current + // object id, objectish is not well-defined; so stop resolving and return null instead. + return null; + } + else + { + possibleObjectIds.Add(objectId.Value); + } + } + } } } - - value = null; - return false; } - /// - /// Gets cache usage statistics. - /// - /// - /// A which represents the cache usage statistics. - /// - public string GetCacheStatistics() + if (possibleObjectIds.Count == 1) { - StringBuilder builder = new StringBuilder(); + return possibleObjectIds[0]; + } -#if DEBUG - int histogramCount = 25; + return null; + } - builder.AppendLine("Overall repository:"); - builder.AppendLine($"Top {histogramCount} / {this.histogram.Count} items:"); + /// + /// Gets a tree object by its Git object Id. + /// + /// + /// The Git object Id of the tree. + /// + /// + /// The requested tree. + /// + public GitTree GetTree(GitObjectId sha) + { + using Stream? stream = this.GetObjectBySha(sha, "tree"); + if (stream is null) + { + throw new GitException($"The tree {sha} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; + } - foreach (var item in this.histogram.OrderByDescending(v => v.Value).Take(25)) - { - builder.AppendLine($" {item.Key}: {item.Value}"); - } + return GitTreeReader.Read(stream, sha); + } - builder.AppendLine(); -#endif + /// + /// Gets an entry in a git tree. + /// + /// + /// The Git object Id of the Git tree. + /// + /// + /// The name of the node in the Git tree. + /// + /// + /// The object Id of the requested entry. Returns if the entry + /// could not be found. + /// + public GitObjectId GetTreeEntry(GitObjectId treeId, ReadOnlySpan nodeName) + { + using Stream? treeStream = this.GetObjectBySha(treeId, "tree"); + if (treeStream is null) + { + throw new GitException($"The tree {treeId} was not found in this repository.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; + } - foreach (var pack in this.packs.Value.Span) - { - pack.GetCacheStatistics(builder); - } + return GitTreeStreamingReader.FindNode(treeStream, nodeName); + } - return builder.ToString(); + /// + /// Gets a Git object by its Git object Id. + /// + /// + /// The Git object id of the object to retrieve. + /// + /// + /// The type of object to retrieve. + /// + /// + /// A which represents the requested object. + /// + /// + /// The requested object could not be found. + /// + /// + /// As a special case, a value will be returned for + /// . + /// + public Stream? GetObjectBySha(GitObjectId sha, string objectType) + { + if (sha == GitObjectId.Empty) + { + return null; } - /// - public override string ToString() + if (this.TryGetObjectBySha(sha, objectType, out Stream? value)) { - return $"Git Repository: {this.WorkingDirectory}"; + return value; } - - /// - public void Dispose() + else { - if (this.packs.IsValueCreated) - { - foreach (var pack in this.packs.Value.Span) - { - pack.Dispose(); - } - } + throw new GitException($"An {objectType} object with SHA {sha} could not be found.") { ErrorCode = GitException.ErrorCodes.ObjectNotFound }; } + } - private bool TryGetObjectByPath(GitObjectId sha, string objectType, [NotNullWhen(true)] out Stream? value) + /// + /// Gets a Git object by its Git object Id. + /// + /// + /// The Git object id of the object to retrieve. + /// + /// + /// The type of object to retrieve. + /// + /// + /// An output parameter which retrieves the requested Git object. + /// + /// + /// if the object could be found; otherwise, + /// . + /// + public bool TryGetObjectBySha(GitObjectId sha, string objectType, out Stream? value) + { +#if DEBUG + if (!this.histogram.TryAdd(sha, 1)) { - sha.CopyAsHex(0, 1, this.objectPathBuffer.AsSpan(this.ObjectDirectory.Length + 1, 2)); - sha.CopyAsHex(1, 19, this.objectPathBuffer.AsSpan(this.ObjectDirectory.Length + 1 + 2 + 1)); - - if (!FileHelpers.TryOpen(this.objectPathBuffer, out var compressedFile)) - { - value = null; - return false; - } - - var objectStream = new GitObjectStream(compressedFile!, objectType); + this.histogram[sha] += 1; + } +#endif - if (string.CompareOrdinal(objectStream.ObjectType, objectType) != 0) + foreach (GitPack? pack in this.packs.Value.Span) + { + if (pack.TryGetObject(sha, objectType, out value)) { - throw new GitException($"Got a {objectStream.ObjectType} instead of a {objectType} when opening object {sha}"); + return true; } + } - value = objectStream; + if (this.TryGetObjectByPath(sha, objectType, out value)) + { return true; } - private ReadOnlyMemory LoadPacks() + foreach (GitRepository? alternate in this.alternates) { - var packDirectory = Path.Combine(this.ObjectDirectory, "pack/"); - - if (!Directory.Exists(packDirectory)) + if (alternate.TryGetObjectBySha(sha, objectType, out value)) { - return Array.Empty(); + return true; } + } - var indexFiles = Directory.GetFiles(packDirectory, "*.idx"); - var packs = new GitPack[indexFiles.Length]; - int addCount = 0; + value = null; + return false; + } - for (int i = 0; i < indexFiles.Length; i++) - { - var name = Path.GetFileNameWithoutExtension(indexFiles[i]); - var indexPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.idx"); - var packPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.pack"); + /// + /// Gets cache usage statistics. + /// + /// + /// A which represents the cache usage statistics. + /// + public string GetCacheStatistics() + { + var builder = new StringBuilder(); - // Only proceed if both the packfile and index file exist. - if (File.Exists(packPath)) - { - packs[addCount++] = new GitPack(this.GetObjectBySha, indexPath, packPath); - } - } +#if DEBUG + int histogramCount = 25; - return packs.AsMemory(0, addCount); + builder.AppendLine("Overall repository:"); + builder.AppendLine($"Top {histogramCount} / {this.histogram.Count} items:"); + + foreach (KeyValuePair item in this.histogram.OrderByDescending(v => v.Value).Take(25)) + { + builder.AppendLine($" {item.Key}: {item.Value}"); } - private static string TrimEndingDirectorySeparator(string path) + builder.AppendLine(); +#endif + + foreach (GitPack? pack in this.packs.Value.Span) { -#if NETSTANDARD2_0 - if (string.IsNullOrEmpty(path) || path.Length == 1) - { - return path; - } + pack.GetCacheStatistics(builder); + } + + return builder.ToString(); + } - var last = path[path.Length - 1]; + /// + public override string ToString() + { + return $"Git Repository: {this.WorkingDirectory}"; + } - if (last == Path.DirectorySeparatorChar || last == Path.AltDirectorySeparatorChar) + /// + public void Dispose() + { + if (this.packs.IsValueCreated) + { + foreach (GitPack? pack in this.packs.Value.Span) { - return path.Substring(0, path.Length - 1); + pack.Dispose(); } + } + } + private static string TrimEndingDirectorySeparator(string path) + { +#if NETSTANDARD2_0 + if (string.IsNullOrEmpty(path) || path.Length == 1) + { return path; + } + + char last = path[path.Length - 1]; + + if (last == Path.DirectorySeparatorChar || last == Path.AltDirectorySeparatorChar) + { + return path.Substring(0, path.Length - 1); + } + + return path; #else - return Path.TrimEndingDirectorySeparator(path); + return Path.TrimEndingDirectorySeparator(path); #endif + } + + private static bool TryConvertHexStringToByteArray(string hexString, Span data) + { + // https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array + if (hexString.Length % 2 != 0) + { + data = null; + return false; } - private static bool TryConvertHexStringToByteArray(string hexString, Span data) + Requires.Argument(data.Length == hexString.Length / 2, nameof(data), "Length must be exactly half that of " + nameof(hexString) + "."); + for (int index = 0; index < data.Length; index++) { - // https://stackoverflow.com/questions/321370/how-can-i-convert-a-hex-string-to-a-byte-array - if (hexString.Length % 2 != 0) +#if !NETSTANDARD2_0 + ReadOnlySpan byteValue = hexString.AsSpan(index * 2, 2); + if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) { - data = null; return false; } - - Requires.Argument(data.Length == hexString.Length / 2, nameof(data), "Length must be exactly half that of " + nameof(hexString) + "."); - for (int index = 0; index < data.Length; index++) - { -#if !NETSTANDARD2_0 - ReadOnlySpan byteValue = hexString.AsSpan(index * 2, 2); - if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) - { - return false; - } #else - string byteValue = hexString.Substring(index * 2, 2); - if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) - { - return false; - } -#endif + string byteValue = hexString.Substring(index * 2, 2); + if (!byte.TryParse(byteValue, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out data[index])) + { + return false; } +#endif + } - return true; + return true; + } + + private bool TryGetObjectByPath(GitObjectId sha, string objectType, [NotNullWhen(true)] out Stream? value) + { + sha.CopyAsHex(0, 1, this.objectPathBuffer.AsSpan(this.ObjectDirectory.Length + 1, 2)); + sha.CopyAsHex(1, 19, this.objectPathBuffer.AsSpan(this.ObjectDirectory.Length + 1 + 2 + 1)); + + if (!FileHelpers.TryOpen(this.objectPathBuffer, out FileStream? compressedFile)) + { + value = null; + return false; } - /// - /// Decodes a sequence of bytes from the specified byte array into a . - /// - /// - /// The span containing the sequence of UTF-8 bytes to decode. - /// - /// - /// A that contains the results of decoding the specified sequence of bytes. - /// - public static unsafe string GetString(ReadOnlySpan bytes) + var objectStream = new GitObjectStream(compressedFile!, objectType); + + if (string.CompareOrdinal(objectStream.ObjectType, objectType) != 0) { - fixed (byte* pBytes = bytes) - { - return Encoding.GetString(pBytes, bytes.Length); - } + throw new GitException($"Got a {objectStream.ObjectType} instead of a {objectType} when opening object {sha}"); } - /// - /// Parses the contents of the alternates file, and returns a list of (relative) paths to the alternate object directories. - /// - /// - /// The contents of the alternates files. - /// - /// - /// A list of (relative) paths to the alternate object directories. - /// - public static List ParseAlternates(ReadOnlySpan alternates) - => ParseAlternates(alternates, RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? 2 : 0); - - /// - /// Parses the contents of the alternates file, and returns a list of (relative) paths to the alternate object directories. - /// - /// - /// The contents of the alternates files. - /// - /// - /// The number of bytes to skip in the span when looking for a delimiter. - /// - /// - /// A list of (relative) paths to the alternate object directories. - /// - public static List ParseAlternates(ReadOnlySpan alternates, int skipCount) - { - List values = new List(); - - int index; - int length; - - // The alternates path is colon (:)-separated. On Windows, there may be full paths, such as - // C:/Users/username/source/repos/nbgv/.git, which also contain a colon. Because the colon - // can only appear at the second position, we skip the first two characters (e.g. C:) on Windows. - while (alternates.Length > skipCount) - { - index = alternates.Slice(skipCount).IndexOfAny((byte)':', (byte)'\n'); - length = index > 0 ? skipCount + index : alternates.Length; + value = objectStream; + return true; + } - values.Add(GetString(alternates.Slice(0, length))); - alternates = index > 0 ? alternates.Slice(length + 1) : Span.Empty; - } + private ReadOnlyMemory LoadPacks() + { + string? packDirectory = Path.Combine(this.ObjectDirectory, "pack/"); + + if (!Directory.Exists(packDirectory)) + { + return Array.Empty(); + } + + string[]? indexFiles = Directory.GetFiles(packDirectory, "*.idx"); + var packs = new GitPack[indexFiles.Length]; + int addCount = 0; - return values; + for (int i = 0; i < indexFiles.Length; i++) + { + string? name = Path.GetFileNameWithoutExtension(indexFiles[i]); + string? indexPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.idx"); + string? packPath = Path.Combine(this.ObjectDirectory, "pack", $"{name}.pack"); + + // Only proceed if both the packfile and index file exist. + if (File.Exists(packPath)) + { + packs[addCount++] = new GitPack(this.GetObjectBySha, indexPath, packPath); + } } + + return packs.AsMemory(0, addCount); } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs b/src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs index 53d56759..e3d65410 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs @@ -1,27 +1,27 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System; +#nullable enable -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Represents the signature of a Git committer or author. +/// +public struct GitSignature { /// - /// Represents the signature of a Git committer or author. + /// Gets or sets the name of the committer or author. /// - public struct GitSignature - { - /// - /// Gets or sets the name of the committer or author. - /// - public string Name { get; set; } + public string Name { get; set; } - /// - /// Gets or sets the e-mail address of the commiter or author. - /// - public string Email { get; set; } + /// + /// Gets or sets the e-mail address of the commiter or author. + /// + public string Email { get; set; } - /// - /// Gets or sets the date and time at which the commit was made. - /// - public DateTimeOffset Date { get; set; } - } + /// + /// Gets or sets the date and time at which the commit was made. + /// + public DateTimeOffset Date { get; set; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTree.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTree.cs index 6635d630..adeb7968 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitTree.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitTree.cs @@ -1,33 +1,33 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -using System.Collections.Generic; +#nullable enable -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Represents a git tree. +/// +public class GitTree { /// - /// Represents a git tree. + /// Gets an empty . /// - public class GitTree - { - /// - /// Gets an empty . - /// - public static GitTree Empty { get; } = new GitTree(); + public static GitTree Empty { get; } = new GitTree(); - /// - /// The Git object Id of this . - /// - public GitObjectId Sha { get; set; } + /// + /// Gets or sets the Git object Id of this . + /// + public GitObjectId Sha { get; set; } - /// - /// Gets a dictionary which contains all entries in the current tree, accessible by name. - /// - public Dictionary Children { get; } = new Dictionary(); + /// + /// Gets a dictionary which contains all entries in the current tree, accessible by name. + /// + public Dictionary Children { get; } = new Dictionary(); - /// - public override string ToString() - { - return $"Git tree: {this.Sha}"; - } + /// + public override string ToString() + { + return $"Git tree: {this.Sha}"; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs index a213b268..57590dc7 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs @@ -1,50 +1,52 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning.ManagedGit +#nullable enable + +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Represents an individual entry in the Git tree. +/// +public class GitTreeEntry { /// - /// Represents an individual entry in the Git tree. + /// Initializes a new instance of the class. /// - public class GitTreeEntry + /// + /// The name of the entry. + /// + /// + /// A vaolue indicating whether the current entry is a file. + /// + /// + /// The Git object Id of the blob or tree of the current entry. + /// + public GitTreeEntry(string name, bool isFile, GitObjectId sha) { - /// - /// Initializes a new instance of the class. - /// - /// - /// The name of the entry. - /// - /// - /// A vaolue indicating whether the current entry is a file. - /// - /// - /// The Git object Id of the blob or tree of the current entry. - /// - public GitTreeEntry(string name, bool isFile, GitObjectId sha) - { - this.Name = name; - this.IsFile = isFile; - this.Sha = sha; - } + this.Name = name; + this.IsFile = isFile; + this.Sha = sha; + } - /// - /// Gets the name of the entry. - /// - public string Name { get; } + /// + /// Gets the name of the entry. + /// + public string Name { get; } - /// - /// Gets a value indicating whether the current entry is a file. - /// - public bool IsFile { get; } + /// + /// Gets a value indicating whether the current entry is a file. + /// + public bool IsFile { get; } - /// - /// Gets the Git object Id of the blob or tree of the current entry. - /// - public GitObjectId Sha { get; } + /// + /// Gets the Git object Id of the blob or tree of the current entry. + /// + public GitObjectId Sha { get; } - /// - public override string ToString() - { - return this.Name; - } + /// + public override string ToString() + { + return this.Name; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs index 7baf8451..d230a2e4 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs @@ -1,57 +1,57 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers; -using System.IO; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +internal static class GitTreeReader { - internal static class GitTreeReader + public static GitTree Read(Stream stream, GitObjectId objectId) { - public static GitTree Read(Stream stream, GitObjectId objectId) - { - byte[] buffer = ArrayPool.Shared.Rent((int)stream.Length); + byte[] buffer = ArrayPool.Shared.Rent((int)stream.Length); #if DEBUG - Array.Clear(buffer, 0, buffer.Length); + Array.Clear(buffer, 0, buffer.Length); #endif - GitTree value = new GitTree() - { - Sha = objectId, - }; + var value = new GitTree() + { + Sha = objectId, + }; - try - { - Span contents = buffer.AsSpan(0, (int)stream.Length); - stream.ReadAll(contents); + try + { + Span contents = buffer.AsSpan(0, (int)stream.Length); + stream.ReadAll(contents); - while (contents.Length > 0) - { - // Format: [mode] [file/ folder name]\0[SHA - 1 of referencing blob or tree] - // Mode is either 6-bytes long (directory) or 7-bytes long (file). - // If the entry is a file, the first byte is '1' - var fileNameEnds = contents.IndexOf((byte)0); - bool isFile = contents[0] == (byte)'1'; - var modeLength = isFile ? 7 : 6; + while (contents.Length > 0) + { + // Format: [mode] [file/ folder name]\0[SHA - 1 of referencing blob or tree] + // Mode is either 6-bytes long (directory) or 7-bytes long (file). + // If the entry is a file, the first byte is '1' + int fileNameEnds = contents.IndexOf((byte)0); + bool isFile = contents[0] == (byte)'1'; + int modeLength = isFile ? 7 : 6; - var currentName = contents.Slice(modeLength, fileNameEnds - modeLength); - var currentObjectId = GitObjectId.Parse(contents.Slice(fileNameEnds + 1, 20)); + Span currentName = contents.Slice(modeLength, fileNameEnds - modeLength); + var currentObjectId = GitObjectId.Parse(contents.Slice(fileNameEnds + 1, 20)); - var name = GitRepository.GetString(currentName); + string? name = GitRepository.GetString(currentName); - value.Children.Add( - name, - new GitTreeEntry(name, isFile, currentObjectId)); + value.Children.Add( + name, + new GitTreeEntry(name, isFile, currentObjectId)); - contents = contents.Slice(fileNameEnds + 1 + 20); - } - } - finally - { - ArrayPool.Shared.Return(buffer); + contents = contents.Slice(fileNameEnds + 1 + 20); } - - return value; } + finally + { + ArrayPool.Shared.Return(buffer); + } + + return value; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs index fe0db93a..6799b7a0 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs @@ -1,62 +1,62 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers; -using System.IO; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Reads git tree objects. +/// +public class GitTreeStreamingReader { /// - /// Reads git tree objects. + /// Finds a specific node in a git tree. /// - public class GitTreeStreamingReader + /// + /// A which represents the git tree. + /// + /// + /// The name of the node to find, in it UTF-8 representation. + /// + /// + /// The of the requested node. + /// + public static GitObjectId FindNode(Stream stream, ReadOnlySpan name) { - /// - /// Finds a specific node in a git tree. - /// - /// - /// A which represents the git tree. - /// - /// - /// The name of the node to find, in it UTF-8 representation. - /// - /// - /// The of the requested node. - /// - public static GitObjectId FindNode(Stream stream, ReadOnlySpan name) - { - byte[] buffer = ArrayPool.Shared.Rent((int)stream.Length); - Span contents = new Span(buffer, 0, (int)stream.Length); + byte[] buffer = ArrayPool.Shared.Rent((int)stream.Length); + var contents = new Span(buffer, 0, (int)stream.Length); + + stream.ReadAll(contents); + + GitObjectId value = GitObjectId.Empty; - stream.ReadAll(contents); + while (contents.Length > 0) + { + // Format: [mode] [file/ folder name]\0[SHA - 1 of referencing blob or tree] + // Mode is either 6-bytes long (directory) or 7-bytes long (file). + // If the entry is a file, the first byte is '1' + int fileNameEnds = contents.IndexOf((byte)0); + bool isFile = contents[0] == (byte)'1'; + int modeLength = isFile ? 7 : 6; - GitObjectId value = GitObjectId.Empty; + Span currentName = contents.Slice(modeLength, fileNameEnds - modeLength); - while (contents.Length > 0) + if (currentName.SequenceEqual(name)) + { + value = GitObjectId.Parse(contents.Slice(fileNameEnds + 1, 20)); + break; + } + else { - // Format: [mode] [file/ folder name]\0[SHA - 1 of referencing blob or tree] - // Mode is either 6-bytes long (directory) or 7-bytes long (file). - // If the entry is a file, the first byte is '1' - var fileNameEnds = contents.IndexOf((byte)0); - bool isFile = contents[0] == (byte)'1'; - var modeLength = isFile ? 7 : 6; - - var currentName = contents.Slice(modeLength, fileNameEnds - modeLength); - - if (currentName.SequenceEqual(name)) - { - value = GitObjectId.Parse(contents.Slice(fileNameEnds + 1, 20)); - break; - } - else - { - contents = contents.Slice(fileNameEnds + 1 + 20); - } + contents = contents.Slice(fileNameEnds + 1 + 20); } + } - ArrayPool.Shared.Return(buffer); + ArrayPool.Shared.Return(buffer); - return value; - } + return value; } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs index 8128dbf4..cecef5ed 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs @@ -1,156 +1,156 @@ -using System; -using System.IO; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System.IO.MemoryMappedFiles; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Provides read-only, seekable access to a . +/// +public unsafe class MemoryMappedStream : Stream { + private readonly MemoryMappedViewAccessor accessor; + private readonly long length; + private readonly byte* ptr; + private long position; + private bool disposed; + /// - /// Provides read-only, seekable access to a . + /// Initializes a new instance of the class. /// - public unsafe class MemoryMappedStream : Stream + /// + /// The accessor to the memory mapped stream. + /// + public MemoryMappedStream(MemoryMappedViewAccessor accessor) { - private readonly MemoryMappedViewAccessor accessor; - private readonly long length; - private long position; - private byte* ptr; - private bool disposed; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The accessor to the memory mapped stream. - /// - public MemoryMappedStream(MemoryMappedViewAccessor accessor) - { - this.accessor = accessor ?? throw new ArgumentNullException(nameof(accessor)); - this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.ptr); - this.length = this.accessor.Capacity; - } + this.accessor = accessor ?? throw new ArgumentNullException(nameof(accessor)); + this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.ptr); + this.length = this.accessor.Capacity; + } - /// - public override bool CanRead => true; + /// + public override bool CanRead => true; - /// - public override bool CanSeek => true; + /// + public override bool CanSeek => true; - /// - public override bool CanWrite => false; + /// + public override bool CanWrite => false; - /// - public override long Length => this.length; + /// + public override long Length => this.length; - /// - public override long Position + /// + public override long Position + { + get => this.position; + set { - get => this.position; - set - { - this.position = (int)value; - } + this.position = (int)value; } + } - /// - public override void Flush() - { - } + /// + public override void Flush() + { + } - /// - public override int Read(byte[] buffer, int offset, int count) + /// + public override int Read(byte[] buffer, int offset, int count) + { + if (this.disposed) { - if (this.disposed) - { - throw new ObjectDisposedException(nameof(MemoryMappedStream)); - } + throw new ObjectDisposedException(nameof(MemoryMappedStream)); + } - int read = (int)Math.Min(count, this.length - this.position); + int read = (int)Math.Min(count, this.length - this.position); - new Span(this.ptr + this.position, read) - .CopyTo(buffer.AsSpan(offset, count)); + new Span(this.ptr + this.position, read) + .CopyTo(buffer.AsSpan(offset, count)); - this.position += read; - return read; - } + this.position += read; + return read; + } #if !NETSTANDARD2_0 - /// - public override int Read(Span buffer) + /// + public override int Read(Span buffer) + { + if (this.disposed) { - if (this.disposed) - { - throw new ObjectDisposedException(nameof(MemoryMappedStream)); - } - - int read = (int)Math.Min(buffer.Length, this.length - this.position); - - new Span(this.ptr + this.position, read) - .CopyTo(buffer); - - this.position += read; - return read; + throw new ObjectDisposedException(nameof(MemoryMappedStream)); } + + int read = (int)Math.Min(buffer.Length, this.length - this.position); + + new Span(this.ptr + this.position, read) + .CopyTo(buffer); + + this.position += read; + return read; + } #endif - /// - public override long Seek(long offset, SeekOrigin origin) + /// + public override long Seek(long offset, SeekOrigin origin) + { + if (this.disposed) { - if (this.disposed) - { - throw new ObjectDisposedException(nameof(MemoryMappedStream)); - } - - long newPosition = this.position; - - switch (origin) - { - case SeekOrigin.Begin: - newPosition = offset; - break; - - case SeekOrigin.Current: - newPosition += offset; - break; - - case SeekOrigin.End: - throw new NotSupportedException(); - } - - if (newPosition > this.length) - { - newPosition = this.length; - } - - if (newPosition < 0) - { - throw new IOException("Attempted to seek before the start or beyond the end of the stream."); - } - - this.position = newPosition; - return this.position; + throw new ObjectDisposedException(nameof(MemoryMappedStream)); } - /// - public override void SetLength(long value) + long newPosition = this.position; + + switch (origin) { - throw new NotSupportedException(); + case SeekOrigin.Begin: + newPosition = offset; + break; + + case SeekOrigin.Current: + newPosition += offset; + break; + + case SeekOrigin.End: + throw new NotSupportedException(); } - /// - public override void Write(byte[] buffer, int offset, int count) + if (newPosition > this.length) { - throw new NotSupportedException(); + newPosition = this.length; } - /// - protected override void Dispose(bool disposing) + if (newPosition < 0) { - if (disposing) - { - this.accessor.SafeMemoryMappedViewHandle.ReleasePointer(); - this.disposed = true; - } + throw new IOException("Attempted to seek before the start or beyond the end of the stream."); + } + + this.position = newPosition; + return this.position; + } - base.Dispose(disposing); + /// + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + /// + protected override void Dispose(bool disposing) + { + if (disposing) + { + this.accessor.SafeMemoryMappedViewHandle.ReleasePointer(); + this.disposed = true; } + + base.Dispose(disposing); } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs b/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs index 550431c8..d7c9cb33 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs @@ -1,154 +1,154 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Buffers; -using System.IO; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// Provides extension methods for the class. +/// +public static class StreamExtensions { /// - /// Provides extension methods for the class. + /// Reads data from a to fill a given buffer. /// - public static class StreamExtensions + /// + /// The from which to read data. + /// + /// + /// A buffer into which to store the data read. + /// + /// Thrown when the stream runs out of data before could be filled. + public static void ReadAll(this Stream stream, Span buffer) { - /// - /// Reads data from a to fill a given buffer. - /// - /// - /// The from which to read data. - /// - /// - /// A buffer into which to store the data read. - /// - /// Thrown when the stream runs out of data before could be filled. - public static void ReadAll(this Stream stream, Span buffer) + if (buffer.Length == 0) { - if (buffer.Length == 0) - { - return; - } - - int totalBytesRead = 0; - while (totalBytesRead < buffer.Length) - { - int bytesRead = stream.Read(buffer.Slice(totalBytesRead)); - if (bytesRead == 0) - { - throw new EndOfStreamException(); - } - - totalBytesRead += bytesRead; - } + return; } - /// - /// Reads an variable-length integer off a . - /// - /// - /// The stream off which to read the variable-length integer. - /// - /// - /// The requested value. - /// - /// Thrown when the stream runs out of data before the integer could be read. - public static int ReadMbsInt(this Stream stream) + int totalBytesRead = 0; + while (totalBytesRead < buffer.Length) { - int value = 0; - int currentBit = 0; - int read; - - while (true) + int bytesRead = stream.Read(buffer.Slice(totalBytesRead)); + if (bytesRead == 0) { - read = stream.ReadByte(); - if (read == -1) - { - throw new EndOfStreamException(); - } - - value |= (read & 0b_0111_1111) << currentBit; - currentBit += 7; - - if (read < 128) - { - break; - } + throw new EndOfStreamException(); } - return value; + totalBytesRead += bytesRead; } + } -#if NETSTANDARD2_0 - /// - /// Reads a sequence of bytes from the current stream and advances the position within the stream by - /// the number of bytes read. - /// - /// - /// The from which to read the data. - /// - /// - /// A region of memory. When this method returns, the contents of this region are replaced by the bytes - /// read from the current source. - /// - /// - /// The total number of bytes read into the buffer. This can be less than the number of bytes allocated - /// in the buffer if that many bytes are not currently available, or zero (0) if the end of the stream - /// has been reached. - /// - public static int Read(this Stream stream, Span span) - { - byte[]? buffer = null; + /// + /// Reads an variable-length integer off a . + /// + /// + /// The stream off which to read the variable-length integer. + /// + /// + /// The requested value. + /// + /// Thrown when the stream runs out of data before the integer could be read. + public static int ReadMbsInt(this Stream stream) + { + int value = 0; + int currentBit = 0; + int read; - try + while (true) + { + read = stream.ReadByte(); + if (read == -1) { - buffer = ArrayPool.Shared.Rent(span.Length); - int read = stream.Read(buffer, 0, span.Length); - - buffer.AsSpan(0, read).CopyTo(span); - return read; + throw new EndOfStreamException(); } - finally + + value |= (read & 0b_0111_1111) << currentBit; + currentBit += 7; + + if (read < 128) { - ArrayPool.Shared.Return(buffer); + break; } } - /// - /// Writes a sequence of bytes to the current stream and advances the current position within this stream - /// by the number of bytes written. - /// - /// - /// The to which to write the data. - /// - /// - /// A region of memory. This method copies the contents of this region to the current stream. - /// - public static void Write(this Stream stream, Span span) - { - byte[]? buffer = null; + return value; + } - try - { - buffer = ArrayPool.Shared.Rent(span.Length); - span.CopyTo(buffer.AsSpan(0, span.Length)); +#if NETSTANDARD2_0 + /// + /// Reads a sequence of bytes from the current stream and advances the position within the stream by + /// the number of bytes read. + /// + /// + /// The from which to read the data. + /// + /// + /// A region of memory. When this method returns, the contents of this region are replaced by the bytes + /// read from the current source. + /// + /// + /// The total number of bytes read into the buffer. This can be less than the number of bytes allocated + /// in the buffer if that many bytes are not currently available, or zero (0) if the end of the stream + /// has been reached. + /// + public static int Read(this Stream stream, Span span) + { + byte[]? buffer = null; - stream.Write(buffer, 0, span.Length); - } - finally - { - ArrayPool.Shared.Return(buffer); - } + try + { + buffer = ArrayPool.Shared.Rent(span.Length); + int read = stream.Read(buffer, 0, span.Length); + + buffer.AsSpan(0, read).CopyTo(span); + return read; } + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + /// + /// Writes a sequence of bytes to the current stream and advances the current position within this stream + /// by the number of bytes written. + /// + /// + /// The to which to write the data. + /// + /// + /// A region of memory. This method copies the contents of this region to the current stream. + /// + public static void Write(this Stream stream, Span span) + { + byte[]? buffer = null; - internal static bool TryAdd(this System.Collections.Generic.IDictionary dictionary, TKey key, TValue value) + try { - if (dictionary.ContainsKey(key)) - { - return false; - } + buffer = ArrayPool.Shared.Rent(span.Length); + span.CopyTo(buffer.AsSpan(0, span.Length)); - dictionary.Add(key, value); - return true; + stream.Write(buffer, 0, span.Length); } -#endif + finally + { + ArrayPool.Shared.Return(buffer); + } + } + + internal static bool TryAdd(this System.Collections.Generic.IDictionary dictionary, TKey key, TValue value) + { + if (dictionary.ContainsKey(key)) + { + return false; + } + + dictionary.Add(key, value); + return true; } +#endif } diff --git a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs index 4a350e30..8e3e3b10 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs @@ -1,203 +1,200 @@ - +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + #nullable enable -using System; using System.Buffers; -using System.IO; using System.IO.Compression; -using System.Threading; -using System.Threading.Tasks; -namespace Nerdbank.GitVersioning.ManagedGit +namespace Nerdbank.GitVersioning.ManagedGit; + +/// +/// A which reads zlib-compressed data. +/// +/// +/// +/// This stream parses but ignores the two-byte zlib header at the start of the compressed +/// stream. +/// +/// +/// This stream keeps track of the current position and, if provided via the constructor, +/// the length. +/// +/// +/// This class wraps a rather than inheriting from it, because +/// detects whether Read(Span{byte}) is being overriden +/// and behaves differently when it is. +/// +/// +/// .NET 5.0 ships with a built-in ZLibStream; which may render (parts of) this implementation +/// obsolete. +/// +/// +/// +public class ZLibStream : Stream { + private readonly DeflateStream stream; + private long length; + private long position; + /// - /// A which reads zlib-compressed data. + /// Initializes a new instance of the class. /// - /// - /// - /// This stream parses but ignores the two-byte zlib header at the start of the compressed - /// stream. - /// - /// - /// This stream keeps track of the current position and, if provided via the constructor, - /// the length. - /// - /// - /// This class wraps a rather than inheriting from it, because - /// detects whether Read(Span{byte}) is being overriden - /// and behaves differently when it is. - /// - /// - /// .NET 5.0 ships with a built-in ZLibStream; which may render (parts of) this implementation - /// obsolete. - /// - /// - /// - public class ZLibStream : Stream + /// + /// The from which to read data. + /// + /// + /// The size of the uncompressed data. + /// + public ZLibStream(Stream stream, long length = -1) { - private long length; - private long position; - private DeflateStream stream; - - /// - /// Initializes a new instance of the class. - /// - /// - /// The from which to read data. - /// - /// - /// The size of the uncompressed data. - /// - public ZLibStream(Stream stream, long length = -1) - { - this.stream = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: false); - this.length = length; + this.stream = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: false); + this.length = length; - Span zlibHeader = stackalloc byte[2]; - stream.ReadAll(zlibHeader); + Span zlibHeader = stackalloc byte[2]; + stream.ReadAll(zlibHeader); - if (zlibHeader[0] != 0x78 || (zlibHeader[1] != 0x01 && zlibHeader[1] != 0x9C && zlibHeader[1] != 0x5E && zlibHeader[1] != 0xDA)) - { - throw new GitException($"Invalid zlib header {zlibHeader[0]:X2} {zlibHeader[1]:X2}"); - } + if (zlibHeader[0] != 0x78 || (zlibHeader[1] != 0x01 && zlibHeader[1] != 0x9C && zlibHeader[1] != 0x5E && zlibHeader[1] != 0xDA)) + { + throw new GitException($"Invalid zlib header {zlibHeader[0]:X2} {zlibHeader[1]:X2}"); } + } - /// - /// Gets the from which the data is being read. - /// - public Stream BaseStream => this.stream; + /// + /// Gets the from which the data is being read. + /// + public Stream BaseStream => this.stream; - /// - public override long Position - { - get => this.position; - set => throw new NotSupportedException(); - } + /// + public override long Position + { + get => this.position; + set => throw new NotSupportedException(); + } - /// - public override long Length => this.length; + /// + public override long Length => this.length; - /// - public override bool CanRead => true; + /// + public override bool CanRead => true; - /// - public override bool CanSeek => true; + /// + public override bool CanSeek => true; - /// - public override bool CanWrite => false; + /// + public override bool CanWrite => false; - /// - public override int Read(byte[] array, int offset, int count) - { - int read = this.stream.Read(array, offset, count); - this.position += read; - return read; - } + /// + public override int Read(byte[] array, int offset, int count) + { + int read = this.stream.Read(array, offset, count); + this.position += read; + return read; + } #if !NETSTANDARD2_0 - /// - public override int Read(Span buffer) - { - int read = this.stream.Read(buffer); - this.position += read; - return read; - } + /// + public override int Read(Span buffer) + { + int read = this.stream.Read(buffer); + this.position += read; + return read; + } #endif - /// - public override async Task ReadAsync(byte[] array, int offset, int count, CancellationToken cancellationToken) - { - int read = await this.stream.ReadAsync(array, offset, count, cancellationToken); - this.position += read; - return read; - } + /// + public override async Task ReadAsync(byte[] array, int offset, int count, CancellationToken cancellationToken) + { + int read = await this.stream.ReadAsync(array, offset, count, cancellationToken); + this.position += read; + return read; + } #if !NETSTANDARD2_0 - /// - public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) - { - int read = await this.stream.ReadAsync(buffer, cancellationToken); - this.position += read; - return read; - } + /// + public override async ValueTask ReadAsync(Memory buffer, CancellationToken cancellationToken = default) + { + int read = await this.stream.ReadAsync(buffer, cancellationToken); + this.position += read; + return read; + } #endif - /// - public override int ReadByte() - { - int value = this.stream.ReadByte(); - - if (value != -1) - { - this.position += 1; - } - - return value; - } + /// + public override int ReadByte() + { + int value = this.stream.ReadByte(); - /// - public override long Seek(long offset, SeekOrigin origin) + if (value != -1) { - if (origin == SeekOrigin.Begin && offset == this.position) - { - return this.position; - } - - if (origin == SeekOrigin.Current && offset == 0) - { - return this.position; - } - - if (origin == SeekOrigin.Begin && offset > this.position) - { - // We may be able to optimize this by skipping over the compressed data - int length = (int)(offset - this.position); - - byte[] buffer = ArrayPool.Shared.Rent(length); - this.Read(buffer, 0, length); - ArrayPool.Shared.Return(buffer); - return this.position; - } - else - { - throw new NotImplementedException(); - } + this.position += 1; } - /// - public override void Flush() - { - throw new NotSupportedException(); - } + return value; + } - /// - public override void SetLength(long value) + /// + public override long Seek(long offset, SeekOrigin origin) + { + if (origin == SeekOrigin.Begin && offset == this.position) { - throw new NotSupportedException(); + return this.position; } - /// - public override void Write(byte[] buffer, int offset, int count) + if (origin == SeekOrigin.Current && offset == 0) { - throw new NotSupportedException(); + return this.position; } - /// - protected override void Dispose(bool disposing) + if (origin == SeekOrigin.Begin && offset > this.position) { - this.stream.Dispose(); - } + // We may be able to optimize this by skipping over the compressed data + int length = (int)(offset - this.position); - /// - /// Initializes the length and position properties. - /// - /// - /// The length of this class. - /// - protected void Initialize(long length) + byte[] buffer = ArrayPool.Shared.Rent(length); + this.Read(buffer, 0, length); + ArrayPool.Shared.Return(buffer); + return this.position; + } + else { - this.position = 0; - this.length = length; + throw new NotImplementedException(); } } + + /// + public override void Flush() + { + throw new NotSupportedException(); + } + + /// + public override void SetLength(long value) + { + throw new NotSupportedException(); + } + + /// + public override void Write(byte[] buffer, int offset, int count) + { + throw new NotSupportedException(); + } + + /// + protected override void Dispose(bool disposing) + { + this.stream.Dispose(); + } + + /// + /// Initializes the length and position properties. + /// + /// + /// The length of this class. + /// + protected void Initialize(long length) + { + this.position = 0; + this.length = length; + } } diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index 753800e5..6052ac9d 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -14,7 +14,6 @@ - diff --git a/src/NerdBank.GitVersioning/NoGit/NoGitContext.cs b/src/NerdBank.GitVersioning/NoGit/NoGitContext.cs index 4d8324db..b1e15b47 100644 --- a/src/NerdBank.GitVersioning/NoGit/NoGitContext.cs +++ b/src/NerdBank.GitVersioning/NoGit/NoGitContext.cs @@ -1,38 +1,55 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; using System.Diagnostics; -namespace Nerdbank.GitVersioning +namespace Nerdbank.GitVersioning; + +[DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] +internal class NoGitContext : GitContext { - [DebuggerDisplay("{" + nameof(DebuggerDisplay) + ",nq}")] - internal class NoGitContext : GitContext + private const string NotAGitRepoMessage = "Not a git repo"; + + public NoGitContext(string workingTreePath) + : base(workingTreePath, null) { - private const string NotAGitRepoMessage = "Not a git repo"; + this.VersionFile = new NoGitVersionFile(this); + } - public NoGitContext(string workingTreePath) - : base(workingTreePath, null) - { - this.VersionFile = new NoGitVersionFile(this); - } + /// + public override VersionFile VersionFile { get; } - public override VersionFile VersionFile { get; } + /// + public override string? GitCommitId => null; - public override string? GitCommitId => null; + /// + public override bool IsHead => false; - public override bool IsHead => false; + /// + public override DateTimeOffset? GitCommitDate => null; - public override DateTimeOffset? GitCommitDate => null; + /// + public override string? HeadCanonicalName => null; - public override string? HeadCanonicalName => null; + private string DebuggerDisplay => $"\"{this.WorkingTreePath}\" (no-git)"; - private string DebuggerDisplay => $"\"{this.WorkingTreePath}\" (no-git)"; + /// + public override void ApplyTag(string name) => throw new InvalidOperationException(NotAGitRepoMessage); - public override void ApplyTag(string name) => throw new InvalidOperationException(NotAGitRepoMessage); - public override void Stage(string path) => throw new InvalidOperationException(NotAGitRepoMessage); - public override string GetShortUniqueCommitId(int minLength) => throw new InvalidOperationException(NotAGitRepoMessage); - public override bool TrySelectCommit(string committish) => throw new InvalidOperationException(NotAGitRepoMessage); - internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) => 0; - internal override Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) => throw new NotImplementedException(); - } + /// + public override void Stage(string path) => throw new InvalidOperationException(NotAGitRepoMessage); + + /// + public override string GetShortUniqueCommitId(int minLength) => throw new InvalidOperationException(NotAGitRepoMessage); + + /// + public override bool TrySelectCommit(string committish) => throw new InvalidOperationException(NotAGitRepoMessage); + + /// + internal override int CalculateVersionHeight(VersionOptions? committedVersion, VersionOptions? workingVersion) => 0; + + /// + internal override Version GetIdAsVersion(VersionOptions? committedVersion, VersionOptions? workingVersion, int versionHeight) => throw new NotImplementedException(); } diff --git a/src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs b/src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs index 44229691..98aca3a4 100644 --- a/src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs +++ b/src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs @@ -1,14 +1,17 @@ -namespace Nerdbank.GitVersioning -{ - using Validation; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. - internal class NoGitVersionFile : VersionFile - { - public NoGitVersionFile(GitContext context) - : base(context) - { - } +using Validation; + +namespace Nerdbank.GitVersioning; - protected override VersionOptions GetVersionCore(out string actualDirectory) => throw Assumes.NotReachable(); +internal class NoGitVersionFile : VersionFile +{ + public NoGitVersionFile(GitContext context) + : base(context) + { } + + /// + protected override VersionOptions GetVersionCore(out string actualDirectory) => throw Assumes.NotReachable(); } diff --git a/src/NerdBank.GitVersioning/Properties/AssemblyInfo.cs b/src/NerdBank.GitVersioning/Properties/AssemblyInfo.cs deleted file mode 100644 index 86d2abd0..00000000 --- a/src/NerdBank.GitVersioning/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyCopyright("Copyright (c) .NET Foundation and Contributors")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index 09fc5aa8..fa79f252 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -1,486 +1,486 @@ -namespace Nerdbank.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using LibGit2Sharp; +using Nerdbank.GitVersioning.LibGit2; +using Newtonsoft.Json; +using Validation; +using Version = System.Version; + +namespace Nerdbank.GitVersioning; + +/// +/// Methods for creating releases. +/// +/// +/// This class authors git commits, branches, etc. and thus must use libgit2 rather than our internal managed implementation which is read-only. +/// +public class ReleaseManager { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using LibGit2Sharp; - using Nerdbank.GitVersioning.LibGit2; - using Newtonsoft.Json; - using Validation; - using Version = System.Version; + private readonly TextWriter stdout; + private readonly TextWriter stderr; /// - /// Methods for creating releases + /// Initializes a new instance of the class. /// - /// - /// This class authors git commits, branches, etc. and thus must use libgit2 rather than our internal managed implementation which is read-only. - /// - public class ReleaseManager + /// The to write output to (e.g. ). + /// The to write error messages to (e.g. ). + public ReleaseManager(TextWriter outputWriter = null, TextWriter errorWriter = null) + { + this.stdout = outputWriter ?? TextWriter.Null; + this.stderr = errorWriter ?? TextWriter.Null; + } + + /// + /// Defines the possible errors that can occur when preparing a release. + /// + public enum ReleasePreparationError { /// - /// Defines the possible errors that can occur when preparing a release + /// The project directory is not a git repository. /// - public enum ReleasePreparationError - { - /// - /// The project directory is not a git repository - /// - NoGitRepo, - - /// - /// There are pending changes in the project directory - /// - UncommittedChanges, - - /// - /// The "branchName" setting in "version.json" is invalid - /// - InvalidBranchNameSetting, - - /// - /// version.json/version.txt not found - /// - NoVersionFile, - - /// - /// Updating the version would result in a version lower than the previous version - /// - VersionDecrement, - - /// - /// Branch cannot be set to the specified version because the new version is not higher than the current version - /// - NoVersionIncrement, - - /// - /// Cannot create a branch because it already exists - /// - BranchAlreadyExists, - - /// - /// Cannot create a commit because user name and user email are not configured (either at the repo or global level) - /// - UserNotConfigured, - - /// - /// HEAD is detached. A branch must be checked out first. - /// - DetachedHead, - - /// - /// The versionIncrement setting cannot be applied to the current version. - /// - InvalidVersionIncrementSetting, - } + NoGitRepo, /// - /// Exception indicating an error during preparation of a release + /// There are pending changes in the project directory. /// - public class ReleasePreparationException : Exception - { - /// - /// Gets the error that occurred. - /// - public ReleasePreparationError Error { get; } - - /// - /// Initializes a new instance of - /// - /// The error that occurred. - public ReleasePreparationException(ReleasePreparationError error) => this.Error = error; - - /// - /// Initializes a new instance of - /// - /// The error that occurred. - /// The inner exception. - public ReleasePreparationException(ReleasePreparationError error, Exception innerException) - : base(null, innerException) => this.Error = error; - } + UncommittedChanges, /// - /// Encapsulates information on a release created through . + /// The "branchName" setting in "version.json" is invalid. /// - public class ReleaseInfo - { - /// - /// Gets information on the 'current' branch, i.e. the branch the release was created from. - /// - public ReleaseBranchInfo CurrentBranch { get; } - - /// - /// Gets information on the new branch created by . - /// - /// - /// Information on the newly created branch as instance of or null, if no new branch was created. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] - public ReleaseBranchInfo NewBranch { get; } - - /// - /// Initializes a new instance of . - /// - /// Information on the branch the release was created from. - public ReleaseInfo(ReleaseBranchInfo currentBranch) : this(currentBranch, null) - { } - - /// - /// Initializes a new instance of . - /// - /// Information on the branch the release was created from. - /// Information on the newly created branch. - [JsonConstructor] - public ReleaseInfo(ReleaseBranchInfo currentBranch, ReleaseBranchInfo newBranch) - { - Requires.NotNull(currentBranch, nameof(currentBranch)); - // skip null check for newBranch, it is allowed to be null. + InvalidBranchNameSetting, - this.CurrentBranch = currentBranch; - this.NewBranch = newBranch; - } - } + /// + /// version.json/version.txt not found. + /// + NoVersionFile, /// - /// Encapsulates information on a branch created or updated by . + /// Updating the version would result in a version lower than the previous version. /// - public class ReleaseBranchInfo - { - /// - /// The name of the branch, e.g. master. - /// - public string Name { get; } - - /// - /// The id of the branch's tip commit after the update. - /// - public string Commit { get; } - - /// - /// The version configured in the branch's version.json. - /// - public SemanticVersion Version { get; } - - /// - /// Initializes a new instance of . - /// - /// The name of the branch. - /// The id of the branch's tip. - /// The version configured in the branch's version.json. - public ReleaseBranchInfo(string name, string commit, SemanticVersion version) - { - Requires.NotNullOrWhiteSpace(name, nameof(name)); - Requires.NotNullOrWhiteSpace(commit, nameof(commit)); - Requires.NotNull(version, nameof(version)); + VersionDecrement, - this.Name = name; - this.Commit = commit; - this.Version = version; - } - } + /// + /// Branch cannot be set to the specified version because the new version is not higher than the current version. + /// + NoVersionIncrement, /// - /// Enumerates the output formats supported by . + /// Cannot create a branch because it already exists. /// - public enum ReleaseManagerOutputMode - { - /// - /// Use unstructured text output. - /// - Text = 0, - /// - /// Output information about the release as JSON. - /// - Json = 1 - } + BranchAlreadyExists, + /// + /// Cannot create a commit because user name and user email are not configured (either at the repo or global level). + /// + UserNotConfigured, - private readonly TextWriter stdout; - private readonly TextWriter stderr; + /// + /// HEAD is detached. A branch must be checked out first. + /// + DetachedHead, /// - /// Initializes a new instance of . + /// The versionIncrement setting cannot be applied to the current version. /// - /// The to write output to (e.g. ). - /// The to write error messages to (e.g. ). - public ReleaseManager(TextWriter outputWriter = null, TextWriter errorWriter = null) - { - this.stdout = outputWriter ?? TextWriter.Null; - this.stderr = errorWriter ?? TextWriter.Null; - } + InvalidVersionIncrementSetting, + } + /// + /// Enumerates the output formats supported by . + /// + public enum ReleaseManagerOutputMode + { /// - /// Prepares a release for the specified directory by creating a release branch and incrementing the version in the current branch. + /// Use unstructured text output. /// - /// Thrown when the release could not be created. - /// - /// The path to the directory which may (or its ancestors may) define the version file. - /// - /// - /// The prerelease tag to add to the version on the release branch. Pass null to omit/remove the prerelease tag. - /// The leading hyphen may be specified or omitted. - /// - /// - /// The next version to save to the version file on the current branch. Pass null to automatically determine the next - /// version based on the current version and the versionIncrement setting in version.json. - /// Parameter will be ignored if the current branch is a release branch. - /// - /// - /// The increment to apply in order to determine the next version on the current branch. - /// If specified, value will be used instead of the increment specified in version.json. - /// Parameter will be ignored if the current branch is a release branch. - /// - /// - /// The output format to use for writing to stdout. - /// - public void PrepareRelease(string projectDirectory, string releaseUnstableTag = null, Version nextVersion = null, VersionOptions.ReleaseVersionIncrement? versionIncrement = null, ReleaseManagerOutputMode outputMode = default) - { - Requires.NotNull(projectDirectory, nameof(projectDirectory)); + Text = 0, - // open the git repository - var context = this.GetRepository(projectDirectory); - var repository = context.Repository; + /// + /// Output information about the release as JSON. + /// + Json = 1, + } - if (repository.Info.IsHeadDetached) - { - this.stderr.WriteLine("Detached head. Check out a branch first."); - throw new ReleasePreparationException(ReleasePreparationError.DetachedHead); - } + /// + /// Prepares a release for the specified directory by creating a release branch and incrementing the version in the current branch. + /// + /// Thrown when the release could not be created. + /// + /// The path to the directory which may (or its ancestors may) define the version file. + /// + /// + /// The prerelease tag to add to the version on the release branch. Pass null to omit/remove the prerelease tag. + /// The leading hyphen may be specified or omitted. + /// + /// + /// The next version to save to the version file on the current branch. Pass null to automatically determine the next + /// version based on the current version and the versionIncrement setting in version.json. + /// Parameter will be ignored if the current branch is a release branch. + /// + /// + /// The increment to apply in order to determine the next version on the current branch. + /// If specified, value will be used instead of the increment specified in version.json. + /// Parameter will be ignored if the current branch is a release branch. + /// + /// + /// The output format to use for writing to stdout. + /// + public void PrepareRelease(string projectDirectory, string releaseUnstableTag = null, Version nextVersion = null, VersionOptions.ReleaseVersionIncrement? versionIncrement = null, ReleaseManagerOutputMode outputMode = default) + { + Requires.NotNull(projectDirectory, nameof(projectDirectory)); - // get the current version - var versionOptions = context.VersionFile.GetVersion(); - if (versionOptions is null) - { - this.stderr.WriteLine($"Failed to load version file for directory '{projectDirectory}'."); - throw new ReleasePreparationException(ReleasePreparationError.NoVersionFile); - } + // open the git repository + LibGit2Context context = this.GetRepository(projectDirectory); + Repository repository = context.Repository; - var releaseBranchName = this.GetReleaseBranchName(versionOptions); - var originalBranchName = repository.Head.FriendlyName; - var releaseVersion = string.IsNullOrEmpty(releaseUnstableTag) - ? versionOptions.Version.WithoutPrepreleaseTags() - : versionOptions.Version.SetFirstPrereleaseTag(releaseUnstableTag); + if (repository.Info.IsHeadDetached) + { + this.stderr.WriteLine("Detached head. Check out a branch first."); + throw new ReleasePreparationException(ReleasePreparationError.DetachedHead); + } - // check if the current branch is the release branch - if (string.Equals(originalBranchName, releaseBranchName, StringComparison.OrdinalIgnoreCase)) - { - if (outputMode == ReleaseManagerOutputMode.Text) - { - this.stdout.WriteLine($"{releaseBranchName} branch advanced from {versionOptions.Version} to {releaseVersion}."); - } - else - { - var releaseInfo = new ReleaseInfo(new ReleaseBranchInfo(releaseBranchName, repository.Head.Tip.Id.ToString(), releaseVersion)); - this.WriteToOutput(releaseInfo); - } - this.UpdateVersion(context, versionOptions.Version, releaseVersion); - return; - } + // get the current version + VersionOptions versionOptions = context.VersionFile.GetVersion(); + if (versionOptions is null) + { + this.stderr.WriteLine($"Failed to load version file for directory '{projectDirectory}'."); + throw new ReleasePreparationException(ReleasePreparationError.NoVersionFile); + } - var nextDevVersion = this.GetNextDevVersion(versionOptions, nextVersion, versionIncrement); + string releaseBranchName = this.GetReleaseBranchName(versionOptions); + string originalBranchName = repository.Head.FriendlyName; + SemanticVersion releaseVersion = string.IsNullOrEmpty(releaseUnstableTag) + ? versionOptions.Version.WithoutPrepreleaseTags() + : versionOptions.Version.SetFirstPrereleaseTag(releaseUnstableTag); - // check if the current version on the current branch is different from the next version - // otherwise, both the release branch and the dev branch would have the same version - if (versionOptions.Version.Version == nextDevVersion.Version) + // check if the current branch is the release branch + if (string.Equals(originalBranchName, releaseBranchName, StringComparison.OrdinalIgnoreCase)) + { + if (outputMode == ReleaseManagerOutputMode.Text) { - this.stderr.WriteLine($"Version on '{originalBranchName}' is already set to next version {nextDevVersion.Version}."); - throw new ReleasePreparationException(ReleasePreparationError.NoVersionIncrement); + this.stdout.WriteLine($"{releaseBranchName} branch advanced from {versionOptions.Version} to {releaseVersion}."); } - - // check if the release branch already exists - if (repository.Branches[releaseBranchName] is not null) + else { - this.stderr.WriteLine($"Cannot create branch '{releaseBranchName}' because it already exists."); - throw new ReleasePreparationException(ReleasePreparationError.BranchAlreadyExists); + var releaseInfo = new ReleaseInfo(new ReleaseBranchInfo(releaseBranchName, repository.Head.Tip.Id.ToString(), releaseVersion)); + this.WriteToOutput(releaseInfo); } - // create release branch and update version - var releaseBranch = repository.CreateBranch(releaseBranchName); - global::LibGit2Sharp.Commands.Checkout(repository, releaseBranch); this.UpdateVersion(context, versionOptions.Version, releaseVersion); + return; + } - if (outputMode == ReleaseManagerOutputMode.Text) - { - this.stdout.WriteLine($"{releaseBranchName} branch now tracks v{releaseVersion} stabilization and release."); - } - - // update version on main branch - global::LibGit2Sharp.Commands.Checkout(repository, originalBranchName); - this.UpdateVersion(context, versionOptions.Version, nextDevVersion); + SemanticVersion nextDevVersion = this.GetNextDevVersion(versionOptions, nextVersion, versionIncrement); - if (outputMode == ReleaseManagerOutputMode.Text) - { - this.stdout.WriteLine($"{originalBranchName} branch now tracks v{nextDevVersion} development."); - } + // check if the current version on the current branch is different from the next version + // otherwise, both the release branch and the dev branch would have the same version + if (versionOptions.Version.Version == nextDevVersion.Version) + { + this.stderr.WriteLine($"Version on '{originalBranchName}' is already set to next version {nextDevVersion.Version}."); + throw new ReleasePreparationException(ReleasePreparationError.NoVersionIncrement); + } - // Merge release branch back to main branch - var mergeOptions = new MergeOptions() - { - CommitOnSuccess = true, - MergeFileFavor = MergeFileFavor.Ours, - }; - repository.Merge(releaseBranch, this.GetSignature(repository), mergeOptions); + // check if the release branch already exists + if (repository.Branches[releaseBranchName] is not null) + { + this.stderr.WriteLine($"Cannot create branch '{releaseBranchName}' because it already exists."); + throw new ReleasePreparationException(ReleasePreparationError.BranchAlreadyExists); + } - if (outputMode == ReleaseManagerOutputMode.Json) - { - var originalBranchInfo = new ReleaseBranchInfo(originalBranchName, repository.Head.Tip.Sha, nextDevVersion); - var releaseBranchInfo = new ReleaseBranchInfo(releaseBranchName, repository.Branches[releaseBranchName].Tip.Id.ToString(), releaseVersion); - var releaseInfo = new ReleaseInfo(originalBranchInfo, releaseBranchInfo); + // create release branch and update version + Branch releaseBranch = repository.CreateBranch(releaseBranchName); + global::LibGit2Sharp.Commands.Checkout(repository, releaseBranch); + this.UpdateVersion(context, versionOptions.Version, releaseVersion); - this.WriteToOutput(releaseInfo); - } + if (outputMode == ReleaseManagerOutputMode.Text) + { + this.stdout.WriteLine($"{releaseBranchName} branch now tracks v{releaseVersion} stabilization and release."); } - private string GetReleaseBranchName(VersionOptions versionOptions) + // update version on main branch + global::LibGit2Sharp.Commands.Checkout(repository, originalBranchName); + this.UpdateVersion(context, versionOptions.Version, nextDevVersion); + + if (outputMode == ReleaseManagerOutputMode.Text) { - Requires.NotNull(versionOptions, nameof(versionOptions)); + this.stdout.WriteLine($"{originalBranchName} branch now tracks v{nextDevVersion} development."); + } - var branchNameFormat = versionOptions.ReleaseOrDefault.BranchNameOrDefault; + // Merge release branch back to main branch + var mergeOptions = new MergeOptions() + { + CommitOnSuccess = true, + MergeFileFavor = MergeFileFavor.Ours, + }; + repository.Merge(releaseBranch, this.GetSignature(repository), mergeOptions); - // ensure there is a '{version}' placeholder in the branch name - if (string.IsNullOrEmpty(branchNameFormat) || !branchNameFormat.Contains("{version}")) - { - this.stderr.WriteLine($"Invalid 'branchName' setting '{branchNameFormat}'. Missing version placeholder '{{version}}'."); - throw new ReleasePreparationException(ReleasePreparationError.InvalidBranchNameSetting); - } + if (outputMode == ReleaseManagerOutputMode.Json) + { + var originalBranchInfo = new ReleaseBranchInfo(originalBranchName, repository.Head.Tip.Sha, nextDevVersion); + var releaseBranchInfo = new ReleaseBranchInfo(releaseBranchName, repository.Branches[releaseBranchName].Tip.Id.ToString(), releaseVersion); + var releaseInfo = new ReleaseInfo(originalBranchInfo, releaseBranchInfo); - // replace the "{version}" placeholder with the actual version - return branchNameFormat.Replace("{version}", versionOptions.Version.Version.ToString()); + this.WriteToOutput(releaseInfo); } + } - private void UpdateVersion(LibGit2Context context, SemanticVersion oldVersion, SemanticVersion newVersion) + private static bool IsVersionDecrement(SemanticVersion oldVersion, SemanticVersion newVersion) + { + if (newVersion.Version > oldVersion.Version) { - Requires.NotNull(context, nameof(context)); + return false; + } + else if (newVersion.Version == oldVersion.Version) + { + return string.IsNullOrEmpty(oldVersion.Prerelease) && + !string.IsNullOrEmpty(newVersion.Prerelease); + } + else + { + // newVersion.Version < oldVersion.Version + return true; + } + } - var signature = this.GetSignature(context.Repository); - var versionOptions = context.VersionFile.GetVersion(); + private string GetReleaseBranchName(VersionOptions versionOptions) + { + Requires.NotNull(versionOptions, nameof(versionOptions)); - if (IsVersionDecrement(oldVersion, newVersion)) - { - this.stderr.WriteLine($"Cannot change version from {oldVersion} to {newVersion} because {newVersion} is older than {oldVersion}."); - throw new ReleasePreparationException(ReleasePreparationError.VersionDecrement); - } + string branchNameFormat = versionOptions.ReleaseOrDefault.BranchNameOrDefault; - if (!EqualityComparer.Default.Equals(versionOptions.Version, newVersion)) - { - if (versionOptions.VersionHeightPosition.HasValue && SemanticVersion.WillVersionChangeResetVersionHeight(versionOptions.Version, newVersion, versionOptions.VersionHeightPosition.Value)) - { - // The version will be reset by this change, so remove the version height offset property. - versionOptions.VersionHeightOffset = null; - } - - versionOptions.Version = newVersion; - var filePath = context.VersionFile.SetVersion(context.AbsoluteProjectDirectory, versionOptions, includeSchemaProperty: true); - - global::LibGit2Sharp.Commands.Stage(context.Repository, filePath); - - // Author a commit only if we effectively changed something. - if (!context.Repository.Head.Tip.Tree.Equals(context.Repository.Index.WriteToTree())) - { - context.Repository.Commit($"Set version to '{versionOptions.Version}'", signature, signature, new CommitOptions() { AllowEmptyCommit = false }); - } - } + // ensure there is a '{version}' placeholder in the branch name + if (string.IsNullOrEmpty(branchNameFormat) || !branchNameFormat.Contains("{version}")) + { + this.stderr.WriteLine($"Invalid 'branchName' setting '{branchNameFormat}'. Missing version placeholder '{{version}}'."); + throw new ReleasePreparationException(ReleasePreparationError.InvalidBranchNameSetting); } - private Signature GetSignature(Repository repository) - { - var signature = repository.Config.BuildSignature(DateTimeOffset.Now); - if (signature is null) - { - this.stderr.WriteLine("Cannot create commits in this repo because git user name and email are not configured."); - throw new ReleasePreparationException(ReleasePreparationError.UserNotConfigured); - } + // replace the "{version}" placeholder with the actual version + return branchNameFormat.Replace("{version}", versionOptions.Version.Version.ToString()); + } + + private void UpdateVersion(LibGit2Context context, SemanticVersion oldVersion, SemanticVersion newVersion) + { + Requires.NotNull(context, nameof(context)); + + Signature signature = this.GetSignature(context.Repository); + VersionOptions versionOptions = context.VersionFile.GetVersion(); - return signature; + if (IsVersionDecrement(oldVersion, newVersion)) + { + this.stderr.WriteLine($"Cannot change version from {oldVersion} to {newVersion} because {newVersion} is older than {oldVersion}."); + throw new ReleasePreparationException(ReleasePreparationError.VersionDecrement); } - private LibGit2Context GetRepository(string projectDirectory) + if (!EqualityComparer.Default.Equals(versionOptions.Version, newVersion)) { - // open git repo and use default configuration (in order to commit we need a configured user name and email - // which is most likely configured on a user/system level rather than the repo level. - var context = GitContext.Create(projectDirectory, writable: true); - if (!context.IsRepository) + if (versionOptions.VersionHeightPosition.HasValue && SemanticVersion.WillVersionChangeResetVersionHeight(versionOptions.Version, newVersion, versionOptions.VersionHeightPosition.Value)) { - this.stderr.WriteLine($"No git repository found above directory '{projectDirectory}'."); - throw new ReleasePreparationException(ReleasePreparationError.NoGitRepo); + // The version will be reset by this change, so remove the version height offset property. + versionOptions.VersionHeightOffset = null; } - var libgit2context = (LibGit2Context)context; + versionOptions.Version = newVersion; + string filePath = context.VersionFile.SetVersion(context.AbsoluteProjectDirectory, versionOptions, includeSchemaProperty: true); + global::LibGit2Sharp.Commands.Stage(context.Repository, filePath); - // abort if there are any pending changes - var status = libgit2context.Repository.RetrieveStatus(); - if (status.IsDirty) + // Author a commit only if we effectively changed something. + if (!context.Repository.Head.Tip.Tree.Equals(context.Repository.Index.WriteToTree())) { - var changedFiles = status.OfType().ToList(); - var changesFilesFormatted = string.Join(Environment.NewLine, changedFiles.Select(t => $"- {t.FilePath} changed with {nameof(FileStatus)} {t.State}")); - this.stderr.WriteLine($"Uncommitted changes ({changedFiles.Count}) in directory '{projectDirectory}':"); - this.stderr.WriteLine(changesFilesFormatted); - throw new ReleasePreparationException(ReleasePreparationError.UncommittedChanges); + context.Repository.Commit($"Set version to '{versionOptions.Version}'", signature, signature, new CommitOptions() { AllowEmptyCommit = false }); } + } + } - // check if repo is configured so we can create commits - _ = this.GetSignature(libgit2context.Repository); + private Signature GetSignature(Repository repository) + { + Signature signature = repository.Config.BuildSignature(DateTimeOffset.Now); + if (signature is null) + { + this.stderr.WriteLine("Cannot create commits in this repo because git user name and email are not configured."); + throw new ReleasePreparationException(ReleasePreparationError.UserNotConfigured); + } + + return signature; + } - return libgit2context; + private LibGit2Context GetRepository(string projectDirectory) + { + // open git repo and use default configuration (in order to commit we need a configured user name and email + // which is most likely configured on a user/system level rather than the repo level. + var context = GitContext.Create(projectDirectory, writable: true); + if (!context.IsRepository) + { + this.stderr.WriteLine($"No git repository found above directory '{projectDirectory}'."); + throw new ReleasePreparationException(ReleasePreparationError.NoGitRepo); } - private static bool IsVersionDecrement(SemanticVersion oldVersion, SemanticVersion newVersion) + var libgit2context = (LibGit2Context)context; + + // abort if there are any pending changes + RepositoryStatus status = libgit2context.Repository.RetrieveStatus(); + if (status.IsDirty) { - if (newVersion.Version > oldVersion.Version) - { - return false; - } - else if (newVersion.Version == oldVersion.Version) - { - return string.IsNullOrEmpty(oldVersion.Prerelease) && - !string.IsNullOrEmpty(newVersion.Prerelease); - } - else - { - // newVersion.Version < oldVersion.Version - return true; - } + var changedFiles = status.OfType().ToList(); + string changesFilesFormatted = string.Join(Environment.NewLine, changedFiles.Select(t => $"- {t.FilePath} changed with {nameof(FileStatus)} {t.State}")); + this.stderr.WriteLine($"Uncommitted changes ({changedFiles.Count}) in directory '{projectDirectory}':"); + this.stderr.WriteLine(changesFilesFormatted); + throw new ReleasePreparationException(ReleasePreparationError.UncommittedChanges); } - private SemanticVersion GetNextDevVersion(VersionOptions versionOptions, Version nextVersionOverride, VersionOptions.ReleaseVersionIncrement? versionIncrementOverride) + // check if repo is configured so we can create commits + _ = this.GetSignature(libgit2context.Repository); + + return libgit2context; + } + + private SemanticVersion GetNextDevVersion(VersionOptions versionOptions, Version nextVersionOverride, VersionOptions.ReleaseVersionIncrement? versionIncrementOverride) + { + SemanticVersion currentVersion = versionOptions.Version; + + SemanticVersion nextDevVersion; + if (nextVersionOverride is not null) + { + nextDevVersion = new SemanticVersion(nextVersionOverride, currentVersion.Prerelease, currentVersion.BuildMetadata); + } + else { - var currentVersion = versionOptions.Version; + // Determine the increment to use: + // Use parameter versionIncrementOverride if it has a value, otherwise use setting from version.json. + VersionOptions.ReleaseVersionIncrement versionIncrement = versionIncrementOverride ?? versionOptions.ReleaseOrDefault.VersionIncrementOrDefault; - SemanticVersion nextDevVersion; - if (nextVersionOverride is not null) - { - nextDevVersion = new SemanticVersion(nextVersionOverride, currentVersion.Prerelease, currentVersion.BuildMetadata); - } - else + // The increment is only valid if the current version has the required precision: + // - increment settings "Major" and "Minor" are always valid. + // - increment setting "Build" is only valid if the version has at lease three segments. + bool isValidIncrement = versionIncrement != VersionOptions.ReleaseVersionIncrement.Build || + versionOptions.Version.Version.Build >= 0; + + if (!isValidIncrement) { - // Determine the increment to use: - // Use parameter versionIncrementOverride if it has a value, otherwise use setting from version.json. - var versionIncrement = versionIncrementOverride ?? versionOptions.ReleaseOrDefault.VersionIncrementOrDefault; - - // The increment is only valid if the current version has the required precision: - // - increment settings "Major" and "Minor" are always valid. - // - increment setting "Build" is only valid if the version has at lease three segments. - var isValidIncrement = versionIncrement != VersionOptions.ReleaseVersionIncrement.Build || - versionOptions.Version.Version.Build >= 0; - - if (!isValidIncrement) - { - this.stderr.WriteLine($"Cannot apply version increment 'build' to version '{versionOptions.Version}' because it only has major and minor segments."); - throw new ReleasePreparationException(ReleasePreparationError.InvalidVersionIncrementSetting); - } - - nextDevVersion = currentVersion.Increment(versionIncrement); + this.stderr.WriteLine($"Cannot apply version increment 'build' to version '{versionOptions.Version}' because it only has major and minor segments."); + throw new ReleasePreparationException(ReleasePreparationError.InvalidVersionIncrementSetting); } - // return next version with prerelease tag specified in version.json - return nextDevVersion.SetFirstPrereleaseTag(versionOptions.ReleaseOrDefault.FirstUnstableTagOrDefault); + nextDevVersion = currentVersion.Increment(versionIncrement); } - private void WriteToOutput(ReleaseInfo releaseInfo) + // return next version with prerelease tag specified in version.json + return nextDevVersion.SetFirstPrereleaseTag(versionOptions.ReleaseOrDefault.FirstUnstableTagOrDefault); + } + + private void WriteToOutput(ReleaseInfo releaseInfo) + { + string json = JsonConvert.SerializeObject(releaseInfo, Formatting.Indented, new SemanticVersionJsonConverter()); + this.stdout.WriteLine(json); + } + + /// + /// Exception indicating an error during preparation of a release. + /// + public class ReleasePreparationException : Exception + { + /// + /// Initializes a new instance of the class. + /// + /// The error that occurred. + public ReleasePreparationException(ReleasePreparationError error) => this.Error = error; + + /// + /// Initializes a new instance of the class. + /// + /// The error that occurred. + /// The inner exception. + public ReleasePreparationException(ReleasePreparationError error, Exception innerException) + : base(null, innerException) => this.Error = error; + + /// + /// Gets the error that occurred. + /// + public ReleasePreparationError Error { get; } + } + + /// + /// Encapsulates information on a release created through . + /// + public class ReleaseInfo + { + /// + /// Initializes a new instance of the class. + /// + /// Information on the branch the release was created from. + public ReleaseInfo(ReleaseBranchInfo currentBranch) + : this(currentBranch, null) { - var json = JsonConvert.SerializeObject(releaseInfo, Formatting.Indented, new SemanticVersionJsonConverter()); - this.stdout.WriteLine(json); } + + /// + /// Initializes a new instance of the class. + /// + /// Information on the branch the release was created from. + /// Information on the newly created branch. + [JsonConstructor] + public ReleaseInfo(ReleaseBranchInfo currentBranch, ReleaseBranchInfo newBranch) + { + Requires.NotNull(currentBranch, nameof(currentBranch)); + //// skip null check for newBranch, it is allowed to be null. + + this.CurrentBranch = currentBranch; + this.NewBranch = newBranch; + } + + /// + /// Gets information on the 'current' branch, i.e. the branch the release was created from. + /// + public ReleaseBranchInfo CurrentBranch { get; } + + /// + /// Gets information on the new branch created by . + /// + /// + /// Information on the newly created branch as instance of or null, if no new branch was created. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] + public ReleaseBranchInfo NewBranch { get; } + } + + /// + /// Encapsulates information on a branch created or updated by . + /// + public class ReleaseBranchInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The name of the branch. + /// The id of the branch's tip. + /// The version configured in the branch's version.json. + public ReleaseBranchInfo(string name, string commit, SemanticVersion version) + { + Requires.NotNullOrWhiteSpace(name, nameof(name)); + Requires.NotNullOrWhiteSpace(commit, nameof(commit)); + Requires.NotNull(version, nameof(version)); + + this.Name = name; + this.Commit = commit; + this.Version = version; + } + + /// + /// Gets the name of the branch, e.g. master. + /// + public string Name { get; } + + /// + /// Gets the id of the branch's tip commit after the update. + /// + public string Commit { get; } + + /// + /// Gets the version configured in the branch's version.json. + /// + public SemanticVersion Version { get; } } } diff --git a/src/NerdBank.GitVersioning/SemanticVersion.cs b/src/NerdBank.GitVersioning/SemanticVersion.cs index f6840f39..dc267302 100644 --- a/src/NerdBank.GitVersioning/SemanticVersion.cs +++ b/src/NerdBank.GitVersioning/SemanticVersion.cs @@ -1,387 +1,388 @@ -namespace Nerdbank.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Text.RegularExpressions; +using Validation; + +namespace Nerdbank.GitVersioning; + +/// +/// Describes a version with an optional unstable tag. +/// +[DebuggerDisplay("{DebuggerDisplay,nq}")] +public class SemanticVersion : IEquatable { - using System; - using System.Diagnostics; - using System.Text.RegularExpressions; - using Validation; + /// + /// The regular expression with capture groups for semantic versioning. + /// It considers PATCH to be optional and permits the 4th Revision component. + /// + /// + /// Parts of this regex inspired by this code. + /// + private static readonly Regex FullSemVerPattern = new Regex(@"^v?(?0|[1-9][0-9]*)\.(?0|[1-9][0-9]*)(?:\.(?0|[1-9][0-9]*)(?:\.(?0|[1-9][0-9]*))?)?(?-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?\+[\da-z\-]+(?:\.[\da-z\-]+)*)?$", RegexOptions.IgnoreCase); /// - /// Describes a version with an optional unstable tag. + /// The regex pattern that a prerelease must match. /// - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public class SemanticVersion : IEquatable - { - /// - /// The regular expression with capture groups for semantic versioning. - /// It considers PATCH to be optional and permits the 4th Revision component. - /// - /// - /// Parts of this regex inspired by https://github.com/sindresorhus/semver-regex/blob/master/index.js - /// - private static readonly Regex FullSemVerPattern = new Regex(@"^v?(?0|[1-9][0-9]*)\.(?0|[1-9][0-9]*)(?:\.(?0|[1-9][0-9]*)(?:\.(?0|[1-9][0-9]*))?)?(?-[\da-z\-]+(?:\.[\da-z\-]+)*)?(?\+[\da-z\-]+(?:\.[\da-z\-]+)*)?$", RegexOptions.IgnoreCase); + /// + /// Keep in sync with the regex for the version field found in the version.schema.json file. + /// + private static readonly Regex PrereleasePattern = new Regex("-(?:[\\da-z\\-]+|\\{height\\})(?:\\.(?:[\\da-z\\-]+|\\{height\\}))*", RegexOptions.IgnoreCase); - /// - /// The regex pattern that a prerelease must match. - /// - /// - /// Keep in sync with the regex for the version field found in the version.schema.json file. - /// - private static readonly Regex PrereleasePattern = new Regex("-(?:[\\da-z\\-]+|\\{height\\})(?:\\.(?:[\\da-z\\-]+|\\{height\\}))*", RegexOptions.IgnoreCase); + /// + /// The regex pattern that build metadata must match. + /// + /// + /// Keep in sync with the regex for the version field found in the version.schema.json file. + /// + private static readonly Regex BuildMetadataPattern = new Regex("\\+(?:[\\da-z\\-]+|\\{height\\})(?:\\.(?:[\\da-z\\-]+|\\{height\\}))*", RegexOptions.IgnoreCase); - /// - /// The regex pattern that build metadata must match. - /// - /// - /// Keep in sync with the regex for the version field found in the version.schema.json file. - /// - private static readonly Regex BuildMetadataPattern = new Regex("\\+(?:[\\da-z\\-]+|\\{height\\})(?:\\.(?:[\\da-z\\-]+|\\{height\\}))*", RegexOptions.IgnoreCase); + /// + /// The regular expression with capture groups for semantic versioning, + /// allowing for macros such as {height}. + /// + /// + /// Keep in sync with the regex for the version field found in the version.schema.json file. + /// + private static readonly Regex FullSemVerWithMacrosPattern = new Regex("^v?(?0|[1-9][0-9]*)\\.(?0|[1-9][0-9]*)(?:\\.(?0|[1-9][0-9]*)(?:\\.(?0|[1-9][0-9]*))?)?(?" + PrereleasePattern + ")?(?" + BuildMetadataPattern + ")?$", RegexOptions.IgnoreCase); - /// - /// The regular expression with capture groups for semantic versioning, - /// allowing for macros such as {height}. - /// - /// - /// Keep in sync with the regex for the version field found in the version.schema.json file. - /// - private static readonly Regex FullSemVerWithMacrosPattern = new Regex("^v?(?0|[1-9][0-9]*)\\.(?0|[1-9][0-9]*)(?:\\.(?0|[1-9][0-9]*)(?:\\.(?0|[1-9][0-9]*))?)?(?" + PrereleasePattern + ")?(?" + BuildMetadataPattern + ")?$", RegexOptions.IgnoreCase); + /// + /// Initializes a new instance of the class. + /// + /// The numeric version. + /// The prerelease, with leading - character. + /// The build metadata, with leading + character. + public SemanticVersion(Version version, string prerelease = null, string buildMetadata = null) + { + Requires.NotNull(version, nameof(version)); + VerifyPatternMatch(prerelease, PrereleasePattern, nameof(prerelease)); + VerifyPatternMatch(buildMetadata, BuildMetadataPattern, nameof(buildMetadata)); - /// - /// Initializes a new instance of the class. - /// - /// The numeric version. - /// The prerelease, with leading - character. - /// The build metadata, with leading + character. - public SemanticVersion(Version version, string prerelease = null, string buildMetadata = null) - { - Requires.NotNull(version, nameof(version)); - VerifyPatternMatch(prerelease, PrereleasePattern, nameof(prerelease)); - VerifyPatternMatch(buildMetadata, BuildMetadataPattern, nameof(buildMetadata)); + this.Version = version; + this.Prerelease = prerelease ?? string.Empty; + this.BuildMetadata = buildMetadata ?? string.Empty; + } - this.Version = version; - this.Prerelease = prerelease ?? string.Empty; - this.BuildMetadata = buildMetadata ?? string.Empty; - } + /// + /// Initializes a new instance of the class. + /// + /// The x.y.z numeric version. + /// The prerelease, with leading - character. + /// The build metadata, with leading + character. + public SemanticVersion(string version, string prerelease = null, string buildMetadata = null) + : this(new Version(version), prerelease, buildMetadata) + { + } + /// + /// Identifies the various positions in a semantic version. + /// + public enum Position + { /// - /// Initializes a new instance of the class. + /// The component. /// - /// The x.y.z numeric version. - /// The prerelease, with leading - character. - /// The build metadata, with leading + character. - public SemanticVersion(string version, string prerelease = null, string buildMetadata = null) - : this(new Version(version), prerelease, buildMetadata) - { - } + Major, /// - /// Identifies the various positions in a semantic version. + /// The component. /// - public enum Position - { - /// - /// The component. - /// - Major, - - /// - /// The component. - /// - Minor, - - /// - /// The component. - /// - Build, - - /// - /// The component. - /// - Revision, - - /// - /// The portion of the version. - /// - Prerelease, - - /// - /// The portion of the version. - /// - BuildMetadata, - } + Minor, /// - /// Gets the version. + /// The component. /// - public Version Version { get; } + Build, /// - /// Gets an unstable tag (with the leading hyphen), if applicable. + /// The component. /// - /// A string with a leading hyphen or the empty string. - public string Prerelease { get; } + Revision, /// - /// Gets the build metadata (with the leading plus), if applicable. + /// The portion of the version. /// - /// A string with a leading plus or the empty string. - public string BuildMetadata { get; } + Prerelease, /// - /// Gets the position in a computed version that the version height should appear. + /// The portion of the version. /// - public SemanticVersion.Position? VersionHeightPosition + BuildMetadata, + } + + /// + /// Gets the version. + /// + public Version Version { get; } + + /// + /// Gets an unstable tag (with the leading hyphen), if applicable. + /// + /// A string with a leading hyphen or the empty string. + public string Prerelease { get; } + + /// + /// Gets the build metadata (with the leading plus), if applicable. + /// + /// A string with a leading plus or the empty string. + public string BuildMetadata { get; } + + /// + /// Gets the position in a computed version that the version height should appear. + /// + public SemanticVersion.Position? VersionHeightPosition + { + get { - get + if (this.Prerelease?.Contains(VersionOptions.VersionHeightPlaceholder) ?? false) + { + return SemanticVersion.Position.Prerelease; + } + else if (this.Version.Build == -1) + { + return SemanticVersion.Position.Build; + } + else if (this.Version.Revision == -1) { - if (this.Prerelease?.Contains(VersionOptions.VersionHeightPlaceholder) ?? false) - { - return SemanticVersion.Position.Prerelease; - } - else if (this.Version.Build == -1) - { - return SemanticVersion.Position.Build; - } - else if (this.Version.Revision == -1) - { - return SemanticVersion.Position.Revision; - } - else - { - return null; - } + return SemanticVersion.Position.Revision; + } + else + { + return null; } } + } - /// - /// Gets the position in a computed version that the first 16 bits of a git commit ID should appear, if any. - /// - internal SemanticVersion.Position? GitCommitIdPosition + /// + /// Gets the position in a computed version that the first 16 bits of a git commit ID should appear, if any. + /// + internal SemanticVersion.Position? GitCommitIdPosition + { + get { - get + // We can only store the git commit ID info after there was a place to put the version height. + // We don't want to store the commit ID (which is effectively a random integer) in the revision slot + // if the version height does not appear, or only appears later (in the -prerelease tag) since that + // would mess up version ordering. + if (this.VersionHeightPosition == SemanticVersion.Position.Build) { - // We can only store the git commit ID info after there was a place to put the version height. - // We don't want to store the commit ID (which is effectively a random integer) in the revision slot - // if the version height does not appear, or only appears later (in the -prerelease tag) since that - // would mess up version ordering. - if (this.VersionHeightPosition == SemanticVersion.Position.Build) - { - return SemanticVersion.Position.Revision; - } - else - { - return null; - } + return SemanticVersion.Position.Revision; + } + else + { + return null; } } + } - /// - /// Gets a value indicating whether this instance is the default "0.0" instance. - /// - internal bool IsDefault => this.Version?.Major == 0 && this.Version.Minor == 0 && this.Version.Build == -1 && this.Version.Revision == -1 && this.Prerelease is null && this.BuildMetadata is null; + /// + /// Gets a value indicating whether this instance is the default "0.0" instance. + /// + internal bool IsDefault => this.Version?.Major == 0 && this.Version.Minor == 0 && this.Version.Build == -1 && this.Version.Revision == -1 && this.Prerelease is null && this.BuildMetadata is null; - /// - /// Gets the debugger display for this instance. - /// - private string DebuggerDisplay => this.ToString(); + /// + /// Gets the debugger display for this instance. + /// + private string DebuggerDisplay => this.ToString(); - /// - /// Parses a semantic version from the given string. - /// - /// The value which must wholly constitute a semantic version to succeed. - /// Receives the semantic version, if found. - /// true if a semantic version is found; false otherwise. - public static bool TryParse(string semanticVersion, out SemanticVersion version) + /// + /// Parses a semantic version from the given string. + /// + /// The value which must wholly constitute a semantic version to succeed. + /// Receives the semantic version, if found. + /// true if a semantic version is found; false otherwise. + public static bool TryParse(string semanticVersion, out SemanticVersion version) + { + Requires.NotNullOrEmpty(semanticVersion, nameof(semanticVersion)); + + Match m = FullSemVerWithMacrosPattern.Match(semanticVersion); + if (m.Success) { - Requires.NotNullOrEmpty(semanticVersion, nameof(semanticVersion)); + int major = int.Parse(m.Groups["major"].Value); + int minor = int.Parse(m.Groups["minor"].Value); + string patch = m.Groups["patch"].Value; + string revision = m.Groups["revision"].Value; + Version systemVersion = patch.Length > 0 + ? revision.Length > 0 ? new Version(major, minor, int.Parse(patch), int.Parse(revision)) : new Version(major, minor, int.Parse(patch)) + : new Version(major, minor); + string prerelease = m.Groups["prerelease"].Value; + string buildMetadata = m.Groups["buildMetadata"].Value; + version = new SemanticVersion(systemVersion, prerelease, buildMetadata); + return true; + } - Match m = FullSemVerWithMacrosPattern.Match(semanticVersion); - if (m.Success) - { - var major = int.Parse(m.Groups["major"].Value); - var minor = int.Parse(m.Groups["minor"].Value); - var patch = m.Groups["patch"].Value; - var revision = m.Groups["revision"].Value; - var systemVersion = patch.Length > 0 - ? revision.Length > 0 ? new Version(major, minor, int.Parse(patch), int.Parse(revision)) : new Version(major, minor, int.Parse(patch)) - : new Version(major, minor); - var prerelease = m.Groups["prerelease"].Value; - var buildMetadata = m.Groups["buildMetadata"].Value; - version = new SemanticVersion(systemVersion, prerelease, buildMetadata); - return true; - } + version = null; + return false; + } - version = null; - return false; - } + /// + /// Parses a semantic version from the given string. + /// + /// The value which must wholly constitute a semantic version to succeed. + /// An instance of , initialized to the value specified in . + public static SemanticVersion Parse(string semanticVersion) + { + SemanticVersion result; + Requires.Argument(TryParse(semanticVersion, out result), nameof(semanticVersion), "Unrecognized or unsupported semantic version."); + return result; + } - /// - /// Parses a semantic version from the given string. - /// - /// The value which must wholly constitute a semantic version to succeed. - /// An instance of , initialized to the value specified in . - public static SemanticVersion Parse(string semanticVersion) - { - SemanticVersion result; - Requires.Argument(TryParse(semanticVersion, out result), nameof(semanticVersion), "Unrecognized or unsupported semantic version."); - return result; - } + /// + /// Checks equality against another object. + /// + /// The other instance. + /// true if the instances have equal values; false otherwise. + public override bool Equals(object obj) + { + return this.Equals(obj as SemanticVersion); + } - /// - /// Checks equality against another object. - /// - /// The other instance. - /// true if the instances have equal values; false otherwise. - public override bool Equals(object obj) + /// + /// Gets a hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() + { + return this.Version.GetHashCode() + this.Prerelease.GetHashCode(); + } + + /// + /// Prints this instance as a string. + /// + /// A string representation of this object. + public override string ToString() + { + return this.Version + this.Prerelease + this.BuildMetadata; + } + + /// + /// Checks equality against another instance of this class. + /// + /// The other instance. + /// true if the instances have equal values; false otherwise. + public bool Equals(SemanticVersion other) + { + if (other is null) { - return this.Equals(obj as SemanticVersion); + return false; } - /// - /// Gets a hash code for this instance. - /// - /// The hash code. - public override int GetHashCode() + return this.Version == other.Version + && this.Prerelease == other.Prerelease + && this.BuildMetadata == other.BuildMetadata; + } + + /// + /// Tests whether two instances are compatible enough that version height is not reset + /// when progressing from one to the next. + /// + /// The first semantic version. + /// The second semantic version. + /// The position within the version where height is tracked. + /// true if transitioning from one version to the next should reset the version height; false otherwise. + internal static bool WillVersionChangeResetVersionHeight(SemanticVersion first, SemanticVersion second, SemanticVersion.Position versionHeightPosition) + { + Requires.NotNull(first, nameof(first)); + Requires.NotNull(second, nameof(second)); + + if (first == second) { - return this.Version.GetHashCode() + this.Prerelease.GetHashCode(); + return false; } - /// - /// Prints this instance as a string. - /// - /// A string representation of this object. - public override string ToString() + if (versionHeightPosition == SemanticVersion.Position.Prerelease) { - return this.Version + this.Prerelease + this.BuildMetadata; + // The entire version spec must match exactly. + return !first.Equals(second); } - /// - /// Checks equality against another instance of this class. - /// - /// The other instance. - /// true if the instances have equal values; false otherwise. - public bool Equals(SemanticVersion other) + for (SemanticVersion.Position position = SemanticVersion.Position.Major; position <= versionHeightPosition; position++) { - if (other is null) + int expectedValue = ReadVersionPosition(second.Version, position); + int actualValue = ReadVersionPosition(first.Version, position); + if (expectedValue != actualValue) { - return false; + return true; } - - return this.Version == other.Version - && this.Prerelease == other.Prerelease - && this.BuildMetadata == other.BuildMetadata; } - /// - /// Tests whether two instances are compatible enough that version height is not reset - /// when progressing from one to the next. - /// - /// The first semantic version. - /// The second semantic version. - /// The position within the version where height is tracked. - /// true if transitioning from one version to the next should reset the version height; false otherwise. - internal static bool WillVersionChangeResetVersionHeight(SemanticVersion first, SemanticVersion second, SemanticVersion.Position versionHeightPosition) - { - Requires.NotNull(first, nameof(first)); - Requires.NotNull(second, nameof(second)); - - if (first == second) - { - return false; - } + return false; + } - if (versionHeightPosition == SemanticVersion.Position.Prerelease) - { - // The entire version spec must match exactly. - return !first.Equals(second); - } + internal static int ReadVersionPosition(Version version, Position position) + { + Requires.NotNull(version, nameof(version)); - for (SemanticVersion.Position position = SemanticVersion.Position.Major; position <= versionHeightPosition; position++) - { - int expectedValue = ReadVersionPosition(second.Version, position); - int actualValue = ReadVersionPosition(first.Version, position); - if (expectedValue != actualValue) - { - return true; - } - } + return position switch + { + Position.Major => version.Major, + Position.Minor => version.Minor, + Position.Build => version.Build, + Position.Revision => version.Revision, + _ => throw new ArgumentOutOfRangeException(nameof(position), position, "Must be one of the 4 integer parts."), + }; + } - return false; - } + internal int ReadVersionPosition(Position position) => ReadVersionPosition(this.Version, position); - internal static int ReadVersionPosition(Version version, Position position) + /// + /// Checks whether a given version may have been produced by this semantic version. + /// + /// The version to test. + /// if the is a match; otherwise. + internal bool IsMatchingVersion(Version version) + { + Position lastPositionToConsider = Position.Revision; + if (this.VersionHeightPosition <= lastPositionToConsider) { - Requires.NotNull(version, nameof(version)); - - return position switch - { - Position.Major => version.Major, - Position.Minor => version.Minor, - Position.Build => version.Build, - Position.Revision => version.Revision, - _ => throw new ArgumentOutOfRangeException(nameof(position), position, "Must be one of the 4 integer parts."), - }; + lastPositionToConsider = this.VersionHeightPosition.Value - 1; } - internal int ReadVersionPosition(Position position) => ReadVersionPosition(this.Version, position); - - /// - /// Checks whether a given version may have been produced by this semantic version. - /// - /// The version to test. - /// if the is a match; otherwise. - internal bool IsMatchingVersion(Version version) + for (Position i = Position.Major; i <= lastPositionToConsider; i++) { - Position lastPositionToConsider = Position.Revision; - if (this.VersionHeightPosition <= lastPositionToConsider) - { - lastPositionToConsider = this.VersionHeightPosition.Value - 1; - } - - for (Position i = Position.Major; i <= lastPositionToConsider; i++) + if (this.ReadVersionPosition(i) != ReadVersionPosition(version, i)) { - if (this.ReadVersionPosition(i) != ReadVersionPosition(version, i)) - { - return false; - } + return false; } - - return true; } - /// - /// Checks whether a particular version number - /// belongs to the set of versions represented by this semantic version spec. - /// - /// A version, with major and minor components, and possibly build and/or revision components. - /// true if may have been produced by this semantic version; false otherwise. - internal bool Contains(Version version) - { - return - this.Version.Major == version.Major && - this.Version.Minor == version.Minor && - (this.Version.Build == -1 || this.Version.Build == version.Build) && - (this.Version.Revision == -1 || this.Version.Revision == version.Revision); - } + return true; + } - /// - /// Verifies that the prerelease tag follows semver rules. - /// - /// The input string to test. - /// The regex that the string must conform to. - /// The name of the parameter supplying the . - /// - /// Thrown if the does not match the required . - /// - private static void VerifyPatternMatch(string input, Regex pattern, string parameterName) - { - Requires.NotNull(pattern, nameof(pattern)); + /// + /// Checks whether a particular version number + /// belongs to the set of versions represented by this semantic version spec. + /// + /// A version, with major and minor components, and possibly build and/or revision components. + /// true if may have been produced by this semantic version; false otherwise. + internal bool Contains(Version version) + { + return + this.Version.Major == version.Major && + this.Version.Minor == version.Minor && + (this.Version.Build == -1 || this.Version.Build == version.Build) && + (this.Version.Revision == -1 || this.Version.Revision == version.Revision); + } - if (string.IsNullOrEmpty(input)) - { - return; - } + /// + /// Verifies that the prerelease tag follows semver rules. + /// + /// The input string to test. + /// The regex that the string must conform to. + /// The name of the parameter supplying the . + /// + /// Thrown if the does not match the required . + /// + private static void VerifyPatternMatch(string input, Regex pattern, string parameterName) + { + Requires.NotNull(pattern, nameof(pattern)); - Requires.Argument(pattern.IsMatch(input), parameterName, $"The prerelease must match the pattern \"{pattern}\"."); + if (string.IsNullOrEmpty(input)) + { + return; } + + Requires.Argument(pattern.IsMatch(input), parameterName, $"The prerelease must match the pattern \"{pattern}\"."); } } diff --git a/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs b/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs index a4ae7f34..96af49e8 100644 --- a/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs +++ b/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs @@ -1,44 +1,48 @@ -namespace Nerdbank.GitVersioning -{ - using System; - using System.Reflection; - using Newtonsoft.Json; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using Newtonsoft.Json; + +namespace Nerdbank.GitVersioning; - internal class SemanticVersionJsonConverter : JsonConverter +internal class SemanticVersionJsonConverter : JsonConverter +{ + /// + public override bool CanConvert(Type objectType) { - public override bool CanConvert(Type objectType) - { - return typeof(SemanticVersion).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); - } + return typeof(SemanticVersion).GetTypeInfo().IsAssignableFrom(objectType.GetTypeInfo()); + } - public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + /// + public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) + { + if (objectType.Equals(typeof(SemanticVersion)) && reader.Value is string) { - if (objectType.Equals(typeof(SemanticVersion)) && reader.Value is string) + SemanticVersion value; + if (SemanticVersion.TryParse((string)reader.Value, out value)) { - SemanticVersion value; - if (SemanticVersion.TryParse((string)reader.Value, out value)) - { - return value; - } - else - { - throw new FormatException($"The value \"{reader.Value}\" is not a valid semantic version."); - } + return value; } - - throw new NotSupportedException(); - } - - public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) - { - var version = value as SemanticVersion; - if (version is not null) + else { - writer.WriteValue(version.ToString()); - return; + throw new FormatException($"The value \"{reader.Value}\" is not a valid semantic version."); } + } - throw new NotSupportedException(); + throw new NotSupportedException(); + } + + /// + public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) + { + var version = value as SemanticVersion; + if (version is not null) + { + writer.WriteValue(version.ToString()); + return; } + + throw new NotSupportedException(); } } diff --git a/src/NerdBank.GitVersioning/VersionExtensions.cs b/src/NerdBank.GitVersioning/VersionExtensions.cs index 792964df..b9097b9c 100644 --- a/src/NerdBank.GitVersioning/VersionExtensions.cs +++ b/src/NerdBank.GitVersioning/VersionExtensions.cs @@ -1,90 +1,91 @@ -namespace Nerdbank.GitVersioning -{ - using System; - using Validation; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Validation; + +namespace Nerdbank.GitVersioning; +/// +/// Extension methods for the class. +/// +public static class VersionExtensions +{ /// - /// Extension methods for the class. + /// Returns a instance where the specified number of components + /// are guaranteed to be non-negative. Any applicable negative components are converted to zeros. /// - public static class VersionExtensions + /// The version to use as a template for the returned value. + /// The number of version components to ensure are non-negative. + /// + /// The same as except with any applicable negative values + /// translated to zeros. + /// + public static Version EnsureNonNegativeComponents(this Version version, int fieldCount = 4) { - /// - /// Returns a instance where the specified number of components - /// are guaranteed to be non-negative. Any applicable negative components are converted to zeros. - /// - /// The version to use as a template for the returned value. - /// The number of version components to ensure are non-negative. - /// - /// The same as except with any applicable negative values - /// translated to zeros. - /// - public static Version EnsureNonNegativeComponents(this Version version, int fieldCount = 4) - { - Requires.NotNull(version, nameof(version)); - Requires.Range(fieldCount >= 0 && fieldCount <= 4, nameof(fieldCount)); + Requires.NotNull(version, nameof(version)); + Requires.Range(fieldCount >= 0 && fieldCount <= 4, nameof(fieldCount)); - int maj = fieldCount >= 1 ? Math.Max(0, version.Major) : version.Major; - int min = fieldCount >= 2 ? Math.Max(0, version.Minor) : version.Minor; - int bld = fieldCount >= 3 ? Math.Max(0, version.Build) : version.Build; - int rev = fieldCount >= 4 ? Math.Max(0, version.Revision) : version.Revision; + int maj = fieldCount >= 1 ? Math.Max(0, version.Major) : version.Major; + int min = fieldCount >= 2 ? Math.Max(0, version.Minor) : version.Minor; + int bld = fieldCount >= 3 ? Math.Max(0, version.Build) : version.Build; + int rev = fieldCount >= 4 ? Math.Max(0, version.Revision) : version.Revision; - if (version.Major == maj && - version.Minor == min && - version.Build == bld && - version.Revision == rev) - { - return version; - } - - if (rev >= 0) - { - return new Version(maj, min, bld, rev); - } - else if (bld >= 0) - { - return new Version(maj, min, bld); - } - else - { - throw Assumes.NotReachable(); - } + if (version.Major == maj && + version.Minor == min && + version.Build == bld && + version.Revision == rev) + { + return version; } - /// - /// Converts the value of the current System.Version object to its equivalent System.String - /// representation. A specified count indicates the number of components to return. - /// - /// The instance to serialize as a string. - /// The number of components to return. The fieldCount ranges from 0 to 4. - /// - /// The System.String representation of the values of the major, minor, build, and - /// revision components of the current System.Version object, each separated by a - /// period character ('.'). The fieldCount parameter determines how many components - /// are returned.fieldCount Return Value 0 An empty string (""). 1 major 2 major.minor - /// 3 major.minor.build 4 major.minor.build.revision For example, if you create System.Version - /// object using the constructor Version(1,3,5), ToString(2) returns "1.3" and ToString(4) - /// returns "1.3.5.0". - /// - public static string ToStringSafe(this Version version, int fieldCount) + if (rev >= 0) { - return version.EnsureNonNegativeComponents(fieldCount).ToString(fieldCount); + return new Version(maj, min, bld, rev); } - - /// - /// Initializes a new instance of the class, - /// allowing for the last two integers to possibly be -1. - /// - /// The major version. - /// The minor version. - /// The build version. - /// The revision. - /// - internal static Version Create(int major, int minor, int build, int revision) + else if (bld >= 0) + { + return new Version(maj, min, bld); + } + else { - return - build == -1 ? new Version(major, minor) : - revision == -1 ? new Version(major, minor, build) : - new Version(major, minor, build, revision); + throw Assumes.NotReachable(); } } + + /// + /// Converts the value of the current System.Version object to its equivalent System.String + /// representation. A specified count indicates the number of components to return. + /// + /// The instance to serialize as a string. + /// The number of components to return. The fieldCount ranges from 0 to 4. + /// + /// The System.String representation of the values of the major, minor, build, and + /// revision components of the current System.Version object, each separated by a + /// period character ('.'). The fieldCount parameter determines how many components + /// are returned.fieldCount Return Value 0 An empty string (""). 1 major 2 major.minor + /// 3 major.minor.build 4 major.minor.build.revision For example, if you create System.Version + /// object using the constructor Version(1,3,5), ToString(2) returns "1.3" and ToString(4) + /// returns "1.3.5.0". + /// + public static string ToStringSafe(this Version version, int fieldCount) + { + return version.EnsureNonNegativeComponents(fieldCount).ToString(fieldCount); + } + + /// + /// Initializes a new instance of the class, + /// allowing for the last two integers to possibly be -1. + /// + /// The major version. + /// The minor version. + /// The build version. + /// The revision. + /// The newly created . + internal static Version Create(int major, int minor, int build, int revision) + { + return + build == -1 ? new Version(major, minor) : + revision == -1 ? new Version(major, minor, build) : + new Version(major, minor, build, revision); + } } diff --git a/src/NerdBank.GitVersioning/VersionFile.cs b/src/NerdBank.GitVersioning/VersionFile.cs index 936fbb26..0d3b85f3 100644 --- a/src/NerdBank.GitVersioning/VersionFile.cs +++ b/src/NerdBank.GitVersioning/VersionFile.cs @@ -1,245 +1,244 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable -using System; -using System.IO; using Newtonsoft.Json; using Validation; -namespace Nerdbank.GitVersioning +namespace Nerdbank.GitVersioning; + +/// +/// Exposes queries and mutations on a version.json or version.txt file. +/// +public abstract class VersionFile { /// - /// Exposes queries and mutations on a version.json or version.txt file. + /// The filename of the version.txt file. + /// + public const string TxtFileName = "version.txt"; + + /// + /// The filename of the version.json file. /// - public abstract class VersionFile + public const string JsonFileName = "version.json"; + + /// + /// Initializes a new instance of the class. + /// + /// The git context to use when reading version files. + protected VersionFile(GitContext context) { - /// - /// The filename of the version.txt file. - /// - public const string TxtFileName = "version.txt"; - - /// - /// The filename of the version.json file. - /// - public const string JsonFileName = "version.json"; - - /// - /// Initializes a new instance of the class. - /// - /// The git context to use when reading version files. - protected VersionFile(GitContext context) - { - this.Context = context; - } + this.Context = context; + } + + /// + /// Gets the git context to use when reading version files. + /// + protected GitContext Context { get; } + + /// + /// Checks whether a version file is defined. + /// + /// true if the version file is found; otherwise false. + public bool IsVersionDefined() => this.GetVersion() is object; + + /// + public VersionOptions? GetWorkingCopyVersion() => this.GetWorkingCopyVersion(out string _); + + /// + /// Reads the version file from the working tree and returns the deserialized from it. + /// + /// Set to the actual directory that the version file was found in, which may be or one of its ancestors. + /// The version information read from the file, or null if the file wasn't found. + public VersionOptions? GetWorkingCopyVersion(out string? actualDirectory) => this.GetWorkingCopyVersion(this.Context.AbsoluteProjectDirectory, out actualDirectory); - /// - /// Gets the git context to use when reading version files. - /// - protected GitContext Context { get; } - - /// - /// Checks whether a version file is defined. - /// - /// true if the version file is found; otherwise false. - public bool IsVersionDefined() => this.GetVersion() is object; - - /// - public VersionOptions? GetWorkingCopyVersion() => this.GetWorkingCopyVersion(out string _); - - /// - /// Reads the version file from the working tree and returns the deserialized from it. - /// - /// Set to the actual directory that the version file was found in, which may be or one of its ancestors. - /// The version information read from the file, or null if the file wasn't found. - public VersionOptions? GetWorkingCopyVersion(out string? actualDirectory) => this.GetWorkingCopyVersion(this.Context.AbsoluteProjectDirectory, out actualDirectory); - - /// - /// The optional unstable tag to include in the file. + /// + /// The optional unstable tag to include in the file. #pragma warning disable CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) - public string SetVersion(string projectDirectory, System.Version version, string? unstableTag = null, bool includeSchemaProperty = false) + public string SetVersion(string projectDirectory, System.Version version, string? unstableTag = null, bool includeSchemaProperty = false) #pragma warning restore CS1573 // Parameter has no matching param tag in the XML comment (but other parameters do) - { - return this.SetVersion(projectDirectory, VersionOptions.FromVersion(version, unstableTag), includeSchemaProperty); - } + { + return this.SetVersion(projectDirectory, VersionOptions.FromVersion(version, unstableTag), includeSchemaProperty); + } - /// - /// Writes the version.json file to a directory within a repo with the specified version information. - /// - /// - /// The path to the directory in which to write the version.json file. - /// The file's impact will be all descendent projects and directories from this specified directory, - /// except where any of those directories have their own version.json file. - /// - /// The version information to write to the file. - /// A value indicating whether to serialize the $schema property for easier editing in most JSON editors. - /// The path to the file written. - public string SetVersion(string projectDirectory, VersionOptions version, bool includeSchemaProperty = true) - { - Requires.NotNullOrEmpty(projectDirectory, nameof(projectDirectory)); - Requires.NotNull(version, nameof(version)); - Requires.Argument(version.Version is object || version.Inherit, nameof(version), $"{nameof(VersionOptions.Version)} must be set for a root-level version.json file."); + /// + /// Writes the version.json file to a directory within a repo with the specified version information. + /// + /// + /// The path to the directory in which to write the version.json file. + /// The file's impact will be all descendent projects and directories from this specified directory, + /// except where any of those directories have their own version.json file. + /// + /// The version information to write to the file. + /// A value indicating whether to serialize the $schema property for easier editing in most JSON editors. + /// The path to the file written. + public string SetVersion(string projectDirectory, VersionOptions version, bool includeSchemaProperty = true) + { + Requires.NotNullOrEmpty(projectDirectory, nameof(projectDirectory)); + Requires.NotNull(version, nameof(version)); + Requires.Argument(version.Version is object || version.Inherit, nameof(version), $"{nameof(VersionOptions.Version)} must be set for a root-level version.json file."); - Directory.CreateDirectory(projectDirectory); + Directory.CreateDirectory(projectDirectory); - string versionTxtPath = Path.Combine(projectDirectory, TxtFileName); - if (File.Exists(versionTxtPath)) + string versionTxtPath = Path.Combine(projectDirectory, TxtFileName); + if (File.Exists(versionTxtPath)) + { + if (version.IsDefaultVersionTheOnlyPropertySet) { - if (version.IsDefaultVersionTheOnlyPropertySet) - { - File.WriteAllLines( - versionTxtPath, - new[] { version.Version?.Version.ToString(), version.Version?.Prerelease }); - return versionTxtPath; - } - else - { - // The file must be upgraded to use the more descriptive JSON format. - File.Delete(versionTxtPath); - } + File.WriteAllLines( + versionTxtPath, + new[] { version.Version?.Version.ToString(), version.Version?.Prerelease }); + return versionTxtPath; + } + else + { + // The file must be upgraded to use the more descriptive JSON format. + File.Delete(versionTxtPath); } - - string repoRelativeProjectDirectory = this.Context.GetRepoRelativePath(projectDirectory); - string versionJsonPath = Path.Combine(projectDirectory, JsonFileName); - string jsonContent = JsonConvert.SerializeObject( - version, - VersionOptions.GetJsonSettings(version.Inherit, includeSchemaProperty, repoRelativeProjectDirectory)); - File.WriteAllText(versionJsonPath, jsonContent); - return versionJsonPath; } - /// - /// Reads the version file from in the and returns the deserialized from it. - /// - /// Receives the absolute path to the directory where the version file was found, if any. - /// The version information read from the file, or if the file wasn't found. - /// This method is only called if is not null. - protected abstract VersionOptions? GetVersionCore(out string? actualDirectory); - - /// - public VersionOptions? GetVersion() => this.GetVersion(out string? actualDirectory); - - /// - /// Reads the version file from the selected git commit (or working copy if no commit is selected) and returns the deserialized from it. - /// - /// Receives the absolute path to the directory where the version file was found, if any. - /// The version information read from the file, or if the file wasn't found. - public VersionOptions? GetVersion(out string? actualDirectory) + string repoRelativeProjectDirectory = this.Context.GetRepoRelativePath(projectDirectory); + string versionJsonPath = Path.Combine(projectDirectory, JsonFileName); + string jsonContent = JsonConvert.SerializeObject( + version, + VersionOptions.GetJsonSettings(version.Inherit, includeSchemaProperty, repoRelativeProjectDirectory)); + File.WriteAllText(versionJsonPath, jsonContent); + return versionJsonPath; + } + + /// + public VersionOptions? GetVersion() => this.GetVersion(out string? actualDirectory); + + /// + /// Reads the version file from the selected git commit (or working copy if no commit is selected) and returns the deserialized from it. + /// + /// Receives the absolute path to the directory where the version file was found, if any. + /// The version information read from the file, or if the file wasn't found. + public VersionOptions? GetVersion(out string? actualDirectory) + { + return this.Context.GitCommitId is null + ? this.GetWorkingCopyVersion(out actualDirectory) + : this.GetVersionCore(out actualDirectory); + } + + /// + /// Tries to read a version.json file from the specified string, but favors returning null instead of throwing a . + /// + /// The content of the version.json file. + /// Directory that this version.json file is relative to the root of the repository. + /// The deserialized object, if deserialization was successful. + protected static VersionOptions? TryReadVersionJsonContent(string jsonContent, string? repoRelativeBaseDirectory) + { + try { - return this.Context.GitCommitId is null - ? this.GetWorkingCopyVersion(out actualDirectory) - : this.GetVersionCore(out actualDirectory); + return JsonConvert.DeserializeObject(jsonContent, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: repoRelativeBaseDirectory)); } + catch (JsonSerializationException) + { + return null; + } + } - /// - /// Tries to read a version.json file from the specified string, but favors returning null instead of throwing a . - /// - /// The content of the version.json file. - /// Directory that this version.json file is relative to the root of the repository. - /// The deserialized object, if deserialization was successful. - protected static VersionOptions? TryReadVersionJsonContent(string jsonContent, string? repoRelativeBaseDirectory) + /// + /// Reads the version.txt file and returns the and prerelease tag from it. + /// + /// The content of the version.txt file to read. + /// The version information read from the file; or null if a deserialization error occurs. + protected static VersionOptions TryReadVersionFile(TextReader versionTextContent) + { + string? versionLine = versionTextContent.ReadLine(); + string? prereleaseVersion = versionTextContent.ReadLine(); + if (!string.IsNullOrEmpty(prereleaseVersion)) { - try - { - return JsonConvert.DeserializeObject(jsonContent, VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: repoRelativeBaseDirectory)); - } - catch (JsonSerializationException) + if (!prereleaseVersion.StartsWith("-")) { - return null; + // SemVer requires that prerelease suffixes begin with a hyphen, so add one if it's missing. + prereleaseVersion = "-" + prereleaseVersion; } } - /// - /// Reads the version.txt file and returns the and prerelease tag from it. - /// - /// The content of the version.txt file to read. - /// The version information read from the file; or null if a deserialization error occurs. - protected static VersionOptions TryReadVersionFile(TextReader versionTextContent) + SemanticVersion semVer; + Verify.Operation(SemanticVersion.TryParse(versionLine + prereleaseVersion, out semVer), "Unrecognized version format."); + return new VersionOptions + { + Version = semVer, + }; + } + + /// + /// Reads the version file from in the and returns the deserialized from it. + /// + /// Receives the absolute path to the directory where the version file was found, if any. + /// The version information read from the file, or if the file wasn't found. + /// This method is only called if is not null. + protected abstract VersionOptions? GetVersionCore(out string? actualDirectory); + + /// + /// Reads a version file from the working tree, without any regard to a git repo. + /// + /// The path to start the search from. + /// Receives the directory where the version file was found. + /// The version options, if found. + protected VersionOptions? GetWorkingCopyVersion(string startingDirectory, out string? actualDirectory) + { + string? searchDirectory = startingDirectory; + while (searchDirectory is object) { - string? versionLine = versionTextContent.ReadLine(); - string? prereleaseVersion = versionTextContent.ReadLine(); - if (!string.IsNullOrEmpty(prereleaseVersion)) + // Do not search above the working tree root. + string? parentDirectory = string.Equals(searchDirectory, this.Context.WorkingTreePath, StringComparison.OrdinalIgnoreCase) + ? null + : Path.GetDirectoryName(searchDirectory); + string versionTxtPath = Path.Combine(searchDirectory, TxtFileName); + if (File.Exists(versionTxtPath)) { - if (!prereleaseVersion.StartsWith("-")) + using var sr = new StreamReader(File.OpenRead(versionTxtPath)); + VersionOptions? result = TryReadVersionFile(sr); + if (result is object) { - // SemVer requires that prerelease suffixes begin with a hyphen, so add one if it's missing. - prereleaseVersion = "-" + prereleaseVersion; + actualDirectory = searchDirectory; + return result; } } - SemanticVersion semVer; - Verify.Operation(SemanticVersion.TryParse(versionLine + prereleaseVersion, out semVer), "Unrecognized version format."); - return new VersionOptions + string versionJsonPath = Path.Combine(searchDirectory, JsonFileName); + if (File.Exists(versionJsonPath)) { - Version = semVer, - }; - } + string versionJsonContent = File.ReadAllText(versionJsonPath); - /// - /// Reads a version file from the working tree, without any regard to a git repo. - /// - /// The path to start the search from. - /// Receives the directory where the version file was found. - /// The version options, if found. - protected VersionOptions? GetWorkingCopyVersion(string startingDirectory, out string? actualDirectory) - { - string? searchDirectory = startingDirectory; - while (searchDirectory is object) - { - // Do not search above the working tree root. - string? parentDirectory = string.Equals(searchDirectory, this.Context.WorkingTreePath, StringComparison.OrdinalIgnoreCase) - ? null - : Path.GetDirectoryName(searchDirectory); - string versionTxtPath = Path.Combine(searchDirectory, TxtFileName); - if (File.Exists(versionTxtPath)) + string? repoRelativeBaseDirectory = this.Context.GetRepoRelativePath(searchDirectory); + VersionOptions? result = + TryReadVersionJsonContent(versionJsonContent, repoRelativeBaseDirectory); + if (result?.Inherit ?? false) { - using (var sr = new StreamReader(File.OpenRead(versionTxtPath))) + if (parentDirectory is object) { - var result = TryReadVersionFile(sr); + result = this.GetWorkingCopyVersion(parentDirectory, out string _); if (result is object) { + JsonConvert.PopulateObject( + versionJsonContent, + result, + VersionOptions.GetJsonSettings(repoRelativeBaseDirectory: repoRelativeBaseDirectory)); actualDirectory = searchDirectory; return result; } } - } - string versionJsonPath = Path.Combine(searchDirectory, JsonFileName); - if (File.Exists(versionJsonPath)) + throw new InvalidOperationException( + $"\"{versionJsonPath}\" inherits from a parent directory version.json file but none exists."); + } + else if (result is object) { - string versionJsonContent = File.ReadAllText(versionJsonPath); - - var repoRelativeBaseDirectory = this.Context.GetRepoRelativePath(searchDirectory); - VersionOptions? result = - TryReadVersionJsonContent(versionJsonContent, repoRelativeBaseDirectory); - if (result?.Inherit ?? false) - { - if (parentDirectory is object) - { - result = this.GetWorkingCopyVersion(parentDirectory, out string _); - if (result is object) - { - JsonConvert.PopulateObject(versionJsonContent, result, - VersionOptions.GetJsonSettings( - repoRelativeBaseDirectory: repoRelativeBaseDirectory)); - actualDirectory = searchDirectory; - return result; - } - } - - throw new InvalidOperationException( - $"\"{versionJsonPath}\" inherits from a parent directory version.json file but none exists."); - } - else if (result is object) - { - actualDirectory = searchDirectory; - return result; - } + actualDirectory = searchDirectory; + return result; } - - searchDirectory = parentDirectory; } - actualDirectory = null; - return null; + searchDirectory = parentDirectory; } + + actualDirectory = null; + return null; } } diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index b93bd9d1..8984d851 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -1,532 +1,1073 @@ -#nullable enable - -namespace Nerdbank.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Collections.ObjectModel; +using System.Diagnostics; +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Converters; +using Validation; +using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; +using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; + +#nullable enable + +namespace Nerdbank.GitVersioning; + +/// +/// Describes the various versions and options required for the build. +/// +[DebuggerDisplay("{DebuggerDisplay,nq}")] +public class VersionOptions : IEquatable { - using System; - using System.Collections.Generic; - using System.Collections.ObjectModel; - using System.Diagnostics; - using System.Linq; - using System.Reflection; - using Newtonsoft.Json; - using Newtonsoft.Json.Converters; - using Validation; - using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; - using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; - - /// - /// Describes the various versions and options required for the build. - /// - [DebuggerDisplay("{DebuggerDisplay,nq}")] - public class VersionOptions : IEquatable + /// + /// Default value for . + /// + public const VersionPrecision DefaultVersionPrecision = VersionPrecision.Minor; + + /// + /// The placeholder that may appear in the property's + /// to specify where the version height should appear in a computed semantic version. + /// + /// + /// When this macro does not appear in the string, the version height is set as the first unspecified integer of the 4-integer version. + /// If all 4 integers in a version are specified, and the macro does not appear, the version height isn't inserted anywhere. + /// + public const string VersionHeightPlaceholder = "{height}"; + + /// + /// The default value for the property. + /// + public const int DefaultGitCommitIdShortFixedLength = 10; + + /// + /// The default value for the property. + /// + private const int DefaultSemVer1NumericIdentifierPadding = 4; + + /// + /// A value indicating whether mutations of this instance are not allowed. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool isFrozen; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string? gitCommitIdPrefix; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private SemanticVersion? version; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private AssemblyVersionOptions? assemblyVersion; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private int? buildNumberOffset; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private int? semVer1NumericIdentifierPadding; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private int? gitCommitIdShortFixedLength; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private int? gitCommitIdShortAutoMinimum; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private NuGetPackageVersionOptions? nuGetPackageVersion; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private IReadOnlyList? publicReleaseRefSpec; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private CloudBuildOptions? cloudBuild; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ReleaseOptions? release; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private IReadOnlyList? pathFilters; + + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool inherit; + + /// + /// Initializes a new instance of the class. + /// + public VersionOptions() { - /// - /// A value indicating whether mutations of this instance are not allowed. - /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool isFrozen; + } - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string? gitCommitIdPrefix; + /// + /// Initializes a new instance of the class. + /// + /// Another instance to copy values from. + public VersionOptions(VersionOptions copyFrom) + { + Requires.NotNull(copyFrom, nameof(copyFrom)); + + this.gitCommitIdPrefix = copyFrom.gitCommitIdPrefix; + this.version = copyFrom.version; + this.assemblyVersion = copyFrom.assemblyVersion is object ? new AssemblyVersionOptions(copyFrom.assemblyVersion) : null; + this.buildNumberOffset = copyFrom.buildNumberOffset; + this.semVer1NumericIdentifierPadding = copyFrom.semVer1NumericIdentifierPadding; + this.gitCommitIdShortFixedLength = copyFrom.gitCommitIdShortFixedLength; + this.gitCommitIdShortAutoMinimum = copyFrom.gitCommitIdShortAutoMinimum; + this.nuGetPackageVersion = copyFrom.nuGetPackageVersion is object ? new NuGetPackageVersionOptions(copyFrom.nuGetPackageVersion) : null; + this.publicReleaseRefSpec = copyFrom.publicReleaseRefSpec?.ToList(); + this.cloudBuild = copyFrom.cloudBuild is object ? new CloudBuildOptions(copyFrom.cloudBuild) : null; + this.release = copyFrom.release is object ? new ReleaseOptions(copyFrom.release) : null; + this.pathFilters = copyFrom.pathFilters?.ToList(); + } + /// + /// The last component to control in a 4 integer version. + /// + public enum VersionPrecision + { /// - /// Backing field for the property. + /// The first integer is the last number set. The rest will be zeros. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private SemanticVersion? version; + Major, /// - /// Backing field for the property. + /// The second integer is the last number set. The rest will be zeros. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private AssemblyVersionOptions? assemblyVersion; + Minor, /// - /// Backing field for the property. + /// The third integer is the last number set. The fourth will be zero. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private int? buildNumberOffset; + Build, /// - /// Backing field for the property. + /// All four integers will be set. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private int? semVer1NumericIdentifierPadding; + Revision, + } + /// + /// The conditions a commit ID is included in a cloud build number. + /// + public enum CloudBuildNumberCommitWhen + { /// - /// Backing field for the property. + /// Always include the commit information in the cloud Build Number. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private int? gitCommitIdShortFixedLength; + Always, /// - /// Backing field for the property. + /// Only include the commit information when building a non-PublicRelease. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private int? gitCommitIdShortAutoMinimum; + NonPublicReleaseOnly, /// - /// Backing field for the property. + /// Never include the commit information. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private NuGetPackageVersionOptions? nuGetPackageVersion; + Never, + } + /// + /// The position a commit ID can appear in a cloud build number. + /// + public enum CloudBuildNumberCommitWhere + { /// - /// Backing field for the property. + /// The commit ID appears in build metadata (e.g. +ga1b2c3). /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private IReadOnlyList? publicReleaseRefSpec; + BuildMetadata, /// - /// Backing field for the property. + /// The commit ID appears as the 4th integer in the version (e.g. 1.2.3.23523). /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private CloudBuildOptions? cloudBuild; + FourthVersionComponent, + } + /// + /// Possible increments of the version after creating release branches. + /// + public enum ReleaseVersionIncrement + { /// - /// Backing field for the property. + /// Increment the major version after creating a release branch. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ReleaseOptions? release; + Major, /// - /// Backing field for the property. + /// Increment the minor version after creating a release branch. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private IReadOnlyList? pathFilters; + Minor, /// - /// Backing field for the property. + /// Increment the build number (the third number in a version) after creating a release branch. /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool inherit; + Build, + } - /// - /// Default value for . - /// - public const VersionPrecision DefaultVersionPrecision = VersionPrecision.Minor; + /// + /// Gets the $schema field that should be serialized when writing. + /// + [JsonProperty(PropertyName = "$schema")] + public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json"; - /// - /// The placeholder that may appear in the property's - /// to specify where the version height should appear in a computed semantic version. - /// - /// - /// When this macro does not appear in the string, the version height is set as the first unspecified integer of the 4-integer version. - /// If all 4 integers in a version are specified, and the macro does not appear, the version height isn't inserted anywhere. - /// - public const string VersionHeightPlaceholder = "{height}"; + /// + /// Gets or sets the default version to use. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public SemanticVersion? Version + { + get => this.version; + set => this.SetIfNotReadOnly(ref this.version, value); + } - /// - /// The default value for the property. - /// - private const int DefaultSemVer1NumericIdentifierPadding = 4; + /// + /// Gets or sets the version to use particularly for the + /// instead of the default . + /// + /// An instance of or null to simply use the default . + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public AssemblyVersionOptions? AssemblyVersion + { + get => this.assemblyVersion; + set => this.SetIfNotReadOnly(ref this.assemblyVersion, value); + } + + /// + /// Gets or sets the prefix for git commit id in version. + /// Because of semver rules the prefix must lead with a [A-z_] character (not a number) and it cannot be the empty string. + /// If null 'g' will be used. + /// + /// A prefix for git commit id. + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? GitCommitIdPrefix + { + get => this.gitCommitIdPrefix; + set + { + if (string.IsNullOrWhiteSpace(value)) + { + throw new ArgumentNullException(nameof(value), $"{nameof(this.GitCommitIdPrefix)} can't be empty"); + } + + char first = value![0]; + if (first < 'A' || (first > 'Z' && first < 'a' && first != '_') || first > 'z') + { + throw new ArgumentException(nameof(value), $"{nameof(this.GitCommitIdPrefix)} must lead with a [A-z_] character (not a number)"); + } + + this.SetIfNotReadOnly(ref this.gitCommitIdPrefix, value); + } + } + + /// + /// Gets the version to use particularly for the + /// instead of the default . + /// + /// An instance of or null to simply use the default . + [JsonIgnore] + public AssemblyVersionOptions AssemblyVersionOrDefault => this.AssemblyVersion ?? AssemblyVersionOptions.DefaultInstance; + + /// + /// Gets or sets a number to add to the git height when calculating the version height, + /// which typically is used in the portion of the computed version. + /// + /// Any integer (0, positive, or negative). + /// + /// An error will result if this value is negative with such a magnitude as to exceed the git height, + /// resulting in a negative build number. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + [Obsolete("Use " + nameof(VersionHeightOffset) + " instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public int? BuildNumberOffset + { + get => this.buildNumberOffset; + set => this.SetIfNotReadOnly(ref this.buildNumberOffset, value); + } + + /// + /// Gets or sets a number to add to the git height when calculating the number. + /// + /// Any integer (0, positive, or negative). + /// + /// An error will result if this value is negative with such a magnitude as to exceed the git height, + /// resulting in a negative build number. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? VersionHeightOffset + { +#pragma warning disable CS0618 + get => this.BuildNumberOffset; + set => this.BuildNumberOffset = value; +#pragma warning restore CS0618 + } + + /// + /// Gets a number to add to the git height when calculating the number. + /// + /// Any integer (0, positive, or negative). + /// + /// An error will result if this value is negative with such a magnitude as to exceed the git height, + /// resulting in a negative build number. + /// + [JsonIgnore] + [Obsolete("Use " + nameof(VersionHeightOffsetOrDefault) + " instead.")] + [EditorBrowsable(EditorBrowsableState.Never)] + public int BuildNumberOffsetOrDefault => this.BuildNumberOffset ?? 0; + + /// + /// Gets a number to add to the git height when calculating the number. + /// + /// Any integer (0, positive, or negative). + /// + /// An error will result if this value is negative with such a magnitude as to exceed the git height, + /// resulting in a negative build number. + /// + [JsonIgnore] + public int VersionHeightOffsetOrDefault + { +#pragma warning disable CS0618 + get => this.BuildNumberOffsetOrDefault; +#pragma warning restore CS0618 + } + + /// + /// Gets or sets the minimum number of digits to use for numeric identifiers in SemVer 1. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? SemVer1NumericIdentifierPadding + { + get => this.semVer1NumericIdentifierPadding; + set => this.SetIfNotReadOnly(ref this.semVer1NumericIdentifierPadding, value); + } + + /// + /// Gets the minimum number of digits to use for numeric identifiers in SemVer 1. + /// + [JsonIgnore] + public int SemVer1NumericIdentifierPaddingOrDefault => this.SemVer1NumericIdentifierPadding ?? DefaultSemVer1NumericIdentifierPadding; + + /// + /// Gets or sets the abbreviated git commit hash length. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? GitCommitIdShortFixedLength + { + get => this.gitCommitIdShortFixedLength; + set => this.SetIfNotReadOnly(ref this.gitCommitIdShortFixedLength, value); + } + + /// + /// Gets or sets the abbreviated git commit hash length minimum value. + /// The git repository provides the value. + /// If set to 0 or a git repository is not available, is used. + /// The value is 0 by default. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public int? GitCommitIdShortAutoMinimum + { + get => this.gitCommitIdShortAutoMinimum; + set => this.SetIfNotReadOnly(ref this.gitCommitIdShortAutoMinimum, value); + } + + /// + /// Gets or sets the options around NuGet version strings. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public NuGetPackageVersionOptions? NuGetPackageVersion + { + get => this.nuGetPackageVersion; + set => this.SetIfNotReadOnly(ref this.nuGetPackageVersion, value); + } + + /// + /// Gets the options around NuGet version strings. + /// + [JsonIgnore] + public NuGetPackageVersionOptions NuGetPackageVersionOrDefault => this.NuGetPackageVersion ?? NuGetPackageVersionOptions.DefaultInstance; + + /// + /// Gets or sets an array of regular expressions that describes branch or tag names that should + /// be built with PublicRelease=true as the default value on build servers. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public IReadOnlyList? PublicReleaseRefSpec + { + get => this.publicReleaseRefSpec; + set => this.SetIfNotReadOnly(ref this.publicReleaseRefSpec, value); + } + + /// + /// Gets an array of regular expressions that describes branch or tag names that should + /// be built with PublicRelease=true as the default value on build servers. + /// + [JsonIgnore] + public IReadOnlyList PublicReleaseRefSpecOrDefault => this.PublicReleaseRefSpec ?? Array.Empty(); + + /// + /// Gets or sets the options around cloud build. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public CloudBuildOptions? CloudBuild + { + get => this.cloudBuild; + set => this.SetIfNotReadOnly(ref this.cloudBuild, value); + } + + /// + /// Gets the options around cloud build. + /// + [JsonIgnore] + public CloudBuildOptions CloudBuildOrDefault => this.CloudBuild ?? CloudBuildOptions.DefaultInstance; + + /// + /// Gets or sets the options for the prepare-release command. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ReleaseOptions? Release + { + get => this.release; + set => this.SetIfNotReadOnly(ref this.release, value); + } + + /// + /// Gets the options for the prepare-release command. + /// + [JsonIgnore] + public ReleaseOptions ReleaseOrDefault => this.Release ?? ReleaseOptions.DefaultInstance; + + /// + /// Gets or sets a list of paths to use to filter commits when calculating version height. + /// If a given commit does not affect any paths in this filter, it is ignored for version height calculations. + /// Paths should be relative to the root of the repository. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public IReadOnlyList? PathFilters + { + get => this.pathFilters; + set => this.SetIfNotReadOnly(ref this.pathFilters, value); + } + + /// + /// Gets or sets a value indicating whether this options object should inherit from an ancestor any settings that are not explicitly set in this one. + /// + /// + /// When this is true, this object may not completely describe the options to be applied. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public bool Inherit + { + get => this.inherit; + set => this.SetIfNotReadOnly(ref this.inherit, value); + } + + /// + /// Gets a value indicating whether this instance rejects all attempts to mutate it. + /// + [JsonIgnore] + public bool IsFrozen => this.isFrozen; + + /// + /// Gets the position in a computed version that the version height should appear. + /// + [JsonIgnore] + public SemanticVersion.Position? VersionHeightPosition + { + get + { + return this.version?.VersionHeightPosition; + } + } + + /// + /// Gets the position in a computed version that the first 16 bits of a git commit ID should appear, if any. + /// + [JsonIgnore] + internal SemanticVersion.Position? GitCommitIdPosition => this.version?.GitCommitIdPosition; + + /// + /// Gets a value indicating whether is + /// set and the only property on this class that is set. + /// + internal bool IsDefaultVersionTheOnlyPropertySet + { + get + { + return this.Version is not null && this.AssemblyVersion is null && (this.CloudBuild?.IsDefault ?? true) + && this.VersionHeightOffset == 0 + && !this.SemVer1NumericIdentifierPadding.HasValue + && !this.Inherit; + } + } + + /// + /// Gets the debugger display for this instance. + /// + private string DebuggerDisplay => this.Version?.ToString() ?? (this.Inherit ? "Inheriting version info" : "(missing version)"); + + /// + /// Initializes a new instance of the class + /// with initialized with the specified parameters. + /// + /// The version number. + /// The prerelease tag, if any. + /// The new instance of . + public static VersionOptions FromVersion(Version version, string? unstableTag = null) + { + return new VersionOptions + { + Version = new SemanticVersion(version, unstableTag), + }; + } + + /// + /// Gets the to use based on certain requirements. + /// The $schema property is not serialized when using this overload. + /// + /// A value indicating whether default values should be serialized. + /// The serializer settings to use. + public static JsonSerializerSettings GetJsonSettings(bool includeDefaults) => GetJsonSettings(includeDefaults, includeSchemaProperty: false); + + /// + /// Gets the to use based on certain requirements. + /// Path filters cannot be serialized or deserialized when using this overload. + /// + /// A value indicating whether default values should be serialized. + /// A value indicating whether the $schema property should be serialized. + /// The serializer settings to use. + public static JsonSerializerSettings GetJsonSettings(bool includeDefaults, bool includeSchemaProperty) => GetJsonSettings(includeDefaults, includeSchemaProperty, repoRelativeBaseDirectory: null); + + /// + /// Gets the to use based on certain requirements. + /// + /// A value indicating whether default values should be serialized. + /// A value indicating whether the $schema property should be serialized. + /// + /// Directory (relative to the root of the repository) that path + /// filters should be relative to. + /// This should be the directory where the version.json file resides. + /// An empty string represents the root of the repository. + /// Passing null will mean path filters cannot be serialized. + /// + /// The serializer settings to use. + public static JsonSerializerSettings GetJsonSettings(bool includeDefaults = false, bool includeSchemaProperty = false, string? repoRelativeBaseDirectory = null) + { + return new JsonSerializerSettings + { + Converters = new JsonConverter[] + { + new VersionConverter(), + new SemanticVersionJsonConverter(), + new AssemblyVersionOptionsConverter(includeDefaults), + new StringEnumConverter() { CamelCaseText = true }, + new FilterPathJsonConverter(repoRelativeBaseDirectory), + }, + ContractResolver = new VersionOptionsContractResolver + { + IncludeDefaults = includeDefaults, + IncludeSchemaProperty = includeSchemaProperty, + }, + Formatting = Formatting.Indented, + }; + } + + /// + /// Checks equality against another object. + /// + /// The other instance. + /// true if the instances have equal values; false otherwise. + public override bool Equals(object? obj) + { + return this.Equals(obj as VersionOptions); + } + + /// + /// Gets a hash code for this instance. + /// + /// The hash code. + public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); + + /// + /// Checks equality against another instance of this class. + /// + /// The other instance. + /// true if the instances have equal values; false otherwise. + public bool Equals(VersionOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + /// + /// Freezes this instance so no more changes can be made to it. + /// + public void Freeze() + { + if (!this.isFrozen) + { + this.isFrozen = true; + this.assemblyVersion?.Freeze(); + this.nuGetPackageVersion?.Freeze(); + this.publicReleaseRefSpec = this.publicReleaseRefSpec is object ? new ReadOnlyCollection(this.publicReleaseRefSpec.ToList()) : null; + this.cloudBuild?.Freeze(); + this.release?.Freeze(); + this.pathFilters = this.pathFilters is object ? new ReadOnlyCollection(this.pathFilters.ToList()) : null; + } + } + + /// + /// Sets the value of a field if this instance is not marked as read only. + /// + /// The type of the value stored by the field. + /// The field to change. + /// The value to set. + private void SetIfNotReadOnly(ref T field, T value) + { + Verify.Operation(!this.isFrozen, "This instance is read only."); + field = value; + } + + /// + /// The class that contains settings for the property. + /// + public class NuGetPackageVersionOptions : IEquatable + { /// - /// The default value for the property. + /// Default value for . /// - public const int DefaultGitCommitIdShortFixedLength = 10; + public const VersionPrecision DefaultPrecision = VersionPrecision.Build; /// - /// The $schema field that should be serialized when writing + /// The default (uninitialized) instance. /// - [JsonProperty(PropertyName = "$schema")] - public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json"; + internal static readonly NuGetPackageVersionOptions DefaultInstance = new NuGetPackageVersionOptions() + { + isFrozen = true, + semVer = 1.0f, + precision = DefaultPrecision, + }; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool isFrozen; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private float? semVer; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private VersionPrecision? precision; /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - public VersionOptions() + public NuGetPackageVersionOptions() { } /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// Another instance to copy values from. - public VersionOptions(VersionOptions copyFrom) + /// The existing instance to copy from. + public NuGetPackageVersionOptions(NuGetPackageVersionOptions copyFrom) { - Requires.NotNull(copyFrom, nameof(copyFrom)); - - this.gitCommitIdPrefix = copyFrom.gitCommitIdPrefix; - this.version = copyFrom.version; - this.assemblyVersion = copyFrom.assemblyVersion is object ? new AssemblyVersionOptions(copyFrom.assemblyVersion) : null; - this.buildNumberOffset = copyFrom.buildNumberOffset; - this.semVer1NumericIdentifierPadding = copyFrom.semVer1NumericIdentifierPadding; - this.gitCommitIdShortFixedLength = copyFrom.gitCommitIdShortFixedLength; - this.gitCommitIdShortAutoMinimum = copyFrom.gitCommitIdShortAutoMinimum; - this.nuGetPackageVersion = copyFrom.nuGetPackageVersion is object ? new NuGetPackageVersionOptions(copyFrom.nuGetPackageVersion) : null; - this.publicReleaseRefSpec = copyFrom.publicReleaseRefSpec?.ToList(); - this.cloudBuild = copyFrom.cloudBuild is object ? new CloudBuildOptions(copyFrom.cloudBuild) : null; - this.release = copyFrom.release is object ? new ReleaseOptions(copyFrom.release) : null; - this.pathFilters = copyFrom.pathFilters?.ToList(); + this.semVer = copyFrom.semVer; } /// - /// Gets or sets the default version to use. + /// Gets or sets the version of SemVer (e.g. 1 or 2) that should be used when generating the package version. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public SemanticVersion? Version + public float? SemVer { - get => this.version; - set => this.SetIfNotReadOnly(ref this.version, value); + get => this.semVer; + set => this.SetIfNotReadOnly(ref this.semVer, value); } /// - /// Gets or sets the version to use particularly for the - /// instead of the default . + /// Gets the version of SemVer (e.g. 1 or 2) that should be used when generating the package version. + /// + [JsonIgnore] + public float? SemVerOrDefault => this.SemVer ?? DefaultInstance.SemVer; + + /// + /// Gets or sets number of version components to include when generating the package version. /// - /// An instance of or null to simply use the default . [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public AssemblyVersionOptions? AssemblyVersion + public VersionPrecision? Precision { - get => this.assemblyVersion; - set => this.SetIfNotReadOnly(ref this.assemblyVersion, value); + get => this.precision; + set => this.SetIfNotReadOnly(ref this.precision, value); } /// - /// Gets or sets the prefix for git commit id in version. - /// Because of semver rules the prefix must lead with a [A-z_] character (not a number) and it cannot be the empty string. - /// If null 'g' will be used. + /// Gets the number of version components to include when generating the package version. /// - /// A prefix for git commit id. - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? GitCommitIdPrefix + [JsonIgnore] + public VersionPrecision PrecisionOrDefault => this.Precision ?? DefaultInstance.Precision!.Value; + + /// + /// Gets a value indicating whether this instance rejects all attempts to mutate it. + /// + [JsonIgnore] + public bool IsFrozen => this.isFrozen; + + /// + /// Gets a value indicating whether this instance is equivalent to the default instance. + /// + internal bool IsDefault => this.Equals(DefaultInstance); + + /// + /// Freezes this instance so no more changes can be made to it. + /// + public void Freeze() => this.isFrozen = true; + + /// + public override bool Equals(object? obj) => this.Equals(obj as NuGetPackageVersionOptions); + + /// + public bool Equals(NuGetPackageVersionOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + + /// + public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); + + /// + /// Sets the value of a field if this instance is not marked as read only. + /// + /// The type of the value stored by the field. + /// The field to change. + /// The value to set. + private void SetIfNotReadOnly(ref T field, T value) { - get => this.gitCommitIdPrefix; - set + Verify.Operation(!this.isFrozen, "This instance is read only."); + field = value; + } + + internal class EqualWithDefaultsComparer : IEqualityComparer + { + internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); + + private EqualWithDefaultsComparer() { - if (string.IsNullOrWhiteSpace(value)) + } + + /// + public bool Equals(NuGetPackageVersionOptions? x, NuGetPackageVersionOptions? y) + { + if (ReferenceEquals(x, y)) { - throw new ArgumentNullException(nameof(value), $"{nameof(this.GitCommitIdPrefix)} can't be empty"); + return true; } - char first = value![0]; - if (first < 'A' || (first > 'Z' && first < 'a' && first != '_') || first > 'z') + + if (x is null || y is null) { - throw new ArgumentException(nameof(value), $"{nameof(this.GitCommitIdPrefix)} must lead with a [A-z_] character (not a number)"); + return false; } - this.SetIfNotReadOnly(ref this.gitCommitIdPrefix, value); + return x.SemVerOrDefault == y.SemVerOrDefault && + x.PrecisionOrDefault == y.PrecisionOrDefault; } - } - /// - /// Gets the version to use particularly for the - /// instead of the default . - /// - /// An instance of or null to simply use the default . - [JsonIgnore] - public AssemblyVersionOptions AssemblyVersionOrDefault => this.AssemblyVersion ?? AssemblyVersionOptions.DefaultInstance; - - /// - /// Gets or sets a number to add to the git height when calculating the version height, - /// which typically is used in the portion of the computed version. - /// - /// Any integer (0, positive, or negative). - /// - /// An error will result if this value is negative with such a magnitude as to exceed the git height, - /// resulting in a negative build number. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - [Obsolete("Use " + nameof(VersionHeightOffset) + " instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public int? BuildNumberOffset - { - get => this.buildNumberOffset; - set => this.SetIfNotReadOnly(ref this.buildNumberOffset, value); + /// + public int GetHashCode(NuGetPackageVersionOptions? obj) + { + if (obj is null) + { + return 0; + } + + unchecked + { + int hash = obj.SemVerOrDefault.GetHashCode() * 397; + hash ^= obj.PrecisionOrDefault.GetHashCode(); + return hash; + } + } } + } + /// + /// Describes the details of how the AssemblyVersion value will be calculated. + /// + public class AssemblyVersionOptions : IEquatable + { /// - /// Gets or sets a number to add to the git height when calculating the number. + /// The default (uninitialized) instance. /// - /// Any integer (0, positive, or negative). - /// - /// An error will result if this value is negative with such a magnitude as to exceed the git height, - /// resulting in a negative build number. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? VersionHeightOffset + internal static readonly AssemblyVersionOptions DefaultInstance = new AssemblyVersionOptions() { -#pragma warning disable CS0618 - get => this.BuildNumberOffset; - set => this.BuildNumberOffset = value; -#pragma warning restore CS0618 - } + isFrozen = true, + precision = DefaultVersionPrecision, + }; - /// - /// Gets a number to add to the git height when calculating the number. - /// - /// Any integer (0, positive, or negative). - /// - /// An error will result if this value is negative with such a magnitude as to exceed the git height, - /// resulting in a negative build number. - /// - [JsonIgnore] - [Obsolete("Use " + nameof(VersionHeightOffsetOrDefault) + " instead.")] - [EditorBrowsable(EditorBrowsableState.Never)] - public int BuildNumberOffsetOrDefault => this.BuildNumberOffset ?? 0; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool isFrozen; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private Version? version; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private VersionPrecision? precision; /// - /// Gets a number to add to the git height when calculating the number. + /// Initializes a new instance of the class. /// - /// Any integer (0, positive, or negative). - /// - /// An error will result if this value is negative with such a magnitude as to exceed the git height, - /// resulting in a negative build number. - /// - [JsonIgnore] - public int VersionHeightOffsetOrDefault + public AssemblyVersionOptions() { -#pragma warning disable CS0618 - get => this.BuildNumberOffsetOrDefault; -#pragma warning restore CS0618 } /// - /// Gets or sets the minimum number of digits to use for numeric identifiers in SemVer 1. + /// Initializes a new instance of the class. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? SemVer1NumericIdentifierPadding + /// The assembly version (with major.minor components). + /// The additional version precision to add toward matching the AssemblyFileVersion. + public AssemblyVersionOptions(Version version, VersionPrecision? precision = null) { - get => this.semVer1NumericIdentifierPadding; - set => this.SetIfNotReadOnly(ref this.semVer1NumericIdentifierPadding, value); + this.Version = version; + this.Precision = precision; } /// - /// Gets the minimum number of digits to use for numeric identifiers in SemVer 1. - /// - [JsonIgnore] - public int SemVer1NumericIdentifierPaddingOrDefault => this.SemVer1NumericIdentifierPadding ?? DefaultSemVer1NumericIdentifierPadding; - - /// - /// Gets or sets the abbreviated git commit hash length. + /// Initializes a new instance of the class. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? GitCommitIdShortFixedLength + /// The existing instance to copy from. + public AssemblyVersionOptions(AssemblyVersionOptions copyFrom) { - get => this.gitCommitIdShortFixedLength; - set => this.SetIfNotReadOnly(ref this.gitCommitIdShortFixedLength, value); + this.version = copyFrom.version; + this.precision = copyFrom.precision; } /// - /// Gets or sets the abbreviated git commit hash length minimum value. - /// The git repository provides the value. - /// If set to 0 or a git repository is not available, is used. - /// The value is 0 by default. + /// Gets or sets the components of the assembly version (2-4 components). /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public int? GitCommitIdShortAutoMinimum + public Version? Version { - get => this.gitCommitIdShortAutoMinimum; - set => this.SetIfNotReadOnly(ref this.gitCommitIdShortAutoMinimum, value); + get => this.version; + set => this.SetIfNotReadOnly(ref this.version, value); } /// - /// Gets or sets the options around NuGet version strings + /// Gets or sets the additional version precision to add toward matching the AssemblyFileVersion. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public NuGetPackageVersionOptions? NuGetPackageVersion + public VersionPrecision? Precision { - get => this.nuGetPackageVersion; - set => this.SetIfNotReadOnly(ref this.nuGetPackageVersion, value); + get => this.precision; + set => this.SetIfNotReadOnly(ref this.precision, value); } /// - /// Gets the options around NuGet version strings + /// Gets the additional version precision to add toward matching the AssemblyFileVersion. /// [JsonIgnore] - public NuGetPackageVersionOptions NuGetPackageVersionOrDefault => this.NuGetPackageVersion ?? NuGetPackageVersionOptions.DefaultInstance; - - /// - /// Gets or sets an array of regular expressions that describes branch or tag names that should - /// be built with PublicRelease=true as the default value on build servers. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public IReadOnlyList? PublicReleaseRefSpec - { - get => this.publicReleaseRefSpec; - set => this.SetIfNotReadOnly(ref this.publicReleaseRefSpec, value); - } + public VersionPrecision PrecisionOrDefault => this.Precision ?? DefaultVersionPrecision; /// - /// Gets an array of regular expressions that describes branch or tag names that should - /// be built with PublicRelease=true as the default value on build servers. + /// Gets a value indicating whether this instance rejects all attempts to mutate it. /// [JsonIgnore] - public IReadOnlyList PublicReleaseRefSpecOrDefault => this.PublicReleaseRefSpec ?? Array.Empty(); + public bool IsFrozen => this.isFrozen; /// - /// Gets or sets the options around cloud build. + /// Gets a value indicating whether this instance is equivalent to the default instance. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public CloudBuildOptions? CloudBuild - { - get => this.cloudBuild; - set => this.SetIfNotReadOnly(ref this.cloudBuild, value); - } + internal bool IsDefault => this.Equals(DefaultInstance); /// - /// Gets the options around cloud build. + /// Freezes this instance so no more changes can be made to it. /// - [JsonIgnore] - public CloudBuildOptions CloudBuildOrDefault => this.CloudBuild ?? CloudBuildOptions.DefaultInstance; + public void Freeze() => this.isFrozen = true; - /// - /// Gets or sets the options for the prepare-release command - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public ReleaseOptions? Release - { - get => this.release; - set => this.SetIfNotReadOnly(ref this.release, value); - } + /// + public override bool Equals(object? obj) => this.Equals(obj as AssemblyVersionOptions); - /// - /// Gets the options for the prepare-release command - /// - [JsonIgnore] - public ReleaseOptions ReleaseOrDefault => this.Release ?? ReleaseOptions.DefaultInstance; + /// + public bool Equals(AssemblyVersionOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + + /// + public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); /// - /// Gets or sets a list of paths to use to filter commits when calculating version height. - /// If a given commit does not affect any paths in this filter, it is ignored for version height calculations. - /// Paths should be relative to the root of the repository. + /// Sets the value of a field if this instance is not marked as read only. /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public IReadOnlyList? PathFilters + /// The type of the value stored by the field. + /// The field to change. + /// The value to set. + private void SetIfNotReadOnly(ref T field, T value) { - get => this.pathFilters; - set => this.SetIfNotReadOnly(ref this.pathFilters, value); + Verify.Operation(!this.isFrozen, "This instance is read only."); + field = value; } - /// - /// Gets or sets a value indicating whether this options object should inherit from an ancestor any settings that are not explicitly set in this one. - /// - /// - /// When this is true, this object may not completely describe the options to be applied. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public bool Inherit + internal class EqualWithDefaultsComparer : IEqualityComparer { - get => this.inherit; - set => this.SetIfNotReadOnly(ref this.inherit, value); + internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); + + private EqualWithDefaultsComparer() + { + } + + /// + public bool Equals(AssemblyVersionOptions? x, AssemblyVersionOptions? y) + { + if (ReferenceEquals(x, y)) + { + return true; + } + + if (x is null || y is null) + { + return false; + } + + return EqualityComparer.Default.Equals(x.Version, y.Version) + && x.PrecisionOrDefault == y.PrecisionOrDefault; + } + + /// + public int GetHashCode(AssemblyVersionOptions? obj) + { + if (obj is null) + { + return 0; + } + + return (obj.Version?.GetHashCode() ?? 0) + (int)obj.PrecisionOrDefault; + } } + } + /// + /// Options that are applicable specifically to cloud builds (e.g. VSTS, AppVeyor, TeamCity). + /// + public class CloudBuildOptions : IEquatable + { /// - /// Gets a value indicating whether this instance rejects all attempts to mutate it. + /// The default (uninitialized) instance. /// - [JsonIgnore] - public bool IsFrozen => this.isFrozen; + internal static readonly CloudBuildOptions DefaultInstance = new CloudBuildOptions() + { + isFrozen = true, + setAllVariables = false, + setVersionVariables = true, + }; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool isFrozen; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool? setAllVariables; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool? setVersionVariables; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private CloudBuildNumberOptions? buildNumber; /// - /// Gets the position in a computed version that the version height should appear. + /// Initializes a new instance of the class. /// - [JsonIgnore] - public SemanticVersion.Position? VersionHeightPosition + public CloudBuildOptions() { - get - { - return this.version?.VersionHeightPosition; - } } /// - /// Gets the position in a computed version that the first 16 bits of a git commit ID should appear, if any. + /// Initializes a new instance of the class. /// - [JsonIgnore] - internal SemanticVersion.Position? GitCommitIdPosition => this.version?.GitCommitIdPosition; + /// Another instance to copy values from. + public CloudBuildOptions(CloudBuildOptions copyFrom) + { + this.setAllVariables = copyFrom.setAllVariables; + this.setVersionVariables = copyFrom.setVersionVariables; + this.buildNumber = copyFrom.buildNumber is object ? new CloudBuildNumberOptions(copyFrom.buildNumber) : null; + } /// - /// Gets the debugger display for this instance. + /// Gets or sets a value indicating whether to elevate all build properties to cloud build variables prefaced with "NBGV_". /// - private string DebuggerDisplay => this.Version?.ToString() ?? (this.Inherit ? "Inheriting version info" : "(missing version)"); + public bool? SetAllVariables + { + get => this.setAllVariables; + set => this.SetIfNotReadOnly(ref this.setAllVariables, value); + } /// - /// Initializes a new instance of the class - /// with initialized with the specified parameters. + /// Gets or sets a value indicating whether to elevate certain calculated version build properties to cloud build variables. /// - /// The version number. - /// The prerelease tag, if any. - /// The new instance of . - public static VersionOptions FromVersion(Version version, string? unstableTag = null) + public bool? SetVersionVariables { - return new VersionOptions - { - Version = new SemanticVersion(version, unstableTag), - }; + get => this.setVersionVariables; + set => this.SetIfNotReadOnly(ref this.setVersionVariables, value); } /// - /// Gets the to use based on certain requirements. - /// The $schema property is not serialized when using this overload. + /// Gets a value indicating whether to elevate all build properties to cloud build variables prefaced with "NBGV_". /// - /// A value indicating whether default values should be serialized. - /// The serializer settings to use. - public static JsonSerializerSettings GetJsonSettings(bool includeDefaults) => GetJsonSettings(includeDefaults, includeSchemaProperty: false); + [JsonIgnore] + public bool SetAllVariablesOrDefault => this.SetAllVariables ?? DefaultInstance.SetAllVariables!.Value; /// - /// Gets the to use based on certain requirements. - /// Path filters cannot be serialized or deserialized when using this overload. + /// Gets a value indicating whether to elevate certain calculated version build properties to cloud build variables. /// - /// A value indicating whether default values should be serialized. - /// A value indicating whether the $schema property should be serialized. - /// The serializer settings to use. - public static JsonSerializerSettings GetJsonSettings(bool includeDefaults, bool includeSchemaProperty) => GetJsonSettings(includeDefaults, includeSchemaProperty, repoRelativeBaseDirectory: null); + [JsonIgnore] + public bool SetVersionVariablesOrDefault => this.SetVersionVariables ?? DefaultInstance.SetVersionVariables!.Value; /// - /// Gets the to use based on certain requirements. + /// Gets or sets options around how and whether to set the build number preset by the cloud build with one enriched with version information. /// - /// A value indicating whether default values should be serialized. - /// A value indicating whether the $schema property should be serialized. - /// - /// Directory (relative to the root of the repository) that path - /// filters should be relative to. - /// This should be the directory where the version.json file resides. - /// An empty string represents the root of the repository. - /// Passing null will mean path filters cannot be serialized. - /// - /// The serializer settings to use. - public static JsonSerializerSettings GetJsonSettings(bool includeDefaults = false, bool includeSchemaProperty = false, string? repoRelativeBaseDirectory = null) + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public CloudBuildNumberOptions? BuildNumber { - return new JsonSerializerSettings - { - Converters = new JsonConverter[] { - new VersionConverter(), - new SemanticVersionJsonConverter(), - new AssemblyVersionOptionsConverter(includeDefaults), - new StringEnumConverter() { CamelCaseText = true }, - new FilterPathJsonConverter(repoRelativeBaseDirectory), - }, - ContractResolver = new VersionOptionsContractResolver - { - IncludeDefaults = includeDefaults, - IncludeSchemaProperty = includeSchemaProperty, - }, - Formatting = Formatting.Indented, - }; + get => this.buildNumber; + set => this.SetIfNotReadOnly(ref this.buildNumber, value); } /// - /// Checks equality against another object. + /// Gets options around how and whether to set the build number preset by the cloud build with one enriched with version information. /// - /// The other instance. - /// true if the instances have equal values; false otherwise. - public override bool Equals(object? obj) - { - return this.Equals(obj as VersionOptions); - } + [JsonIgnore] + public CloudBuildNumberOptions BuildNumberOrDefault => this.BuildNumber ?? CloudBuildNumberOptions.DefaultInstance; /// - /// Gets a hash code for this instance. + /// Gets a value indicating whether this instance rejects all attempts to mutate it. /// - /// The hash code. - public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); + [JsonIgnore] + public bool IsFrozen => this.isFrozen; /// - /// Checks equality against another instance of this class. + /// Gets a value indicating whether this instance is equivalent to the default instance. /// - /// The other instance. - /// true if the instances have equal values; false otherwise. - public bool Equals(VersionOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + internal bool IsDefault => this.Equals(DefaultInstance); /// /// Freezes this instance so no more changes can be made to it. @@ -536,29 +1077,18 @@ public void Freeze() if (!this.isFrozen) { this.isFrozen = true; - this.assemblyVersion?.Freeze(); - this.nuGetPackageVersion?.Freeze(); - this.publicReleaseRefSpec = this.publicReleaseRefSpec is object ? new ReadOnlyCollection(this.publicReleaseRefSpec.ToList()) : null; - this.cloudBuild?.Freeze(); - this.release?.Freeze(); - this.pathFilters = this.pathFilters is object ? new ReadOnlyCollection(this.pathFilters.ToList()) : null; + this.buildNumber?.Freeze(); } } - /// - /// Gets a value indicating whether is - /// set and the only property on this class that is set. - /// - internal bool IsDefaultVersionTheOnlyPropertySet - { - get - { - return this.Version is not null && this.AssemblyVersion is null && (this.CloudBuild?.IsDefault ?? true) - && this.VersionHeightOffset == 0 - && !this.SemVer1NumericIdentifierPadding.HasValue - && !this.Inherit; - } - } + /// + public override bool Equals(object? obj) => this.Equals(obj as CloudBuildOptions); + + /// + public bool Equals(CloudBuildOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + + /// + public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); /// /// Sets the value of a field if this instance is not marked as read only. @@ -572,779 +1102,316 @@ private void SetIfNotReadOnly(ref T field, T value) field = value; } - /// - /// The class that contains settings for the property. - /// - public class NuGetPackageVersionOptions : IEquatable + internal class EqualWithDefaultsComparer : IEqualityComparer { - /// - /// The default (uninitialized) instance. - /// - internal static readonly NuGetPackageVersionOptions DefaultInstance = new NuGetPackageVersionOptions() - { - isFrozen = true, - semVer = 1.0f, - precision = DefaultPrecision, - }; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool isFrozen; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private float? semVer; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private VersionPrecision? precision; - - /// - /// Default value for . - /// - public const VersionPrecision DefaultPrecision = VersionPrecision.Build; - - /// - /// Initializes a new instance of the class. - /// - public NuGetPackageVersionOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - public NuGetPackageVersionOptions(NuGetPackageVersionOptions copyFrom) - { - this.semVer = copyFrom.semVer; - } - - /// - /// Gets or sets the version of SemVer (e.g. 1 or 2) that should be used when generating the package version. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public float? SemVer - { - get => this.semVer; - set => this.SetIfNotReadOnly(ref this.semVer, value); - } + internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); - /// - /// Gets the version of SemVer (e.g. 1 or 2) that should be used when generating the package version. - /// - [JsonIgnore] - public float? SemVerOrDefault => this.SemVer ?? DefaultInstance.SemVer; - - /// - /// Gets or sets number of version components to include when generating the package version. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public VersionPrecision? Precision + private EqualWithDefaultsComparer() { - get => this.precision; - set => this.SetIfNotReadOnly(ref this.precision, value); } - /// - /// Gets the number of version components to include when generating the package version. - /// - [JsonIgnore] - public VersionPrecision PrecisionOrDefault => this.Precision ?? DefaultInstance.Precision!.Value; - - /// - /// Gets a value indicating whether this instance rejects all attempts to mutate it. - /// - [JsonIgnore] - public bool IsFrozen => this.isFrozen; - - /// - /// Freezes this instance so no more changes can be made to it. - /// - public void Freeze() => this.isFrozen = true; - - /// - public override bool Equals(object? obj) => this.Equals(obj as NuGetPackageVersionOptions); - - /// - public bool Equals(NuGetPackageVersionOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); - /// - public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - - /// - /// Gets a value indicating whether this instance is equivalent to the default instance. - /// - internal bool IsDefault => this.Equals(DefaultInstance); - - /// - /// Sets the value of a field if this instance is not marked as read only. - /// - /// The type of the value stored by the field. - /// The field to change. - /// The value to set. - private void SetIfNotReadOnly(ref T field, T value) - { - Verify.Operation(!this.isFrozen, "This instance is read only."); - field = value; - } - - internal class EqualWithDefaultsComparer : IEqualityComparer + public bool Equals(CloudBuildOptions? x, CloudBuildOptions? y) { - internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); - - private EqualWithDefaultsComparer() { } - - /// - public bool Equals(NuGetPackageVersionOptions? x, NuGetPackageVersionOptions? y) + if (ReferenceEquals(x, y)) { - if (ReferenceEquals(x, y)) - { - return true; - } - - if (x is null || y is null) - { - return false; - } - - return x.SemVerOrDefault == y.SemVerOrDefault && - x.PrecisionOrDefault == y.PrecisionOrDefault; + return true; } - /// - public int GetHashCode(NuGetPackageVersionOptions? obj) + if (x is null || y is null) { - if (obj is null) - return 0; - - unchecked - { - var hash = obj.SemVerOrDefault.GetHashCode() * 397; - hash ^= obj.PrecisionOrDefault.GetHashCode(); - return hash; - } + return false; } - } - } - - /// - /// Describes the details of how the AssemblyVersion value will be calculated. - /// - public class AssemblyVersionOptions : IEquatable - { - /// - /// The default (uninitialized) instance. - /// - internal static readonly AssemblyVersionOptions DefaultInstance = new AssemblyVersionOptions() - { - isFrozen = true, - precision = DefaultVersionPrecision, - }; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool isFrozen; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private Version? version; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private VersionPrecision? precision; - - /// - /// Initializes a new instance of the class. - /// - public AssemblyVersionOptions() - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The assembly version (with major.minor components). - /// The additional version precision to add toward matching the AssemblyFileVersion. - public AssemblyVersionOptions(Version version, VersionPrecision? precision = null) - { - this.Version = version; - this.Precision = precision; - } - - /// - /// Initializes a new instance of the class. - /// - public AssemblyVersionOptions(AssemblyVersionOptions copyFrom) - { - this.version = copyFrom.version; - this.precision = copyFrom.precision; - } - - /// - /// Gets or sets the components of the assembly version (2-4 components). - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public Version? Version - { - get => this.version; - set => this.SetIfNotReadOnly(ref this.version, value); - } - /// - /// Gets or sets the additional version precision to add toward matching the AssemblyFileVersion. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public VersionPrecision? Precision - { - get => this.precision; - set => this.SetIfNotReadOnly(ref this.precision, value); + return x.SetVersionVariablesOrDefault == y.SetVersionVariablesOrDefault + && x.SetAllVariablesOrDefault == y.SetAllVariablesOrDefault + && CloudBuildNumberOptions.EqualWithDefaultsComparer.Singleton.Equals(x.BuildNumberOrDefault, y.BuildNumberOrDefault); } - /// - /// Gets the additional version precision to add toward matching the AssemblyFileVersion. - /// - [JsonIgnore] - public VersionPrecision PrecisionOrDefault => this.Precision ?? DefaultVersionPrecision; - - /// - /// Gets a value indicating whether this instance rejects all attempts to mutate it. - /// - [JsonIgnore] - public bool IsFrozen => this.isFrozen; - - /// - /// Freezes this instance so no more changes can be made to it. - /// - public void Freeze() => this.isFrozen = true; - /// - public override bool Equals(object? obj) => this.Equals(obj as AssemblyVersionOptions); - - /// - public bool Equals(AssemblyVersionOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); - - /// - public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - - /// - /// Gets a value indicating whether this instance is equivalent to the default instance. - /// - internal bool IsDefault => this.Equals(DefaultInstance); - - /// - /// Sets the value of a field if this instance is not marked as read only. - /// - /// The type of the value stored by the field. - /// The field to change. - /// The value to set. - private void SetIfNotReadOnly(ref T field, T value) + public int GetHashCode(CloudBuildOptions? obj) { - Verify.Operation(!this.isFrozen, "This instance is read only."); - field = value; - } - - internal class EqualWithDefaultsComparer : IEqualityComparer - { - internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); - - private EqualWithDefaultsComparer() { } - - /// - public bool Equals(AssemblyVersionOptions? x, AssemblyVersionOptions? y) + if (obj is null) { - if (ReferenceEquals(x, y)) - { - return true; - } - - if (x is null || y is null) - { - return false; - } - - return EqualityComparer.Default.Equals(x.Version, y.Version) - && x.PrecisionOrDefault == y.PrecisionOrDefault; + return 0; } - /// - public int GetHashCode(AssemblyVersionOptions? obj) - { - if (obj is null) - { - return 0; - } - - return (obj.Version?.GetHashCode() ?? 0) + (int)obj.PrecisionOrDefault; - } + return (obj.SetVersionVariablesOrDefault ? 1 : 0) + + (obj.SetAllVariablesOrDefault ? 1 : 0) + + obj.BuildNumberOrDefault.GetHashCode(); } } + } + /// + /// Override the build number preset by the cloud build with one enriched with version information. + /// + public class CloudBuildNumberOptions : IEquatable + { /// - /// Options that are applicable specifically to cloud builds (e.g. VSTS, AppVeyor, TeamCity) + /// The default (uninitialized) instance. /// - public class CloudBuildOptions : IEquatable + internal static readonly CloudBuildNumberOptions DefaultInstance = new CloudBuildNumberOptions() { - /// - /// The default (uninitialized) instance. - /// - internal static readonly CloudBuildOptions DefaultInstance = new CloudBuildOptions() - { - isFrozen = true, - setAllVariables = false, - setVersionVariables = true, - }; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool isFrozen; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool? setAllVariables; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool? setVersionVariables; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private CloudBuildNumberOptions? buildNumber; - - /// - /// Initializes a new instance of the class. - /// - public CloudBuildOptions() - { - } + isFrozen = true, + enabled = false, + }; - /// - /// Initializes a new instance of the class. - /// - /// Another instance to copy values from - public CloudBuildOptions(CloudBuildOptions copyFrom) - { - this.setAllVariables = copyFrom.setAllVariables; - this.setVersionVariables = copyFrom.setVersionVariables; - this.buildNumber = copyFrom.buildNumber is object ? new CloudBuildNumberOptions(copyFrom.buildNumber) : null; - } - - /// - /// Gets or sets a value indicating whether to elevate all build properties to cloud build variables prefaced with "NBGV_". - /// - public bool? SetAllVariables - { - get => this.setAllVariables; - set => this.SetIfNotReadOnly(ref this.setAllVariables, value); - } - - /// - /// Gets or sets a value indicating whether to elevate certain calculated version build properties to cloud build variables. - /// - public bool? SetVersionVariables - { - get => this.setVersionVariables; - set => this.SetIfNotReadOnly(ref this.setVersionVariables, value); - } - - /// - /// Gets a value indicating whether to elevate all build properties to cloud build variables prefaced with "NBGV_". - /// - [JsonIgnore] - public bool SetAllVariablesOrDefault => this.SetAllVariables ?? DefaultInstance.SetAllVariables!.Value; - - /// - /// Gets a value indicating whether to elevate certain calculated version build properties to cloud build variables. - /// - [JsonIgnore] - public bool SetVersionVariablesOrDefault => this.SetVersionVariables ?? DefaultInstance.SetVersionVariables!.Value; - - /// - /// Gets or sets options around how and whether to set the build number preset by the cloud build with one enriched with version information. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public CloudBuildNumberOptions? BuildNumber - { - get => this.buildNumber; - set => this.SetIfNotReadOnly(ref this.buildNumber, value); - } - - /// - /// Gets options around how and whether to set the build number preset by the cloud build with one enriched with version information. - /// - [JsonIgnore] - public CloudBuildNumberOptions BuildNumberOrDefault => this.BuildNumber ?? CloudBuildNumberOptions.DefaultInstance; - - /// - /// Gets a value indicating whether this instance rejects all attempts to mutate it. - /// - [JsonIgnore] - public bool IsFrozen => this.isFrozen; - - /// - /// Freezes this instance so no more changes can be made to it. - /// - public void Freeze() - { - if (!this.isFrozen) - { - this.isFrozen = true; - this.buildNumber?.Freeze(); - } - } - - /// - public override bool Equals(object? obj) => this.Equals(obj as CloudBuildOptions); + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool isFrozen; - /// - public bool Equals(CloudBuildOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool? enabled; + private CloudBuildNumberCommitIdOptions? includeCommitId; - /// - public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - - /// - /// Gets a value indicating whether this instance is equivalent to the default instance. - /// - internal bool IsDefault => this.Equals(DefaultInstance); - - /// - /// Sets the value of a field if this instance is not marked as read only. - /// - /// The type of the value stored by the field. - /// The field to change. - /// The value to set. - private void SetIfNotReadOnly(ref T field, T value) - { - Verify.Operation(!this.isFrozen, "This instance is read only."); - field = value; - } + /// + /// Initializes a new instance of the class. + /// + public CloudBuildNumberOptions() + { + } - internal class EqualWithDefaultsComparer : IEqualityComparer - { - internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); + /// + /// Initializes a new instance of the class. + /// + /// The existing instance to copy from. + public CloudBuildNumberOptions(CloudBuildNumberOptions copyFrom) + { + this.enabled = copyFrom.enabled; + this.includeCommitId = copyFrom.includeCommitId is object ? new CloudBuildNumberCommitIdOptions(copyFrom.includeCommitId) : null; + } - private EqualWithDefaultsComparer() { } + /// + /// Gets or sets a value indicating whether to override the build number preset by the cloud build. + /// + public bool? Enabled + { + get => this.enabled; + set => this.SetIfNotReadOnly(ref this.enabled, value); + } - /// - public bool Equals(CloudBuildOptions? x, CloudBuildOptions? y) - { - if (ReferenceEquals(x, y)) - { - return true; - } - - if (x is null || y is null) - { - return false; - } - - return x.SetVersionVariablesOrDefault == y.SetVersionVariablesOrDefault - && x.SetAllVariablesOrDefault == y.SetAllVariablesOrDefault - && CloudBuildNumberOptions.EqualWithDefaultsComparer.Singleton.Equals(x.BuildNumberOrDefault, y.BuildNumberOrDefault); - } + /// + /// Gets a value indicating whether to override the build number preset by the cloud build. + /// + [JsonIgnore] + public bool EnabledOrDefault => this.Enabled ?? DefaultInstance.Enabled!.Value; - /// - public int GetHashCode(CloudBuildOptions? obj) - { - if (obj is null) - { - return 0; - } - - return (obj.SetVersionVariablesOrDefault ? 1 : 0) - + (obj.SetAllVariablesOrDefault ? 1 : 0) - + obj.BuildNumberOrDefault.GetHashCode(); - } - } + /// + /// Gets or sets when and where to include information about the git commit being built. + /// + public CloudBuildNumberCommitIdOptions? IncludeCommitId + { + get => this.includeCommitId; + set => this.SetIfNotReadOnly(ref this.includeCommitId, value); } /// - /// Override the build number preset by the cloud build with one enriched with version information. + /// Gets when and where to include information about the git commit being built. /// - public class CloudBuildNumberOptions : IEquatable - { - /// - /// The default (uninitialized) instance. - /// - internal static readonly CloudBuildNumberOptions DefaultInstance = new CloudBuildNumberOptions() - { - isFrozen = true, - enabled = false, - }; + [JsonIgnore] + public CloudBuildNumberCommitIdOptions IncludeCommitIdOrDefault => this.IncludeCommitId ?? CloudBuildNumberCommitIdOptions.DefaultInstance; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool isFrozen; + /// + /// Gets a value indicating whether this instance rejects all attempts to mutate it. + /// + [JsonIgnore] + public bool IsFrozen => this.isFrozen; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool? enabled; - private CloudBuildNumberCommitIdOptions? includeCommitId; + /// + /// Gets a value indicating whether this instance is equivalent to the default instance. + /// + internal bool IsDefault => this.Equals(DefaultInstance); - /// - /// Initializes a new instance of the class. - /// - public CloudBuildNumberOptions() + /// + /// Freezes this instance so no more changes can be made to it. + /// + public void Freeze() + { + if (!this.isFrozen) { + this.isFrozen = true; + this.IncludeCommitId?.Freeze(); } + } - /// - /// Initializes a new instance of the class. - /// - public CloudBuildNumberOptions(CloudBuildNumberOptions copyFrom) - { - this.enabled = copyFrom.enabled; - this.includeCommitId = copyFrom.includeCommitId is object ? new CloudBuildNumberCommitIdOptions(copyFrom.includeCommitId) : null; - } + /// + public override bool Equals(object? obj) => this.Equals(obj as CloudBuildNumberOptions); - /// - /// Gets or sets a value indicating whether to override the build number preset by the cloud build. - /// - public bool? Enabled - { - get => this.enabled; - set => this.SetIfNotReadOnly(ref this.enabled, value); - } + /// + public bool Equals(CloudBuildNumberOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + + /// + public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); + + /// + /// Sets the value of a field if this instance is not marked as read only. + /// + /// The type of the value stored by the field. + /// The field to change. + /// The value to set. + private void SetIfNotReadOnly(ref T field, T value) + { + Verify.Operation(!this.isFrozen, "This instance is read only."); + field = value; + } - /// - /// Gets a value indicating whether to override the build number preset by the cloud build. - /// - [JsonIgnore] - public bool EnabledOrDefault => this.Enabled ?? DefaultInstance.Enabled!.Value; + internal class EqualWithDefaultsComparer : IEqualityComparer + { + internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); - /// - /// Gets or sets when and where to include information about the git commit being built. - /// - public CloudBuildNumberCommitIdOptions? IncludeCommitId + private EqualWithDefaultsComparer() { - get => this.includeCommitId; - set => this.SetIfNotReadOnly(ref this.includeCommitId, value); } - /// - /// Gets when and where to include information about the git commit being built. - /// - [JsonIgnore] - public CloudBuildNumberCommitIdOptions IncludeCommitIdOrDefault => this.IncludeCommitId ?? CloudBuildNumberCommitIdOptions.DefaultInstance; - - /// - /// Gets a value indicating whether this instance rejects all attempts to mutate it. - /// - [JsonIgnore] - public bool IsFrozen => this.isFrozen; - - /// - /// Freezes this instance so no more changes can be made to it. - /// - public void Freeze() + /// + public bool Equals(CloudBuildNumberOptions? x, CloudBuildNumberOptions? y) { - if (!this.isFrozen) + if (ReferenceEquals(x, y)) { - this.isFrozen = true; - this.IncludeCommitId?.Freeze(); + return true; } - } - - /// - public override bool Equals(object? obj) => this.Equals(obj as CloudBuildNumberOptions); - /// - public bool Equals(CloudBuildNumberOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + if (x is null || y is null) + { + return false; + } - /// - public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - - /// - /// Gets a value indicating whether this instance is equivalent to the default instance. - /// - internal bool IsDefault => this.Equals(DefaultInstance); - - /// - /// Sets the value of a field if this instance is not marked as read only. - /// - /// The type of the value stored by the field. - /// The field to change. - /// The value to set. - private void SetIfNotReadOnly(ref T field, T value) - { - Verify.Operation(!this.isFrozen, "This instance is read only."); - field = value; + return x.EnabledOrDefault == y.EnabledOrDefault + && CloudBuildNumberCommitIdOptions.EqualWithDefaultsComparer.Singleton.Equals(x.IncludeCommitIdOrDefault, y.IncludeCommitIdOrDefault); } - internal class EqualWithDefaultsComparer : IEqualityComparer + /// + public int GetHashCode(CloudBuildNumberOptions? obj) { - internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); - - private EqualWithDefaultsComparer() { } - - /// - public bool Equals(CloudBuildNumberOptions? x, CloudBuildNumberOptions? y) + if (obj is null) { - if (ReferenceEquals(x, y)) - { - return true; - } - - if (x is null || y is null) - { - return false; - } - - return x.EnabledOrDefault == y.EnabledOrDefault - && CloudBuildNumberCommitIdOptions.EqualWithDefaultsComparer.Singleton.Equals(x.IncludeCommitIdOrDefault, y.IncludeCommitIdOrDefault); + return 0; } - /// - public int GetHashCode(CloudBuildNumberOptions? obj) - { - if (obj is null) - { - return 0; - } - - return obj.EnabledOrDefault ? 1 : 0 - + obj.IncludeCommitIdOrDefault.GetHashCode(); - } + return obj.EnabledOrDefault ? 1 : 0 + + obj.IncludeCommitIdOrDefault.GetHashCode(); } } + } + /// + /// Describes when and where to include information about the git commit being built. + /// + public class CloudBuildNumberCommitIdOptions : IEquatable + { /// - /// Describes when and where to include information about the git commit being built. + /// The default (uninitialized) instance. /// - public class CloudBuildNumberCommitIdOptions : IEquatable + internal static readonly CloudBuildNumberCommitIdOptions DefaultInstance = new CloudBuildNumberCommitIdOptions() { - /// - /// The default (uninitialized) instance. - /// - internal static readonly CloudBuildNumberCommitIdOptions DefaultInstance = new CloudBuildNumberCommitIdOptions() - { - isFrozen = true, - when = CloudBuildNumberCommitWhen.NonPublicReleaseOnly, - where = CloudBuildNumberCommitWhere.BuildMetadata, - }; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool isFrozen; + isFrozen = true, + when = CloudBuildNumberCommitWhen.NonPublicReleaseOnly, + where = CloudBuildNumberCommitWhere.BuildMetadata, + }; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private CloudBuildNumberCommitWhen? when; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private CloudBuildNumberCommitWhere? where; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool isFrozen; - /// - /// Initializes a new instance of the class. - /// - public CloudBuildNumberCommitIdOptions() - { - } + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private CloudBuildNumberCommitWhen? when; - /// - /// Initializes a new instance of the class. - /// - public CloudBuildNumberCommitIdOptions(CloudBuildNumberCommitIdOptions copyFrom) - { - this.when = copyFrom.when; - this.where = copyFrom.where; - } + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private CloudBuildNumberCommitWhere? where; - /// - /// Gets or sets the conditions when the commit ID is included in the build number. - /// - public CloudBuildNumberCommitWhen? When - { - get => this.when; - set => this.SetIfNotReadOnly(ref this.when, value); - } + /// + /// Initializes a new instance of the class. + /// + public CloudBuildNumberCommitIdOptions() + { + } - /// - /// Gets the conditions when the commit ID is included in the build number. - /// - [JsonIgnore] - public CloudBuildNumberCommitWhen WhenOrDefault => this.When ?? DefaultInstance.When!.Value; + /// + /// Initializes a new instance of the class. + /// + /// The instance to copy from. + public CloudBuildNumberCommitIdOptions(CloudBuildNumberCommitIdOptions copyFrom) + { + this.when = copyFrom.when; + this.where = copyFrom.where; + } - /// - /// Gets or sets the position to include the commit ID information. - /// - public CloudBuildNumberCommitWhere? Where - { - get => this.where; - set => this.SetIfNotReadOnly(ref this.where, value); - } + /// + /// Gets or sets the conditions when the commit ID is included in the build number. + /// + public CloudBuildNumberCommitWhen? When + { + get => this.when; + set => this.SetIfNotReadOnly(ref this.when, value); + } - /// - /// Gets the position to include the commit ID information. - /// - [JsonIgnore] - public CloudBuildNumberCommitWhere WhereOrDefault => this.Where ?? DefaultInstance.Where!.Value; + /// + /// Gets the conditions when the commit ID is included in the build number. + /// + [JsonIgnore] + public CloudBuildNumberCommitWhen WhenOrDefault => this.When ?? DefaultInstance.When!.Value; - /// - /// Gets a value indicating whether this instance rejects all attempts to mutate it. - /// - [JsonIgnore] - public bool IsFrozen => this.isFrozen; + /// + /// Gets or sets the position to include the commit ID information. + /// + public CloudBuildNumberCommitWhere? Where + { + get => this.where; + set => this.SetIfNotReadOnly(ref this.where, value); + } - /// - /// Freezes this instance so no more changes can be made to it. - /// - public void Freeze() => this.isFrozen = true; + /// + /// Gets the position to include the commit ID information. + /// + [JsonIgnore] + public CloudBuildNumberCommitWhere WhereOrDefault => this.Where ?? DefaultInstance.Where!.Value; - /// - public override bool Equals(object? obj) => this.Equals(obj as CloudBuildNumberCommitIdOptions); + /// + /// Gets a value indicating whether this instance rejects all attempts to mutate it. + /// + [JsonIgnore] + public bool IsFrozen => this.isFrozen; - /// - public bool Equals(CloudBuildNumberCommitIdOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); - /// - public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - - /// - /// Gets a value indicating whether this instance is equivalent to the default instance. - /// - internal bool IsDefault => this.Equals(DefaultInstance); - - /// - /// Sets the value of a field if this instance is not marked as read only. - /// - /// The type of the value stored by the field. - /// The field to change. - /// The value to set. - private void SetIfNotReadOnly(ref T field, T value) - { - Verify.Operation(!this.isFrozen, "This instance is read only."); - field = value; - } + /// + /// Gets a value indicating whether this instance is equivalent to the default instance. + /// + internal bool IsDefault => this.Equals(DefaultInstance); - internal class EqualWithDefaultsComparer : IEqualityComparer - { - internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); + /// + /// Freezes this instance so no more changes can be made to it. + /// + public void Freeze() => this.isFrozen = true; - private EqualWithDefaultsComparer() { } + /// + public override bool Equals(object? obj) => this.Equals(obj as CloudBuildNumberCommitIdOptions); - /// - public bool Equals(CloudBuildNumberCommitIdOptions? x, CloudBuildNumberCommitIdOptions? y) - { - if (ReferenceEquals(x, y)) - { - return true; - } - - if (x is null || y is null) - { - return false; - } - - return x.WhenOrDefault == y.WhenOrDefault - && x.WhereOrDefault == y.WhereOrDefault; - } + /// + public bool Equals(CloudBuildNumberCommitIdOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); - /// - public int GetHashCode(CloudBuildNumberCommitIdOptions? obj) - { - if (obj is null) - { - return 0; - } + /// + public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - return (int)obj.WhereOrDefault + (int)obj.WhenOrDefault * 0x10; - } - } + /// + /// Sets the value of a field if this instance is not marked as read only. + /// + /// The type of the value stored by the field. + /// The field to change. + /// The value to set. + private void SetIfNotReadOnly(ref T field, T value) + { + Verify.Operation(!this.isFrozen, "This instance is read only."); + field = value; } - private class EqualWithDefaultsComparer : IEqualityComparer + internal class EqualWithDefaultsComparer : IEqualityComparer { internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); - private EqualWithDefaultsComparer() { } + private EqualWithDefaultsComparer() + { + } /// - public bool Equals(VersionOptions? x, VersionOptions? y) + public bool Equals(CloudBuildNumberCommitIdOptions? x, CloudBuildNumberCommitIdOptions? y) { if (ReferenceEquals(x, y)) { @@ -1356,274 +1423,232 @@ public bool Equals(VersionOptions? x, VersionOptions? y) return false; } - return EqualityComparer.Default.Equals(x.Version, y.Version) - && AssemblyVersionOptions.EqualWithDefaultsComparer.Singleton.Equals(x.AssemblyVersionOrDefault, y.AssemblyVersionOrDefault) - && NuGetPackageVersionOptions.EqualWithDefaultsComparer.Singleton.Equals(x.NuGetPackageVersionOrDefault, y.NuGetPackageVersionOrDefault) - && CloudBuildOptions.EqualWithDefaultsComparer.Singleton.Equals(x.CloudBuildOrDefault, y.CloudBuildOrDefault) - && ReleaseOptions.EqualWithDefaultsComparer.Singleton.Equals(x.ReleaseOrDefault, y.ReleaseOrDefault) - && x.VersionHeightOffset == y.VersionHeightOffset; + return x.WhenOrDefault == y.WhenOrDefault + && x.WhereOrDefault == y.WhereOrDefault; } /// - public int GetHashCode(VersionOptions? obj) + public int GetHashCode(CloudBuildNumberCommitIdOptions? obj) { - return obj?.Version?.GetHashCode() ?? 0; + if (obj is null) + { + return 0; + } + + return (int)obj.WhereOrDefault + ((int)obj.WhenOrDefault * 0x10); } } + } + /// + /// Encapsulates settings for the "prepare-release" command. + /// + public class ReleaseOptions : IEquatable + { /// - /// The last component to control in a 4 integer version. + /// The default (uninitialized) instance. /// - public enum VersionPrecision + internal static readonly ReleaseOptions DefaultInstance = new ReleaseOptions() { - /// - /// The first integer is the last number set. The rest will be zeros. - /// - Major, - - /// - /// The second integer is the last number set. The rest will be zeros. - /// - Minor, - - /// - /// The third integer is the last number set. The fourth will be zero. - /// - Build, - - /// - /// All four integers will be set. - /// - Revision, - } + isFrozen = true, + branchName = "v{version}", + versionIncrement = ReleaseVersionIncrement.Minor, + firstUnstableTag = "alpha", + }; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private bool isFrozen; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string? branchName; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private ReleaseVersionIncrement? versionIncrement; + + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string? firstUnstableTag; /// - /// The conditions a commit ID is included in a cloud build number. + /// Initializes a new instance of the class. /// - public enum CloudBuildNumberCommitWhen + public ReleaseOptions() { - /// - /// Always include the commit information in the cloud Build Number. - /// - Always, - - /// - /// Only include the commit information when building a non-PublicRelease. - /// - NonPublicReleaseOnly, - - /// - /// Never include the commit information. - /// - Never, } /// - /// The position a commit ID can appear in a cloud build number. + /// Initializes a new instance of the class. /// - public enum CloudBuildNumberCommitWhere + /// The existing instance to copy from. + public ReleaseOptions(ReleaseOptions copyFrom) { - /// - /// The commit ID appears in build metadata (e.g. +ga1b2c3). - /// - BuildMetadata, - - /// - /// The commit ID appears as the 4th integer in the version (e.g. 1.2.3.23523). - /// - FourthVersionComponent, + this.branchName = copyFrom.branchName; + this.versionIncrement = copyFrom.versionIncrement; + this.firstUnstableTag = copyFrom.firstUnstableTag; } /// - /// Encapsulates settings for the "prepare-release" command + /// Gets or sets the branch name template for release branches. /// - public class ReleaseOptions : IEquatable + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? BranchName { - /// - /// The default (uninitialized) instance. - /// - internal static readonly ReleaseOptions DefaultInstance = new ReleaseOptions() - { - isFrozen = true, - branchName = "v{version}", - versionIncrement = ReleaseVersionIncrement.Minor, - firstUnstableTag = "alpha" - }; - - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private bool isFrozen; + get => this.branchName; + set => this.SetIfNotReadOnly(ref this.branchName, value); + } - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string? branchName; + /// + /// Gets the set branch name template for release branches. + /// + [JsonIgnore] + public string BranchNameOrDefault => this.BranchName ?? DefaultInstance.BranchName!; - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private ReleaseVersionIncrement? versionIncrement; + /// + /// Gets or sets the setting specifying how to increment the version when creating a release. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public ReleaseVersionIncrement? VersionIncrement + { + get => this.versionIncrement; + set => this.SetIfNotReadOnly(ref this.versionIncrement, value); + } - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string? firstUnstableTag; + /// + /// Gets the setting specifying how to increment the version when creating a release. + /// + [JsonIgnore] + public ReleaseVersionIncrement VersionIncrementOrDefault => this.VersionIncrement ?? DefaultInstance.VersionIncrement!.Value; - /// - /// Initializes a new instance of the class - /// - public ReleaseOptions() - { - } + /// + /// Gets or sets the first/default prerelease tag for new versions. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? FirstUnstableTag + { + get => this.firstUnstableTag; + set => this.SetIfNotReadOnly(ref this.firstUnstableTag, value); + } - /// - /// Initializes a new instance of the class - /// - public ReleaseOptions(ReleaseOptions copyFrom) - { - this.branchName = copyFrom.branchName; - this.versionIncrement = copyFrom.versionIncrement; - this.firstUnstableTag = copyFrom.firstUnstableTag; - } + /// + /// Gets the first/default prerelease tag for new versions. + /// + [JsonIgnore] + public string FirstUnstableTagOrDefault => this.FirstUnstableTag ?? DefaultInstance.FirstUnstableTag!; - /// - /// Gets or sets the branch name template for release branches - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? BranchName - { - get => this.branchName; - set => this.SetIfNotReadOnly(ref this.branchName, value); - } + /// + /// Gets a value indicating whether this instance rejects all attempts to mutate it. + /// + [JsonIgnore] + public bool IsFrozen => this.isFrozen; - /// - /// Gets the set branch name template for release branches - /// - [JsonIgnore] - public string BranchNameOrDefault => this.BranchName ?? DefaultInstance.BranchName!; - - /// - /// Gets or sets the setting specifying how to increment the version when creating a release - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public ReleaseVersionIncrement? VersionIncrement - { - get => this.versionIncrement; - set => this.SetIfNotReadOnly(ref this.versionIncrement, value); - } + /// + /// Gets a value indicating whether this instance is equivalent to the default instance. + /// + internal bool IsDefault => this.Equals(DefaultInstance); - /// - /// Gets or sets the setting specifying how to increment the version when creating a release. - /// - [JsonIgnore] - public ReleaseVersionIncrement VersionIncrementOrDefault => this.VersionIncrement ?? DefaultInstance.VersionIncrement!.Value; - - /// - /// Gets or sets the first/default prerelease tag for new versions. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? FirstUnstableTag - { - get => this.firstUnstableTag; - set => this.SetIfNotReadOnly(ref this.firstUnstableTag, value); - } + /// + /// Freezes this instance so no more changes can be made to it. + /// + public void Freeze() => this.isFrozen = true; - /// - /// Gets or sets the first/default prerelease tag for new versions. - /// - [JsonIgnore] - public string FirstUnstableTagOrDefault => this.FirstUnstableTag ?? DefaultInstance.FirstUnstableTag!; + /// + public override bool Equals(object? obj) => this.Equals(obj as ReleaseOptions); - /// - /// Gets a value indicating whether this instance rejects all attempts to mutate it. - /// - [JsonIgnore] - public bool IsFrozen => this.isFrozen; + /// + public bool Equals(ReleaseOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); - /// - /// Freezes this instance so no more changes can be made to it. - /// - public void Freeze() => this.isFrozen = true; + /// + public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - /// - public override bool Equals(object? obj) => this.Equals(obj as ReleaseOptions); + /// + /// Sets the value of a field if this instance is not marked as read only. + /// + /// The type of the value stored by the field. + /// The field to change. + /// The value to set. + private void SetIfNotReadOnly(ref T field, T value) + { + Verify.Operation(!this.isFrozen, "This instance is read only."); + field = value; + } - /// - public bool Equals(ReleaseOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); + internal class EqualWithDefaultsComparer : IEqualityComparer + { + internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); - /// - public override int GetHashCode() => EqualWithDefaultsComparer.Singleton.GetHashCode(this); - - /// - /// Gets a value indicating whether this instance is equivalent to the default instance. - /// - internal bool IsDefault => this.Equals(DefaultInstance); - - /// - /// Sets the value of a field if this instance is not marked as read only. - /// - /// The type of the value stored by the field. - /// The field to change. - /// The value to set. - private void SetIfNotReadOnly(ref T field, T value) + private EqualWithDefaultsComparer() { - Verify.Operation(!this.isFrozen, "This instance is read only."); - field = value; } - internal class EqualWithDefaultsComparer : IEqualityComparer + /// + public bool Equals(ReleaseOptions? x, ReleaseOptions? y) { - internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); + if (ReferenceEquals(x, y)) + { + return true; + } + + if (x is null || y is null) + { + return false; + } - private EqualWithDefaultsComparer() { } + return StringComparer.Ordinal.Equals(x.BranchNameOrDefault, y.BranchNameOrDefault) && + x.VersionIncrementOrDefault == y.VersionIncrementOrDefault && + StringComparer.Ordinal.Equals(x.FirstUnstableTagOrDefault, y.FirstUnstableTagOrDefault); + } - /// - public bool Equals(ReleaseOptions? x, ReleaseOptions? y) + /// + public int GetHashCode(ReleaseOptions? obj) + { + if (obj is null) { - if (ReferenceEquals(x, y)) - { - return true; - } - - if (x is null || y is null) - { - return false; - } - - return StringComparer.Ordinal.Equals(x.BranchNameOrDefault, y.BranchNameOrDefault) && - x.VersionIncrementOrDefault == y.VersionIncrementOrDefault && - StringComparer.Ordinal.Equals(x.FirstUnstableTagOrDefault, y.FirstUnstableTagOrDefault); + return 0; } - /// - public int GetHashCode(ReleaseOptions? obj) + unchecked { - if (obj is null) - return 0; - - unchecked - { - var hash = StringComparer.Ordinal.GetHashCode(obj.BranchNameOrDefault) * 397; - hash ^= (int)obj.VersionIncrementOrDefault; - hash ^= StringComparer.Ordinal.GetHashCode(obj.FirstUnstableTagOrDefault); - return hash; - } + int hash = StringComparer.Ordinal.GetHashCode(obj.BranchNameOrDefault) * 397; + hash ^= (int)obj.VersionIncrementOrDefault; + hash ^= StringComparer.Ordinal.GetHashCode(obj.FirstUnstableTagOrDefault); + return hash; } } } + } + + private class EqualWithDefaultsComparer : IEqualityComparer + { + internal static readonly EqualWithDefaultsComparer Singleton = new EqualWithDefaultsComparer(); + + private EqualWithDefaultsComparer() + { + } + + /// + public bool Equals(VersionOptions? x, VersionOptions? y) + { + if (ReferenceEquals(x, y)) + { + return true; + } + + if (x is null || y is null) + { + return false; + } + + return EqualityComparer.Default.Equals(x.Version, y.Version) + && AssemblyVersionOptions.EqualWithDefaultsComparer.Singleton.Equals(x.AssemblyVersionOrDefault, y.AssemblyVersionOrDefault) + && NuGetPackageVersionOptions.EqualWithDefaultsComparer.Singleton.Equals(x.NuGetPackageVersionOrDefault, y.NuGetPackageVersionOrDefault) + && CloudBuildOptions.EqualWithDefaultsComparer.Singleton.Equals(x.CloudBuildOrDefault, y.CloudBuildOrDefault) + && ReleaseOptions.EqualWithDefaultsComparer.Singleton.Equals(x.ReleaseOrDefault, y.ReleaseOrDefault) + && x.VersionHeightOffset == y.VersionHeightOffset; + } - /// - /// Possible increments of the version after creating release branches - /// - public enum ReleaseVersionIncrement + /// + public int GetHashCode(VersionOptions? obj) { - /// - /// Increment the major version after creating a release branch - /// - Major, - - /// - /// Increment the minor version after creating a release branch - /// - Minor, - - /// - /// Increment the build number (the third number in a version) after creating a release branch. - /// - Build, + return obj?.Version?.GetHashCode() ?? 0; } } } diff --git a/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs b/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs index 00944f67..4975daa3 100644 --- a/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs +++ b/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs @@ -1,146 +1,147 @@ -namespace Nerdbank.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using Newtonsoft.Json; +using Newtonsoft.Json.Serialization; + +namespace Nerdbank.GitVersioning; + +internal class VersionOptionsContractResolver : CamelCasePropertyNamesContractResolver { - using System; - using System.Collections.Generic; - using System.Reflection; - using Newtonsoft.Json; - using Newtonsoft.Json.Serialization; + private static readonly object TypeContractCacheLock = new object(); + + private static readonly Dictionary, JsonContract> ContractCache = new Dictionary, JsonContract>(); - internal class VersionOptionsContractResolver : CamelCasePropertyNamesContractResolver + public VersionOptionsContractResolver() { - private static readonly object TypeContractCacheLock = new object(); + } - private static readonly Dictionary, JsonContract> contractCache = new Dictionary, JsonContract>(); + internal bool IncludeSchemaProperty { get; set; } + + internal bool IncludeDefaults { get; set; } = true; + + /// + /// Obtains a contract for a given type. + /// + /// The type to obtain a contract for. + /// The contract. + /// + /// This override changes the caching policy from the base class, which caches based on this.GetType(). + /// The inherited policy is problematic because we have instance properties that change the contract. + /// So instead, we cache with a complex key to capture the settings as well. + /// + public override JsonContract ResolveContract(Type type) + { + var contractKey = Tuple.Create(this.IncludeSchemaProperty, this.IncludeDefaults, type); - public VersionOptionsContractResolver() + JsonContract contract; + lock (TypeContractCacheLock) { + if (ContractCache.TryGetValue(contractKey, out contract)) + { + return contract; + } } - internal bool IncludeSchemaProperty { get; set; } - - internal bool IncludeDefaults { get; set; } = true; - - /// - /// Obtains a contract for a given type. - /// - /// The type to obtain a contract for. - /// The contract. - /// - /// This override changes the caching policy from the base class, which caches based on this.GetType(). - /// The inherited policy is problematic because we have instance properties that change the contract. - /// So instead, we cache with a complex key to capture the settings as well. - /// - public override JsonContract ResolveContract(Type type) + contract = this.CreateContract(type); + + lock (TypeContractCacheLock) { - var contractKey = Tuple.Create(this.IncludeSchemaProperty, this.IncludeDefaults, type); + if (!ContractCache.ContainsKey(contractKey)) + { + ContractCache.Add(contractKey, contract); + } + } + + return contract; + } - JsonContract contract; - lock (TypeContractCacheLock) + /// + protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) + { + JsonProperty property = base.CreateProperty(member, memberSerialization); + + if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.Schema)) + { + property.ShouldSerialize = instance => this.IncludeSchemaProperty; + } + + if (!this.IncludeDefaults) + { + if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.AssemblyVersion)) { - if (contractCache.TryGetValue(contractKey, out contract)) - { - return contract; - } + property.ShouldSerialize = instance => !((VersionOptions)instance).AssemblyVersionOrDefault.IsDefault; } - contract = base.CreateContract(type); +#pragma warning disable CS0618 // Type or member is obsolete + if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.BuildNumberOffset)) +#pragma warning restore CS0618 // Type or member is obsolete + { + property.ShouldSerialize = instance => false; // always serialized by its new name + } - lock (TypeContractCacheLock) + if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.VersionHeightOffset)) { - if (!contractCache.ContainsKey(contractKey)) - { - contractCache.Add(contractKey, contract); - } + property.ShouldSerialize = instance => ((VersionOptions)instance).VersionHeightOffsetOrDefault != 0; } - return contract; - } + if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.NuGetPackageVersion)) + { + property.ShouldSerialize = instance => !((VersionOptions)instance).NuGetPackageVersionOrDefault.IsDefault; + } - protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization) - { - var property = base.CreateProperty(member, memberSerialization); + if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.CloudBuild)) + { + property.ShouldSerialize = instance => !((VersionOptions)instance).CloudBuildOrDefault.IsDefault; + } - if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.Schema)) + if (property.DeclaringType == typeof(VersionOptions.CloudBuildOptions) && member.Name == nameof(VersionOptions.CloudBuildOptions.SetAllVariables)) { - property.ShouldSerialize = instance => this.IncludeSchemaProperty; + property.ShouldSerialize = instance => ((VersionOptions.CloudBuildOptions)instance).SetAllVariablesOrDefault != VersionOptions.CloudBuildOptions.DefaultInstance.SetAllVariables.Value; } - if (!this.IncludeDefaults) + if (property.DeclaringType == typeof(VersionOptions.CloudBuildOptions) && member.Name == nameof(VersionOptions.CloudBuildOptions.SetVersionVariables)) { - if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.AssemblyVersion)) - { - property.ShouldSerialize = instance => !((VersionOptions)instance).AssemblyVersionOrDefault.IsDefault; - } + property.ShouldSerialize = instance => ((VersionOptions.CloudBuildOptions)instance).SetVersionVariablesOrDefault != VersionOptions.CloudBuildOptions.DefaultInstance.SetVersionVariables.Value; + } -#pragma warning disable CS0618 // Type or member is obsolete - if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.BuildNumberOffset)) -#pragma warning restore CS0618 // Type or member is obsolete - { - property.ShouldSerialize = instance => false; // always serialized by its new name - } - - if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.VersionHeightOffset)) - { - property.ShouldSerialize = instance => ((VersionOptions)instance).VersionHeightOffsetOrDefault != 0; - } - - if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.NuGetPackageVersion)) - { - property.ShouldSerialize = instance => !((VersionOptions)instance).NuGetPackageVersionOrDefault.IsDefault; - } - - if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.CloudBuild)) - { - property.ShouldSerialize = instance => !((VersionOptions)instance).CloudBuildOrDefault.IsDefault; - } - - if (property.DeclaringType == typeof(VersionOptions.CloudBuildOptions) && member.Name == nameof(VersionOptions.CloudBuildOptions.SetAllVariables)) - { - property.ShouldSerialize = instance => ((VersionOptions.CloudBuildOptions)instance).SetAllVariablesOrDefault != VersionOptions.CloudBuildOptions.DefaultInstance.SetAllVariables.Value; - } - - if (property.DeclaringType == typeof(VersionOptions.CloudBuildOptions) && member.Name == nameof(VersionOptions.CloudBuildOptions.SetVersionVariables)) - { - property.ShouldSerialize = instance => ((VersionOptions.CloudBuildOptions)instance).SetVersionVariablesOrDefault != VersionOptions.CloudBuildOptions.DefaultInstance.SetVersionVariables.Value; - } - - if (property.DeclaringType == typeof(VersionOptions.CloudBuildNumberOptions) && member.Name == nameof(VersionOptions.CloudBuildNumberOptions.IncludeCommitId)) - { - property.ShouldSerialize = instance => !((VersionOptions.CloudBuildNumberOptions)instance).IncludeCommitIdOrDefault.IsDefault; - } - - if (property.DeclaringType == typeof(VersionOptions.CloudBuildNumberCommitIdOptions) && member.Name == nameof(VersionOptions.CloudBuildNumberCommitIdOptions.When)) - { - property.ShouldSerialize = instance => ((VersionOptions.CloudBuildNumberCommitIdOptions)instance).WhenOrDefault != VersionOptions.CloudBuildNumberCommitIdOptions.DefaultInstance.When.Value; - } - - if (property.DeclaringType == typeof(VersionOptions.CloudBuildNumberCommitIdOptions) && member.Name == nameof(VersionOptions.CloudBuildNumberCommitIdOptions.Where)) - { - property.ShouldSerialize = instance => ((VersionOptions.CloudBuildNumberCommitIdOptions)instance).WhereOrDefault != VersionOptions.CloudBuildNumberCommitIdOptions.DefaultInstance.Where.Value; - } - - if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.Release)) - { - property.ShouldSerialize = instance => !((VersionOptions)instance).ReleaseOrDefault.IsDefault; - } - - if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.BranchName)) - { - property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).BranchNameOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.BranchName; - } - - if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.VersionIncrement)) - { - property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).VersionIncrementOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.VersionIncrement.Value; - } - - if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.FirstUnstableTag)) - { - property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).FirstUnstableTagOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.FirstUnstableTag; - } - } - - return property; + if (property.DeclaringType == typeof(VersionOptions.CloudBuildNumberOptions) && member.Name == nameof(VersionOptions.CloudBuildNumberOptions.IncludeCommitId)) + { + property.ShouldSerialize = instance => !((VersionOptions.CloudBuildNumberOptions)instance).IncludeCommitIdOrDefault.IsDefault; + } + + if (property.DeclaringType == typeof(VersionOptions.CloudBuildNumberCommitIdOptions) && member.Name == nameof(VersionOptions.CloudBuildNumberCommitIdOptions.When)) + { + property.ShouldSerialize = instance => ((VersionOptions.CloudBuildNumberCommitIdOptions)instance).WhenOrDefault != VersionOptions.CloudBuildNumberCommitIdOptions.DefaultInstance.When.Value; + } + + if (property.DeclaringType == typeof(VersionOptions.CloudBuildNumberCommitIdOptions) && member.Name == nameof(VersionOptions.CloudBuildNumberCommitIdOptions.Where)) + { + property.ShouldSerialize = instance => ((VersionOptions.CloudBuildNumberCommitIdOptions)instance).WhereOrDefault != VersionOptions.CloudBuildNumberCommitIdOptions.DefaultInstance.Where.Value; + } + + if (property.DeclaringType == typeof(VersionOptions) && member.Name == nameof(VersionOptions.Release)) + { + property.ShouldSerialize = instance => !((VersionOptions)instance).ReleaseOrDefault.IsDefault; + } + + if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.BranchName)) + { + property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).BranchNameOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.BranchName; + } + + if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.VersionIncrement)) + { + property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).VersionIncrementOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.VersionIncrement.Value; + } + + if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.FirstUnstableTag)) + { + property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).FirstUnstableTagOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.FirstUnstableTag; + } } + + return property; } } diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index a416e79e..23927c71 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -1,531 +1,530 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. -namespace Nerdbank.GitVersioning -{ - using System; - using System.Collections.Generic; - using System.Globalization; - using System.Linq; - using System.Reflection; - using System.Text.RegularExpressions; +using System.Globalization; +using System.Reflection; +using System.Text.RegularExpressions; + +#nullable enable +namespace Nerdbank.GitVersioning; + +/// +/// Assembles version information in a variety of formats. +/// +public class VersionOracle +{ /// - /// Assembles version information in a variety of formats. + /// The 0.0 version. /// - public class VersionOracle - { - private const bool UseLibGit2 = false; + private protected static readonly Version Version0 = new Version(0, 0); - /// - /// The 0.0 version. - /// - private protected static readonly Version Version0 = new Version(0, 0); + private const bool UseLibGit2 = false; - private readonly GitContext context; + private readonly GitContext context; - private readonly ICloudBuild? cloudBuild; + private readonly ICloudBuild? cloudBuild; - /// - /// The number of version components (up to the 4 integers) to include in . - /// - private readonly int assemblyInformationalVersionComponentCount; + /// + /// The number of version components (up to the 4 integers) to include in . + /// + private readonly int assemblyInformationalVersionComponentCount; - /// - /// Initializes a new instance of the class. - /// - /// The git context from which to calculate version data. - /// An optional cloud build provider that may offer additional context. Typically set to . - /// An optional value to override the version height offset. - public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? overrideVersionHeightOffset = null) - { - this.context = context; - this.cloudBuild = cloudBuild; + /// + /// Initializes a new instance of the class. + /// + /// The git context from which to calculate version data. + /// An optional cloud build provider that may offer additional context. Typically set to . + /// An optional value to override the version height offset. + public VersionOracle(GitContext context, ICloudBuild? cloudBuild = null, int? overrideVersionHeightOffset = null) + { + this.context = context; + this.cloudBuild = cloudBuild; - this.CommittedVersion = context.VersionFile.GetVersion(); + this.CommittedVersion = context.VersionFile.GetVersion(); - // Consider the working version only if the commit being inspected is HEAD. - // Otherwise we're looking at historical data and should not consider the state of the working tree at all. - this.WorkingVersion = context.IsHead ? context.VersionFile.GetWorkingCopyVersion() : this.CommittedVersion; + // Consider the working version only if the commit being inspected is HEAD. + // Otherwise we're looking at historical data and should not consider the state of the working tree at all. + this.WorkingVersion = context.IsHead ? context.VersionFile.GetWorkingCopyVersion() : this.CommittedVersion; - if (overrideVersionHeightOffset.HasValue) + if (overrideVersionHeightOffset.HasValue) + { + if (this.CommittedVersion is object) { - if (this.CommittedVersion is object) - { - this.CommittedVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; - } - - if (this.WorkingVersion is object) - { - this.WorkingVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; - } + this.CommittedVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } - this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? context.HeadCanonicalName; - try - { - this.VersionHeight = context.CalculateVersionHeight(this.CommittedVersion, this.WorkingVersion); - } - catch (GitException ex) when (context.IsShallow && ex.ErrorCode == GitException.ErrorCodes.ObjectNotFound) - { - // Our managed git implementation throws this on shallow clones. - throw ThrowShallowClone(ex); - } - catch (InvalidOperationException ex) when (context.IsShallow && (ex.InnerException is NullReferenceException || ex.InnerException is LibGit2Sharp.NotFoundException)) + if (this.WorkingVersion is object) { - // Libgit2 throws this on shallow clones. - throw ThrowShallowClone(ex); + this.WorkingVersion.VersionHeightOffset = overrideVersionHeightOffset.Value; } + } - static Exception ThrowShallowClone(Exception inner) => throw new GitException("Shallow clone lacks the objects required to calculate version height. Use full clones or clones with a history at least as deep as the last version height resetting change.", inner) { iSShallowClone = true, ErrorCode = GitException.ErrorCodes.ObjectNotFound }; + this.BuildingRef = cloudBuild?.BuildingTag ?? cloudBuild?.BuildingBranch ?? context.HeadCanonicalName; + try + { + this.VersionHeight = context.CalculateVersionHeight(this.CommittedVersion, this.WorkingVersion); + } + catch (GitException ex) when (context.IsShallow && ex.ErrorCode == GitException.ErrorCodes.ObjectNotFound) + { + // Our managed git implementation throws this on shallow clones. + throw ThrowShallowClone(ex); + } + catch (InvalidOperationException ex) when (context.IsShallow && (ex.InnerException is NullReferenceException || ex.InnerException is LibGit2Sharp.NotFoundException)) + { + // Libgit2 throws this on shallow clones. + throw ThrowShallowClone(ex); + } - this.VersionOptions = this.CommittedVersion ?? this.WorkingVersion; - this.Version = this.VersionOptions?.Version?.Version ?? Version0; - this.assemblyInformationalVersionComponentCount = this.VersionOptions?.VersionHeightPosition == SemanticVersion.Position.Revision ? 4 : 3; + static Exception ThrowShallowClone(Exception inner) => throw new GitException("Shallow clone lacks the objects required to calculate version height. Use full clones or clones with a history at least as deep as the last version height resetting change.", inner) { IsShallowClone = true, ErrorCode = GitException.ErrorCodes.ObjectNotFound }; - // Override the typedVersion with the special build number and revision components, when available. - if (context.IsRepository) - { - this.Version = context.GetIdAsVersion(this.CommittedVersion, this.WorkingVersion, this.VersionHeight); - } + this.VersionOptions = this.CommittedVersion ?? this.WorkingVersion; + this.Version = this.VersionOptions?.Version?.Version ?? Version0; + this.assemblyInformationalVersionComponentCount = this.VersionOptions?.VersionHeightPosition == SemanticVersion.Position.Revision ? 4 : 3; - this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance; + // Override the typedVersion with the special build number and revision components, when available. + if (context.IsRepository) + { + this.Version = context.GetIdAsVersion(this.CommittedVersion, this.WorkingVersion, this.VersionHeight); + } - // get the commit id abbreviation only if the commit id is set - if (!string.IsNullOrEmpty(this.GitCommitId)) - { - var gitCommitIdShortFixedLength = this.VersionOptions?.GitCommitIdShortFixedLength ?? VersionOptions.DefaultGitCommitIdShortFixedLength; - var gitCommitIdShortAutoMinimum = this.VersionOptions?.GitCommitIdShortAutoMinimum ?? 0; + this.CloudBuildNumberOptions = this.VersionOptions?.CloudBuild?.BuildNumberOrDefault ?? VersionOptions.CloudBuildNumberOptions.DefaultInstance; - // Get it from the git repository if there is a repository present and it is enabled. - this.GitCommitIdShort = this.GitCommitId is object && gitCommitIdShortAutoMinimum > 0 - ? this.context.GetShortUniqueCommitId(gitCommitIdShortAutoMinimum) - : this.GitCommitId!.Substring(0, gitCommitIdShortFixedLength); - } + // get the commit id abbreviation only if the commit id is set + if (!string.IsNullOrEmpty(this.GitCommitId)) + { + int gitCommitIdShortFixedLength = this.VersionOptions?.GitCommitIdShortFixedLength ?? VersionOptions.DefaultGitCommitIdShortFixedLength; + int gitCommitIdShortAutoMinimum = this.VersionOptions?.GitCommitIdShortAutoMinimum ?? 0; - if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Count > 0) - { - this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any( - expr => Regex.IsMatch(this.BuildingRef, expr)); - } + // Get it from the git repository if there is a repository present and it is enabled. + this.GitCommitIdShort = this.GitCommitId is object && gitCommitIdShortAutoMinimum > 0 + ? this.context.GetShortUniqueCommitId(gitCommitIdShortAutoMinimum) + : this.GitCommitId!.Substring(0, gitCommitIdShortFixedLength); } - /// - /// Gets the that were deserialized from the contextual commit, if any. - /// - protected VersionOptions? CommittedVersion { get; } - - /// - /// Gets the that were deserialized from the working tree, if any. - /// - protected VersionOptions? WorkingVersion { get; } + if (!string.IsNullOrEmpty(this.BuildingRef) && this.VersionOptions?.PublicReleaseRefSpec?.Count > 0) + { + this.PublicRelease = this.VersionOptions.PublicReleaseRefSpec.Any( + expr => Regex.IsMatch(this.BuildingRef, expr)); + } + } - /// - /// Gets the BuildNumber to set the cloud build to (if applicable). - /// - public string CloudBuildNumber + /// + /// Gets the BuildNumber to set the cloud build to (if applicable). + /// + public string CloudBuildNumber + { + get { - get - { - var commitIdOptions = this.CloudBuildNumberOptions.IncludeCommitIdOrDefault; - bool includeCommitInfo = commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.Always || - (commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.NonPublicReleaseOnly && !this.PublicRelease); - bool commitIdInBuildMetadata = includeCommitInfo && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata; - - // Include the revision in the build number if, either - // - The commit id is configured to be included as a revision or - // - 3 version fields are configured in version.json (and thus the version height is encoded as revision) or - // - 4 version fields are configured in version.json. - bool includeRevision = includeCommitInfo && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent || - this.VersionOptions?.Version?.VersionHeightPosition == SemanticVersion.Position.Revision || - this.VersionOptions?.Version?.Version.Revision != -1; - - string buildNumberMetadata = FormatBuildMetadata(commitIdInBuildMetadata ? this.BuildMetadataWithCommitId : this.BuildMetadata); - - Version buildNumberVersion = includeRevision ? this.Version : this.SimpleVersion; - return $"{buildNumberVersion}{this.PrereleaseVersion}{buildNumberMetadata}"; - } + VersionOptions.CloudBuildNumberCommitIdOptions? commitIdOptions = this.CloudBuildNumberOptions.IncludeCommitIdOrDefault; + bool includeCommitInfo = commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.Always || + (commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.NonPublicReleaseOnly && !this.PublicRelease); + bool commitIdInBuildMetadata = includeCommitInfo && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata; + + // Include the revision in the build number if, either + // - The commit id is configured to be included as a revision or + // - 3 version fields are configured in version.json (and thus the version height is encoded as revision) or + // - 4 version fields are configured in version.json. + bool includeRevision = (includeCommitInfo && commitIdOptions.WhereOrDefault == VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent) || + this.VersionOptions?.Version?.VersionHeightPosition == SemanticVersion.Position.Revision || + this.VersionOptions?.Version?.Version.Revision != -1; + + string buildNumberMetadata = FormatBuildMetadata(commitIdInBuildMetadata ? this.BuildMetadataWithCommitId : this.BuildMetadata); + + Version buildNumberVersion = includeRevision ? this.Version : this.SimpleVersion; + return $"{buildNumberVersion}{this.PrereleaseVersion}{buildNumberMetadata}"; } + } - /// - /// Gets a value indicating whether the cloud build number should be set. - /// - [Ignore] - public bool CloudBuildNumberEnabled => this.CloudBuildNumberOptions.EnabledOrDefault; - - /// - /// Gets the build metadata identifiers, including the git commit ID as the first identifier if appropriate. - /// - [Ignore] - public IEnumerable BuildMetadataWithCommitId + /// + /// Gets a value indicating whether the cloud build number should be set. + /// + [Ignore] + public bool CloudBuildNumberEnabled => this.CloudBuildNumberOptions.EnabledOrDefault; + + /// + /// Gets the build metadata identifiers, including the git commit ID as the first identifier if appropriate. + /// + [Ignore] + public IEnumerable BuildMetadataWithCommitId + { + get { - get + if (!string.IsNullOrEmpty(this.GitCommitIdShort)) { - if (!string.IsNullOrEmpty(this.GitCommitIdShort)) - { - yield return this.GitCommitIdShort!; - } + yield return this.GitCommitIdShort!; + } - foreach (string identifier in this.BuildMetadata) - { - yield return identifier; - } + foreach (string identifier in this.BuildMetadata) + { + yield return identifier; } } + } + + /// + /// Gets a value indicating whether a version.json or version.txt file was found. + /// + public bool VersionFileFound => this.VersionOptions is object; + + /// + /// Gets the version options used to initialize this instance. + /// + public VersionOptions? VersionOptions { get; } + + /// + /// Gets the version string to use for the . + /// + public Version AssemblyVersion => GetAssemblyVersion(this.Version, this.VersionOptions).EnsureNonNegativeComponents(); + + /// + /// Gets the version string to use for the . + /// + public Version AssemblyFileVersion => this.Version; + + /// + /// Gets the version string to use for the . + /// + public string AssemblyInformationalVersion => + $"{this.Version.ToStringSafe(this.assemblyInformationalVersionComponentCount)}{this.PrereleaseVersion}{FormatBuildMetadata(this.BuildMetadataWithCommitId)}"; + + /// + /// Gets or sets a value indicating whether the project is building + /// in PublicRelease mode. + /// + public bool PublicRelease { get; set; } + + /// + /// Gets the prerelease version information, including a leading hyphen. + /// + public string PrereleaseVersion => this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty); + + /// + /// Gets the prerelease version information, omitting the leading hyphen, if any. + /// + public string? PrereleaseVersionNoLeadingHyphen => this.PrereleaseVersion?.TrimStart('-'); + + /// + /// Gets the version information without a Revision component. + /// + public Version SimpleVersion => this.Version.Build >= 0 + ? new Version(this.Version.Major, this.Version.Minor, this.Version.Build) + : new Version(this.Version.Major, this.Version.Minor); + + /// + /// Gets the build number (i.e. third integer, or PATCH) for this version. + /// + public int BuildNumber => Math.Max(0, this.Version.Build); + + /// + /// Gets the component of the . + /// + public int VersionRevision => this.Version.Revision; + + /// + /// Gets the major.minor version string. + /// + /// + /// The x.y string (no build number or revision number). + /// + public Version MajorMinorVersion => new Version(this.Version.Major, this.Version.Minor); + + /// + /// Gets the component of the . + /// + public int VersionMajor => this.Version.Major; + + /// + /// Gets the component of the . + /// + public int VersionMinor => this.Version.Minor; + + /// + /// Gets the Git revision control commit id for HEAD (the current source code version). + /// + public string? GitCommitId => this.context.GitCommitId ?? this.cloudBuild?.GitCommitId; + + /// + /// Gets the first several characters of the Git revision control commit id for HEAD (the current source code version). + /// + public string? GitCommitIdShort { get; } + + /// + /// Gets the Git revision control commit date for HEAD (the current source code version). + /// + public DateTimeOffset? GitCommitDate => this.context.GitCommitDate; + + /// + /// Gets or sets the number of commits in the longest single path between + /// the specified commit and the most distant ancestor (inclusive) + /// that set the version to the value at HEAD. + /// + public int VersionHeight { get; protected set; } + + /// + /// Gets the offset to add to the + /// when calculating the integer to use as the + /// or elsewhere that the {height} macro is used. + /// + public int VersionHeightOffset => this.VersionOptions?.VersionHeightOffsetOrDefault ?? 0; + + /// + /// Gets or sets the ref (branch or tag) being built. + /// + public string? BuildingRef { get; protected set; } + + /// + /// Gets or sets the version for this project, with up to 4 components. + /// + public Version Version { get; protected set; } + + /// + /// Gets a value indicating whether to set all cloud build variables prefaced with "NBGV_". + /// + [Ignore] + public bool CloudBuildAllVarsEnabled => this.VersionOptions?.CloudBuildOrDefault.SetAllVariablesOrDefault + ?? VersionOptions.CloudBuildOptions.DefaultInstance.SetAllVariablesOrDefault; - /// - /// Gets a value indicating whether a version.json or version.txt file was found. - /// - public bool VersionFileFound => this.VersionOptions is object; - - /// - /// Gets the version options used to initialize this instance. - /// - public VersionOptions? VersionOptions { get; } - - /// - /// Gets the version string to use for the . - /// - public Version AssemblyVersion => GetAssemblyVersion(this.Version, this.VersionOptions).EnsureNonNegativeComponents(); - - /// - /// Gets the version string to use for the . - /// - public Version AssemblyFileVersion => this.Version; - - /// - /// Gets the version string to use for the . - /// - public string AssemblyInformationalVersion => - $"{this.Version.ToStringSafe(this.assemblyInformationalVersionComponentCount)}{this.PrereleaseVersion}{FormatBuildMetadata(this.BuildMetadataWithCommitId)}"; - - /// - /// Gets or sets a value indicating whether the project is building - /// in PublicRelease mode. - /// - public bool PublicRelease { get; set; } - - /// - /// Gets the prerelease version information, including a leading hyphen. - /// - public string PrereleaseVersion => this.ReplaceMacros(this.VersionOptions?.Version?.Prerelease ?? string.Empty); - - /// - /// Gets the prerelease version information, omitting the leading hyphen, if any. - /// - public string? PrereleaseVersionNoLeadingHyphen => this.PrereleaseVersion?.TrimStart('-'); - - /// - /// Gets the version information without a Revision component. - /// - public Version SimpleVersion => this.Version.Build >= 0 - ? new Version(this.Version.Major, this.Version.Minor, this.Version.Build) - : new Version(this.Version.Major, this.Version.Minor); - - /// - /// Gets the build number (i.e. third integer, or PATCH) for this version. - /// - public int BuildNumber => Math.Max(0, this.Version.Build); - - /// - /// Gets the component of the . - /// - public int VersionRevision => this.Version.Revision; - - /// - /// Gets the major.minor version string. - /// - /// - /// The x.y string (no build number or revision number). - /// - public Version MajorMinorVersion => new Version(this.Version.Major, this.Version.Minor); - - /// - /// Gets the component of the . - /// - public int VersionMajor => this.Version.Major; - - /// - /// Gets the component of the . - /// - public int VersionMinor => this.Version.Minor; - - /// - /// Gets the Git revision control commit id for HEAD (the current source code version). - /// - public string? GitCommitId => this.context.GitCommitId ?? this.cloudBuild?.GitCommitId; - - /// - /// Gets the first several characters of the Git revision control commit id for HEAD (the current source code version). - /// - public string? GitCommitIdShort { get; } - - /// - /// Gets the Git revision control commit date for HEAD (the current source code version). - /// - public DateTimeOffset? GitCommitDate => this.context.GitCommitDate; - - /// - /// Gets the number of commits in the longest single path between - /// the specified commit and the most distant ancestor (inclusive) - /// that set the version to the value at HEAD. - /// - public int VersionHeight { get; protected set; } - - /// - /// The offset to add to the - /// when calculating the integer to use as the - /// or elsewhere that the {height} macro is used. - /// - public int VersionHeightOffset => this.VersionOptions?.VersionHeightOffsetOrDefault ?? 0; - - /// - /// Gets the ref (branch or tag) being built. - /// - public string? BuildingRef { get; protected set; } - - /// - /// Gets the version for this project, with up to 4 components. - /// - public Version Version { get; protected set; } - - /// - /// Gets a value indicating whether to set all cloud build variables prefaced with "NBGV_". - /// - [Ignore] - public bool CloudBuildAllVarsEnabled => this.VersionOptions?.CloudBuildOrDefault.SetAllVariablesOrDefault - ?? VersionOptions.CloudBuildOptions.DefaultInstance.SetAllVariablesOrDefault; - - /// - /// Gets a dictionary of all cloud build variables that applies to this project, - /// regardless of the current setting of . - /// - [Ignore] - public IDictionary CloudBuildAllVars + /// + /// Gets a dictionary of all cloud build variables that applies to this project, + /// regardless of the current setting of . + /// + [Ignore] + public IDictionary CloudBuildAllVars + { + get { - get - { - var variables = new Dictionary(StringComparer.OrdinalIgnoreCase); + var variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - var properties = this.GetType().GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); - foreach (var property in properties) + PropertyInfo[]? properties = this.GetType().GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); + foreach (PropertyInfo? property in properties) + { + if (property.GetCustomAttribute() is null) { - if (property.GetCustomAttribute() is null) + object? value = property.GetValue(this); + if (value is object) { - var value = property.GetValue(this); - if (value is object) - { - variables.Add($"NBGV_{property.Name}", value.ToString() ?? string.Empty); - } + variables.Add($"NBGV_{property.Name}", value.ToString() ?? string.Empty); } } - - return variables; } + + return variables; } + } - /// - /// Gets a value indicating whether to set cloud build version variables. - /// - [Ignore] - public bool CloudBuildVersionVarsEnabled => this.VersionOptions?.CloudBuildOrDefault.SetVersionVariablesOrDefault - ?? VersionOptions.CloudBuildOptions.DefaultInstance.SetVersionVariablesOrDefault; - - /// - /// Gets a dictionary of cloud build variables that applies to this project, - /// regardless of the current setting of . - /// - [Ignore] - public IDictionary CloudBuildVersionVars + /// + /// Gets a value indicating whether to set cloud build version variables. + /// + [Ignore] + public bool CloudBuildVersionVarsEnabled => this.VersionOptions?.CloudBuildOrDefault.SetVersionVariablesOrDefault + ?? VersionOptions.CloudBuildOptions.DefaultInstance.SetVersionVariablesOrDefault; + + /// + /// Gets a dictionary of cloud build variables that applies to this project, + /// regardless of the current setting of . + /// + [Ignore] + public IDictionary CloudBuildVersionVars + { + get { - get + return new Dictionary(StringComparer.OrdinalIgnoreCase) { - return new Dictionary(StringComparer.OrdinalIgnoreCase) - { - { "GitAssemblyInformationalVersion", this.AssemblyInformationalVersion }, - { "GitBuildVersion", this.Version.ToString() }, - { "GitBuildVersionSimple", this.SimpleVersion.ToString() }, - }; - } + { "GitAssemblyInformationalVersion", this.AssemblyInformationalVersion }, + { "GitBuildVersion", this.Version.ToString() }, + { "GitBuildVersionSimple", this.SimpleVersion.ToString() }, + }; } + } + + /// + /// Gets the list of build metadata identifiers to include in semver version strings. + /// + [Ignore] + public List BuildMetadata { get; } = new List(); + + /// + /// Gets the +buildMetadata fragment for the semantic version. + /// + public string BuildMetadataFragment => FormatBuildMetadata(this.BuildMetadataWithCommitId); + + /// + /// Gets the version to use for NuGet packages. + /// + public string NuGetPackageVersion => this.VersionOptions?.NuGetPackageVersionOrDefault.SemVerOrDefault == 1 ? this.NuGetSemVer1 : this.NuGetSemVer2; + + /// + /// Gets the version to use for Chocolatey packages. + /// + /// + /// This always returns the NuGet subset of SemVer 1.0. + /// + public string ChocolateyPackageVersion => this.NuGetSemVer1; + + /// + /// Gets the version to use for NPM packages. + /// + public string NpmPackageVersion => this.SemVer2; + + /// + /// Gets a SemVer 1.0 compliant string that represents this version, including the -COMMITID suffix + /// when is false. + /// + public string SemVer1 => + $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersionSemVer1}{this.SemVer1BuildMetadata}"; + + /// + /// Gets a SemVer 2.0 compliant string that represents this version, including a +COMMITID suffix + /// when is false. + /// + public string SemVer2 => + $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersion}{this.SemVer2BuildMetadata}"; + + /// + /// Gets the minimum number of digits to use for numeric identifiers in SemVer 1. + /// + public int SemVer1NumericIdentifierPadding => this.VersionOptions?.SemVer1NumericIdentifierPaddingOrDefault ?? 4; + + /// + /// Gets or sets the . + /// + protected VersionOptions.CloudBuildNumberOptions CloudBuildNumberOptions { get; set; } + + /// + /// Gets the that were deserialized from the contextual commit, if any. + /// + protected VersionOptions? CommittedVersion { get; } + + /// + /// Gets the that were deserialized from the working tree, if any. + /// + protected VersionOptions? WorkingVersion { get; } + + /// + /// Gets the build metadata, compliant to the NuGet-compatible subset of SemVer 1.0. + /// + /// + /// When adding the git commit ID in a -prerelease tag, prefix a `g` because + /// older NuGet clients (the ones that support only a subset of semver 1.0) + /// cannot handle prerelease tags that begin with a number (which a git commit ID might). + /// See this discussion. + /// + private string NuGetSemVer1BuildMetadata => + this.PublicRelease ? string.Empty : $"-{this.VersionOptions?.GitCommitIdPrefix ?? "g"}{this.GitCommitIdShort}"; - /// - /// Gets the list of build metadata identifiers to include in semver version strings. - /// - [Ignore] - public List BuildMetadata { get; } = new List(); - - /// - /// Gets the +buildMetadata fragment for the semantic version. - /// - public string BuildMetadataFragment => FormatBuildMetadata(this.BuildMetadataWithCommitId); - - /// - /// Gets the version to use for NuGet packages. - /// - public string NuGetPackageVersion => this.VersionOptions?.NuGetPackageVersionOrDefault.SemVerOrDefault == 1 ? this.NuGetSemVer1 : this.NuGetSemVer2; - - /// - /// Gets the version to use for Chocolatey packages. - /// - /// - /// This always returns the NuGet subset of SemVer 1.0. - /// - public string ChocolateyPackageVersion => this.NuGetSemVer1; - - /// - /// Gets the version to use for NPM packages. - /// - public string NpmPackageVersion => this.SemVer2; - - /// - /// Gets a SemVer 1.0 compliant string that represents this version, including the -COMMITID suffix - /// when is false. - /// - public string SemVer1 => - $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersionSemVer1}{this.SemVer1BuildMetadata}"; - - /// - /// Gets a SemVer 2.0 compliant string that represents this version, including a +COMMITID suffix - /// when is false. - /// - public string SemVer2 => - $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersion}{this.SemVer2BuildMetadata}"; - - /// - /// Gets the minimum number of digits to use for numeric identifiers in SemVer 1. - /// - public int SemVer1NumericIdentifierPadding => this.VersionOptions?.SemVer1NumericIdentifierPaddingOrDefault ?? 4; - - /// - /// Gets or sets the . - /// - protected VersionOptions.CloudBuildNumberOptions CloudBuildNumberOptions { get; set; } - - /// - /// Gets the build metadata, compliant to the NuGet-compatible subset of SemVer 1.0. - /// - /// - /// When adding the git commit ID in a -prerelease tag, prefix a `g` because - /// older NuGet clients (the ones that support only a subset of semver 1.0) - /// cannot handle prerelease tags that begin with a number (which a git commit ID might). - /// See this discussion. - /// - private string NuGetSemVer1BuildMetadata => - this.PublicRelease ? string.Empty : $"-{this.VersionOptions?.GitCommitIdPrefix ?? "g"}{this.GitCommitIdShort}"; - - /// - /// Gets the build metadata, compliant to SemVer 1.0. - /// - private string SemVer1BuildMetadata => - this.PublicRelease ? string.Empty : $"-{this.GitCommitIdShort}"; - - /// - /// Gets a SemVer 1.0 compliant string that represents this version, including the -gCOMMITID suffix - /// when is false. - /// - private string NuGetSemVer1 + /// + /// Gets the build metadata, compliant to SemVer 1.0. + /// + private string SemVer1BuildMetadata => + this.PublicRelease ? string.Empty : $"-{this.GitCommitIdShort}"; + + /// + /// Gets a SemVer 1.0 compliant string that represents this version, including the -gCOMMITID suffix + /// when is false. + /// + private string NuGetSemVer1 + { + get { - get - { - var precision = this.VersionOptions?.NuGetPackageVersionOrDefault.PrecisionOrDefault ?? VersionOptions.NuGetPackageVersionOptions.DefaultPrecision; - var version = this.Version.EnsureNonNegativeComponents(); - version = ApplyVersionPrecision(version, precision); + VersionOptions.VersionPrecision precision = this.VersionOptions?.NuGetPackageVersionOrDefault.PrecisionOrDefault ?? VersionOptions.NuGetPackageVersionOptions.DefaultPrecision; + Version? version = this.Version.EnsureNonNegativeComponents(); + version = ApplyVersionPrecision(version, precision); - // If precision is set to include the 4th version component, return all 4 version fields, otherwise return 3 fields. - var fieldCount = precision >= VersionOptions.VersionPrecision.Revision ? 4 : 3; + // If precision is set to include the 4th version component, return all 4 version fields, otherwise return 3 fields. + int fieldCount = precision >= VersionOptions.VersionPrecision.Revision ? 4 : 3; - return $"{version.ToStringSafe(fieldCount)}{this.PrereleaseVersionSemVer1}{this.NuGetSemVer1BuildMetadata}"; - } + return $"{version.ToStringSafe(fieldCount)}{this.PrereleaseVersionSemVer1}{this.NuGetSemVer1BuildMetadata}"; } + } - /// - /// Gets a SemVer 2.0 compliant string that represents this version, including the -gCOMMITID suffix - /// when is false. - /// - private string NuGetSemVer2 + /// + /// Gets a SemVer 2.0 compliant string that represents this version, including the -gCOMMITID suffix + /// when is false. + /// + private string NuGetSemVer2 + { + get { - get - { - var precision = this.VersionOptions?.NuGetPackageVersionOrDefault.PrecisionOrDefault ?? VersionOptions.NuGetPackageVersionOptions.DefaultPrecision; - var version = this.Version.EnsureNonNegativeComponents(); - version = ApplyVersionPrecision(version, precision); + VersionOptions.VersionPrecision precision = this.VersionOptions?.NuGetPackageVersionOrDefault.PrecisionOrDefault ?? VersionOptions.NuGetPackageVersionOptions.DefaultPrecision; + Version? version = this.Version.EnsureNonNegativeComponents(); + version = ApplyVersionPrecision(version, precision); - // If precision is set to include the 4th version component, return all 4 version fields, otherwise return 3 fields. - var fieldCount = precision >= VersionOptions.VersionPrecision.Revision ? 4 : 3; + // If precision is set to include the 4th version component, return all 4 version fields, otherwise return 3 fields. + int fieldCount = precision >= VersionOptions.VersionPrecision.Revision ? 4 : 3; - return $"{version.ToStringSafe(fieldCount)}{this.PrereleaseVersion}{this.SemVer2BuildMetadata}"; - } + return $"{version.ToStringSafe(fieldCount)}{this.PrereleaseVersion}{this.SemVer2BuildMetadata}"; } + } - /// - /// Gets the build metadata that is appropriate for SemVer2 use. - /// - /// - /// We always put the commit ID in the -prerelease tag for non-public releases. - /// But for public releases, we don't include it in the +buildMetadata section since it may be confusing for NuGet. - /// See https://github.com/dotnet/Nerdbank.GitVersioning/pull/132#issuecomment-307208561 - /// - private string SemVer2BuildMetadata => - (this.PublicRelease ? string.Empty : this.GitCommitIdShortForNonPublicPrereleaseTag) + FormatBuildMetadata(this.BuildMetadata); - - private string PrereleaseVersionSemVer1 => SemanticVersionExtensions.MakePrereleaseSemVer1Compliant(this.PrereleaseVersion, this.SemVer1NumericIdentifierPadding); - - /// - /// Gets the -gc0ffee or .gc0ffee suffix for the version. - /// The g in the prefix might be changed if is set. - /// - /// - /// The prefix to the commit ID is to remain SemVer2 compliant particularly when the partial commit ID we use is made up entirely of numerals. - /// SemVer2 forbids numerals to begin with leading zeros, but a git commit just might, so we begin with prefix always to avoid failures when the commit ID happens to be problematic. - /// - private string GitCommitIdShortForNonPublicPrereleaseTag => (string.IsNullOrEmpty(this.PrereleaseVersion) ? "-" : ".") + (this.VersionOptions?.GitCommitIdPrefix ?? "g") + this.GitCommitIdShort; - - private int VersionHeightWithOffset => this.VersionHeight + this.VersionHeightOffset; - - private static string FormatBuildMetadata(IEnumerable identifiers) => - (identifiers?.Any() ?? false) ? "+" + string.Join(".", identifiers) : string.Empty; - - private static Version GetAssemblyVersion(Version version, VersionOptions? versionOptions) - { - // If there is no repo, "version" could have uninitialized components (-1). - version = version.EnsureNonNegativeComponents(); + /// + /// Gets the build metadata that is appropriate for SemVer2 use. + /// + /// + /// We always put the commit ID in the -prerelease tag for non-public releases. + /// But for public releases, we don't include it in the +buildMetadata section since it may be confusing for NuGet. + /// + /// + private string SemVer2BuildMetadata => + (this.PublicRelease ? string.Empty : this.GitCommitIdShortForNonPublicPrereleaseTag) + FormatBuildMetadata(this.BuildMetadata); - Version assemblyVersion; + private string PrereleaseVersionSemVer1 => SemanticVersionExtensions.MakePrereleaseSemVer1Compliant(this.PrereleaseVersion, this.SemVer1NumericIdentifierPadding); - if (versionOptions?.AssemblyVersion?.Version is not null) - { - // When specified explicitly, use the assembly version as the user defines it. - assemblyVersion = versionOptions.AssemblyVersion.Version; - } - else - { - // Otherwise consider precision to base the assembly version off of the main computed version. - VersionOptions.VersionPrecision precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision; - assemblyVersion = ApplyVersionPrecision(version, precision); - } + /// + /// Gets the -gc0ffee or .gc0ffee suffix for the version. + /// The g in the prefix might be changed if is set. + /// + /// + /// The prefix to the commit ID is to remain SemVer2 compliant particularly when the partial commit ID we use is made up entirely of numerals. + /// SemVer2 forbids numerals to begin with leading zeros, but a git commit just might, so we begin with prefix always to avoid failures when the commit ID happens to be problematic. + /// + private string GitCommitIdShortForNonPublicPrereleaseTag => (string.IsNullOrEmpty(this.PrereleaseVersion) ? "-" : ".") + (this.VersionOptions?.GitCommitIdPrefix ?? "g") + this.GitCommitIdShort; - return assemblyVersion.EnsureNonNegativeComponents(4); - } + private int VersionHeightWithOffset => this.VersionHeight + this.VersionHeightOffset; - private static Version ApplyVersionPrecision(Version version, VersionOptions.VersionPrecision precision) - { - return new Version( - version.Major, - precision >= VersionOptions.VersionPrecision.Minor ? version.Minor : 0, - precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0, - precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0); - } + private static string FormatBuildMetadata(IEnumerable identifiers) => + (identifiers?.Any() ?? false) ? "+" + string.Join(".", identifiers) : string.Empty; - /// - /// Replaces any macros found in a prerelease or build metadata string. - /// - /// The prerelease or build metadata. - /// The specified string, with macros substituted for actual values. - private string ReplaceMacros(string prereleaseOrBuildMetadata) => prereleaseOrBuildMetadata.Replace(VersionOptions.VersionHeightPlaceholder, this.VersionHeightWithOffset.ToString(CultureInfo.InvariantCulture)); + private static Version GetAssemblyVersion(Version version, VersionOptions? versionOptions) + { + // If there is no repo, "version" could have uninitialized components (-1). + version = version.EnsureNonNegativeComponents(); - [AttributeUsage(AttributeTargets.Property)] - private class IgnoreAttribute : Attribute + Version assemblyVersion; + + if (versionOptions?.AssemblyVersion?.Version is not null) + { + // When specified explicitly, use the assembly version as the user defines it. + assemblyVersion = versionOptions.AssemblyVersion.Version; + } + else { + // Otherwise consider precision to base the assembly version off of the main computed version. + VersionOptions.VersionPrecision precision = versionOptions?.AssemblyVersion?.Precision ?? VersionOptions.DefaultVersionPrecision; + assemblyVersion = ApplyVersionPrecision(version, precision); } + + return assemblyVersion.EnsureNonNegativeComponents(4); + } + + private static Version ApplyVersionPrecision(Version version, VersionOptions.VersionPrecision precision) + { + return new Version( + version.Major, + precision >= VersionOptions.VersionPrecision.Minor ? version.Minor : 0, + precision >= VersionOptions.VersionPrecision.Build ? version.Build : 0, + precision >= VersionOptions.VersionPrecision.Revision ? version.Revision : 0); + } + + /// + /// Replaces any macros found in a prerelease or build metadata string. + /// + /// The prerelease or build metadata. + /// The specified string, with macros substituted for actual values. + private string ReplaceMacros(string prereleaseOrBuildMetadata) => prereleaseOrBuildMetadata.Replace(VersionOptions.VersionHeightPlaceholder, this.VersionHeightWithOffset.ToString(CultureInfo.InvariantCulture)); + + [AttributeUsage(AttributeTargets.Property)] + private class IgnoreAttribute : Attribute + { } } diff --git a/src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs b/src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs index 55da8b8b..ab99844e 100644 --- a/src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs +++ b/src/Nerdbank.GitVersioning.Tasks/AssemblyLoader.cs @@ -1,4 +1,11 @@ -#if NETFRAMEWORK +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable SA1403 // File may only contain a single namespace +#pragma warning disable SA1649 // File name should match first type name + +#if NETFRAMEWORK using System; using System.IO; @@ -8,14 +15,18 @@ namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)] - public sealed class ModuleInitializerAttribute : Attribute { } + public sealed class ModuleInitializerAttribute : Attribute + { + } } namespace Nerdbank.GitVersioning.Tasks { internal static class AssemblyLoader { +#pragma warning disable CA2255 // The 'ModuleInitializer' attribute should not be used in libraries [ModuleInitializer] +#pragma warning restore CA2255 // The 'ModuleInitializer' attribute should not be used in libraries internal static void LoaderInitializer() { AppDomain.CurrentDomain.AssemblyResolve += CurrentDomain_AssemblyResolve; diff --git a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs index 2f39ca05..8c619600 100644 --- a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs @@ -1,39 +1,31 @@ -namespace Nerdbank.GitVersioning.Tasks +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.CodeDom; +using System.CodeDom.Compiler; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using Validation; + +namespace Nerdbank.GitVersioning.Tasks { - using System; - using System.CodeDom; - using System.CodeDom.Compiler; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Reflection; - using System.Text; - using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; - using Validation; - - public class AssemblyVersionInfo : Task + public class AssemblyVersionInfo : Microsoft.Build.Utilities.Task { + public static readonly string GeneratorName = ThisAssembly.AssemblyName; + public static readonly string GeneratorVersion = ThisAssembly.AssemblyVersion; + /// /// The #if expression that surrounds a to avoid a compilation failure when targeting the nano framework. /// - /// - /// See https://github.com/dotnet/Nerdbank.GitVersioning/issues/346 - /// + /// private const string CompilerDefinesAroundGeneratedCodeAttribute = "NETSTANDARD || NETFRAMEWORK || NETCOREAPP"; private const string CompilerDefinesAroundExcludeFromCodeCoverageAttribute = "NETFRAMEWORK || NETCOREAPP || NETSTANDARD2_0 || NETSTANDARD2_1"; - - public static readonly string GeneratorName = ThisAssembly.AssemblyName; - public static readonly string GeneratorVersion = ThisAssembly.AssemblyVersion; -#if NET461 - private static readonly CodeGeneratorOptions codeGeneratorOptions = new CodeGeneratorOptions - { - BlankLinesBetweenMembers = false, - IndentString = " ", - }; - - private CodeCompileUnit generatedFile; -#endif private const string FileHeaderComment = @"------------------------------------------------------------------------------ This code was generated by a tool. @@ -45,6 +37,16 @@ the code is regenerated. ------------------------------------------------------------------------------ "; +#if NET461 + private static readonly CodeGeneratorOptions CodeGeneratorOptions = new CodeGeneratorOptions + { + BlankLinesBetweenMembers = false, + IndentString = " ", + }; + + private CodeCompileUnit generatedFile; +#endif + private CodeGenerator generator; [Required] @@ -90,7 +92,7 @@ the code is regenerated. public bool EmitThisAssemblyClass { get; set; } = true; /// - /// Specify additional fields to be added to the ThisAssembly class. + /// Gets or sets the additional fields to be added to the ThisAssembly class. /// /// /// Field name is given by %(Identity). Provide the field value by specifying exactly one metadata value that is %(String), %(Boolean) or %(Ticks) (for UTC DateTime). @@ -108,7 +110,31 @@ the code is regenerated. /// public ITaskItem[] AdditionalThisAssemblyFields { get; set; } + public string BuildCode() + { + this.generator = this.CreateGenerator(); + if (this.generator is object) + { + this.generator.AddComment(FileHeaderComment); + this.generator.AddBlankLine(); + this.generator.AddAnalysisSuppressions(); + this.generator.AddBlankLine(); + this.generator.EmitNamespaceIfRequired(this.RootNamespace ?? "AssemblyInfo"); + this.GenerateAssemblyAttributes(); + + if (this.EmitThisAssemblyClass) + { + this.GenerateThisAssemblyClass(); + } + + return this.generator.GetCode(); + } + + return null; + } + #if NET461 + /// public override bool Execute() { // attempt to use local codegen @@ -140,7 +166,7 @@ public override bool Execute() { using (var fileWriter = new StreamWriter(file, new UTF8Encoding(true), 4096, leaveOpen: true)) { - codeDomProvider.GenerateCodeFromCompileUnit(this.generatedFile, fileWriter, codeGeneratorOptions); + codeDomProvider.GenerateCodeFromCompileUnit(this.generatedFile, fileWriter, CodeGeneratorOptions); } // truncate to new size. @@ -155,6 +181,104 @@ public override bool Execute() return !this.Log.HasLoggedErrors; } +#endif + +#if !NET461 + /// + public override bool Execute() + { + string fileContent = this.BuildCode(); + if (fileContent is object) + { + Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile)); + Utilities.FileOperationWithRetry(() => File.WriteAllText(this.OutputFile, fileContent)); + } + else + { + this.Log.LogError("CodeDomProvider not available for language: {0}. No version info will be embedded into assembly.", this.CodeLanguage); + } + + return !this.Log.HasLoggedErrors; + } +#endif + + private static string ToHex(byte[] data) + { + return BitConverter.ToString(data).Replace("-", string.Empty).ToLowerInvariant(); + } + + /// + /// Gets the public key from a key container. + /// + /// The name of the container. + /// The public key. + private static byte[] GetPublicKeyFromKeyContainer(string containerName) + { + throw new NotImplementedException(); + } + + private static byte[] GetPublicKeyFromKeyPair(byte[] keyPair) + { + byte[] publicKey; + if (CryptoBlobParser.TryGetPublicKeyFromPrivateKeyBlob(keyPair, out publicKey)) + { + return publicKey; + } + else + { + throw new ArgumentException("Invalid keypair"); + } + } + +#if NET461 + private static CodeMemberField CreateField(string name, T value) + { + return new CodeMemberField(typeof(T), name) + { + Attributes = MemberAttributes.Const | MemberAttributes.Assembly, + InitExpression = new CodePrimitiveExpression(value), + }; + } + + private static IEnumerable CreateDateTimeField(string name, DateTime value) + { + Requires.NotNullOrEmpty(name, nameof(name)); + + ////internal static System.DateTime GitCommitDate => new System.DateTime({ticks}, System.DateTimeKind.Utc);"); + + var property = new CodeMemberProperty() + { + Attributes = MemberAttributes.Assembly | MemberAttributes.Static | MemberAttributes.Final, + Type = new CodeTypeReference(typeof(DateTime)), + Name = name, + HasGet = true, + HasSet = false, + }; + + property.GetStatements.Add( + new CodeMethodReturnStatement( + new CodeObjectCreateExpression( + typeof(DateTime), + new CodePrimitiveExpression(value.Ticks), + new CodePropertyReferenceExpression( + new CodeTypeReferenceExpression(typeof(DateTimeKind)), + nameof(DateTimeKind.Utc))))); + + yield return property; + } + + private static CodeAttributeDeclaration DeclareAttribute(Type attributeType, params CodeAttributeArgument[] arguments) + { + var assemblyTypeReference = new CodeTypeReference(attributeType); + return new CodeAttributeDeclaration(assemblyTypeReference, arguments); + } + + private static CodeAttributeDeclaration DeclareAttribute(Type attributeType, params string[] arguments) + { + return DeclareAttribute( + attributeType, + arguments.Select(a => new CodeAttributeArgument(new CodePrimitiveExpression(a))).ToArray()); + } private CodeTypeDeclaration CreateThisAssemblyClass() { @@ -166,7 +290,8 @@ private CodeTypeDeclaration CreateThisAssemblyClass() }; var codeAttributeDeclarationCollection = new CodeAttributeDeclarationCollection(); - codeAttributeDeclarationCollection.Add(new CodeAttributeDeclaration("System.CodeDom.Compiler.GeneratedCode", + codeAttributeDeclarationCollection.Add(new CodeAttributeDeclaration( + "System.CodeDom.Compiler.GeneratedCode", new CodeAttributeArgument(new CodePrimitiveExpression(GeneratorName)), new CodeAttributeArgument(new CodePrimitiveExpression(GeneratorVersion)))); thisAssembly.CustomAttributes = codeAttributeDeclarationCollection; @@ -174,9 +299,9 @@ private CodeTypeDeclaration CreateThisAssemblyClass() // CodeDOM doesn't support static classes, so hide the constructor instead. thisAssembly.Members.Add(new CodeConstructor { Attributes = MemberAttributes.Private }); - var fields = this.GetFieldsForThisAssembly(); + List> fields = this.GetFieldsForThisAssembly(); - foreach (var pair in fields) + foreach (KeyValuePair pair in fields) { switch (pair.Value.Value) { @@ -192,6 +317,7 @@ private CodeTypeDeclaration CreateThisAssemblyClass() { thisAssembly.Members.Add(CreateField(pair.Key, stringValue)); } + break; case bool boolValue: @@ -238,99 +364,8 @@ private IEnumerable CreateAssemblyAttributes() } } } - - private static CodeMemberField CreateField(string name, T value) - { - return new CodeMemberField(typeof(T), name) - { - Attributes = MemberAttributes.Const | MemberAttributes.Assembly, - InitExpression = new CodePrimitiveExpression(value), - }; - } - - private static IEnumerable CreateDateTimeField(string name, DateTime value) - { - Requires.NotNullOrEmpty(name, nameof(name)); - - // internal static System.DateTime GitCommitDate => new System.DateTime({ticks}, System.DateTimeKind.Utc);"); - - var property = new CodeMemberProperty() - { - Attributes = MemberAttributes.Assembly | MemberAttributes.Static | MemberAttributes.Final, - Type = new CodeTypeReference(typeof(DateTime)), - Name = name, - HasGet = true, - HasSet = false, - }; - - property.GetStatements.Add( - new CodeMethodReturnStatement( - new CodeObjectCreateExpression( - typeof(DateTime), - new CodePrimitiveExpression(value.Ticks), - new CodePropertyReferenceExpression( - new CodeTypeReferenceExpression(typeof(DateTimeKind)), - nameof(DateTimeKind.Utc))))); - - yield return property; - } - - private static CodeAttributeDeclaration DeclareAttribute(Type attributeType, params CodeAttributeArgument[] arguments) - { - var assemblyTypeReference = new CodeTypeReference(attributeType); - return new CodeAttributeDeclaration(assemblyTypeReference, arguments); - } - - private static CodeAttributeDeclaration DeclareAttribute(Type attributeType, params string[] arguments) - { - return DeclareAttribute( - attributeType, - arguments.Select(a => new CodeAttributeArgument(new CodePrimitiveExpression(a))).ToArray()); - } - -#else - - public override bool Execute() - { - string fileContent = this.BuildCode(); - if (fileContent is object) - { - Directory.CreateDirectory(Path.GetDirectoryName(this.OutputFile)); - Utilities.FileOperationWithRetry(() => File.WriteAllText(this.OutputFile, fileContent)); - } - else - { - this.Log.LogError("CodeDomProvider not available for language: {0}. No version info will be embedded into assembly.", this.CodeLanguage); - } - - return !this.Log.HasLoggedErrors; - } - #endif - public string BuildCode() - { - this.generator = this.CreateGenerator(); - if (this.generator is object) - { - this.generator.AddComment(FileHeaderComment); - this.generator.AddBlankLine(); - this.generator.AddAnalysisSuppressions(); - this.generator.AddBlankLine(); - this.generator.EmitNamespaceIfRequired(this.RootNamespace ?? "AssemblyInfo"); - this.GenerateAssemblyAttributes(); - - if (this.EmitThisAssemblyClass) - { - this.GenerateThisAssemblyClass(); - } - - return this.generator.GetCode(); - } - - return null; - } - private void GenerateAssemblyAttributes() { this.generator.DeclareAttribute(typeof(AssemblyVersionAttribute), this.AssemblyVersion); @@ -379,8 +414,10 @@ private void GenerateAssemblyAttributes() { "AssemblyCompany", (this.AssemblyCompany, false) }, { "AssemblyConfiguration", (this.AssemblyConfiguration, false) }, { "GitCommitId", (this.GitCommitId, false) }, + // These properties should be defined even if they are empty strings: { "RootNamespace", (this.RootNamespace, true) }, + // These non-string properties are always emitted: { "IsPublicRelease", (this.PublicRelease, true) }, { "IsPrerelease", (!string.IsNullOrEmpty(this.PrereleaseVersion), true) }, @@ -399,9 +436,9 @@ private void GenerateAssemblyAttributes() if (this.AdditionalThisAssemblyFields is object) { - foreach (var item in this.AdditionalThisAssemblyFields) + foreach (ITaskItem item in this.AdditionalThisAssemblyFields) { - var name = item.ItemSpec.Trim(); + string name = item.ItemSpec.Trim(); var meta = new Dictionary(item.MetadataCount, StringComparer.OrdinalIgnoreCase); foreach (string metadataName in item.MetadataNames) { @@ -485,9 +522,9 @@ private void GenerateThisAssemblyClass() { this.generator.StartThisAssemblyClass(); - var fields = this.GetFieldsForThisAssembly(); + List> fields = this.GetFieldsForThisAssembly(); - foreach (var pair in fields) + foreach (KeyValuePair pair in fields) { switch (pair.Value.Value) { @@ -496,6 +533,7 @@ private void GenerateThisAssemblyClass() { this.generator.AddThisAssemblyMember(pair.Key, string.Empty); } + break; case string stringValue: @@ -503,6 +541,7 @@ private void GenerateThisAssemblyClass() { this.generator.AddThisAssemblyMember(pair.Key, stringValue); } + break; case bool boolValue: @@ -538,15 +577,62 @@ private CodeGenerator CreateGenerator() } } - private abstract class CodeGenerator + private bool TryReadKeyInfo(out string publicKey, out string publicKeyToken) { - protected readonly StringBuilder codeBuilder; + try + { + byte[] publicKeyBytes = null; + if (!string.IsNullOrEmpty(this.AssemblyOriginatorKeyFile) && File.Exists(this.AssemblyOriginatorKeyFile)) + { + if (Path.GetExtension(this.AssemblyOriginatorKeyFile).Equals(".snk", StringComparison.OrdinalIgnoreCase)) + { + byte[] keyBytes = File.ReadAllBytes(this.AssemblyOriginatorKeyFile); + bool publicKeyOnly = keyBytes[0] != 0x07; + publicKeyBytes = publicKeyOnly ? keyBytes : GetPublicKeyFromKeyPair(keyBytes); + } + } + else if (!string.IsNullOrEmpty(this.AssemblyKeyContainerName)) + { + publicKeyBytes = GetPublicKeyFromKeyContainer(this.AssemblyKeyContainerName); + } + + // If .NET 2.0 isn't installed, we get byte[0] back. + if (publicKeyBytes is object && publicKeyBytes.Length > 0) + { + publicKey = ToHex(publicKeyBytes); + publicKeyToken = ToHex(CryptoBlobParser.GetStrongNameTokenFromPublicKey(publicKeyBytes)); + } + else + { + if (publicKeyBytes is object) + { + this.Log.LogWarning("Unable to emit public key fields in ThisAssembly class because .NET 2.0 isn't installed."); + } + + publicKey = null; + publicKeyToken = null; + return false; + } + + return true; + } + catch (NotImplementedException) + { + publicKey = null; + publicKeyToken = null; + return false; + } + } + private abstract class CodeGenerator + { internal CodeGenerator() { - this.codeBuilder = new StringBuilder(); + this.CodeBuilder = new StringBuilder(); } + protected StringBuilder CodeBuilder { get; } + protected virtual IEnumerable WarningCodesToSuppress { get; } = new string[] { "CA2243", // Attribute string literals should parse correctly @@ -572,13 +658,15 @@ internal CodeGenerator() /// Gives languages that *require* a namespace a chance to emit such. /// /// The RootNamespace of the project. - internal virtual void EmitNamespaceIfRequired(string ns) { } + internal virtual void EmitNamespaceIfRequired(string ns) + { + } - internal string GetCode() => this.codeBuilder.ToString(); + internal string GetCode() => this.CodeBuilder.ToString(); internal void AddBlankLine() { - this.codeBuilder.AppendLine(); + this.CodeBuilder.AppendLine(); } protected void AddCodeComment(string comment, string token) @@ -587,8 +675,8 @@ protected void AddCodeComment(string comment, string token) string line; while ((line = sr.ReadLine()) is object) { - this.codeBuilder.Append(token); - this.codeBuilder.AppendLine(line); + this.CodeBuilder.Append(token); + this.CodeBuilder.AppendLine(line); } } } @@ -597,7 +685,7 @@ private class FSharpCodeGenerator : CodeGenerator { internal override void AddAnalysisSuppressions() { - this.codeBuilder.AppendLine($"#nowarn {string.Join(" ", this.WarningCodesToSuppress.Select(c => $"\"{c}\""))}"); + this.CodeBuilder.AppendLine($"#nowarn {string.Join(" ", this.WarningCodesToSuppress.Select(c => $"\"{c}\""))}"); } internal override void AddComment(string comment) @@ -607,44 +695,44 @@ internal override void AddComment(string comment) internal override void AddThisAssemblyMember(string name, string value) { - this.codeBuilder.AppendLine($" static member internal {name} = \"{value}\""); + this.CodeBuilder.AppendLine($" static member internal {name} = \"{value}\""); } internal override void AddThisAssemblyMember(string name, bool value) { - this.codeBuilder.AppendLine($" static member internal {name} = {(value ? "true" : "false")}"); + this.CodeBuilder.AppendLine($" static member internal {name} = {(value ? "true" : "false")}"); } internal override void AddThisAssemblyMember(string name, DateTime value) { - this.codeBuilder.AppendLine($" static member internal {name} = new System.DateTime({value.Ticks}L, System.DateTimeKind.Utc)"); + this.CodeBuilder.AppendLine($" static member internal {name} = new System.DateTime({value.Ticks}L, System.DateTimeKind.Utc)"); } internal override void EmitNamespaceIfRequired(string ns) { - this.codeBuilder.AppendLine($"namespace {ns}"); + this.CodeBuilder.AppendLine($"namespace {ns}"); } internal override void DeclareAttribute(Type type, string arg) { - this.codeBuilder.AppendLine($"[]"); + this.CodeBuilder.AppendLine($"[]"); } internal override void EndThisAssemblyClass() { - this.codeBuilder.AppendLine("do()"); + this.CodeBuilder.AppendLine("do()"); } internal override void StartThisAssemblyClass() { - this.codeBuilder.AppendLine("do()"); - this.codeBuilder.AppendLine($"#if {CompilerDefinesAroundGeneratedCodeAttribute}"); - this.codeBuilder.AppendLine($"[]"); - this.codeBuilder.AppendLine("#endif"); - this.codeBuilder.AppendLine($"#if {CompilerDefinesAroundExcludeFromCodeCoverageAttribute}"); - this.codeBuilder.AppendLine("[]"); - this.codeBuilder.AppendLine("#endif"); - this.codeBuilder.AppendLine("type internal ThisAssembly() ="); + this.CodeBuilder.AppendLine("do()"); + this.CodeBuilder.AppendLine($"#if {CompilerDefinesAroundGeneratedCodeAttribute}"); + this.CodeBuilder.AppendLine($"[]"); + this.CodeBuilder.AppendLine("#endif"); + this.CodeBuilder.AppendLine($"#if {CompilerDefinesAroundExcludeFromCodeCoverageAttribute}"); + this.CodeBuilder.AppendLine("[]"); + this.CodeBuilder.AppendLine("#endif"); + this.CodeBuilder.AppendLine("type internal ThisAssembly() ="); } } @@ -652,7 +740,7 @@ private class CSharpCodeGenerator : CodeGenerator { internal override void AddAnalysisSuppressions() { - this.codeBuilder.AppendLine($"#pragma warning disable {string.Join(", ", this.WarningCodesToSuppress)}"); + this.CodeBuilder.AppendLine($"#pragma warning disable {string.Join(", ", this.WarningCodesToSuppress)}"); } internal override void AddComment(string comment) @@ -662,38 +750,38 @@ internal override void AddComment(string comment) internal override void DeclareAttribute(Type type, string arg) { - this.codeBuilder.AppendLine($"[assembly: {type.FullName}(\"{arg}\")]"); + this.CodeBuilder.AppendLine($"[assembly: {type.FullName}(\"{arg}\")]"); } internal override void StartThisAssemblyClass() { - this.codeBuilder.AppendLine($"#if {CompilerDefinesAroundGeneratedCodeAttribute}"); - this.codeBuilder.AppendLine($"[System.CodeDom.Compiler.GeneratedCode(\"{GeneratorName}\",\"{GeneratorVersion}\")]"); - this.codeBuilder.AppendLine("#endif"); - this.codeBuilder.AppendLine($"#if {CompilerDefinesAroundExcludeFromCodeCoverageAttribute}"); - this.codeBuilder.AppendLine("[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]"); - this.codeBuilder.AppendLine("#endif"); - this.codeBuilder.AppendLine("internal static partial class ThisAssembly {"); + this.CodeBuilder.AppendLine($"#if {CompilerDefinesAroundGeneratedCodeAttribute}"); + this.CodeBuilder.AppendLine($"[System.CodeDom.Compiler.GeneratedCode(\"{GeneratorName}\",\"{GeneratorVersion}\")]"); + this.CodeBuilder.AppendLine("#endif"); + this.CodeBuilder.AppendLine($"#if {CompilerDefinesAroundExcludeFromCodeCoverageAttribute}"); + this.CodeBuilder.AppendLine("[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]"); + this.CodeBuilder.AppendLine("#endif"); + this.CodeBuilder.AppendLine("internal static partial class ThisAssembly {"); } internal override void AddThisAssemblyMember(string name, string value) { - this.codeBuilder.AppendLine($" internal const string {name} = \"{value}\";"); + this.CodeBuilder.AppendLine($" internal const string {name} = \"{value}\";"); } internal override void AddThisAssemblyMember(string name, bool value) { - this.codeBuilder.AppendLine($" internal const bool {name} = {(value ? "true" : "false")};"); + this.CodeBuilder.AppendLine($" internal const bool {name} = {(value ? "true" : "false")};"); } internal override void AddThisAssemblyMember(string name, DateTime value) { - this.codeBuilder.AppendLine($" internal static readonly System.DateTime {name} = new System.DateTime({value.Ticks}L, System.DateTimeKind.Utc);"); + this.CodeBuilder.AppendLine($" internal static readonly System.DateTime {name} = new System.DateTime({value.Ticks}L, System.DateTimeKind.Utc);"); } internal override void EndThisAssemblyClass() { - this.codeBuilder.AppendLine("}"); + this.CodeBuilder.AppendLine("}"); } } @@ -701,7 +789,7 @@ private class VisualBasicCodeGenerator : CodeGenerator { internal override void AddAnalysisSuppressions() { - this.codeBuilder.AppendLine($"#Disable Warning {string.Join(", ", this.WarningCodesToSuppress)}"); + this.CodeBuilder.AppendLine($"#Disable Warning {string.Join(", ", this.WarningCodesToSuppress)}"); } internal override void AddComment(string comment) @@ -711,115 +799,41 @@ internal override void AddComment(string comment) internal override void DeclareAttribute(Type type, string arg) { - this.codeBuilder.AppendLine($""); + this.CodeBuilder.AppendLine($""); } internal override void StartThisAssemblyClass() { - this.codeBuilder.AppendLine($"#If {CompilerDefinesAroundExcludeFromCodeCoverageAttribute.Replace("||", " Or ")} Then"); - this.codeBuilder.AppendLine($""); - this.codeBuilder.AppendLine(""); - this.codeBuilder.AppendLine("Partial Friend NotInheritable Class ThisAssembly"); - this.codeBuilder.AppendLine($"#ElseIf {CompilerDefinesAroundGeneratedCodeAttribute.Replace("||", " Or ")} Then"); - this.codeBuilder.AppendLine($""); - this.codeBuilder.AppendLine("Partial Friend NotInheritable Class ThisAssembly"); - this.codeBuilder.AppendLine("#Else"); - this.codeBuilder.AppendLine("Partial Friend NotInheritable Class ThisAssembly"); - this.codeBuilder.AppendLine("#End If"); + this.CodeBuilder.AppendLine($"#If {CompilerDefinesAroundExcludeFromCodeCoverageAttribute.Replace("||", " Or ")} Then"); + this.CodeBuilder.AppendLine($""); + this.CodeBuilder.AppendLine(""); + this.CodeBuilder.AppendLine("Partial Friend NotInheritable Class ThisAssembly"); + this.CodeBuilder.AppendLine($"#ElseIf {CompilerDefinesAroundGeneratedCodeAttribute.Replace("||", " Or ")} Then"); + this.CodeBuilder.AppendLine($""); + this.CodeBuilder.AppendLine("Partial Friend NotInheritable Class ThisAssembly"); + this.CodeBuilder.AppendLine("#Else"); + this.CodeBuilder.AppendLine("Partial Friend NotInheritable Class ThisAssembly"); + this.CodeBuilder.AppendLine("#End If"); } internal override void AddThisAssemblyMember(string name, string value) { - this.codeBuilder.AppendLine($" Friend Const {name} As String = \"{value}\""); + this.CodeBuilder.AppendLine($" Friend Const {name} As String = \"{value}\""); } internal override void AddThisAssemblyMember(string name, bool value) { - this.codeBuilder.AppendLine($" Friend Const {name} As Boolean = {(value ? "True" : "False")}"); + this.CodeBuilder.AppendLine($" Friend Const {name} As Boolean = {(value ? "True" : "False")}"); } internal override void AddThisAssemblyMember(string name, DateTime value) { - this.codeBuilder.AppendLine($" Friend Shared ReadOnly {name} As System.DateTime = New System.DateTime({value.Ticks}L, System.DateTimeKind.Utc)"); + this.CodeBuilder.AppendLine($" Friend Shared ReadOnly {name} As System.DateTime = New System.DateTime({value.Ticks}L, System.DateTimeKind.Utc)"); } internal override void EndThisAssemblyClass() { - this.codeBuilder.AppendLine("End Class"); - } - } - - private static string ToHex(byte[] data) - { - return BitConverter.ToString(data).Replace("-", "").ToLowerInvariant(); - } - - /// - /// Gets the public key from a key container. - /// - /// The name of the container. - /// The public key. - private static byte[] GetPublicKeyFromKeyContainer(string containerName) - { - throw new NotImplementedException(); - } - - private static byte[] GetPublicKeyFromKeyPair(byte[] keyPair) - { - byte[] publicKey; - if (CryptoBlobParser.TryGetPublicKeyFromPrivateKeyBlob(keyPair, out publicKey)) - { - return publicKey; - } - else - { - throw new ArgumentException("Invalid keypair"); - } - } - - private bool TryReadKeyInfo(out string publicKey, out string publicKeyToken) - { - try - { - byte[] publicKeyBytes = null; - if (!string.IsNullOrEmpty(this.AssemblyOriginatorKeyFile) && File.Exists(this.AssemblyOriginatorKeyFile)) - { - if (Path.GetExtension(this.AssemblyOriginatorKeyFile).Equals(".snk", StringComparison.OrdinalIgnoreCase)) - { - byte[] keyBytes = File.ReadAllBytes(this.AssemblyOriginatorKeyFile); - bool publicKeyOnly = keyBytes[0] != 0x07; - publicKeyBytes = publicKeyOnly ? keyBytes : GetPublicKeyFromKeyPair(keyBytes); - } - } - else if (!string.IsNullOrEmpty(this.AssemblyKeyContainerName)) - { - publicKeyBytes = GetPublicKeyFromKeyContainer(this.AssemblyKeyContainerName); - } - - if (publicKeyBytes is object && publicKeyBytes.Length > 0) // If .NET 2.0 isn't installed, we get byte[0] back. - { - publicKey = ToHex(publicKeyBytes); - publicKeyToken = ToHex(CryptoBlobParser.GetStrongNameTokenFromPublicKey(publicKeyBytes)); - } - else - { - if (publicKeyBytes is object) - { - this.Log.LogWarning("Unable to emit public key fields in ThisAssembly class because .NET 2.0 isn't installed."); - } - - publicKey = null; - publicKeyToken = null; - return false; - } - - return true; - } - catch (NotImplementedException) - { - publicKey = null; - publicKeyToken = null; - return false; + this.CodeBuilder.AppendLine("End Class"); } } } diff --git a/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs b/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs index aa0a62d7..51c86547 100644 --- a/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs +++ b/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs @@ -1,45 +1,82 @@ -namespace Nerdbank.GitVersioning.Tasks +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Nerdbank.GitVersioning.Tasks { - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Text; - using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; - - public class CompareFiles : Task + public class CompareFiles : Microsoft.Build.Utilities.Task { /// - /// One set of items to compare. + /// Gets or sets one set of items to compare. /// [Required] public ITaskItem[] OriginalItems { get; set; } /// - /// The other set of items to compare. + /// Gets or sets the other set of items to compare. /// [Required] public ITaskItem[] NewItems { get; set; } /// - /// Gets whether the items lists contain items that are identical going down the list. + /// Gets a value indicating whether the items lists contain items that are identical going down the list. /// [Output] public bool AreSame { get; private set; } /// - /// Same as , but opposite. + /// Gets a value indicating whether the item lists contain items that are not identical, going down the list. /// [Output] - public bool AreChanged { get { return !this.AreSame; } } + public bool AreChanged + { + get { return !this.AreSame; } + } + /// public override bool Execute() { this.AreSame = this.AreFilesIdentical(); return true; } + /// + /// Tests whether a file is up to date with respect to another, + /// based on existence, last write time and file size. + /// + /// The source path. + /// The dest path. + /// true if the files are the same; false if the files are different. + internal static bool FastFileEqualityCheck(string sourcePath, string destPath) + { + FileInfo sourceInfo = new FileInfo(sourcePath); + FileInfo destInfo = new FileInfo(destPath); + + if (sourceInfo.Exists ^ destInfo.Exists) + { + // Either the source file or the destination file is missing. + return false; + } + + if (!sourceInfo.Exists) + { + // Neither file exists. + return true; + } + + // We'll say the files are the same if their modification date and length are the same. + return + sourceInfo.LastWriteTimeUtc == destInfo.LastWriteTimeUtc && + sourceInfo.Length == destInfo.Length; + } + private bool AreFilesIdentical() { if (this.OriginalItems.Length != this.NewItems.Length) @@ -61,15 +98,27 @@ private bool AreFilesIdentical() private bool IsContentOfFilesTheSame(string file1, string file2) { // If exactly one file is missing, that's different. - if (File.Exists(file1) ^ File.Exists(file2)) return false; + if (File.Exists(file1) ^ File.Exists(file2)) + { + return false; + } + // If both are missing, that's the same. - if (!File.Exists(file1)) return true; + if (!File.Exists(file1)) + { + return true; + } + // If both are present, we need to do a content comparison. using (FileStream fileStream1 = File.OpenRead(file1)) { using (FileStream fileStream2 = File.OpenRead(file2)) { - if (fileStream1.Length != fileStream2.Length) return false; + if (fileStream1.Length != fileStream2.Length) + { + return false; + } + byte[] buffer1 = new byte[4096]; byte[] buffer2 = new byte[buffer1.Length]; int bytesRead; @@ -82,6 +131,7 @@ private bool IsContentOfFilesTheSame(string file1, string file2) // this is a sanity check. return false; } + for (int i = 0; i < bytesRead; i++) { if (buffer1[i] != buffer2[i]) @@ -89,41 +139,12 @@ private bool IsContentOfFilesTheSame(string file1, string file2) return false; } } - } while (bytesRead == buffer1.Length); + } + while (bytesRead == buffer1.Length); } } return true; } - - /// - /// Tests whether a file is up to date with respect to another, - /// based on existence, last write time and file size. - /// - /// The source path. - /// The dest path. - /// true if the files are the same; false if the files are different - internal static bool FastFileEqualityCheck(string sourcePath, string destPath) - { - FileInfo sourceInfo = new FileInfo(sourcePath); - FileInfo destInfo = new FileInfo(destPath); - - if (sourceInfo.Exists ^ destInfo.Exists) - { - // Either the source file or the destination file is missing. - return false; - } - - if (!sourceInfo.Exists) - { - // Neither file exists. - return true; - } - - // We'll say the files are the same if their modification date and length are the same. - return - sourceInfo.LastWriteTimeUtc == destInfo.LastWriteTimeUtc && - sourceInfo.Length == destInfo.Length; - } } } diff --git a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs index 7ba03cb6..9d3beb3e 100644 --- a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs +++ b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs @@ -1,24 +1,26 @@ -namespace MSBuildExtensionTask -{ - using System; - using System.IO; - using System.Linq; - using System.Reflection; -#if NETCOREAPP - using System.Runtime.Loader; -#endif - using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.IO; +using System.Linq; +using System.Reflection; #if NETCOREAPP - using Nerdbank.GitVersioning; +using System.Runtime.Loader; +using Nerdbank.GitVersioning; #endif +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; - public abstract class ContextAwareTask : Task +namespace MSBuildExtensionTask +{ + public abstract class ContextAwareTask : Microsoft.Build.Utilities.Task { protected virtual string ManagedDllDirectory => Path.GetDirectoryName(new Uri(this.GetType().GetTypeInfo().Assembly.CodeBase).LocalPath); protected virtual string UnmanagedDllDirectory => null; + /// public override bool Execute() { #if NETCOREAPP @@ -43,7 +45,7 @@ where outerProperty.SetMethod is not null && outerProperty.GetMethod is not null propertyPair.innerProperty.SetValue(innerTask, outerPropertyValue); } - var executeInnerMethod = innerTaskType.GetMethod(nameof(ExecuteInner), BindingFlags.Instance | BindingFlags.NonPublic); + MethodInfo executeInnerMethod = innerTaskType.GetMethod(nameof(this.ExecuteInner), BindingFlags.Instance | BindingFlags.NonPublic); bool result = (bool)executeInnerMethod.Invoke(innerTask, new object[0]); foreach (var propertyPair in outputPropertiesMap) diff --git a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+BlobHeader.cs b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+BlobHeader.cs index 912a0c3b..5dccb210 100644 --- a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+BlobHeader.cs +++ b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+BlobHeader.cs @@ -1,11 +1,14 @@ -namespace Nerdbank.GitVersioning.Tasks -{ - using System.Runtime.InteropServices; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; +namespace Nerdbank.GitVersioning.Tasks +{ /// /// The struct. /// - partial class CryptoBlobParser + internal partial class CryptoBlobParser { [StructLayout(LayoutKind.Sequential)] private struct BlobHeader @@ -16,17 +19,17 @@ private struct BlobHeader public byte Type; /// - /// Blob format version + /// Blob format version. /// public byte Version; /// - /// Must be 0 + /// Must be 0. /// public ushort Reserved; /// - /// Algorithm ID. Must be one of ALG_ID specified in wincrypto.h + /// Algorithm ID. Must be one of ALG_ID specified in wincrypto.h. /// public uint AlgId; } diff --git a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+RsaPubKey.cs b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+RsaPubKey.cs index 30f2067b..62b1908d 100644 --- a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+RsaPubKey.cs +++ b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+RsaPubKey.cs @@ -1,17 +1,20 @@ -namespace Nerdbank.GitVersioning.Tasks -{ - using System.Runtime.InteropServices; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; - partial class CryptoBlobParser +namespace Nerdbank.GitVersioning.Tasks +{ + internal partial class CryptoBlobParser { /// - /// RSAPUBKEY struct from wincrypt.h + /// RSAPUBKEY struct from wincrypt.h. /// [StructLayout(LayoutKind.Sequential)] private struct RsaPubKey { /// - /// Indicates RSA1 or RSA2 + /// Indicates RSA1 or RSA2. /// public uint Magic; @@ -21,7 +24,7 @@ private struct RsaPubKey public uint BitLen; /// - /// The public exponent + /// The public exponent. /// public uint PubExp; } diff --git a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+SnPublicKeyBlob.cs b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+SnPublicKeyBlob.cs index 2d3884a5..0c01fdd3 100644 --- a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+SnPublicKeyBlob.cs +++ b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser+SnPublicKeyBlob.cs @@ -1,39 +1,42 @@ -namespace Nerdbank.GitVersioning.Tasks -{ - using System.Runtime.InteropServices; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Runtime.InteropServices; +namespace Nerdbank.GitVersioning.Tasks +{ /// /// The struct. /// - partial class CryptoBlobParser + internal partial class CryptoBlobParser { /// /// The strong name public key blob binary format. /// - /// + /// [StructLayout(LayoutKind.Sequential, Pack = 1)] private unsafe struct SnPublicKeyBlob { /// - /// Signature algorithm ID + /// Signature algorithm ID. /// public uint SigAlgId; /// - /// Hash algorithm ID + /// Hash algorithm ID. /// public uint HashAlgId; /// - /// Size of public key data in bytes, not including the header + /// Size of public key data in bytes, not including the header. /// public uint PublicKeySize; /// - /// PublicKeySize bytes of public key data + /// PublicKeySize bytes of public key data. /// /// - /// Note: PublicKey is variable sized + /// Note: PublicKey is variable sized. /// public fixed byte PublicKey[1]; } diff --git a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser.cs b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser.cs index edac5036..b947c1e2 100644 --- a/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser.cs +++ b/src/Nerdbank.GitVersioning.Tasks/CryptoBlobParser.cs @@ -1,29 +1,31 @@ -// Liberally copied from (with slight modifications) https://github.com/dotnet/roslyn/blob/6181abfdf59da26da27f0dbedae2978df2f83768/src/Compilers/Core/Portable/StrongName/CryptoBlobParser.cs +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// Liberally copied from (with slight modifications) https://github.com/dotnet/roslyn/blob/6181abfdf59da26da27f0dbedae2978df2f83768/src/Compilers/Core/Portable/StrongName/CryptoBlobParser.cs // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See https://github.com/dotnet/roslyn/blob/6181abfdf59da26da27f0dbedae2978df2f83768/License.txt for license information. +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.InteropServices; +using System.Security.Cryptography; +using System.Text; +using Validation; namespace Nerdbank.GitVersioning.Tasks { - using System; - using System.Collections.Generic; - using System.IO; - using System.Runtime.InteropServices; - using System.Security.Cryptography; - using System.Text; - using Validation; - internal static partial class CryptoBlobParser { /// /// The size of a public key token, in bytes. /// - private const int SN_SIZEOF_TOKEN = 8; + private const int PublicKeyTokenSize = 8; /// /// The length of a SHA1 hash, in bytes. /// - private const int SHA1_HASH_SIZE = 20; + private const int Sha1HashSize = 20; - private const UInt32 RSA1 = 0x31415352; + private const uint RSA1 = 0x31415352; // From wincrypt.h private const byte PublicKeyBlobId = 0x06; @@ -31,7 +33,7 @@ internal static partial class CryptoBlobParser // In wincrypt.h both public and private key blobs start with a // PUBLICKEYSTRUC and RSAPUBKEY and then start the key data - private unsafe static readonly int s_offsetToKeyData = sizeof(BlobHeader) + sizeof(RsaPubKey); + private static unsafe readonly int OffsetToKeyData = sizeof(BlobHeader) + sizeof(RsaPubKey); /// /// Derives the public key token from a full public key. @@ -39,27 +41,27 @@ internal static partial class CryptoBlobParser /// The public key. /// The public key token. /// - /// Heavily inspired by https://github.com/dotnet/coreclr/blob/2efbb9282c059eb9742ba5a59b8a1d52ac4dfa4c/src/strongname/api/strongname.cpp#L270 + /// Heavily inspired by this code. /// internal static unsafe byte[] GetStrongNameTokenFromPublicKey(byte[] publicKey) { Requires.NotNull(publicKey, nameof(publicKey)); - byte[] strongNameToken = new byte[SN_SIZEOF_TOKEN]; + byte[] strongNameToken = new byte[PublicKeyTokenSize]; fixed (byte* publicKeyPtr = publicKey) { - //var publicKeyBlob = (SnPublicKeyBlob*)publicKeyPtr; + ////var publicKeyBlob = (SnPublicKeyBlob*)publicKeyPtr; using (var sha1 = SHA1.Create()) { byte[] hash = sha1.ComputeHash(publicKey); - int hashLenMinusTokenSize = SHA1_HASH_SIZE - SN_SIZEOF_TOKEN; + int hashLenMinusTokenSize = Sha1HashSize - PublicKeyTokenSize; // Take the last few bytes of the hash value for our token. (These are the // low order bytes from a network byte order point of view). Reverse the // order of these bytes in the output buffer to get host byte order. - for (int i = 0; i < SN_SIZEOF_TOKEN; i++) + for (int i = 0; i < PublicKeyTokenSize; i++) { - strongNameToken[SN_SIZEOF_TOKEN - (i + 1)] = hash[i + hashLenMinusTokenSize]; + strongNameToken[PublicKeyTokenSize - (i + 1)] = hash[i + hashLenMinusTokenSize]; } } } @@ -67,70 +69,39 @@ internal static unsafe byte[] GetStrongNameTokenFromPublicKey(byte[] publicKey) return strongNameToken; } - private static byte[] CreateSnPublicKeyBlob(BlobHeader header, RsaPubKey rsa, byte[] pubKeyData) - { - var snPubKey = new SnPublicKeyBlob() - { - SigAlgId = AlgorithmId.RsaSign, - HashAlgId = AlgorithmId.Sha, - PublicKeySize = (UInt32)(s_offsetToKeyData + pubKeyData.Length) - }; - - using (var ms = new MemoryStream(160)) - using (var binaryWriter = new BinaryWriter(ms)) - { - binaryWriter.Write(snPubKey.SigAlgId); - binaryWriter.Write(snPubKey.HashAlgId); - binaryWriter.Write(snPubKey.PublicKeySize); - - binaryWriter.Write(header.Type); - binaryWriter.Write(header.Version); - binaryWriter.Write(header.Reserved); - binaryWriter.Write(header.AlgId); - - binaryWriter.Write(rsa.Magic); - binaryWriter.Write(rsa.BitLen); - binaryWriter.Write(rsa.PubExp); - - binaryWriter.Write(pubKeyData); - - return ms.ToArray(); - } - } - - internal unsafe static bool TryGetPublicKeyFromPrivateKeyBlob(byte[] blob, out byte[] publicKey) + internal static unsafe bool TryGetPublicKeyFromPrivateKeyBlob(byte[] blob, out byte[] publicKey) { fixed (byte* blobPtr = blob) { var header = (BlobHeader*)blobPtr; var rsa = (RsaPubKey*)(blobPtr + sizeof(BlobHeader)); - var version = header->Version; - var modulusBitLength = rsa->BitLen; - var exponent = rsa->PubExp; - var modulus = new byte[modulusBitLength >> 3]; + byte version = header->Version; + uint modulusBitLength = rsa->BitLen; + uint exponent = rsa->PubExp; + byte[] modulus = new byte[modulusBitLength >> 3]; - if (blob.Length - s_offsetToKeyData < modulus.Length) + if (blob.Length - OffsetToKeyData < modulus.Length) { publicKey = null; return false; } - Marshal.Copy((IntPtr)(blobPtr + s_offsetToKeyData), modulus, 0, modulus.Length); + Marshal.Copy((IntPtr)(blobPtr + OffsetToKeyData), modulus, 0, modulus.Length); var newHeader = new BlobHeader() { Type = PublicKeyBlobId, Version = version, Reserved = 0, - AlgId = AlgorithmId.RsaSign + AlgId = AlgorithmId.RsaSign, }; var newRsaKey = new RsaPubKey() { Magic = RSA1, // Public key BitLen = modulusBitLength, - PubExp = exponent + PubExp = exponent, }; publicKey = CreateSnPublicKeyBlob(newHeader, newRsaKey, modulus); @@ -138,27 +109,58 @@ internal unsafe static bool TryGetPublicKeyFromPrivateKeyBlob(byte[] blob, out b } } + private static byte[] CreateSnPublicKeyBlob(BlobHeader header, RsaPubKey rsa, byte[] pubKeyData) + { + var snPubKey = new SnPublicKeyBlob() + { + SigAlgId = AlgorithmId.RsaSign, + HashAlgId = AlgorithmId.Sha, + PublicKeySize = (uint)(OffsetToKeyData + pubKeyData.Length), + }; + + using (var ms = new MemoryStream(160)) + using (var binaryWriter = new BinaryWriter(ms)) + { + binaryWriter.Write(snPubKey.SigAlgId); + binaryWriter.Write(snPubKey.HashAlgId); + binaryWriter.Write(snPubKey.PublicKeySize); + + binaryWriter.Write(header.Type); + binaryWriter.Write(header.Version); + binaryWriter.Write(header.Reserved); + binaryWriter.Write(header.AlgId); + + binaryWriter.Write(rsa.Magic); + binaryWriter.Write(rsa.BitLen); + binaryWriter.Write(rsa.PubExp); + + binaryWriter.Write(pubKeyData); + + return ms.ToArray(); + } + } + private struct AlgorithmId { + public const int RsaSign = 0x00002400; + public const int Sha = 0x00008004; + // From wincrypt.h private const int AlgorithmClassOffset = 13; private const int AlgorithmClassMask = 0x7; private const int AlgorithmSubIdOffset = 0; private const int AlgorithmSubIdMask = 0x1ff; - private readonly uint _flags; - - public const int RsaSign = 0x00002400; - public const int Sha = 0x00008004; + private readonly uint flags; - public bool IsSet + public AlgorithmId(uint flags) { - get { return this._flags != 0; } + this.flags = flags; } - public AlgorithmId(uint flags) + public bool IsSet { - this._flags = flags; + get { return this.flags != 0; } } } } diff --git a/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs b/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs index 77b79342..816951e1 100644 --- a/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs +++ b/src/Nerdbank.GitVersioning.Tasks/GetBuildVersion.cs @@ -1,16 +1,19 @@ -namespace Nerdbank.GitVersioning.Tasks +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Reflection; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; +using MSBuildExtensionTask; +using Validation; + +namespace Nerdbank.GitVersioning.Tasks { - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using System.Linq; - using System.Reflection; - using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; - using MSBuildExtensionTask; - using Validation; - public class GetBuildVersion : ContextAwareTask { /// @@ -83,7 +86,7 @@ public GetBuildVersion() public ITaskItem[] OutputProperties { get; set; } /// - /// Gets or sets a value indicating whether the project is building + /// Gets a value indicating whether the project is building /// in PublicRelease mode. /// [Output] @@ -200,8 +203,10 @@ public GetBuildVersion() [Output] public ITaskItem[] CloudBuildVersionVars { get; private set; } + /// protected override string UnmanagedDllDirectory => LibGit2.LibGit2GitExtensions.FindLibGit2NativeBinaries(this.TargetsPath); + /// protected override bool ExecuteInner() { try @@ -209,11 +214,9 @@ protected override bool ExecuteInner() if (!string.IsNullOrEmpty(this.ProjectPathRelativeToGitRepoRoot)) { Requires.Argument(!Path.IsPathRooted(this.ProjectPathRelativeToGitRepoRoot), nameof(this.ProjectPathRelativeToGitRepoRoot), "Path must be relative."); - Requires.Argument(!( - this.ProjectPathRelativeToGitRepoRoot.Contains(".." + Path.DirectorySeparatorChar) || - this.ProjectPathRelativeToGitRepoRoot.Contains(".." + Path.AltDirectorySeparatorChar)), - nameof(this.ProjectPathRelativeToGitRepoRoot), - "Path must not use ..\\"); + bool containsDotDotSlash = this.ProjectPathRelativeToGitRepoRoot.Contains(".." + Path.DirectorySeparatorChar) || + this.ProjectPathRelativeToGitRepoRoot.Contains(".." + Path.AltDirectorySeparatorChar); + Requires.Argument(!containsDotDotSlash, nameof(this.ProjectPathRelativeToGitRepoRoot), "Path must not use ..\\"); } bool useLibGit2 = false; @@ -225,8 +228,8 @@ protected override bool ExecuteInner() throw new ArgumentException("GitEngine property must be set to either \"Managed\" or \"LibGit2\" or left empty."); } - var cloudBuild = CloudBuild.Active; - var overrideBuildNumberOffset = (this.OverrideBuildNumberOffset == int.MaxValue) ? (int?)null : this.OverrideBuildNumberOffset; + ICloudBuild cloudBuild = CloudBuild.Active; + int? overrideBuildNumberOffset = (this.OverrideBuildNumberOffset == int.MaxValue) ? (int?)null : this.OverrideBuildNumberOffset; string projectDirectory = this.ProjectPathRelativeToGitRepoRoot is object && this.GitRepoRoot is object ? Path.Combine(this.GitRepoRoot, this.ProjectPathRelativeToGitRepoRoot) : this.ProjectDirectory; @@ -276,7 +279,7 @@ protected override bool ExecuteInner() if (oracle.CloudBuildAllVarsEnabled) { - var allVariables = oracle.CloudBuildAllVars + IEnumerable allVariables = oracle.CloudBuildAllVars .Select(item => new TaskItem(item.Key, new Dictionary { { "Value", item.Value } })); if (cloudBuildVersionVars is not null) diff --git a/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs b/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs index 609329e9..c0ec84e1 100644 --- a/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs +++ b/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs @@ -1,3 +1,6 @@ +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + // This code originally copied from https://github.com/dotnet/sourcelink/tree/c092238370e0437eb95722f28c79273244dc7f1a/src/Microsoft.Build.Tasks.Git // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See license information at https://github.com/dotnet/sourcelink/blob/c092238370e0437eb95722f28c79273244dc7f1a/License.txt. #if NETCOREAPP @@ -13,13 +16,14 @@ namespace Nerdbank.GitVersioning { public class GitLoaderContext : AssemblyLoadContext { - public static readonly GitLoaderContext Instance = new GitLoaderContext(); - public const string RuntimePath = "./runtimes"; + public static readonly GitLoaderContext Instance = new GitLoaderContext(); + + /// protected override Assembly Load(AssemblyName assemblyName) { - var path = Path.Combine(Path.GetDirectoryName(typeof(GitLoaderContext).Assembly.Location), assemblyName.Name + ".dll"); + string path = Path.Combine(Path.GetDirectoryName(typeof(GitLoaderContext).Assembly.Location), assemblyName.Name + ".dll"); return File.Exists(path) ? this.LoadFromAssemblyPath(path) : Default.LoadFromAssemblyName(assemblyName); diff --git a/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs index 8153a545..08fd4669 100644 --- a/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs @@ -1,17 +1,22 @@ -namespace Nerdbank.GitVersioning.Tasks +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; + +namespace Nerdbank.GitVersioning.Tasks { - using System; - using System.Collections.Generic; - using System.Globalization; - using System.IO; - using System.Text; - using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; - - public class NativeVersionInfo : Task + public class NativeVersionInfo : Microsoft.Build.Utilities.Task { +#pragma warning disable SA1310 // Field names should not contain underscore private const int VFT_APP = 0x1; private const int VFT_DLL = 0x2; +#pragma warning restore SA1310 // Field names should not contain underscore private const string FileHeaderComment = @"------------------------------------------------------------------------------ @@ -103,6 +108,7 @@ BLOCK NBGV_VERSION_BLOCK public string TargetFileName { get; set; } + /// public override bool Execute() { this.generator = this.CreateGenerator(); @@ -130,9 +136,14 @@ public override bool Execute() return !this.Log.HasLoggedErrors; } + private static string DefaultIfEmpty(string value, string defaultValue) + { + return string.IsNullOrWhiteSpace(value) ? defaultValue : value; + } + private void CreateDefines() { - var fileType = 0; + int fileType = 0; switch (this.ConfigurationType.ToUpperInvariant()) { @@ -149,18 +160,18 @@ private void CreateDefines() return; } - if (!Version.TryParse(this.AssemblyFileVersion, out var fileVersion)) + if (!Version.TryParse(this.AssemblyFileVersion, out Version fileVersion)) { this.Log.LogError("Cannot process AssemblyFileVersion '{0}' into a valid four part version.", this.AssemblyFileVersion); return; } - if (!Version.TryParse(this.AssemblyVersion, out var productVersion)) + if (!Version.TryParse(this.AssemblyVersion, out Version productVersion)) { productVersion = fileVersion; } - var lcid = 0; + int lcid = 0; if (!string.IsNullOrWhiteSpace(this.AssemblyLanguage)) { @@ -184,7 +195,7 @@ private void CreateDefines() } } - if (!int.TryParse(this.AssemblyCodepage, out var codepage)) + if (!int.TryParse(this.AssemblyCodepage, out int codepage)) { codepage = 0; } @@ -218,12 +229,12 @@ private void CreateDefines() { "NBGV_VERSION_BLOCK", (lcid << 16 | codepage).ToString("X8") }, }; - foreach (var pair in numericFields) + foreach (KeyValuePair pair in numericFields) { this.generator.AddDefine(pair.Key, pair.Value); } - foreach (var pair in stringFields) + foreach (KeyValuePair pair in stringFields) { if (!string.IsNullOrWhiteSpace(pair.Value)) { @@ -251,13 +262,13 @@ private CodeGenerator CreateGenerator() private class CodeGenerator { - protected readonly StringBuilder codeBuilder; - internal CodeGenerator() { - this.codeBuilder = new StringBuilder(); + this.CodeBuilder = new StringBuilder(); } + protected StringBuilder CodeBuilder { get; } + internal void AddComment(string comment) { this.AddCodeComment(comment, "//"); @@ -265,35 +276,35 @@ internal void AddComment(string comment) internal void StartFile() { - this.codeBuilder.AppendLine("#pragma once"); + this.CodeBuilder.AppendLine("#pragma once"); } internal void AddContent(string content) { - this.codeBuilder.AppendLine(content); + this.CodeBuilder.AppendLine(content); } internal void AddDefine(string name, int value) { - this.codeBuilder.AppendLine($"#define {name} {value}"); + this.CodeBuilder.AppendLine($"#define {name} {value}"); } internal void AddDefine(string name, string value) { - var escapedValue = value.Replace("\\", "\\\\"); + string escapedValue = value.Replace("\\", "\\\\"); - this.codeBuilder.AppendLine($"#define {name} NBGV_VERSION_STRING(\"{escapedValue}\")"); + this.CodeBuilder.AppendLine($"#define {name} NBGV_VERSION_STRING(\"{escapedValue}\")"); } internal void EndFile() { } - internal string GetCode() => this.codeBuilder.ToString(); + internal string GetCode() => this.CodeBuilder.ToString(); internal void AddBlankLine() { - this.codeBuilder.AppendLine(); + this.CodeBuilder.AppendLine(); } protected void AddCodeComment(string comment, string token) @@ -302,15 +313,10 @@ protected void AddCodeComment(string comment, string token) string line; while ((line = sr.ReadLine()) is not null) { - this.codeBuilder.Append(token); - this.codeBuilder.AppendLine(line); + this.CodeBuilder.Append(token); + this.CodeBuilder.AppendLine(line); } } } - - private static string DefaultIfEmpty(string value, string defaultValue) - { - return string.IsNullOrWhiteSpace(value) ? defaultValue : value; - } } } diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj index da481512..b03f89ed 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj @@ -31,16 +31,7 @@ - + build\$(BuildSubDir) @@ -78,7 +69,7 @@ - + diff --git a/src/Nerdbank.GitVersioning.Tasks/Properties/AssemblyInfo.cs b/src/Nerdbank.GitVersioning.Tasks/Properties/AssemblyInfo.cs deleted file mode 100644 index 6ca0b3d2..00000000 --- a/src/Nerdbank.GitVersioning.Tasks/Properties/AssemblyInfo.cs +++ /dev/null @@ -1,7 +0,0 @@ -using System.Reflection; -using System.Runtime.InteropServices; - -[assembly: AssemblyCopyright("Copyright © 2015")] -[assembly: AssemblyTrademark("")] -[assembly: AssemblyCulture("")] -[assembly: ComVisible(false)] diff --git a/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs b/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs index b721152c..6480f605 100644 --- a/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs +++ b/src/Nerdbank.GitVersioning.Tasks/SetCloudBuildVariables.cs @@ -1,14 +1,17 @@ -namespace Nerdbank.GitVersioning.Tasks -{ - using System; - using System.Collections.Generic; - using System.IO; - using System.Linq; - using System.Text; - using Microsoft.Build.Framework; - using Microsoft.Build.Utilities; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using Microsoft.Build.Framework; +using Microsoft.Build.Utilities; - public class SetCloudBuildVariables : Task +namespace Nerdbank.GitVersioning.Tasks +{ + public class SetCloudBuildVariables : Microsoft.Build.Utilities.Task { public ITaskItem[] CloudBuildVersionVars { get; set; } @@ -17,9 +20,10 @@ public class SetCloudBuildVariables : Task public string CloudBuildNumber { get; set; } + /// public override bool Execute() { - var cloudBuild = CloudBuild.Active; + ICloudBuild cloudBuild = CloudBuild.Active; if (cloudBuild is not null) { var envVars = new Dictionary(StringComparer.OrdinalIgnoreCase); @@ -35,8 +39,8 @@ public override bool Execute() if (!string.IsNullOrWhiteSpace(this.CloudBuildNumber)) { - var newVars = cloudBuild.SetCloudBuildNumber(this.CloudBuildNumber, stdout, stderr); - foreach (var item in newVars) + IReadOnlyDictionary newVars = cloudBuild.SetCloudBuildNumber(this.CloudBuildNumber, stdout, stderr); + foreach (KeyValuePair item in newVars) { envVars[item.Key] = item.Value; } @@ -44,10 +48,10 @@ public override bool Execute() if (this.CloudBuildVersionVars is not null) { - foreach (var variable in this.CloudBuildVersionVars) + foreach (ITaskItem variable in this.CloudBuildVersionVars) { - var newVars = cloudBuild.SetCloudBuildVariable(variable.ItemSpec, variable.GetMetadata("Value"), stdout, stderr); - foreach (var item in newVars) + IReadOnlyDictionary newVars = cloudBuild.SetCloudBuildVariable(variable.ItemSpec, variable.GetMetadata("Value"), stdout, stderr); + foreach (KeyValuePair item in newVars) { envVars[item.Key] = item.Value; } @@ -58,7 +62,7 @@ public override bool Execute() let metadata = new Dictionary { { "Value", envVar.Value } } select new TaskItem(envVar.Key, metadata)).ToArray(); - foreach (var item in envVars) + foreach (KeyValuePair item in envVars) { Environment.SetEnvironmentVariable(item.Key, item.Value); } diff --git a/src/Shared/SemanticVersionExtensions.cs b/src/Shared/SemanticVersionExtensions.cs index 4f58a58b..95b87467 100644 --- a/src/Shared/SemanticVersionExtensions.cs +++ b/src/Shared/SemanticVersionExtensions.cs @@ -1,144 +1,151 @@ -namespace Nerdbank.GitVersioning +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Globalization; +using System.Text.RegularExpressions; +using Validation; + +namespace Nerdbank.GitVersioning; + +/// +/// Extension methods for . +/// +internal static class SemanticVersionExtensions { - using System; - using System.Globalization; - using System.Text.RegularExpressions; - using Validation; + /// + /// A regex that matches on numeric identifiers for prerelease or build metadata. + /// + private static readonly Regex NumericIdentifierRegex = new Regex(@"(? - /// Extension methods for + /// Gets a new semantic with the specified version component (major/minor) incremented. /// - internal static class SemanticVersionExtensions + /// The version to increment. + /// Specifies whether to increment the major or minor version. + /// Returns a new object with either the major or minor version incremented by 1. + internal static SemanticVersion Increment(this SemanticVersion currentVersion, VersionOptions.ReleaseVersionIncrement increment) { - /// - /// A regex that matches on numeric identifiers for prerelease or build metadata. - /// - private static readonly Regex NumericIdentifierRegex = new Regex(@"(? - /// Gets a new semantic with the specified version component (major/minor) incremented. - /// - /// The version to increment. - /// Specifies whether to increment the major or minor version. - /// Returns a new object with either the major or minor version incremented by 1. - internal static SemanticVersion Increment(this SemanticVersion currentVersion, VersionOptions.ReleaseVersionIncrement increment) + Requires.NotNull(currentVersion, nameof(currentVersion)); + Requires.Argument( + increment != VersionOptions.ReleaseVersionIncrement.Build || currentVersion.Version.Build >= 0, + nameof(increment), + "Cannot apply version increment '{0}' to version '{1}'", + increment, + currentVersion); + + int major = currentVersion.Version.Major; + int minor = currentVersion.Version.Minor; + int build = currentVersion.Version.Build; + + switch (increment) { - Requires.NotNull(currentVersion, nameof(currentVersion)); - Requires.Argument(increment != VersionOptions.ReleaseVersionIncrement.Build || currentVersion.Version.Build >= 0, nameof(increment), - "Cannot apply version increment '{0}' to version '{1}'", increment, currentVersion); - - var major = currentVersion.Version.Major; - var minor = currentVersion.Version.Minor; - var build = currentVersion.Version.Build; - - switch (increment) - { - case VersionOptions.ReleaseVersionIncrement.Major: - major += 1; - minor = 0; - build = 0; - break; - case VersionOptions.ReleaseVersionIncrement.Minor: - minor += 1; - build = 0; - break; - - case VersionOptions.ReleaseVersionIncrement.Build: - build += 1; - break; - - default: - throw new ArgumentOutOfRangeException(nameof(increment)); - } - - // use the appropriate constructor for the new version object - // depending on whether the current versions has 2, 3 or 4 segments - Version newVersion; - if (currentVersion.Version.Build >= 0 && currentVersion.Version.Revision > 0) - { - // 4 segment version - newVersion = new Version(major, minor, build, 0); - } - else if (currentVersion.Version.Build >= 0) - { - // 3 segment version - newVersion = new Version(major, minor, build); - } - else - { - // 2 segment version - newVersion = new Version(major, minor); - } - - return new SemanticVersion(newVersion, currentVersion.Prerelease, currentVersion.BuildMetadata); + case VersionOptions.ReleaseVersionIncrement.Major: + major += 1; + minor = 0; + build = 0; + break; + case VersionOptions.ReleaseVersionIncrement.Minor: + minor += 1; + build = 0; + break; + + case VersionOptions.ReleaseVersionIncrement.Build: + build += 1; + break; + + default: + throw new ArgumentOutOfRangeException(nameof(increment)); } - /// - /// Sets the first prerelease tag of the specified semantic version to the specified value. - /// - /// The version which's prerelease tag to modify. - /// The new prerelease tag. The leading hyphen may be specified or omitted. - /// Returns a new instance of with the updated prerelease tag - internal static SemanticVersion SetFirstPrereleaseTag(this SemanticVersion version, string newFirstTag) + // use the appropriate constructor for the new version object + // depending on whether the current versions has 2, 3 or 4 segments + Version newVersion; + if (currentVersion.Version.Build >= 0 && currentVersion.Version.Revision > 0) + { + // 4 segment version + newVersion = new Version(major, minor, build, 0); + } + else if (currentVersion.Version.Build >= 0) + { + // 3 segment version + newVersion = new Version(major, minor, build); + } + else { - Requires.NotNull(version, nameof(version)); - - newFirstTag = newFirstTag ?? ""; - - string preRelease; - if (string.IsNullOrEmpty(version.Prerelease)) - { - preRelease = newFirstTag; - } - else if (version.Prerelease.Contains(".")) - { - preRelease = newFirstTag + version.Prerelease.Substring(version.Prerelease.IndexOf(".")); - } - else - { - preRelease = newFirstTag; - } - - if (!string.IsNullOrEmpty(preRelease) && !preRelease.StartsWith("-")) - preRelease = "-" + preRelease; - - return new SemanticVersion(version.Version, preRelease, version.BuildMetadata); + // 2 segment version + newVersion = new Version(major, minor); } - /// - /// Removes all prerelease tags from the semantic version. - /// - /// The version to remove the prerelease tags from. - /// Returns a new instance which does not contain any prerelease tags. - internal static SemanticVersion WithoutPrepreleaseTags(this SemanticVersion version) + return new SemanticVersion(newVersion, currentVersion.Prerelease, currentVersion.BuildMetadata); + } + + /// + /// Sets the first prerelease tag of the specified semantic version to the specified value. + /// + /// The version which's prerelease tag to modify. + /// The new prerelease tag. The leading hyphen may be specified or omitted. + /// Returns a new instance of with the updated prerelease tag. + internal static SemanticVersion SetFirstPrereleaseTag(this SemanticVersion version, string newFirstTag) + { + Requires.NotNull(version, nameof(version)); + + newFirstTag = newFirstTag ?? string.Empty; + + string preRelease; + if (string.IsNullOrEmpty(version.Prerelease)) + { + preRelease = newFirstTag; + } + else if (version.Prerelease.Contains(".")) { - return new SemanticVersion(version.Version, null, version.BuildMetadata); + preRelease = newFirstTag + version.Prerelease.Substring(version.Prerelease.IndexOf(".")); + } + else + { + preRelease = newFirstTag; } - /// - /// Converts a semver 2 compliant "-beta.5" prerelease tag to a semver 1 compatible one. - /// - /// The semver 2 prerelease tag, including its leading hyphen. - /// The minimum number of digits to use for any numeric identifier. - /// A semver 1 compliant prerelease tag. For example "-beta-0005". - internal static string MakePrereleaseSemVer1Compliant(string prerelease, int paddingSize) + if (!string.IsNullOrEmpty(preRelease) && !preRelease.StartsWith("-")) { - if (string.IsNullOrEmpty(prerelease)) - { - return prerelease; - } + preRelease = "-" + preRelease; + } - string paddingFormatter = "{0:" + new string('0', paddingSize) + "}"; + return new SemanticVersion(version.Version, preRelease, version.BuildMetadata); + } - string semver1 = prerelease; + /// + /// Removes all prerelease tags from the semantic version. + /// + /// The version to remove the prerelease tags from. + /// Returns a new instance which does not contain any prerelease tags. + internal static SemanticVersion WithoutPrepreleaseTags(this SemanticVersion version) + { + return new SemanticVersion(version.Version, null, version.BuildMetadata); + } - // Identify numeric identifiers and pad them. - Assumes.True(prerelease.StartsWith("-")); - semver1 = "-" + NumericIdentifierRegex.Replace(semver1.Substring(1), m => string.Format(CultureInfo.InvariantCulture, paddingFormatter, int.Parse(m.Groups[1].Value))); + /// + /// Converts a semver 2 compliant "-beta.5" prerelease tag to a semver 1 compatible one. + /// + /// The semver 2 prerelease tag, including its leading hyphen. + /// The minimum number of digits to use for any numeric identifier. + /// A semver 1 compliant prerelease tag. For example "-beta-0005". + internal static string MakePrereleaseSemVer1Compliant(string prerelease, int paddingSize) + { + if (string.IsNullOrEmpty(prerelease)) + { + return prerelease; + } - semver1 = semver1.Replace('.', '-'); + string paddingFormatter = "{0:" + new string('0', paddingSize) + "}"; - return semver1; - } + string semver1 = prerelease; + + // Identify numeric identifiers and pad them. + Assumes.True(prerelease.StartsWith("-")); + semver1 = "-" + NumericIdentifierRegex.Replace(semver1.Substring(1), m => string.Format(CultureInfo.InvariantCulture, paddingFormatter, int.Parse(m.Groups[1].Value))); + + semver1 = semver1.Replace('.', '-'); + + return semver1; } } diff --git a/src/Shared/Utilities.cs b/src/Shared/Utilities.cs index c20f34a0..8207acdf 100644 --- a/src/Shared/Utilities.cs +++ b/src/Shared/Utilities.cs @@ -1,31 +1,29 @@ -using System; -using System.IO; -using System.Threading; -using System.Threading.Tasks; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using Validation; -namespace Nerdbank.GitVersioning +namespace Nerdbank.GitVersioning; + +internal static class Utilities { - internal static class Utilities + private const int ProcessCannotAccessFileHR = unchecked((int)0x80070020); + + internal static void FileOperationWithRetry(Action operation) { - private const int ProcessCannotAccessFileHR = unchecked((int)0x80070020); + Requires.NotNull(operation, nameof(operation)); - internal static void FileOperationWithRetry(Action operation) + for (int retriesLeft = 6; retriesLeft > 0; retriesLeft--) { - Requires.NotNull(operation, nameof(operation)); - - for (int retriesLeft = 6; retriesLeft > 0; retriesLeft--) + try + { + operation(); + break; + } + catch (IOException ex) when (ex.HResult == ProcessCannotAccessFileHR && retriesLeft > 0) { - try - { - operation(); - break; - } - catch (IOException ex) when (ex.HResult == ProcessCannotAccessFileHR && retriesLeft > 0) - { - Task.Delay(100).Wait(); - continue; - } + Task.Delay(100).Wait(); + continue; } } } diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 43da7fa8..fd4407b0 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -1,28 +1,31 @@ +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.CommandLine; +using System.CommandLine.Builder; +using System.CommandLine.Invocation; +using System.CommandLine.Parsing; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Build.Construction; +using Nerdbank.GitVersioning.Commands; +using Nerdbank.GitVersioning.LibGit2; +using Newtonsoft.Json; +using NuGet.Common; +using NuGet.Configuration; +using NuGet.PackageManagement; +using NuGet.Protocol; +using NuGet.Protocol.Core.Types; +using NuGet.Resolver; +using Validation; + namespace Nerdbank.GitVersioning.Tool { - using System; - using System.Collections.Generic; - using System.CommandLine; - using System.CommandLine.Builder; - using System.CommandLine.Invocation; - using System.CommandLine.Parsing; - using System.IO; - using System.Linq; - using System.Reflection; - using System.Threading; - using System.Threading.Tasks; - using Microsoft.Build.Construction; - using Nerdbank.GitVersioning.Commands; - using Nerdbank.GitVersioning.LibGit2; - using Newtonsoft.Json; - using NuGet.Common; - using NuGet.Configuration; - using NuGet.PackageManagement; - using NuGet.Protocol; - using NuGet.Protocol.Core.Types; - using NuGet.Resolver; - using Validation; - internal class Program { private const string DefaultVersionSpec = "1.0-beta"; @@ -35,6 +38,9 @@ internal class Program private const BindingFlags CaseInsensitiveFlags = BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.IgnoreCase; + private static readonly string[] SupportedFormats = new[] { "text", "json" }; + private static ExitCodes exitCode; + private enum ExitCodes { OK, @@ -64,11 +70,10 @@ private enum ExitCodes InternalError, } - private static readonly string[] SupportedFormats = new[] { "text", "json" }; - private static ExitCodes exitCode; - private static bool AlwaysUseLibGit2 => string.Equals(Environment.GetEnvironmentVariable("NBGV_GitEngine"), "LibGit2", StringComparison.Ordinal); + private static string[] CloudProviderNames => CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name).ToArray(); + public static int Main(string[] args) { string thisAssemblyPath = new Uri(typeof(Program).GetTypeInfo().Assembly.CodeBase).LocalPath; @@ -77,7 +82,7 @@ public static int Main(string[] args) Type innerProgramType = inContextAssembly.GetType(typeof(Program).FullName); object innerProgram = Activator.CreateInstance(innerProgramType); - var mainInnerMethod = innerProgramType.GetMethod(nameof(MainInner), BindingFlags.Static | BindingFlags.NonPublic); + MethodInfo mainInnerMethod = innerProgramType.GetMethod(nameof(MainInner), BindingFlags.Static | BindingFlags.NonPublic); int result = (int)mainInnerMethod.Invoke(null, new object[] { args }); return result; } @@ -199,23 +204,25 @@ private static Parser BuildCommandLine() return new CommandLineBuilder(root) .UseDefaults() - .UseMiddleware(context => - { - // System.CommandLine 0.1 parsed arguments after optional --. Restore that behavior for compatibility. - // TODO: Remove this middleware when https://github.com/dotnet/command-line-api/issues/1238 is resolved. - if (context.ParseResult.UnparsedTokens.Count > 0) + .UseMiddleware( + context => { - var arguments = context.ParseResult.CommandResult.Command.Arguments; - if (arguments.Count() == context.ParseResult.UnparsedTokens.Count) + // System.CommandLine 0.1 parsed arguments after optional --. Restore that behavior for compatibility. + // TODO: Remove this middleware when https://github.com/dotnet/command-line-api/issues/1238 is resolved. + if (context.ParseResult.UnparsedTokens.Count > 0) { - context.ParseResult = context.Parser.Parse( - context.ParseResult.Tokens - .Where(token => token.Type != TokenType.EndOfArguments) - .Select(token => token.Value) - .ToArray()); + IEnumerable arguments = context.ParseResult.CommandResult.Command.Arguments; + if (arguments.Count() == context.ParseResult.UnparsedTokens.Count) + { + context.ParseResult = context.Parser.Parse( + context.ParseResult.Tokens + .Where(token => token.Type != TokenType.EndOfArguments) + .Select(token => token.Value) + .ToArray()); + } } - } - }, (MiddlewareOrder)(-3000)) // MiddlewareOrderInternal.ExceptionHandler so [parse] directive is accurate. + }, + (MiddlewareOrder)(-3000)) // MiddlewareOrderInternal.ExceptionHandler so [parse] directive is accurate. .UseExceptionHandler((ex, context) => PrintException(ex, context)) .Build(); } @@ -237,7 +244,7 @@ private static int MainInner(string[] args) { try { - var parser = BuildCommandLine(); + Parser parser = BuildCommandLine(); exitCode = (ExitCodes)parser.Invoke(args); } catch (GitException ex) @@ -245,7 +252,7 @@ private static int MainInner(string[] args) Console.Error.WriteLine($"ERROR: {ex.Message}"); exitCode = ex.ErrorCode switch { - GitException.ErrorCodes.ObjectNotFound when ex.iSShallowClone => ExitCodes.ShallowClone, + GitException.ErrorCodes.ObjectNotFound when ex.IsShallowClone => ExitCodes.ShallowClone, _ => ExitCodes.InternalError, }; } @@ -255,7 +262,7 @@ private static int MainInner(string[] args) private static int OnInstallCommand(string path, string version, IReadOnlyList source) { - if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out var semver)) + if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out SemanticVersion semver)) { Console.Error.WriteLine($"\"{version}\" is not a semver-compliant version spec."); return (int)ExitCodes.InvalidVersionSpec; @@ -296,12 +303,12 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList to validate argument during parsing. - if (!Uri.TryCreate(src, UriKind.Absolute, out var _)) + if (!Uri.TryCreate(src, UriKind.Absolute, out Uri _)) { Console.Error.WriteLine($"\"{src}\" is not a valid NuGet package source."); return (int)ExitCodes.InvalidNuGetPackageSource; @@ -345,7 +352,7 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList i.ItemType == PackageReferenceItemType && i.Include == PackageId); + ProjectItemElement item = propsFile.Items.FirstOrDefault(i => i.ItemType == PackageReferenceItemType && i.Include == PackageId); if (item is null) { @@ -355,12 +362,12 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList { { PrivateAssetsMetadataName, "all" }, - { VersionMetadataName, packageVersion } + { VersionMetadataName, packageVersion }, }); } else { - var versionMetadata = item.Metadata.Single(m => m.Name == VersionMetadataName); + ProjectMetadataElement versionMetadata = item.Metadata.Single(m => m.Name == VersionMetadataName); versionMetadata.Value = packageVersion; } @@ -442,7 +449,7 @@ private static int OnGetVersionCommand(string project, IReadOnlyList met return (int)ExitCodes.UnsupportedFormat; } - var property = oracle.GetType().GetProperty(variable, CaseInsensitiveFlags); + PropertyInfo property = oracle.GetType().GetProperty(variable, CaseInsensitiveFlags); if (property is null) { Console.Error.WriteLine("Variable \"{0}\" not a version property.", variable); @@ -457,7 +464,7 @@ private static int OnGetVersionCommand(string project, IReadOnlyList met private static int OnSetVersionCommand(string project, string version) { - if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out var semver)) + if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out SemanticVersion semver)) { Console.Error.WriteLine($"\"{version}\" is not a semver-compliant version spec."); return (int)ExitCodes.InvalidVersionSpec; @@ -470,7 +477,7 @@ private static int OnSetVersionCommand(string project, string version) string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); using var context = GitContext.Create(searchPath, writable: true); - var existingOptions = context.VersionFile.GetVersion(out string actualDirectory); + VersionOptions existingOptions = context.VersionFile.GetVersion(out string actualDirectory); string versionJsonPath; if (existingOptions is not null) { @@ -516,7 +523,7 @@ private static int OnTagCommand(string project, string versionOrRef) return (int)ExitCodes.NoGitRepo; } - var repository = context.Repository; + LibGit2Sharp.Repository repository = context.Repository; if (!context.TrySelectCommit(versionOrRef)) { if (!Version.TryParse(versionOrRef, out Version parsedVersion)) @@ -593,7 +600,7 @@ private static int OnGetCommitsCommand(string project, bool quiet, string versio return (int)ExitCodes.NoGitRepo; } - var candidateCommits = LibGit2GitExtensions.GetCommitsFromVersion(context, parsedVersion); + IEnumerable candidateCommits = LibGit2GitExtensions.GetCommitsFromVersion(context, parsedVersion); PrintCommits(quiet, context, candidateCommits); return (int)ExitCodes.OK; @@ -638,6 +645,7 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata catch (CloudCommand.CloudCommandException ex) { Console.Error.WriteLine(ex.Message); + // map error codes switch (ex.Error) { @@ -654,7 +662,6 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata } return (int)ExitCodes.OK; - } private static int OnPrepareReleaseCommand(string project, string nextVersion, string versionIncrement, string format, string tag) @@ -678,11 +685,12 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s VersionOptions.ReleaseVersionIncrement? versionIncrementParsed = default; if (!string.IsNullOrEmpty(versionIncrement)) { - if (!Enum.TryParse(versionIncrement, true, out var parsed)) + if (!Enum.TryParse(versionIncrement, true, out VersionOptions.ReleaseVersionIncrement parsed)) { Console.Error.WriteLine($"\"{versionIncrement}\" is not a valid version increment"); return (int)ExitCodes.InvalidVersionIncrement; } + versionIncrementParsed = parsed; } @@ -702,6 +710,7 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s { format = DefaultOutputFormat; } + if (!Enum.TryParse(format, true, out ReleaseManager.ReleaseManagerOutputMode outputMode)) { Console.Error.WriteLine($"Unsupported format: {format}"); @@ -748,7 +757,7 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s private static async Task GetLatestPackageVersionAsync(string packageId, string root, IReadOnlyList sources, CancellationToken cancellationToken = default) { - var settings = Settings.LoadDefaultSettings(root); + ISettings settings = Settings.LoadDefaultSettings(root); var providers = new List>(); providers.AddRange(Repository.Provider.GetCoreV3()); // Add v3 API support @@ -757,12 +766,12 @@ private static async Task GetLatestPackageVersionAsync(string packageId, // Select package sources based on NuGet.Config files or given options, as 'nuget.exe restore' command does // See also 'DownloadCommandBase.GetPackageSources(ISettings)' at https://github.com/NuGet/NuGet.Client/blob/dev/src/NuGet.Clients/NuGet.CommandLine/Commands/DownloadCommandBase.cs - var availableSources = sourceRepositoryProvider.PackageSourceProvider.LoadPackageSources().Where(s => s.IsEnabled); + IEnumerable availableSources = sourceRepositoryProvider.PackageSourceProvider.LoadPackageSources().Where(s => s.IsEnabled); var packageSources = new List(); - foreach (var source in sources) + foreach (string source in sources) { - var resolvedSource = availableSources.FirstOrDefault(s => s.Source.Equals(source, StringComparison.OrdinalIgnoreCase) || s.Name.Equals(source, StringComparison.OrdinalIgnoreCase)); + PackageSource resolvedSource = availableSources.FirstOrDefault(s => s.Source.Equals(source, StringComparison.OrdinalIgnoreCase) || s.Name.Equals(source, StringComparison.OrdinalIgnoreCase)); packageSources.Add(resolvedSource ?? new PackageSource(source)); } @@ -771,7 +780,7 @@ private static async Task GetLatestPackageVersionAsync(string packageId, packageSources.AddRange(availableSources); } - var sourceRepositories = packageSources.Select(sourceRepositoryProvider.CreateRepository).ToArray(); + SourceRepository[] sourceRepositories = packageSources.Select(sourceRepositoryProvider.CreateRepository).ToArray(); var resolutionContext = new ResolutionContext( DependencyBehavior.Highest, includePrelease: false, @@ -781,7 +790,7 @@ private static async Task GetLatestPackageVersionAsync(string packageId, // The target framework doesn't matter, since our package doesn't depend on this for its target projects. var framework = new NuGet.Frameworks.NuGetFramework("net45"); - var pkg = await NuGetPackageManager.GetLatestVersionAsync( + ResolvedPackage pkg = await NuGetPackageManager.GetLatestVersionAsync( packageId, framework, resolutionContext, @@ -815,7 +824,7 @@ private static string ShouldHaveTrailingDirectorySeparator(string path) private static void PrintCommits(bool quiet, GitContext context, IEnumerable candidateCommits, bool includeOptions = false) { int index = 1; - foreach (var commit in candidateCommits) + foreach (LibGit2Sharp.Commit commit in candidateCommits) { if (includeOptions) { @@ -834,7 +843,5 @@ private static void PrintCommits(bool quiet, GitContext context, IEnumerable CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name).ToArray(); } } diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 29b376ce..345cb47f 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -22,6 +22,6 @@ - + diff --git a/stylecop.json b/stylecop.json index 4d2f211b..840fd358 100644 --- a/stylecop.json +++ b/stylecop.json @@ -10,6 +10,9 @@ }, "fileNamingConvention": "metadata", "xmlHeader": false + }, + "orderingRules": { + "usingDirectivesPlacement": "outsideNamespace" } } } diff --git a/test/.editorconfig b/test/.editorconfig index 8aa791be..a055c537 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -50,3 +50,9 @@ dotnet_diagnostic.CA2007.severity = none # SA1401: Fields should be private dotnet_diagnostic.SA1401.severity = silent + +# SA1133: Do not combine attributes +dotnet_diagnostic.SA1133.severity = silent + +# SA1515: Single-line comment should be preceded by blank line +dotnet_diagnostic.SA1515.severity = suggestion diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 12d772f1..388b19e0 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -11,18 +11,15 @@ - - + + - + + + - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - diff --git a/test/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs b/test/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs index 2e22e39c..918507fd 100644 --- a/test/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs +++ b/test/Cake.GitVersioning.Tests/GitVersioningCloudProviderTests.cs @@ -1,30 +1,29 @@ -using System; -using System.Linq; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using Cake.GitVersioning; using Nerdbank.GitVersioning; using Xunit; /// -/// Tests to verify the enum (part of the Cake integration) is up-to-date +/// Tests to verify the enum (part of the Cake integration) is up-to-date. /// public class GitVersioningCloudProviderTests { [Fact] public void HasExpectedValues() { - var expectedValues = CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name); - var actualValues = Enum.GetNames(typeof(GitVersioningCloudProvider)); + IEnumerable expectedValues = CloudBuild.SupportedCloudBuilds.Select(cb => cb.GetType().Name); + string[] actualValues = Enum.GetNames(typeof(GitVersioningCloudProvider)); - var missingValues = expectedValues.Except(actualValues); + IEnumerable missingValues = expectedValues.Except(actualValues); Assert.True( !missingValues.Any(), - $"Enumeration is missing the following values of supported cloud build providers: {string.Join(", ", missingValues)}" - ); + $"Enumeration is missing the following values of supported cloud build providers: {string.Join(", ", missingValues)}"); - var redundantValues = actualValues.Except(expectedValues); + IEnumerable redundantValues = actualValues.Except(expectedValues); Assert.True( !redundantValues.Any(), - $"Enumeration contains values which were not found among supported cloud build providers: {string.Join(",", redundantValues)}" - ); + $"Enumeration contains values which were not found among supported cloud build providers: {string.Join(",", redundantValues)}"); } } diff --git a/test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs b/test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs index 8445996c..3e74e994 100644 --- a/test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs +++ b/test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.Runtime.InteropServices; using BenchmarkDotNet.Attributes; diff --git a/test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index 53f34443..71e37780 100644 --- a/test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/NerdBank.GitVersioning.Benchmarks/Program.cs b/test/NerdBank.GitVersioning.Benchmarks/Program.cs index 90149bd6..9ea48d86 100644 --- a/test/NerdBank.GitVersioning.Benchmarks/Program.cs +++ b/test/NerdBank.GitVersioning.Benchmarks/Program.cs @@ -1,11 +1,14 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using BenchmarkDotNet.Running; namespace Nerdbank.GitVersioning.Benchmarks { - class Program + internal class Program { - static void Main(string[] args) => + private static void Main(string[] args) => BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args); } } diff --git a/test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs b/test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs index 253fdeb6..bfc659b6 100644 --- a/test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs +++ b/test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -24,19 +27,19 @@ public void FSharpGenerator(bool? thisAssemblyClass) { new TaskItem( "CustomString1", - new Dictionary() { { "String", "abc" } } ), + new Dictionary() { { "String", "abc" } }), new TaskItem( "CustomString2", - new Dictionary() { { "String", "" } } ), + new Dictionary() { { "String", string.Empty } }), new TaskItem( "CustomString3", - new Dictionary() { { "String", "" }, { "EmitIfEmpty", "true" } } ), + new Dictionary() { { "String", string.Empty }, { "EmitIfEmpty", "true" } }), new TaskItem( "CustomBool", - new Dictionary() { { "Boolean", "true" } } ), + new Dictionary() { { "Boolean", "true" } }), new TaskItem( "CustomTicks", - new Dictionary() { { "Ticks", "637509805729817056" } } ), + new Dictionary() { { "Ticks", "637509805729817056" } }), }; info.CodeLanguage = "f#"; @@ -45,9 +48,9 @@ public void FSharpGenerator(bool? thisAssemblyClass) info.EmitThisAssemblyClass = thisAssemblyClass.GetValueOrDefault(); } - var built = info.BuildCode(); + string built = info.BuildCode(); - var expected = $@"//------------------------------------------------------------------------------ + string expected = $@"//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -82,7 +85,7 @@ type internal ThisAssembly() = static member internal IsPublicRelease = false static member internal RootNamespace = """" do() -" : "")}"; +" : string.Empty)}"; Assert.Equal(expected, built); } @@ -103,19 +106,19 @@ public void CSharpGenerator(bool? thisAssemblyClass) { new TaskItem( "CustomString1", - new Dictionary() { { "String", "abc" } } ), + new Dictionary() { { "String", "abc" } }), new TaskItem( "CustomString2", - new Dictionary() { { "String", "" } } ), + new Dictionary() { { "String", string.Empty } }), new TaskItem( "CustomString3", - new Dictionary() { { "String", "" }, { "EmitIfEmpty", "true" } } ), + new Dictionary() { { "String", string.Empty }, { "EmitIfEmpty", "true" } }), new TaskItem( "CustomBool", - new Dictionary() { { "Boolean", "true" } } ), + new Dictionary() { { "Boolean", "true" } }), new TaskItem( "CustomTicks", - new Dictionary() { { "Ticks", "637509805729817056" } } ), + new Dictionary() { { "Ticks", "637509805729817056" } }), }; if (thisAssemblyClass.HasValue) @@ -123,9 +126,9 @@ public void CSharpGenerator(bool? thisAssemblyClass) info.EmitThisAssemblyClass = thisAssemblyClass.GetValueOrDefault(); } - var built = info.BuildCode(); + string built = info.BuildCode(); - var expected = $@"//------------------------------------------------------------------------------ + string expected = $@"//------------------------------------------------------------------------------ // // This code was generated by a tool. // Runtime Version:4.0.30319.42000 @@ -158,7 +161,7 @@ internal static partial class ThisAssembly {{ internal const bool IsPublicRelease = false; internal const string RootNamespace = """"; }} -" : "")}"; +" : string.Empty)}"; Assert.Equal(expected, built); } @@ -180,9 +183,9 @@ public void VisualBasicGenerator(bool? thisAssemblyClass) info.EmitThisAssemblyClass = thisAssemblyClass.GetValueOrDefault(); } - var built = info.BuildCode(); + string built = info.BuildCode(); - var expected = $@"'------------------------------------------------------------------------------ + string expected = $@"'------------------------------------------------------------------------------ ' ' This code was generated by a tool. ' Runtime Version:4.0.30319.42000 @@ -214,7 +217,7 @@ Partial Friend NotInheritable Class ThisAssembly Friend Const IsPublicRelease As Boolean = False Friend Const RootNamespace As String = """" End Class -" : "")}"; +" : string.Empty)}"; Assert.Equal(expected, built); } diff --git a/test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs index 159ee377..7dbc5400 100644 --- a/test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -1,13 +1,11 @@ -using System; -using System.Collections.Generic; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using System.Collections.Immutable; using System.Diagnostics; using System.Globalization; -using System.IO; -using System.Linq; using System.Reflection; using System.Text; -using System.Threading.Tasks; using System.Xml; using LibGit2Sharp; using Microsoft.Build.Construction; @@ -23,6 +21,9 @@ using Xunit.Abstractions; using Version = System.Version; +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable SA1649 // File name should match first type name + [Trait("Engine", "Managed")] [Collection("Build")] // msbuild sets current directory in the process, so we can't have it be concurrent with other build tests. public class BuildIntegrationManagedTests : BuildIntegrationTests @@ -32,9 +33,11 @@ public BuildIntegrationManagedTests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: false); + /// protected override void ApplyGlobalProperties(IDictionary globalProperties) => globalProperties["NBGV_GitEngine"] = "Managed"; } @@ -48,9 +51,11 @@ public BuildIntegrationInProjectManagedTests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: false); + /// protected override void ApplyGlobalProperties(IDictionary globalProperties) { globalProperties["NBGV_GitEngine"] = "Managed"; @@ -67,9 +72,11 @@ public BuildIntegrationLibGit2Tests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); + /// protected override void ApplyGlobalProperties(IDictionary globalProperties) => globalProperties["NBGV_GitEngine"] = "LibGit2"; } @@ -86,6 +93,7 @@ public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture name.StartsWith(toxic, StringComparison.OrdinalIgnoreCase))) + return new object[][] { - this.globalProperties[name] = string.Empty; - } + new object[] { CloudBuild.VSTS, "##vso[task.setvariable variable={NAME};]{VALUE}", false }, + new object[] { CloudBuild.VSTS, "##vso[task.setvariable variable={NAME};]{VALUE}", true }, + }; } } - private string CommitIdShort => this.Context.GitCommitId?.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength); + private static VersionOptions BuildNumberVersionOptionsBasis + { + get + { + return new VersionOptions + { + Version = SemanticVersion.Parse("1.0"), + CloudBuild = new VersionOptions.CloudBuildOptions + { + BuildNumber = new VersionOptions.CloudBuildNumberOptions + { + Enabled = true, + IncludeCommitId = new VersionOptions.CloudBuildNumberCommitIdOptions(), + }, + }, + }; + } + } - protected abstract void ApplyGlobalProperties(IDictionary globalProperties); + private string CommitIdShort => this.Context.GitCommitId?.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength); - protected override void Dispose(bool disposing) + public static IEnumerable CloudBuildOfBranch(string branchName) { - Environment.SetEnvironmentVariable("_NBGV_UnitTest", string.Empty); - base.Dispose(disposing); + return new object[][] + { + new object[] { CloudBuild.AppVeyor.SetItem("APPVEYOR_REPO_BRANCH", branchName) }, + new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/heads/{branchName}") }, + new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/tags/{branchName}") }, + new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/heads/{branchName}") }, + new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/tags/{branchName}") }, + }; } [Fact] @@ -148,7 +178,7 @@ public async Task GetBuildVersion_Returns_BuildVersion_Property() { this.WriteVersionFile(); this.InitializeSourceControl(); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.Equal( buildResult.BuildVersion, buildResult.BuildResult.ResultsByTarget[Targets.GetBuildVersion].Items.Single().ItemSpec); @@ -158,7 +188,7 @@ public async Task GetBuildVersion_Returns_BuildVersion_Property() public async Task GetBuildVersion_Without_Git() { this.WriteVersionFile("3.4"); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.Equal("3.4", buildResult.BuildVersion); Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion); } @@ -173,7 +203,7 @@ public async Task GetBuildVersion_WithThreeVersionIntegers() }; this.WriteVersionFile(workingCopyVersion); this.InitializeSourceControl(); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(workingCopyVersion, buildResult); } @@ -188,7 +218,7 @@ public async Task GetBuildVersion_Without_Git_HighPrecisionAssemblyVersion() Precision = VersionOptions.VersionPrecision.Revision, }, }); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.Equal("3.4", buildResult.BuildVersion); Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion); } @@ -213,7 +243,7 @@ public async Task GetBuildVersion_OutsideGit_PointingToGit() this.testProject.AddProperty("GitRepoRoot", this.RepoPath); this.testProject.AddProperty("ProjectPathRelativeToGitRepoRoot", repoRelativeProjectPath); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); var workingCopyVersion = VersionOptions.FromVersion(new Version(version)); @@ -227,7 +257,7 @@ public async Task GetBuildVersion_In_Git_But_Without_Commits() var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later this.WriteVersionFile("3.4"); Assumes.False(repo.Head.Commits.Any()); // verification that the test is doing what it claims - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.Equal("3.4.0.0", buildResult.BuildVersion); Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion); } @@ -240,7 +270,7 @@ public async Task GetBuildVersion_In_Git_But_Head_Lacks_VersionFile() repo.Commit("empty", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); this.WriteVersionFile("3.4"); Assumes.True(repo.Index[VersionFile.JsonFileName] is null); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.Equal("3.4.0." + this.GetVersion().Revision, buildResult.BuildVersion); Assert.Equal("3.4.0+" + repo.Head.Tip.Id.Sha.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength), buildResult.AssemblyInformationalVersion); } @@ -255,7 +285,7 @@ public async Task GetBuildVersion_In_Git_But_WorkingCopy_Has_Changes() this.InitializeSourceControl(); var workingCopyVersion = VersionOptions.FromVersion(new Version("6.0")); this.Context.VersionFile.SetVersion(this.RepoPath, workingCopyVersion); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(workingCopyVersion, buildResult); } @@ -265,7 +295,7 @@ public async Task GetBuildVersion_In_Git_No_VersionFile_At_All() Repository.Init(this.RepoPath); var repo = new Repository(this.RepoPath); // do not assign Repo property to avoid commits being generated later repo.Commit("empty", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.Equal("0.0.0." + this.GetVersion().Revision, buildResult.BuildVersion); Assert.Equal("0.0.0+" + repo.Head.Tip.Id.Sha.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength), buildResult.AssemblyInformationalVersion); } @@ -280,7 +310,7 @@ public async Task GetBuildVersion_In_Git_With_Version_File_In_Subdirectory_Works this.WriteVersionFile(majorMinorVersion, prerelease, subdirectory); this.InitializeSourceControl(); this.AddCommits(this.random.Next(15)); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult, subdirectory); } @@ -299,7 +329,7 @@ public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Subdirect this.WriteVersionFile(subdirVersionSpec, subdirectory); this.InitializeSourceControl(); this.AddCommits(this.random.Next(15)); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(subdirVersionSpec, buildResult, subdirectory); } @@ -316,7 +346,7 @@ public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Project_I this.InitializeSourceControl(); this.AddCommits(this.random.Next(15)); this.testProject = this.CreateProjectRootElement(this.RepoPath, "root.proj"); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(rootVersionSpec, buildResult); } @@ -329,7 +359,7 @@ public async Task GetBuildVersion_StablePreRelease() this.WriteVersionFile(majorMinorVersion, prerelease); this.InitializeSourceControl(); this.AddCommits(this.random.Next(15)); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult); } @@ -343,7 +373,7 @@ public async Task GetBuildVersion_StableRelease() this.InitializeSourceControl(); this.AddCommits(this.random.Next(15)); this.globalProperties["PublicRelease"] = "true"; - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult); Version version = this.GetVersion(); @@ -359,7 +389,7 @@ public async Task GetBuildVersion_UnstablePreRelease() this.WriteVersionFile(majorMinorVersion, prerelease); this.InitializeSourceControl(); this.AddCommits(this.random.Next(15)); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult); } @@ -373,7 +403,7 @@ public async Task GetBuildVersion_UnstableRelease() this.InitializeSourceControl(); this.AddCommits(this.random.Next(15)); this.globalProperties["PublicRelease"] = "true"; - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult); } @@ -388,7 +418,7 @@ public async Task GetBuildVersion_CustomAssemblyVersion() AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)), }; this.WriteVersionFile(versionOptions); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); } @@ -409,7 +439,7 @@ public async Task GetBuildVersion_CustomAssemblyVersionWithPrecision(VersionOpti }; this.WriteVersionFile(versionOptions); this.InitializeSourceControl(); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); } @@ -429,7 +459,7 @@ public async Task GetBuildVersion_CustomAssemblyVersionPrecision(VersionOptions. }; this.WriteVersionFile(versionOptions); this.InitializeSourceControl(); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); } @@ -444,7 +474,7 @@ public async Task GetBuildVersion_CustomBuildNumberOffset() VersionHeightOffset = 5, }; this.WriteVersionFile(versionOptions); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); } @@ -455,11 +485,11 @@ public async Task GetBuildVersion_OverrideBuildNumberOffset() this.InitializeSourceControl(); var versionOptions = new VersionOptions { - Version = new SemanticVersion(new Version(14, 1)) + Version = new SemanticVersion(new Version(14, 1)), }; this.WriteVersionFile(versionOptions); this.testProject.AddProperty("OverrideBuildNumberOffset", "10"); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.StartsWith("14.1.11.", buildResult.AssemblyFileVersion); } @@ -474,7 +504,7 @@ public async Task GetBuildVersion_Minus1BuildOffset_NotYetCommitted() VersionHeightOffset = -1, }; this.Context.VersionFile.SetVersion(this.RepoPath, versionOptions); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); } @@ -489,7 +519,7 @@ public async Task GetBuildVersion_BuildNumberSpecifiedInVersionJson(int buildNum }; this.WriteVersionFile(versionOptions); this.InitializeSourceControl(); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); } @@ -505,23 +535,11 @@ public async Task PublicRelease_RegEx_Unsatisfied() this.InitializeSourceControl(); // Just build "master", which doesn't conform to the regex. - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.False(buildResult.PublicRelease); this.AssertStandardProperties(versionOptions, buildResult); } - public static IEnumerable CloudBuildOfBranch(string branchName) - { - return new object[][] - { - new object[] { CloudBuild.AppVeyor.SetItem("APPVEYOR_REPO_BRANCH", branchName) }, - new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/heads/{branchName}") }, - new object[] { CloudBuild.VSTS.SetItem("BUILD_SOURCEBRANCH", $"refs/tags/{branchName}") }, - new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/heads/{branchName}") }, - new object[] { CloudBuild.Teamcity.SetItem("BUILD_GIT_BRANCH", $"refs/tags/{branchName}") }, - }; - } - [Theory] [MemberData(nameof(CloudBuildOfBranch), "release")] public async Task PublicRelease_RegEx_SatisfiedByCI(IReadOnlyDictionary serverProperties) @@ -529,10 +547,10 @@ public async Task PublicRelease_RegEx_SatisfiedByCI(IReadOnlyDictionary properties, string expectedBuildNumberMessage) @@ -684,7 +660,7 @@ public async Task BuildNumber_SetInCI(VersionOptions versionOptions, IReadOnlyDi this.InitializeSourceControl(); using (ApplyEnvironmentVariables(properties)) { - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); expectedBuildNumberMessage = expectedBuildNumberMessage.Replace("{CLOUDBUILDNUMBER}", buildResult.CloudBuildNumber); Assert.Contains(UnitTestCloudBuildPrefix + expectedBuildNumberMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); @@ -694,7 +670,7 @@ public async Task BuildNumber_SetInCI(VersionOptions versionOptions, IReadOnlyDi this.WriteVersionFile(versionOptions); using (ApplyEnvironmentVariables(properties)) { - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); expectedBuildNumberMessage = expectedBuildNumberMessage.Replace("{CLOUDBUILDNUMBER}", buildResult.CloudBuildNumber); Assert.DoesNotContain(UnitTestCloudBuildPrefix + expectedBuildNumberMessage, buildResult.LoggedEvents.Select(e => e.Message.TrimEnd())); @@ -705,7 +681,7 @@ public async Task BuildNumber_SetInCI(VersionOptions versionOptions, IReadOnlyDi [PairwiseData] public async Task BuildNumber_VariousOptions(bool isPublic, VersionOptions.CloudBuildNumberCommitWhere where, VersionOptions.CloudBuildNumberCommitWhen when, [CombinatorialValues(0, 1, 2)] int extraBuildMetadataCount, [CombinatorialValues(1, 2)] int semVer) { - var versionOptions = BuildNumberVersionOptionsBasis; + VersionOptions versionOptions = BuildNumberVersionOptionsBasis; versionOptions.CloudBuild.BuildNumber.IncludeCommitId.Where = where; versionOptions.CloudBuild.BuildNumber.IncludeCommitId.When = when; versionOptions.NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions @@ -721,7 +697,7 @@ public async Task BuildNumber_VariousOptions(bool isPublic, VersionOptions.Cloud this.testProject.AddItem("BuildMetadata", $"A{i}"); } - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); this.AssertStandardProperties(versionOptions, buildResult); } @@ -736,10 +712,10 @@ public void GitLab_BuildTag() { "CI_COMMIT_TAG", "1.0.0" }, { "CI_COMMIT_SHA", "1ecfd275763eff1d6b4844ea3168962458c9f27a" }, { "GITLAB_CI", "true" }, - { "SYSTEM_TEAMPROJECTID", string.Empty } + { "SYSTEM_TEAMPROJECTID", string.Empty }, }))) { - var activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; + ICloudBuild activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; Assert.NotNull(activeCloudBuild); Assert.Null(activeCloudBuild.BuildingBranch); Assert.Equal("refs/tags/1.0.0", activeCloudBuild.BuildingTag); @@ -760,9 +736,9 @@ public void GitLab_BuildBranch() { "CI_COMMIT_REF_NAME", "master" }, { "CI_COMMIT_SHA", "1ecfd275763eff1d6b4844ea3168962458c9f27a" }, { "GITLAB_CI", "true" }, - }))) + }))) { - var activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; + ICloudBuild activeCloudBuild = Nerdbank.GitVersioning.CloudBuild.Active; Assert.NotNull(activeCloudBuild); Assert.Equal("refs/heads/master", activeCloudBuild.BuildingBranch); Assert.Null(activeCloudBuild.BuildingTag); @@ -786,9 +762,9 @@ public async Task PublicRelease_RegEx_SatisfiedByCheckedOutBranch() using (ApplyEnvironmentVariables(CloudBuild.SuppressEnvironment)) { // Check out a branch that conforms. - var releaseBranch = this.LibGit2Repository.CreateBranch("release"); + Branch releaseBranch = this.LibGit2Repository.CreateBranch("release"); Commands.Checkout(this.LibGit2Repository, releaseBranch); - var buildResult = await this.BuildAsync(); + BuildResults buildResult = await this.BuildAsync(); Assert.True(buildResult.PublicRelease); this.AssertStandardProperties(versionOptions, buildResult); } @@ -818,20 +794,20 @@ public async Task AssemblyInfo(bool isVB, bool includeNonVersionAttributes, bool this.globalProperties["PublicRelease"] = isPublicRelease ? "true" : "false"; - var result = await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); + BuildResults result = await this.BuildAsync("Build", logVerbosity: LoggerVerbosity.Minimal); string assemblyPath = result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("TargetPath"); string versionFileContent = File.ReadAllText(Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile"))); this.Logger.WriteLine(versionFileContent); var assembly = Assembly.LoadFile(assemblyPath); - var assemblyFileVersion = assembly.GetCustomAttribute(); - var assemblyInformationalVersion = assembly.GetCustomAttribute(); - var assemblyTitle = assembly.GetCustomAttribute(); - var assemblyProduct = assembly.GetCustomAttribute(); - var assemblyCompany = assembly.GetCustomAttribute(); - var assemblyCopyright = assembly.GetCustomAttribute(); - var thisAssemblyClass = assembly.GetType("ThisAssembly") ?? assembly.GetType("TestNamespace.ThisAssembly"); + AssemblyFileVersionAttribute assemblyFileVersion = assembly.GetCustomAttribute(); + AssemblyInformationalVersionAttribute assemblyInformationalVersion = assembly.GetCustomAttribute(); + AssemblyTitleAttribute assemblyTitle = assembly.GetCustomAttribute(); + AssemblyProductAttribute assemblyProduct = assembly.GetCustomAttribute(); + AssemblyCompanyAttribute assemblyCompany = assembly.GetCustomAttribute(); + AssemblyCopyrightAttribute assemblyCopyright = assembly.GetCustomAttribute(); + Type thisAssemblyClass = assembly.GetType("ThisAssembly") ?? assembly.GetType("TestNamespace.ThisAssembly"); Assert.NotNull(thisAssemblyClass); Assert.Equal(new Version(result.AssemblyVersion), assembly.GetName().Version); @@ -897,7 +873,7 @@ public async Task AssemblyInfo_HasKeyData(string keyFile, bool delaySigned) this.testProject.AddProperty("DelaySign", delaySigned.ToString()); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); + BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); string versionCsContent = File.ReadAllText( Path.GetFullPath( Path.Combine( @@ -905,9 +881,9 @@ public async Task AssemblyInfo_HasKeyData(string keyFile, bool delaySigned) result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile")))); this.Logger.WriteLine(versionCsContent); - var sourceFile = CSharpSyntaxTree.ParseText(versionCsContent); - var syntaxTree = await sourceFile.GetRootAsync(); - var fields = syntaxTree.DescendantNodes().OfType(); + SyntaxTree sourceFile = CSharpSyntaxTree.ParseText(versionCsContent); + SyntaxNode syntaxTree = await sourceFile.GetRootAsync(); + IEnumerable fields = syntaxTree.DescendantNodes().OfType(); var publicKeyField = (LiteralExpressionSyntax)fields.SingleOrDefault(f => f.Identifier.ValueText == "PublicKey")?.Initializer.Value; var publicKeyTokenField = (LiteralExpressionSyntax)fields.SingleOrDefault(f => f.Identifier.ValueText == "PublicKeyToken")?.Initializer.Value; @@ -946,12 +922,12 @@ public async Task AssemblyInfo_IncrementalBuild() [Fact] public async Task AssemblyInfo_NotProducedWithoutCodeDomProvider() { - var propertyGroup = this.testProject.CreatePropertyGroupElement(); + ProjectPropertyGroupElement propertyGroup = this.testProject.CreatePropertyGroupElement(); this.testProject.AppendChild(propertyGroup); propertyGroup.AddProperty("Language", "NoCodeDOMProviderForThisLanguage"); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal, assertSuccessfulBuild: false); + BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal, assertSuccessfulBuild: false); Assert.Equal(BuildResultCode.Failure, result.BuildResult.OverallResult); string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile")); Assert.False(File.Exists(versionCsFilePath)); @@ -965,13 +941,13 @@ public async Task AssemblyInfo_NotProducedWithoutCodeDomProvider() [Fact] public async Task AssemblyInfo_Suppressed() { - var propertyGroup = this.testProject.CreatePropertyGroupElement(); + ProjectPropertyGroupElement propertyGroup = this.testProject.CreatePropertyGroupElement(); this.testProject.AppendChild(propertyGroup); propertyGroup.AddProperty("Language", "NoCodeDOMProviderForThisLanguage"); propertyGroup.AddProperty(Properties.GenerateAssemblyVersionInfo, "false"); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); + BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile")); Assert.False(File.Exists(versionCsFilePath)); Assert.Empty(result.LoggedEvents.OfType()); @@ -985,21 +961,19 @@ public async Task AssemblyInfo_Suppressed() [Fact] public async Task AssemblyInfo_SuppressedImplicitlyByTargetExt() { - var propertyGroup = this.testProject.CreatePropertyGroupElement(); + ProjectPropertyGroupElement propertyGroup = this.testProject.CreatePropertyGroupElement(); this.testProject.InsertAfterChild(propertyGroup, this.testProject.Imports.First()); // insert just after the Common.Targets import. propertyGroup.AddProperty("Language", "NoCodeDOMProviderForThisLanguage"); propertyGroup.AddProperty("TargetExt", ".notdll"); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); + BuildResults result = await this.BuildAsync(Targets.GenerateAssemblyNBGVVersionInfo, logVerbosity: LoggerVerbosity.Minimal); string versionCsFilePath = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("VersionSourceFile")); Assert.False(File.Exists(versionCsFilePath)); Assert.Empty(result.LoggedEvents.OfType()); Assert.Empty(result.LoggedEvents.OfType()); } - protected override GitContext CreateGitContext(string path, string committish = null) => throw new NotImplementedException(); - #if !NETCOREAPP /// /// Create a native resource .dll and verify that its version @@ -1010,7 +984,7 @@ public async Task NativeVersionInfo_CreateNativeResourceDll() { this.testProject = this.CreateNativeProjectRootElement(this.projectDirectory, "test.vcxproj"); this.WriteVersionFile(); - var result = await this.BuildAsync(Targets.Build, logVerbosity: LoggerVerbosity.Minimal); + BuildResults result = await this.BuildAsync(Targets.Build, logVerbosity: LoggerVerbosity.Minimal); Assert.Empty(result.LoggedEvents.OfType()); string targetFile = Path.Combine(this.projectDirectory, result.BuildResult.ProjectStateAfterBuild.GetPropertyValue("TargetPath")); @@ -1025,10 +999,22 @@ public async Task NativeVersionInfo_CreateNativeResourceDll() } #endif + /// + protected override GitContext CreateGitContext(string path, string committish = null) => throw new NotImplementedException(); + + protected abstract void ApplyGlobalProperties(IDictionary globalProperties); + + /// + protected override void Dispose(bool disposing) + { + Environment.SetEnvironmentVariable("_NBGV_UnitTest", string.Empty); + base.Dispose(disposing); + } + private static Version GetExpectedAssemblyVersion(VersionOptions versionOptions, Version version) { // Function should be very similar to VersionOracle.GetAssemblyVersion() - var assemblyVersion = (versionOptions?.AssemblyVersion?.Version ?? versionOptions.Version.Version).EnsureNonNegativeComponents(); + Version assemblyVersion = (versionOptions?.AssemblyVersion?.Version ?? versionOptions.Version.Version).EnsureNonNegativeComponents(); if (versionOptions?.AssemblyVersion?.Version is null) { @@ -1050,7 +1036,7 @@ private static RestoreEnvironmentVariables ApplyEnvironmentVariables(IReadOnlyDi Requires.NotNull(variables, nameof(variables)); var oldValues = new Dictionary(StringComparer.OrdinalIgnoreCase); - foreach (var variable in variables) + foreach (KeyValuePair variable in variables) { oldValues[variable.Key] = Environment.GetEnvironmentVariable(variable.Key); Environment.SetEnvironmentVariable(variable.Key, variable.Value); @@ -1059,6 +1045,13 @@ private static RestoreEnvironmentVariables ApplyEnvironmentVariables(IReadOnlyDi return new RestoreEnvironmentVariables(oldValues); } + private static string GetSemVerAppropriatePrereleaseTag(VersionOptions versionOptions) + { + return versionOptions.NuGetPackageVersionOrDefault.SemVer == 1 + ? versionOptions.Version.Prerelease?.Replace('.', '-') + : versionOptions.Version.Prerelease; + } + private void AssertStandardProperties(VersionOptions versionOptions, BuildResults buildResult, string relativeProjectDirectory = null) { int versionHeight = this.GetVersionHeight(relativeProjectDirectory); @@ -1066,9 +1059,9 @@ private void AssertStandardProperties(VersionOptions versionOptions, BuildResult string commitIdShort = this.CommitIdShort; Version version = this.GetVersion(relativeProjectDirectory); Version assemblyVersion = GetExpectedAssemblyVersion(versionOptions, version); - var additionalBuildMetadata = from item in buildResult.BuildResult.ProjectStateAfterBuild.GetItems("BuildMetadata") + IEnumerable additionalBuildMetadata = from item in buildResult.BuildResult.ProjectStateAfterBuild.GetItems("BuildMetadata") select item.EvaluatedInclude; - var expectedBuildMetadata = $"+{commitIdShort}"; + string expectedBuildMetadata = $"+{commitIdShort}"; if (additionalBuildMetadata.Any()) { expectedBuildMetadata += "." + string.Join(".", additionalBuildMetadata); @@ -1116,10 +1109,10 @@ string GetPkgVersionSuffix(bool useSemVer2) string chocolateyPkgVersionSuffix = GetPkgVersionSuffix(useSemVer2: false); Assert.Equal($"{idAsVersion.Major}.{idAsVersion.Minor}.{idAsVersion.Build}{GetSemVerAppropriatePrereleaseTag(versionOptions)}{chocolateyPkgVersionSuffix}", buildResult.ChocolateyPackageVersion); - var buildNumberOptions = versionOptions.CloudBuildOrDefault.BuildNumberOrDefault; + VersionOptions.CloudBuildNumberOptions buildNumberOptions = versionOptions.CloudBuildOrDefault.BuildNumberOrDefault; if (buildNumberOptions.EnabledOrDefault) { - var commitIdOptions = buildNumberOptions.IncludeCommitIdOrDefault; + VersionOptions.CloudBuildNumberCommitIdOptions commitIdOptions = buildNumberOptions.IncludeCommitIdOrDefault; var buildNumberSemVer = SemanticVersion.Parse(buildResult.CloudBuildNumber); bool hasCommitData = commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.Always || (commitIdOptions.WhenOrDefault == VersionOptions.CloudBuildNumberCommitWhen.NonPublicReleaseOnly && !buildResult.PublicRelease); @@ -1146,20 +1139,13 @@ string GetPkgVersionSuffix(bool useSemVer2) } } - private static string GetSemVerAppropriatePrereleaseTag(VersionOptions versionOptions) - { - return versionOptions.NuGetPackageVersionOrDefault.SemVer == 1 - ? versionOptions.Version.Prerelease?.Replace('.', '-') - : versionOptions.Version.Prerelease; - } - private async Task BuildAsync(string target = Targets.GetBuildVersion, LoggerVerbosity logVerbosity = LoggerVerbosity.Detailed, bool assertSuccessfulBuild = true) { var eventLogger = new MSBuildLogger { Verbosity = LoggerVerbosity.Minimal }; var loggers = new ILogger[] { eventLogger }; this.testProject.Save(); // persist generated project on disk for analysis this.ApplyGlobalProperties(this.globalProperties); - var buildResult = await this.buildManager.BuildAsync( + BuildResult buildResult = await this.buildManager.BuildAsync( this.Logger, this.projectCollection, this.testProject, @@ -1181,12 +1167,12 @@ private void LoadTargetsIntoProjectCollection() { string prefix = $"{ThisAssembly.RootNamespace}.Targets."; - var streamNames = from name in Assembly.GetExecutingAssembly().GetManifestResourceNames() + IEnumerable streamNames = from name in Assembly.GetExecutingAssembly().GetManifestResourceNames() where name.StartsWith(prefix, StringComparison.Ordinal) select name; foreach (string name in streamNames) { - using (var stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name)) + using (Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream(name)) { var targetsFile = ProjectRootElement.Create(XmlReader.Create(stream), this.projectCollection); targetsFile.FullPath = Path.Combine(this.RepoPath, name.Substring(prefix.Length)); @@ -1221,12 +1207,37 @@ private ProjectRootElement CreateProjectRootElement(string projectDirectory, str private void MakeItAVBProject() { - var csharpImport = this.testProject.Imports.Single(i => i.Project.Contains("CSharp")); + ProjectImportElement csharpImport = this.testProject.Imports.Single(i => i.Project.Contains("CSharp")); csharpImport.Project = "$(MSBuildToolsPath)/Microsoft.VisualBasic.targets"; - var isVbProperty = this.testProject.Properties.Single(p => p.Name == "IsVB"); + ProjectPropertyElement isVbProperty = this.testProject.Properties.Single(p => p.Name == "IsVB"); isVbProperty.Value = "true"; } + private void Init() + { + int seed = (int)DateTime.Now.Ticks; + this.random = new Random(seed); + this.Logger.WriteLine("Random seed: {0}", seed); + this.buildManager = new BuildManager(); + this.projectCollection = new ProjectCollection(); + this.projectDirectory = Path.Combine(this.RepoPath, "projdir"); + Directory.CreateDirectory(this.projectDirectory); + this.LoadTargetsIntoProjectCollection(); + this.testProject = this.CreateProjectRootElement(this.projectDirectory, "test.prj"); + this.globalProperties.Add("NerdbankGitVersioningTasksPath", Environment.CurrentDirectory + "\\"); + Environment.SetEnvironmentVariable("_NBGV_UnitTest", "true"); + + // Sterilize the test of any environment variables. + foreach (System.Collections.DictionaryEntry variable in Environment.GetEnvironmentVariables()) + { + string name = (string)variable.Key; + if (ToxicEnvironmentVariablePrefixes.Any(toxic => name.StartsWith(toxic, StringComparison.OrdinalIgnoreCase))) + { + this.globalProperties[name] = string.Empty; + } + } + } + private struct RestoreEnvironmentVariables : IDisposable { private readonly IReadOnlyDictionary applyVariables; @@ -1245,21 +1256,27 @@ public void Dispose() private static class CloudBuild { public static readonly ImmutableDictionary SuppressEnvironment = ImmutableDictionary.Empty + // AppVeyor .Add("APPVEYOR", string.Empty) .Add("APPVEYOR_REPO_TAG", string.Empty) .Add("APPVEYOR_REPO_TAG_NAME", string.Empty) .Add("APPVEYOR_PULL_REQUEST_NUMBER", string.Empty) + // VSTS .Add("SYSTEM_TEAMPROJECTID", string.Empty) .Add("BUILD_SOURCEBRANCH", string.Empty) + // Teamcity .Add("BUILD_VCS_NUMBER", string.Empty) .Add("BUILD_GIT_BRANCH", string.Empty); + public static readonly ImmutableDictionary VSTS = SuppressEnvironment .SetItem("SYSTEM_TEAMPROJECTID", "1"); + public static readonly ImmutableDictionary AppVeyor = SuppressEnvironment .SetItem("APPVEYOR", "True"); + public static readonly ImmutableDictionary Teamcity = SuppressEnvironment .SetItem("BUILD_VCS_NUMBER", "1"); } @@ -1292,45 +1309,73 @@ internal BuildResults(BuildResult buildResult, IReadOnlyList log public IReadOnlyList LoggedEvents { get; private set; } public bool PublicRelease => string.Equals("true", this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("PublicRelease"), StringComparison.OrdinalIgnoreCase); + public string BuildNumber => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("BuildNumber"); + public string GitCommitId => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitCommitId"); + public string BuildVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("BuildVersion"); + public string BuildVersionSimple => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("BuildVersionSimple"); + public string PrereleaseVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("PrereleaseVersion"); + public string MajorMinorVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("MajorMinorVersion"); + public string BuildVersionNumberComponent => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("BuildVersionNumberComponent"); + public string GitCommitIdShort => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitCommitIdShort"); + public string GitCommitDateTicks => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitCommitDateTicks"); + public string GitVersionHeight => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitVersionHeight"); + public string SemVerBuildSuffix => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("SemVerBuildSuffix"); + public string BuildVersion3Components => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("BuildVersion3Components"); + public string AssemblyInformationalVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyInformationalVersion"); + public string AssemblyFileVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyFileVersion"); + public string AssemblyVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyVersion"); + public string NuGetPackageVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("NuGetPackageVersion"); + public string ChocolateyPackageVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("ChocolateyPackageVersion"); + public string CloudBuildNumber => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("CloudBuildNumber"); + public string AssemblyName => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyName"); + public string AssemblyTitle => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyTitle"); + public string AssemblyProduct => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyProduct"); + public string AssemblyCompany => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyCompany"); + public string AssemblyCopyright => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("AssemblyCopyright"); + public string AssemblyConfiguration => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("Configuration"); + public string RootNamespace => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("RootNamespace"); public string GitBuildVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitBuildVersion"); + public string GitBuildVersionSimple => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitBuildVersionSimple"); + public string GitAssemblyInformationalVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("GitAssemblyInformationalVersion"); // Just a sampling of other properties optionally set in cloud build. public string NBGV_GitCommitIdShort => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("NBGV_GitCommitIdShort"); + public string NBGV_NuGetPackageVersion => this.BuildResult.ProjectStateAfterBuild.GetPropertyValue("NBGV_NuGetPackageVersion"); public override string ToString() { var sb = new StringBuilder(); - foreach (var property in this.GetType().GetRuntimeProperties().OrderBy(p => p.Name, StringComparer.OrdinalIgnoreCase)) + foreach (PropertyInfo property in this.GetType().GetRuntimeProperties().OrderBy(p => p.Name, StringComparer.OrdinalIgnoreCase)) { if (property.DeclaringType == this.GetType() && property.Name != nameof(this.BuildResult)) { diff --git a/test/NerdBank.GitVersioning.Tests/FilterPathTests.cs b/test/NerdBank.GitVersioning.Tests/FilterPathTests.cs index b6c5a6da..22016971 100644 --- a/test/NerdBank.GitVersioning.Tests/FilterPathTests.cs +++ b/test/NerdBank.GitVersioning.Tests/FilterPathTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Runtime.InteropServices; using Nerdbank.GitVersioning; using Xunit; @@ -107,10 +110,10 @@ public void NonMatchingPathsAreNotExcludedCaseSensitive(string pathSpec, string [Fact] public void InvalidPathspecsThrow() { - Assert.Throws(() => new FilterPath(null, "")); - Assert.Throws(() => new FilterPath("", "")); - Assert.Throws(() => new FilterPath(":?", "")); - Assert.Throws(() => new FilterPath("../foo.txt", "")); + Assert.Throws(() => new FilterPath(null, string.Empty)); + Assert.Throws(() => new FilterPath(string.Empty, string.Empty)); + Assert.Throws(() => new FilterPath(":?", string.Empty)); + Assert.Throws(() => new FilterPath("../foo.txt", string.Empty)); Assert.Throws(() => new FilterPath(".././a/../../foo.txt", "foo")); } diff --git a/test/NerdBank.GitVersioning.Tests/GitContextTests.cs b/test/NerdBank.GitVersioning.Tests/GitContextTests.cs index ccb93142..185e8e2b 100644 --- a/test/NerdBank.GitVersioning.Tests/GitContextTests.cs +++ b/test/NerdBank.GitVersioning.Tests/GitContextTests.cs @@ -1,9 +1,15 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using Nerdbank.GitVersioning; using Xunit; using Xunit.Abstractions; +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable SA1649 // File name should match first type name + [Trait("Engine", "Managed")] public class GitContextManagedTests : GitContextTests { @@ -12,6 +18,7 @@ public GitContextManagedTests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: false); } @@ -24,13 +31,15 @@ public GitContextLibGit2Tests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); } public abstract class GitContextTests : RepoTestBase { - protected GitContextTests(ITestOutputHelper logger) : base(logger) + protected GitContextTests(ITestOutputHelper logger) + : base(logger) { this.InitializeSourceControl(); this.AddCommits(); @@ -166,7 +175,7 @@ public void SelectDirectory_SubDir() [Fact] public void GetVersion_PackedHead() { - using var expandedRepo = TestUtilities.ExtractRepoArchive("PackedHeadRef"); + using TestUtilities.ExpandedRepo expandedRepo = TestUtilities.ExtractRepoArchive("PackedHeadRef"); this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath)); var oracle = new VersionOracle(this.Context); Assert.Equal("1.0.1", oracle.SimpleVersion.ToString()); @@ -177,7 +186,7 @@ public void GetVersion_PackedHead() [Fact] public void HeadCanonicalName_PackedHead() { - using var expandedRepo = TestUtilities.ExtractRepoArchive("PackedHeadRef"); + using TestUtilities.ExpandedRepo expandedRepo = TestUtilities.ExtractRepoArchive("PackedHeadRef"); this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath)); Assert.Equal("refs/heads/main", this.Context.HeadCanonicalName); } diff --git a/test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs index 41d92807..8d908bd8 100644 --- a/test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs +++ b/test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Buffers.Binary; using System.Collections.Generic; using System.Diagnostics; @@ -14,16 +17,14 @@ public class LibGit2GitExtensionsTests : RepoTestBase { - public LibGit2GitExtensionsTests(ITestOutputHelper Logger) - : base(Logger) + public LibGit2GitExtensionsTests(ITestOutputHelper logger) + : base(logger) { this.InitializeSourceControl(); } protected new LibGit2Context Context => (LibGit2Context)base.Context; - protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); - [Fact] public void GetHeight_EmptyRepo() { @@ -37,9 +38,9 @@ public void GetHeight_EmptyRepo() [Fact] public void GetHeight_SinglePath() { - var first = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - var second = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - var third = this.LibGit2Repository.Commit("Third", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Commit first = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Commit second = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Commit third = this.LibGit2Repository.Commit("Third", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); this.SetContextToHead(); Assert.Equal(3, LibGit2GitExtensions.GetHeight(this.Context)); Assert.Equal(3, LibGit2GitExtensions.GetHeight(this.Context, c => true)); @@ -51,9 +52,9 @@ public void GetHeight_SinglePath() [Fact] public void GetHeight_Merge() { - var firstCommit = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - var anotherBranch = this.LibGit2Repository.CreateBranch("another"); - var secondCommit = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Commit firstCommit = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Branch anotherBranch = this.LibGit2Repository.CreateBranch("another"); + Commit secondCommit = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); Commands.Checkout(this.LibGit2Repository, anotherBranch); Commit[] branchCommits = new Commit[5]; for (int i = 1; i <= branchCommits.Length; i++) @@ -88,18 +89,18 @@ public void GetCommitsFromVersion_WithPathFilters() { new FilterPath("./", relativeDirectory), new FilterPath(":^/some-sub-dir/ignore.txt", relativeDirectory), - new FilterPath(":^excluded-dir", relativeDirectory) + new FilterPath(":^excluded-dir", relativeDirectory), }; commitsAt121.Add(this.WriteVersionFile(versionData, relativeDirectory)); // Commit touching excluded path does not affect version height - var ignoredFilePath = Path.Combine(this.RepoPath, relativeDirectory, "ignore.txt"); + string ignoredFilePath = Path.Combine(this.RepoPath, relativeDirectory, "ignore.txt"); File.WriteAllText(ignoredFilePath, "hello"); Commands.Stage(this.LibGit2Repository, ignoredFilePath); commitsAt121.Add(this.LibGit2Repository.Commit("Add excluded file", this.Signer, this.Signer)); // Commit touching both excluded and included path does affect height - var includedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); + string includedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); File.WriteAllText(includedFilePath, "hello"); File.WriteAllText(ignoredFilePath, "changed"); Commands.Stage(this.LibGit2Repository, includedFilePath); @@ -107,7 +108,7 @@ public void GetCommitsFromVersion_WithPathFilters() commitsAt122.Add(this.LibGit2Repository.Commit("Change both excluded and included file", this.Signer, this.Signer)); // Commit touching excluded directory does not affect version height - var fileInExcludedDirPath = Path.Combine(this.RepoPath, relativeDirectory, "excluded-dir", "ignore.txt"); + string fileInExcludedDirPath = Path.Combine(this.RepoPath, relativeDirectory, "excluded-dir", "ignore.txt"); Directory.CreateDirectory(Path.GetDirectoryName(fileInExcludedDirPath)); File.WriteAllText(fileInExcludedDirPath, "hello"); Commands.Stage(this.LibGit2Repository, fileInExcludedDirPath); @@ -183,7 +184,7 @@ public void GetVersionHeight_ProgressAndReset(string version1, string version2, public void GetIdAsVersion_ReadsMajorMinorFromVersionTxt() { this.WriteVersionFile("4.8"); - var firstCommit = this.LibGit2Repository.Commits.First(); + Commit firstCommit = this.LibGit2Repository.Commits.First(); Version v1 = this.GetVersion(committish: firstCommit.Sha); Assert.Equal(4, v1.Major); @@ -194,7 +195,7 @@ public void GetIdAsVersion_ReadsMajorMinorFromVersionTxt() public void GetIdAsVersion_ReadsMajorMinorFromVersionTxtInSubdirectory() { this.WriteVersionFile("4.8", relativeDirectory: "foo/bar"); - var firstCommit = this.LibGit2Repository.Commits.First(); + Commit firstCommit = this.LibGit2Repository.Commits.First(); Version v1 = this.GetVersion("foo/bar", firstCommit.Sha); Assert.Equal(4, v1.Major); @@ -205,7 +206,7 @@ public void GetIdAsVersion_ReadsMajorMinorFromVersionTxtInSubdirectory() public void GetIdAsVersion_MissingVersionTxt() { this.AddCommits(); - var firstCommit = this.LibGit2Repository.Commits.First(); + Commit firstCommit = this.LibGit2Repository.Commits.First(); Version v1 = this.GetVersion(committish: firstCommit.Sha); Assert.Equal(0, v1.Major); @@ -247,7 +248,7 @@ public void GetIdAsVersion_VersionFileNeverCheckedIn_2Ints() public void GetIdAsVersion_VersionFileChangedOnDisk() { this.WriteVersionFile(); - var versionChangeCommit = this.LibGit2Repository.Commits.First(); + Commit versionChangeCommit = this.LibGit2Repository.Commits.First(); this.AddCommits(); // Verify that we're seeing the original version. @@ -363,7 +364,7 @@ public void GetIdAsVersion_Roundtrip_UnstableOffset(int startingOffset, int offs this.Logger.WriteLine($"Commit {commits[i + 1].Id.Sha.Substring(0, 8)} as version: {versions[i + 1]}"); // Find the commits we just wrote while they are still at the tip of the branch. - var matchingCommits = LibGit2GitExtensions.GetCommitsFromVersion(this.Context, versions[i]); + IEnumerable matchingCommits = LibGit2GitExtensions.GetCommitsFromVersion(this.Context, versions[i]); Assert.Contains(commits[i], matchingCommits); matchingCommits = LibGit2GitExtensions.GetCommitsFromVersion(this.Context, versions[i + 1]); Assert.Contains(commits[i + 1], matchingCommits); @@ -431,7 +432,7 @@ public void GetIdAsVersion_Roundtrip_WithSubdirectoryVersionFiles() public void GetIdAsVersion_FitsInsideCompilerConstraints() { this.WriteVersionFile("2.5"); - var firstCommit = this.LibGit2Repository.Commits.First(); + Commit firstCommit = this.LibGit2Repository.Commits.First(); Version version = this.GetVersion(committish: firstCommit.Sha); this.Logger.WriteLine(version.ToString()); @@ -445,11 +446,11 @@ public void GetIdAsVersion_FitsInsideCompilerConstraints() [Fact] public void GetIdAsVersion_MigrationFromVersionTxtToJson() { - var txtCommit = this.WriteVersionTxtFile("4.8"); + Commit txtCommit = this.WriteVersionTxtFile("4.8"); // Delete the version.txt file so the system writes the version.json file. File.Delete(Path.Combine(this.RepoPath, "version.txt")); - var jsonCommit = this.WriteVersionFile("4.8"); + Commit jsonCommit = this.WriteVersionFile("4.8"); Assert.True(File.Exists(Path.Combine(this.RepoPath, "version.json"))); Version v1 = this.GetVersion(committish: txtCommit.Sha); @@ -466,20 +467,23 @@ public void GetIdAsVersion_MigrationFromVersionTxtToJson() [SkippableFact(Skip = "It fails already.")] // Skippable, only run test on specific machine public void TestBiggerRepo() { - var testBiggerRepoPath = @"D:\git\NerdBank.GitVersioning"; + string testBiggerRepoPath = @"D:\git\NerdBank.GitVersioning"; Skip.If(!Directory.Exists(testBiggerRepoPath)); using var largeRepo = new Repository(testBiggerRepoPath); - foreach (var commit in largeRepo.Head.Commits) + foreach (Commit commit in largeRepo.Head.Commits) { - var version = this.GetVersion("src", commit.Sha); + Version version = this.GetVersion("src", commit.Sha); this.Logger.WriteLine($"commit {commit.Id} got version {version}"); using var context = LibGit2Context.Create("src", commit.Sha); - var backAgain = LibGit2GitExtensions.GetCommitFromVersion(context, version); + Commit backAgain = LibGit2GitExtensions.GetCommitFromVersion(context, version); Assert.Equal(commit, backAgain); } } + /// + protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); + private Commit[] CommitsWithVersion(string majorMinorVersion) { this.WriteVersionFile(majorMinorVersion); diff --git a/test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs b/test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs index 5edbbd07..84679522 100644 --- a/test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs +++ b/test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs @@ -1,8 +1,6 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + using Microsoft.Build.Construction; using Microsoft.Build.Evaluation; using Microsoft.Build.Execution; @@ -14,12 +12,12 @@ internal static class MSBuildExtensions { - private static readonly object loadLock = new object(); + private static readonly object LoadLock = new object(); private static bool loaded; internal static void LoadMSBuild() { - lock (loadLock) + lock (LoadLock) { if (!loaded) { @@ -48,7 +46,7 @@ internal static async Task BuildAsync(this BuildManager buildManage buildManager.BeginBuild(parameters); - var result = await buildManager.BuildAsync(brd); + BuildResult result = await buildManager.BuildAsync(brd); buildManager.EndBuild(); @@ -61,7 +59,7 @@ internal static Task BuildAsync(this BuildManager buildManager, Bui Requires.NotNull(buildRequestData, nameof(buildRequestData)); var tcs = new TaskCompletionSource(); - var submission = buildManager.PendBuildRequest(buildRequestData); + BuildSubmission submission = buildManager.PendBuildRequest(buildRequestData); submission.ExecuteAsync(s => tcs.SetResult(s.BuildResult), null); return tcs.Task; } diff --git a/test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs b/test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs index 059f36f6..97191ad5 100644 --- a/test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs +++ b/test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs @@ -1,4 +1,7 @@ -public class MSBuildFixture +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +public class MSBuildFixture { public MSBuildFixture() { diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs index 279e0a16..b0b7a595 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs @@ -1,150 +1,103 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.ObjectModel; using System.IO; using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace ManagedGit +namespace ManagedGit; + +// Test case borrowed from https://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/#format-of-the-delta-representation +public class DeltaStreamReaderTests { - // Test case borrowed from https://stefan.saasen.me/articles/git-clone-in-haskell-from-the-bottom-up/#format-of-the-delta-representation - public class DeltaStreamReaderTests + [Fact] + public void ReadCopyInstruction() { - [Fact] - public void ReadCopyInstruction() - { - using (Stream stream = new MemoryStream( - new byte[] - { - 0b_10110000, - 0b_11010001, - 0b_00000001 - })) - { - var instruction = DeltaStreamReader.Read(stream).Value; - - Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); - Assert.Equal(0, instruction.Offset); - Assert.Equal(465, instruction.Size); - } - } - - [Fact] - public void ReadCopyInstruction_Memory() - { - var stream = new byte[] + using (Stream stream = new MemoryStream( + new byte[] { 0b_10110000, 0b_11010001, - 0b_00000001 - }; - var memory = new ReadOnlyMemory(stream); - - var instruction = DeltaStreamReader.Read(ref memory).Value; + 0b_00000001, + })) + { + DeltaInstruction instruction = DeltaStreamReader.Read(stream).Value; - Assert.Equal(0, memory.Length); Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); Assert.Equal(0, instruction.Offset); Assert.Equal(465, instruction.Size); } + } - [Fact] - public void ReadInsertInstruction() + [Fact] + public void ReadCopyInstruction_Memory() + { + byte[] stream = new byte[] { - using (Stream stream = new MemoryStream(new byte[] { 0b_00010111 })) - { - var instruction = DeltaStreamReader.Read(stream).Value; - - Assert.Equal(DeltaInstructionType.Insert, instruction.InstructionType); - Assert.Equal(0, instruction.Offset); - Assert.Equal(23, instruction.Size); - } - } + 0b_10110000, + 0b_11010001, + 0b_00000001, + }; + var memory = new ReadOnlyMemory(stream); + + DeltaInstruction instruction = DeltaStreamReader.Read(ref memory).Value; + + Assert.Equal(0, memory.Length); + Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); + Assert.Equal(0, instruction.Offset); + Assert.Equal(465, instruction.Size); + } - [Fact] - public void ReadInsertInstruction_Memory() + [Fact] + public void ReadInsertInstruction() + { + using (Stream stream = new MemoryStream(new byte[] { 0b_00010111 })) { - var stream = new byte[] { 0b_00010111 }; - var memory = new ReadOnlyMemory(stream); - - var instruction = DeltaStreamReader.Read(ref memory).Value; + DeltaInstruction instruction = DeltaStreamReader.Read(stream).Value; - Assert.Equal(0, memory.Length); Assert.Equal(DeltaInstructionType.Insert, instruction.InstructionType); Assert.Equal(0, instruction.Offset); Assert.Equal(23, instruction.Size); } + } - [Fact] - public void ReadStreamTest() - { - using (Stream stream = new MemoryStream( - new byte[] - { - 0b_10110011, 0b_11001110, 0b_00000001, 0b_00100111, 0b_00000001, - 0b_10110011, 0b_01011111, 0b_00000011, 0b_01101100, 0b_00010000, 0b_10010011, - 0b_11110101, 0b_00000010, 0b_01101011, 0b_10110011, 0b_11001011, 0b_00010011, - 0b_01000110, 0b_00000011})) - { - Collection instructions = new Collection(); + [Fact] + public void ReadInsertInstruction_Memory() + { + byte[] stream = new byte[] { 0b_00010111 }; + var memory = new ReadOnlyMemory(stream); - DeltaInstruction? current; + DeltaInstruction instruction = DeltaStreamReader.Read(ref memory).Value; - while ((current = DeltaStreamReader.Read(stream)) is not null) - { - instructions.Add(current.Value); - } - - Assert.Collection( - instructions, - instruction => - { - Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); - Assert.Equal(462, instruction.Offset); - Assert.Equal(295, instruction.Size); - }, - instruction => - { - Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); - Assert.Equal(863, instruction.Offset); - Assert.Equal(4204, instruction.Size); - }, - instruction => - { - Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); - Assert.Equal(757, instruction.Offset); - Assert.Equal(107, instruction.Size); - }, - instruction => - { - Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); - Assert.Equal(5067, instruction.Offset); - Assert.Equal(838, instruction.Size); - }); - } - } + Assert.Equal(0, memory.Length); + Assert.Equal(DeltaInstructionType.Insert, instruction.InstructionType); + Assert.Equal(0, instruction.Offset); + Assert.Equal(23, instruction.Size); + } - [Fact] - public void ReadStreamTest_Memory() + [Fact] + public void ReadStreamTest() + { + using (Stream stream = new MemoryStream( + new byte[] + { + 0b_10110011, 0b_11001110, 0b_00000001, 0b_00100111, 0b_00000001, + 0b_10110011, 0b_01011111, 0b_00000011, 0b_01101100, 0b_00010000, 0b_10010011, + 0b_11110101, 0b_00000010, 0b_01101011, 0b_10110011, 0b_11001011, 0b_00010011, + 0b_01000110, 0b_00000011, + })) { - var stream = - new byte[] - { - 0b_10110011, 0b_11001110, 0b_00000001, 0b_00100111, 0b_00000001, - 0b_10110011, 0b_01011111, 0b_00000011, 0b_01101100, 0b_00010000, 0b_10010011, - 0b_11110101, 0b_00000010, 0b_01101011, 0b_10110011, 0b_11001011, 0b_00010011, - 0b_01000110, 0b_00000011}; - var memory = new ReadOnlyMemory(stream); - Collection instructions = new Collection(); DeltaInstruction? current; - while ((current = DeltaStreamReader.Read(ref memory)) is not null) + while ((current = DeltaStreamReader.Read(stream)) is not null) { instructions.Add(current.Value); } - Assert.Equal(0, memory.Length); Assert.Collection( instructions, instruction => @@ -173,4 +126,55 @@ public void ReadStreamTest_Memory() }); } } + + [Fact] + public void ReadStreamTest_Memory() + { + byte[] stream = + new byte[] + { + 0b_10110011, 0b_11001110, 0b_00000001, 0b_00100111, 0b_00000001, + 0b_10110011, 0b_01011111, 0b_00000011, 0b_01101100, 0b_00010000, 0b_10010011, + 0b_11110101, 0b_00000010, 0b_01101011, 0b_10110011, 0b_11001011, 0b_00010011, + 0b_01000110, 0b_00000011, + }; + var memory = new ReadOnlyMemory(stream); + + Collection instructions = new Collection(); + + DeltaInstruction? current; + + while ((current = DeltaStreamReader.Read(ref memory)) is not null) + { + instructions.Add(current.Value); + } + + Assert.Equal(0, memory.Length); + Assert.Collection( + instructions, + instruction => + { + Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); + Assert.Equal(462, instruction.Offset); + Assert.Equal(295, instruction.Size); + }, + instruction => + { + Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); + Assert.Equal(863, instruction.Offset); + Assert.Equal(4204, instruction.Size); + }, + instruction => + { + Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); + Assert.Equal(757, instruction.Offset); + Assert.Equal(107, instruction.Size); + }, + instruction => + { + Assert.Equal(DeltaInstructionType.Copy, instruction.InstructionType); + Assert.Equal(5067, instruction.Offset); + Assert.Equal(838, instruction.Size); + }); + } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs index ea4feeab..c4c96d60 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs @@ -1,53 +1,55 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.Linq; using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace ManagedGit +namespace ManagedGit; + +public class GitCommitReaderTests { - public class GitCommitReaderTests + [Fact] + public void ReadTest() { - [Fact] - public void ReadTest() + using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\commit-d56dc3ed179053abef2097d1120b4507769bcf1a")) { - using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\commit-d56dc3ed179053abef2097d1120b4507769bcf1a")) - { - var commit = GitCommitReader.Read(stream, GitObjectId.Parse("d56dc3ed179053abef2097d1120b4507769bcf1a"), readAuthor: true); + GitCommit commit = GitCommitReader.Read(stream, GitObjectId.Parse("d56dc3ed179053abef2097d1120b4507769bcf1a"), readAuthor: true); - Assert.Equal("d56dc3ed179053abef2097d1120b4507769bcf1a", commit.Sha.ToString()); - Assert.Equal("f914b48023c7c804a4f3be780d451f31aef74ac1", commit.Tree.ToString()); + Assert.Equal("d56dc3ed179053abef2097d1120b4507769bcf1a", commit.Sha.ToString()); + Assert.Equal("f914b48023c7c804a4f3be780d451f31aef74ac1", commit.Tree.ToString()); - Assert.Collection( - commit.Parents, - c => Assert.Equal("4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6", c.ToString()), - c => Assert.Equal("0989e8fe0cd0e0900173b26decdfb24bc0cc8232", c.ToString())); + Assert.Collection( + commit.Parents, + c => Assert.Equal("4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6", c.ToString()), + c => Assert.Equal("0989e8fe0cd0e0900173b26decdfb24bc0cc8232", c.ToString())); - var author = commit.Author.Value; + GitSignature author = commit.Author.Value; - Assert.Equal("Andrew Arnott", author.Name); - Assert.Equal(new DateTimeOffset(2020, 10, 6, 13, 40, 09, TimeSpan.FromHours(-6)), author.Date); - Assert.Equal("andrewarnott@gmail.com", author.Email); + Assert.Equal("Andrew Arnott", author.Name); + Assert.Equal(new DateTimeOffset(2020, 10, 6, 13, 40, 09, TimeSpan.FromHours(-6)), author.Date); + Assert.Equal("andrewarnott@gmail.com", author.Email); - // Committer and commit message are not read - } + // Committer and commit message are not read } + } - [Fact] - public void ReadCommitWithThreeParents() + [Fact] + public void ReadCommitWithThreeParents() + { + using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\commit-ab39e8acac105fa0db88514f259341c9f0201b22")) { - using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\commit-ab39e8acac105fa0db88514f259341c9f0201b22")) - { - var commit = GitCommitReader.Read(stream, GitObjectId.Parse("ab39e8acac105fa0db88514f259341c9f0201b22"), readAuthor: true); - - Assert.Equal(3, commit.Parents.Count()); - - Assert.Collection( - commit.Parents, - c => Assert.Equal("e0b4d66ef7915417e04e88d5fa173185bb940029", c.ToString()), - c => Assert.Equal("10e67ce38fbee44b3f5584d4f9df6de6c5f4cc5c", c.ToString()), - c => Assert.Equal("a7fef320334121af85dce4b9b731f6c9a9127cfd", c.ToString())); - } + GitCommit commit = GitCommitReader.Read(stream, GitObjectId.Parse("ab39e8acac105fa0db88514f259341c9f0201b22"), readAuthor: true); + + Assert.Equal(3, commit.Parents.Count()); + + Assert.Collection( + commit.Parents, + c => Assert.Equal("e0b4d66ef7915417e04e88d5fa173185bb940029", c.ToString()), + c => Assert.Equal("10e67ce38fbee44b3f5584d4f9df6de6c5f4cc5c", c.ToString()), + c => Assert.Equal("a7fef320334121af85dce4b9b731f6c9a9127cfd", c.ToString())); } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs index 36aebaeb..d053ba2a 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs @@ -1,98 +1,100 @@ -using Nerdbank.GitVersioning.ManagedGit; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace ManagedGit +namespace ManagedGit; + +public class GitCommitTests { - public class GitCommitTests + private readonly byte[] shaAsByteArray = new byte[] { 0x4e, 0x91, 0x27, 0x36, 0xc2, 0x7e, 0x40, 0xb3, 0x89, 0x90, 0x4d, 0x04, 0x6d, 0xc6, 0x3d, 0xc9, 0xf5, 0x78, 0x11, 0x7f }; + + [Fact] + public void EqualsObjectTest() + { + var commit = new GitCommit() + { + Sha = GitObjectId.Parse(this.shaAsByteArray), + }; + + var commit2 = new GitCommit() + { + Sha = GitObjectId.Parse(this.shaAsByteArray), + }; + + var emptyCommit = new GitCommit() + { + Sha = GitObjectId.Empty, + }; + + // Must be equal to itself + Assert.True(commit.Equals((object)commit)); + Assert.True(commit.Equals((object)commit2)); + + // Not equal to null + Assert.False(commit.Equals(null)); + + // Not equal to other representations of the commit + Assert.False(commit.Equals(this.shaAsByteArray)); + Assert.False(commit.Equals(commit.Sha)); + + // Not equal to other object ids + Assert.False(commit.Equals((object)emptyCommit)); + } + + [Fact] + public void EqualsCommitTest() { - private readonly byte[] shaAsByteArray = new byte[] { 0x4e, 0x91, 0x27, 0x36, 0xc2, 0x7e, 0x40, 0xb3, 0x89, 0x90, 0x4d, 0x04, 0x6d, 0xc6, 0x3d, 0xc9, 0xf5, 0x78, 0x11, 0x7f }; + var commit = new GitCommit() + { + Sha = GitObjectId.Parse(this.shaAsByteArray), + }; + + var commit2 = new GitCommit() + { + Sha = GitObjectId.Parse(this.shaAsByteArray), + }; - [Fact] - public void EqualsObjectTest() + var emptyCommit = new GitCommit() { - var commit = new GitCommit() - { - Sha = GitObjectId.Parse(this.shaAsByteArray), - }; - - var commit2 = new GitCommit() - { - Sha = GitObjectId.Parse(this.shaAsByteArray), - }; - - var emptyCommit = new GitCommit() - { - Sha = GitObjectId.Empty, - }; - - // Must be equal to itself - Assert.True(commit.Equals((object)commit)); - Assert.True(commit.Equals((object)commit2)); - - // Not equal to null - Assert.False(commit.Equals(null)); - - // Not equal to other representations of the commit - Assert.False(commit.Equals(this.shaAsByteArray)); - Assert.False(commit.Equals(commit.Sha)); - - // Not equal to other object ids - Assert.False(commit.Equals((object)emptyCommit)); - } - - [Fact] - public void EqualsCommitTest() + Sha = GitObjectId.Empty, + }; + + // Must be equal to itself + Assert.True(commit.Equals(commit2)); + Assert.True(commit.Equals(commit2)); + + // Not equal to other object ids + Assert.False(commit.Equals(emptyCommit)); + } + + [Fact] + public void GetHashCodeTest() + { + var commit = new GitCommit() { - var commit = new GitCommit() - { - Sha = GitObjectId.Parse(this.shaAsByteArray), - }; - - var commit2 = new GitCommit() - { - Sha = GitObjectId.Parse(this.shaAsByteArray), - }; - - var emptyCommit = new GitCommit() - { - Sha = GitObjectId.Empty, - }; - - // Must be equal to itself - Assert.True(commit.Equals(commit2)); - Assert.True(commit.Equals(commit2)); - - // Not equal to other object ids - Assert.False(commit.Equals(emptyCommit)); - } - - [Fact] - public void GetHashCodeTest() + Sha = GitObjectId.Parse(this.shaAsByteArray), + }; + + var emptyCommit = new GitCommit() { - var commit = new GitCommit() - { - Sha = GitObjectId.Parse(this.shaAsByteArray), - }; - - var emptyCommit = new GitCommit() - { - Sha = GitObjectId.Empty, - }; - - // The hash code is the int32 representation of the first 4 bytes of the SHA hash - Assert.Equal(0x3627914e, commit.GetHashCode()); - Assert.Equal(0, emptyCommit.GetHashCode()); - } - - [Fact] - public void ToStringTest() + Sha = GitObjectId.Empty, + }; + + // The hash code is the int32 representation of the first 4 bytes of the SHA hash + Assert.Equal(0x3627914e, commit.GetHashCode()); + Assert.Equal(0, emptyCommit.GetHashCode()); + } + + [Fact] + public void ToStringTest() + { + var commit = new GitCommit() { - var commit = new GitCommit() - { - Sha = GitObjectId.Parse(this.shaAsByteArray), - }; + Sha = GitObjectId.Parse(this.shaAsByteArray), + }; - Assert.Equal("Git Commit: 4e912736c27e40b389904d046dc63dc9f578117f", commit.ToString()); - } + Assert.Equal("Git Commit: 4e912736c27e40b389904d046dc63dc9f578117f", commit.ToString()); } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs index baeb4ff7..273f65ad 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs @@ -1,134 +1,136 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Runtime.InteropServices; using System.Text; using Nerdbank.GitVersioning.ManagedGit; using Xunit; using Xunit.Abstractions; -namespace ManagedGit +namespace ManagedGit; + +public class GitObjectIdTests { - public class GitObjectIdTests + private const string ShaAsHexString = "4e912736c27e40b389904d046dc63dc9f578117f"; + private readonly byte[] shaAsByteArray = new byte[] { 0x4e, 0x91, 0x27, 0x36, 0xc2, 0x7e, 0x40, 0xb3, 0x89, 0x90, 0x4d, 0x04, 0x6d, 0xc6, 0x3d, 0xc9, 0xf5, 0x78, 0x11, 0x7f }; + private readonly byte[] shaAsHexAsciiByteArray = Encoding.ASCII.GetBytes(ShaAsHexString); + + [Fact] + public void ParseByteArrayTest() + { + var objectId = GitObjectId.Parse(this.shaAsByteArray); + + Span value = stackalloc byte[20]; + objectId.CopyTo(value); + Assert.True(value.SequenceEqual(this.shaAsByteArray.AsSpan())); + } + + [Fact] + public void ParseStringTest() + { + var objectId = GitObjectId.Parse(ShaAsHexString); + + Span value = stackalloc byte[20]; + objectId.CopyTo(value); + Assert.True(value.SequenceEqual(this.shaAsByteArray.AsSpan())); + } + + [Fact] + public void ParseHexArrayTest() + { + var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + + Span value = stackalloc byte[20]; + objectId.CopyTo(value); + Assert.True(value.SequenceEqual(this.shaAsByteArray.AsSpan())); + } + + [Fact] + public void EqualsObjectTest() + { + var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + var objectId2 = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + + // Must be equal to itself + Assert.True(objectId.Equals((object)objectId)); + Assert.True(objectId.Equals((object)objectId2)); + + // Not equal to null + Assert.False(objectId.Equals(null)); + + // Not equal to other representations of the object id + Assert.False(objectId.Equals(this.shaAsHexAsciiByteArray)); + Assert.False(objectId.Equals(this.shaAsByteArray)); + Assert.False(objectId.Equals(ShaAsHexString)); + + // Not equal to other object ids + Assert.False(objectId.Equals((object)GitObjectId.Empty)); + } + + [Fact] + public void EqualsObjectIdTest() { - private readonly byte[] shaAsByteArray = new byte[] { 0x4e, 0x91, 0x27, 0x36, 0xc2, 0x7e, 0x40, 0xb3, 0x89, 0x90, 0x4d, 0x04, 0x6d, 0xc6, 0x3d, 0xc9, 0xf5, 0x78, 0x11, 0x7f }; - private const string shaAsHexString = "4e912736c27e40b389904d046dc63dc9f578117f"; - private readonly byte[] shaAsHexAsciiByteArray = Encoding.ASCII.GetBytes(shaAsHexString); - - [Fact] - public void ParseByteArrayTest() - { - var objectId = GitObjectId.Parse(this.shaAsByteArray); - - Span value = stackalloc byte[20]; - objectId.CopyTo(value); - Assert.True(value.SequenceEqual(this.shaAsByteArray.AsSpan())); - } - - [Fact] - public void ParseStringTest() - { - var objectId = GitObjectId.Parse(shaAsHexString); - - Span value = stackalloc byte[20]; - objectId.CopyTo(value); - Assert.True(value.SequenceEqual(this.shaAsByteArray.AsSpan())); - } - - [Fact] - public void ParseHexArrayTest() - { - var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - - Span value = stackalloc byte[20]; - objectId.CopyTo(value); - Assert.True(value.SequenceEqual(this.shaAsByteArray.AsSpan())); - } - - [Fact] - public void EqualsObjectTest() - { - var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - var objectId2 = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - - // Must be equal to itself - Assert.True(objectId.Equals((object)objectId)); - Assert.True(objectId.Equals((object)objectId2)); - - // Not equal to null - Assert.False(objectId.Equals(null)); - - // Not equal to other representations of the object id - Assert.False(objectId.Equals(this.shaAsHexAsciiByteArray)); - Assert.False(objectId.Equals(this.shaAsByteArray)); - Assert.False(objectId.Equals(shaAsHexString)); - - // Not equal to other object ids - Assert.False(objectId.Equals((object)GitObjectId.Empty)); - } - - [Fact] - public void EqualsObjectIdTest() - { - var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - var objectId2 = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - - // Must be equal to itself - Assert.True(objectId.Equals(objectId)); - Assert.True(objectId.Equals(objectId2)); - - // Not equal to other object ids - Assert.False(objectId.Equals(GitObjectId.Empty)); - } - - [Fact] - public void GetHashCodeTest() - { - // The hash code is the int32 representation of the first 4 bytes - var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - Assert.Equal(0x3627914e, objectId.GetHashCode()); - Assert.Equal(0, GitObjectId.Empty.GetHashCode()); - } - - [Fact] - public void AsUInt16Test() - { - // The hash code is the int32 representation of the first 4 bytes - var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - Assert.Equal(0x4e91, objectId.AsUInt16()); - Assert.Equal(0, GitObjectId.Empty.GetHashCode()); - } - - [Fact] - public void ToStringTest() - { - var objectId = GitObjectId.Parse(this.shaAsByteArray); - Assert.Equal(shaAsHexString, objectId.ToString()); - } - - [Fact] - public void CopyToUtf16StringTest() - { - // Common use case: create the path to the object in the Git object store, - // e.g. git/objects/[byte 0]/[bytes 1 - 19] - byte[] valueAsBytes = Encoding.Unicode.GetBytes("git/objects/00/01020304050607080910111213141516171819"); - Span valueAsChars = MemoryMarshal.Cast(valueAsBytes); - - var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); - objectId.CopyAsHex(0, 1, valueAsChars.Slice(12, 1 * 2)); - objectId.CopyAsHex(1, 19, valueAsChars.Slice(15, 19 * 2)); - - var path = Encoding.Unicode.GetString(valueAsBytes); - Assert.Equal("git/objects/4e/912736c27e40b389904d046dc63dc9f578117f", path); - } - - [Fact] - public void CopyToTest() - { - var objectId = GitObjectId.Parse(this.shaAsByteArray); - - byte[] actual = new byte[20]; - objectId.CopyTo(actual); - - Assert.Equal(this.shaAsByteArray, actual); - } + var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + var objectId2 = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + + // Must be equal to itself + Assert.True(objectId.Equals(objectId)); + Assert.True(objectId.Equals(objectId2)); + + // Not equal to other object ids + Assert.False(objectId.Equals(GitObjectId.Empty)); + } + + [Fact] + public void GetHashCodeTest() + { + // The hash code is the int32 representation of the first 4 bytes + var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + Assert.Equal(0x3627914e, objectId.GetHashCode()); + Assert.Equal(0, GitObjectId.Empty.GetHashCode()); + } + + [Fact] + public void AsUInt16Test() + { + // The hash code is the int32 representation of the first 4 bytes + var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + Assert.Equal(0x4e91, objectId.AsUInt16()); + Assert.Equal(0, GitObjectId.Empty.GetHashCode()); + } + + [Fact] + public void ToStringTest() + { + var objectId = GitObjectId.Parse(this.shaAsByteArray); + Assert.Equal(ShaAsHexString, objectId.ToString()); + } + + [Fact] + public void CopyToUtf16StringTest() + { + // Common use case: create the path to the object in the Git object store, + // e.g. git/objects/[byte 0]/[bytes 1 - 19] + byte[] valueAsBytes = Encoding.Unicode.GetBytes("git/objects/00/01020304050607080910111213141516171819"); + Span valueAsChars = MemoryMarshal.Cast(valueAsBytes); + + var objectId = GitObjectId.ParseHex(this.shaAsHexAsciiByteArray); + objectId.CopyAsHex(0, 1, valueAsChars.Slice(12, 1 * 2)); + objectId.CopyAsHex(1, 19, valueAsChars.Slice(15, 19 * 2)); + + string path = Encoding.Unicode.GetString(valueAsBytes); + Assert.Equal("git/objects/4e/912736c27e40b389904d046dc63dc9f578117f", path); + } + + [Fact] + public void CopyToTest() + { + var objectId = GitObjectId.Parse(this.shaAsByteArray); + + byte[] actual = new byte[20]; + objectId.CopyTo(actual); + + Assert.Equal(this.shaAsByteArray, actual); } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs index cd525257..2ffeaee9 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs @@ -1,32 +1,34 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.IO.Compression; using System.Security.Cryptography; using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace ManagedGit +namespace ManagedGit; + +public class GitObjectStreamTests { - public class GitObjectStreamTests + [Fact] + public void ReadTest() { - [Fact] - public void ReadTest() + using (Stream rawStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\3596ffe59898103a2675547d4597e742e1f2389c.gz")) + using (GitObjectStream stream = new GitObjectStream(rawStream, "commit")) + using (var sha = SHA1.Create()) { - using (Stream rawStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\3596ffe59898103a2675547d4597e742e1f2389c.gz")) - using (GitObjectStream stream = new GitObjectStream(rawStream, "commit")) - using (var sha = SHA1.Create()) - { - Assert.Equal(137, stream.Length); - var deflateStream = Assert.IsType(stream.BaseStream); - Assert.Same(rawStream, deflateStream.BaseStream); - Assert.Equal("commit", stream.ObjectType); - Assert.Equal(0, stream.Position); + Assert.Equal(137, stream.Length); + DeflateStream deflateStream = Assert.IsType(stream.BaseStream); + Assert.Same(rawStream, deflateStream.BaseStream); + Assert.Equal("commit", stream.ObjectType); + Assert.Equal(0, stream.Position); - var hash = sha.ComputeHash(stream); - Assert.Equal("U1WYLbBP+xD47Y32m+hpCCTpnLA=", Convert.ToBase64String(hash)); + byte[] hash = sha.ComputeHash(stream); + Assert.Equal("U1WYLbBP+xD47Y32m+hpCCTpnLA=", Convert.ToBase64String(hash)); - Assert.Equal(stream.Length, stream.Position); - } + Assert.Equal(stream.Length, stream.Position); } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs index 70728cfd..6f2af74a 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs @@ -1,40 +1,42 @@ -using System.IO; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace ManagedGit +namespace ManagedGit; + +public class GitPackDeltafiedStreamTests { - public class GitPackDeltafiedStreamTests + // Reconstructs an object by reading the base stream and the delta stream. + // You can create delta representations of an object by running the + // test tool which is located in the t/helper/ folder of the Git source repository. + // Use with the delta -d [base file,in] [updated file,in] [delta file,out] arguments. + [Theory] + [InlineData(@"ManagedGit\commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6", @"ManagedGit\commit.delta", @"ManagedGit\commit-d56dc3ed179053abef2097d1120b4507769bcf1a")] + [InlineData(@"ManagedGit\tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9", @"ManagedGit\tree.delta", @"ManagedGit\tree-f914b48023c7c804a4f3be780d451f31aef74ac1")] + public void TestDeltaStream(string basePath, string deltaPath, string expectedPath) { - // Reconstructs an object by reading the base stream and the delta stream. - // You can create delta representations of an object by running the - // test tool which is located in the t/helper/ folder of the Git source repository. - // Use with the delta -d [base file,in] [updated file,in] [delta file,out] arguments. - [Theory] - [InlineData(@"ManagedGit\commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6", @"ManagedGit\commit.delta", @"ManagedGit\commit-d56dc3ed179053abef2097d1120b4507769bcf1a")] - [InlineData(@"ManagedGit\tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9", @"ManagedGit\tree.delta", @"ManagedGit\tree-f914b48023c7c804a4f3be780d451f31aef74ac1")] - public void TestDeltaStream(string basePath, string deltaPath, string expectedPath) - { - byte[] expected = null; + byte[] expected = null; - using (Stream expectedStream = TestUtilities.GetEmbeddedResource(expectedPath)) - { - expected = new byte[expectedStream.Length]; - expectedStream.Read(expected); - } + using (Stream expectedStream = TestUtilities.GetEmbeddedResource(expectedPath)) + { + expected = new byte[expectedStream.Length]; + expectedStream.Read(expected); + } - byte[] actual = new byte[expected.Length]; + byte[] actual = new byte[expected.Length]; - using (Stream baseStream = TestUtilities.GetEmbeddedResource(basePath)) - using (Stream deltaStream = TestUtilities.GetEmbeddedResource(deltaPath)) - using (GitPackDeltafiedStream deltafiedStream = new GitPackDeltafiedStream(baseStream, deltaStream)) - { - // Assert.Equal(expected.Length, deltafiedStream.Length); + using (Stream baseStream = TestUtilities.GetEmbeddedResource(basePath)) + using (Stream deltaStream = TestUtilities.GetEmbeddedResource(deltaPath)) + using (GitPackDeltafiedStream deltafiedStream = new GitPackDeltafiedStream(baseStream, deltaStream)) + { + ////Assert.Equal(expected.Length, deltafiedStream.Length); - deltafiedStream.Read(actual); + deltafiedStream.Read(actual); - Assert.Equal(expected, actual); - } + Assert.Equal(expected, actual); } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs index 153839b7..d4e96eda 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs @@ -1,89 +1,89 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace ManagedGit +namespace ManagedGit; + +public class GitPackIndexMappedReaderTests { - public class GitPackIndexMappedReaderTests + [Fact] + public void ConstructorNullTest() + { + Assert.Throws(() => new GitPackIndexMappedReader(null)); + } + + [Fact] + public void GetOffsetTest() { - [Fact] - public void ConstructorNullTest() + string indexFile = Path.GetTempFileName(); + + using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx")) + using (FileStream stream = File.Open(indexFile, FileMode.Open)) { - Assert.Throws(() => new GitPackIndexMappedReader(null)); + resourceStream.CopyTo(stream); } - [Fact] - public void GetOffsetTest() + using (FileStream stream = File.OpenRead(indexFile)) + using (GitPackIndexReader reader = new GitPackIndexMappedReader(stream)) { - var indexFile = Path.GetTempFileName(); - - using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx")) - using (FileStream stream = File.Open(indexFile, FileMode.Open)) - { - resourceStream.CopyTo(stream); - } - - using (FileStream stream = File.OpenRead(indexFile)) - using (GitPackIndexReader reader = new GitPackIndexMappedReader(stream)) - { - // Offset of an object which is present - Assert.Equal(12, reader.GetOffset(GitObjectId.Parse("f5b401f40ad83f13030e946c9ea22cb54cb853cd"))); - Assert.Equal(317, reader.GetOffset(GitObjectId.Parse("d6781552a0a94adbf73ed77696712084754dc274"))); - - // null for an object which is not present - Assert.Null(reader.GetOffset(GitObjectId.Empty)); - } - - try - { - File.Delete(indexFile); - } - catch (UnauthorizedAccessException) - { - // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. - } + // Offset of an object which is present + Assert.Equal(12, reader.GetOffset(GitObjectId.Parse("f5b401f40ad83f13030e946c9ea22cb54cb853cd"))); + Assert.Equal(317, reader.GetOffset(GitObjectId.Parse("d6781552a0a94adbf73ed77696712084754dc274"))); + // null for an object which is not present + Assert.Null(reader.GetOffset(GitObjectId.Empty)); } - [Fact] - public void GetOffsetFromPartialTest() + try + { + File.Delete(indexFile); + } + catch (UnauthorizedAccessException) { - var indexFile = Path.GetTempFileName(); + // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. + } + } - using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx")) - using (FileStream stream = File.Open(indexFile, FileMode.Open)) - { - resourceStream.CopyTo(stream); - } + [Fact] + public void GetOffsetFromPartialTest() + { + string indexFile = Path.GetTempFileName(); - using (FileStream stream = File.OpenRead(indexFile)) - using (var reader = new GitPackIndexMappedReader(stream)) - { - // Offset of an object which is present - (var offset, var objectId) = reader.GetOffset(new byte[] { 0xf5, 0xb4, 0x01, 0xf4 }); - Assert.Equal(12, offset); - Assert.Equal(GitObjectId.Parse("f5b401f40ad83f13030e946c9ea22cb54cb853cd"), objectId); + using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx")) + using (FileStream stream = File.Open(indexFile, FileMode.Open)) + { + resourceStream.CopyTo(stream); + } - (offset, objectId) = reader.GetOffset(new byte[] { 0xd6, 0x78, 0x15, 0x52 }); - Assert.Equal(317, offset); - Assert.Equal(GitObjectId.Parse("d6781552a0a94adbf73ed77696712084754dc274"), objectId); + using (FileStream stream = File.OpenRead(indexFile)) + using (var reader = new GitPackIndexMappedReader(stream)) + { + // Offset of an object which is present + (long? offset, GitObjectId? objectId) = reader.GetOffset(new byte[] { 0xf5, 0xb4, 0x01, 0xf4 }); + Assert.Equal(12, offset); + Assert.Equal(GitObjectId.Parse("f5b401f40ad83f13030e946c9ea22cb54cb853cd"), objectId); - // null for an object which is not present - (offset, objectId) = reader.GetOffset(new byte[] { 0x00, 0x00, 0x00, 0x00 }); - Assert.Null(offset); - Assert.Null(objectId); - } + (offset, objectId) = reader.GetOffset(new byte[] { 0xd6, 0x78, 0x15, 0x52 }); + Assert.Equal(317, offset); + Assert.Equal(GitObjectId.Parse("d6781552a0a94adbf73ed77696712084754dc274"), objectId); - try - { - File.Delete(indexFile); - } - catch (UnauthorizedAccessException) - { - // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. - } + // null for an object which is not present + (offset, objectId) = reader.GetOffset(new byte[] { 0x00, 0x00, 0x00, 0x00 }); + Assert.Null(offset); + Assert.Null(objectId); + } + try + { + File.Delete(indexFile); + } + catch (UnauthorizedAccessException) + { + // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs index c9c51820..c03ae858 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs @@ -1,40 +1,42 @@ -using System.IO; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace NerdBank.GitVersioning.Tests.ManagedGit +namespace ManagedGit; + +/// +/// Tests the class. +/// +public class GitPackMemoryCacheTests { - /// - /// Tests the class. - /// - public class GitPackMemoryCacheTests + [Fact] + public void StreamsAreIndependent() { - [Fact] - public void StreamsAreIndependent() + using (MemoryStream stream = new MemoryStream( + new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })) { - using (MemoryStream stream = new MemoryStream( - new byte[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 })) - { - var cache = new GitPackMemoryCache(); + var cache = new GitPackMemoryCache(); - var stream1 = cache.Add(0, stream); - Assert.True(cache.TryOpen(0, out Stream stream2)); + Stream stream1 = cache.Add(0, stream); + Assert.True(cache.TryOpen(0, out Stream stream2)); - using (stream1) - using (stream2) - { - stream1.Seek(5, SeekOrigin.Begin); - Assert.Equal(5, stream1.Position); - Assert.Equal(0, stream2.Position); - Assert.Equal(5, stream1.ReadByte()); + using (stream1) + using (stream2) + { + stream1.Seek(5, SeekOrigin.Begin); + Assert.Equal(5, stream1.Position); + Assert.Equal(0, stream2.Position); + Assert.Equal(5, stream1.ReadByte()); - Assert.Equal(6, stream1.Position); - Assert.Equal(0, stream2.Position); + Assert.Equal(6, stream1.Position); + Assert.Equal(0, stream2.Position); - Assert.Equal(0, stream2.ReadByte()); - Assert.Equal(6, stream1.Position); - Assert.Equal(1, stream2.Position); - } + Assert.Equal(0, stream2.ReadByte()); + Assert.Equal(6, stream1.Position); + Assert.Equal(1, stream2.Position); } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs index e904dd09..61e9793f 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.IO.Compression; using System.Security.Cryptography; @@ -7,168 +10,168 @@ using Xunit; using ZLibStream = Nerdbank.GitVersioning.ManagedGit.ZLibStream; -namespace ManagedGit +namespace ManagedGit; + +public class GitPackTests : IDisposable { - public class GitPackTests : IDisposable + private readonly string indexFile = Path.GetTempFileName(); + private readonly string packFile = Path.GetTempFileName(); + + public GitPackTests() { - private readonly string indexFile = Path.GetTempFileName(); - private readonly string packFile = Path.GetTempFileName(); + using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx")) + using (FileStream stream = File.Open(this.indexFile, FileMode.Open)) + { + resourceStream.CopyTo(stream); + } - public GitPackTests() + using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack")) + using (FileStream stream = File.Open(this.packFile, FileMode.Open)) { - using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx")) - using (FileStream stream = File.Open(this.indexFile, FileMode.Open)) - { - resourceStream.CopyTo(stream); - } + resourceStream.CopyTo(stream); + } + } - using (Stream resourceStream = TestUtilities.GetEmbeddedResource(@"ManagedGit\pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack")) - using (FileStream stream = File.Open(this.packFile, FileMode.Open)) - { - resourceStream.CopyTo(stream); - } + /// + public void Dispose() + { + try + { + File.Delete(this.indexFile); + } + catch (UnauthorizedAccessException) + { + // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. } - public void Dispose() + try + { + File.Delete(this.packFile); + } + catch (UnauthorizedAccessException) { - try + // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. + } + } + + [Fact] + public void GetPackedObject() + { + using (var gitPack = new GitPack( + (sha, objectType) => null, + new Lazy(() => File.OpenRead(this.indexFile)), + () => File.OpenRead(this.packFile), + GitPackNullCache.Instance)) + using (Stream commitStream = gitPack.GetObject(12, "commit")) + using (SHA1 sha = SHA1.Create()) + { + // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. + ZLibStream zlibStream = Assert.IsType(commitStream); + DeflateStream deflateStream = Assert.IsType(zlibStream.BaseStream); + + if (IntPtr.Size > 4) { - File.Delete(this.indexFile); + MemoryMappedStream pooledStream = Assert.IsType(deflateStream.BaseStream); } - catch (UnauthorizedAccessException) + else { - // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. + FileStream pooledStream = Assert.IsType(deflateStream.BaseStream); } - try + Assert.Equal(222, commitStream.Length); + Assert.Equal("/zgldANj+jvgOwlecnOKylZDVQg=", Convert.ToBase64String(sha.ComputeHash(commitStream))); + } + } + + [Fact] + public void GetDeltafiedObject() + { + using (var gitPack = new GitPack( + (sha, objectType) => null, + new Lazy(() => File.OpenRead(this.indexFile)), + () => File.OpenRead(this.packFile), + GitPackNullCache.Instance)) + using (Stream commitStream = gitPack.GetObject(317, "commit")) + using (SHA1 sha = SHA1.Create()) + { + // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. + GitPackDeltafiedStream deltaStream = Assert.IsType(commitStream); + ZLibStream zlibStream = Assert.IsType(deltaStream.BaseStream); + DeflateStream deflateStream = Assert.IsType(zlibStream.BaseStream); + + if (IntPtr.Size > 4) { - File.Delete(this.packFile); + MemoryMappedStream pooledStream = Assert.IsType(deflateStream.BaseStream); } - catch (UnauthorizedAccessException) + else { - // TBD: Figure out what's keeping a lock on the file. Seems to be unique to Windows. + FileStream directAccessStream = Assert.IsType(deflateStream.BaseStream); } + + Assert.Equal(137, commitStream.Length); + Assert.Equal("lZu/7nGb0n1UuO9SlPluFnSvj4o=", Convert.ToBase64String(sha.ComputeHash(commitStream))); } + } - [Fact] - public void GetPackedObject() + [Fact] + public void GetInvalidObject() + { + using (var gitPack = new GitPack( + (sha, objectType) => null, + new Lazy(() => File.OpenRead(this.indexFile)), + () => File.OpenRead(this.packFile), + GitPackNullCache.Instance)) { - using (var gitPack = new GitPack( - (sha, objectType) => null, - new Lazy(() => File.OpenRead(this.indexFile)), - () => File.OpenRead(this.packFile), - GitPackNullCache.Instance)) - using (Stream commitStream = gitPack.GetObject(12, "commit")) - using (SHA1 sha = SHA1.Create()) - { - // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. - var zlibStream = Assert.IsType(commitStream); - var deflateStream = Assert.IsType(zlibStream.BaseStream); - - if (IntPtr.Size > 4) - { - var pooledStream = Assert.IsType(deflateStream.BaseStream); - } - else - { - var pooledStream = Assert.IsType(deflateStream.BaseStream); - } - - Assert.Equal(222, commitStream.Length); - Assert.Equal("/zgldANj+jvgOwlecnOKylZDVQg=", Convert.ToBase64String(sha.ComputeHash(commitStream))); - } + Assert.Throws(() => gitPack.GetObject(12, "invalid")); + Assert.Throws(() => gitPack.GetObject(-1, "commit")); + Assert.Throws(() => gitPack.GetObject(1, "commit")); + Assert.Throws(() => gitPack.GetObject(2, "commit")); + Assert.Throws(() => gitPack.GetObject(int.MaxValue, "commit")); } + } - [Fact] - public void GetDeltafiedObject() + [Fact] + public void TryGetObjectTest() + { + using (var gitPack = new GitPack( + (sha, objectType) => null, + new Lazy(() => File.OpenRead(this.indexFile)), + () => File.OpenRead(this.packFile), + GitPackNullCache.Instance)) + using (SHA1 sha = SHA1.Create()) { - using (var gitPack = new GitPack( - (sha, objectType) => null, - new Lazy(() => File.OpenRead(this.indexFile)), - () => File.OpenRead(this.packFile), - GitPackNullCache.Instance)) - using (Stream commitStream = gitPack.GetObject(317, "commit")) - using (SHA1 sha = SHA1.Create()) + Assert.True(gitPack.TryGetObject(GitObjectId.Parse("f5b401f40ad83f13030e946c9ea22cb54cb853cd"), "commit", out Stream commitStream)); + using (commitStream) { // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. - var deltaStream = Assert.IsType(commitStream); - var zlibStream = Assert.IsType(deltaStream.BaseStream); - var deflateStream = Assert.IsType(zlibStream.BaseStream); + ZLibStream zlibStream = Assert.IsType(commitStream); + DeflateStream deflateStream = Assert.IsType(zlibStream.BaseStream); if (IntPtr.Size > 4) { - var pooledStream = Assert.IsType(deflateStream.BaseStream); + MemoryMappedStream pooledStream = Assert.IsType(deflateStream.BaseStream); } else { - var directAccessStream = Assert.IsType(deflateStream.BaseStream); + FileStream directAccessStream = Assert.IsType(deflateStream.BaseStream); } - Assert.Equal(137, commitStream.Length); - Assert.Equal("lZu/7nGb0n1UuO9SlPluFnSvj4o=", Convert.ToBase64String(sha.ComputeHash(commitStream))); - } - } - - [Fact] - public void GetInvalidObject() - { - using (var gitPack = new GitPack( - (sha, objectType) => null, - new Lazy(() => File.OpenRead(this.indexFile)), - () => File.OpenRead(this.packFile), - GitPackNullCache.Instance)) - { - Assert.Throws(() => gitPack.GetObject(12, "invalid")); - Assert.Throws(() => gitPack.GetObject(-1, "commit")); - Assert.Throws(() => gitPack.GetObject(1, "commit")); - Assert.Throws(() => gitPack.GetObject(2, "commit")); - Assert.Throws(() => gitPack.GetObject(int.MaxValue, "commit")); - } - } - - [Fact] - public void TryGetObjectTest() - { - using (var gitPack = new GitPack( - (sha, objectType) => null, - new Lazy(() => File.OpenRead(this.indexFile)), - () => File.OpenRead(this.packFile), - GitPackNullCache.Instance)) - using (SHA1 sha = SHA1.Create()) - { - Assert.True(gitPack.TryGetObject(GitObjectId.Parse("f5b401f40ad83f13030e946c9ea22cb54cb853cd"), "commit", out Stream commitStream)); - using (commitStream) - { - // This commit is not deltafied. It is stored as a .gz-compressed stream in the pack file. - var zlibStream = Assert.IsType(commitStream); - var deflateStream = Assert.IsType(zlibStream.BaseStream); - - if (IntPtr.Size > 4) - { - var pooledStream = Assert.IsType(deflateStream.BaseStream); - } - else - { - var directAccessStream = Assert.IsType(deflateStream.BaseStream); - } - - Assert.Equal(222, commitStream.Length); - Assert.Equal("/zgldANj+jvgOwlecnOKylZDVQg=", Convert.ToBase64String(sha.ComputeHash(commitStream))); - } + Assert.Equal(222, commitStream.Length); + Assert.Equal("/zgldANj+jvgOwlecnOKylZDVQg=", Convert.ToBase64String(sha.ComputeHash(commitStream))); } } + } - [Fact] - public void TryGetMissingObjectTest() + [Fact] + public void TryGetMissingObjectTest() + { + using (var gitPack = new GitPack( + (sha, objectType) => null, + new Lazy(() => File.OpenRead(this.indexFile)), + () => File.OpenRead(this.packFile), + GitPackNullCache.Instance)) { - using (var gitPack = new GitPack( - (sha, objectType) => null, - new Lazy(() => File.OpenRead(this.indexFile)), - () => File.OpenRead(this.packFile), - GitPackNullCache.Instance)) - { - Assert.False(gitPack.TryGetObject(GitObjectId.Empty, "commit", out Stream commitStream)); - } + Assert.False(gitPack.TryGetObject(GitObjectId.Empty, "commit", out Stream commitStream)); } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs index edbbbb80..3a30c162 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.Linq; using System.Text; @@ -8,330 +11,330 @@ using Xunit; using Xunit.Abstractions; -namespace ManagedGit +namespace ManagedGit; + +public class GitRepositoryTests : RepoTestBase { - public class GitRepositoryTests : RepoTestBase + public GitRepositoryTests(ITestOutputHelper logger) + : base(logger) { - public GitRepositoryTests(ITestOutputHelper logger) - : base(logger) - { - } + } - protected override Nerdbank.GitVersioning.GitContext CreateGitContext(string path, string committish = null) - => Nerdbank.GitVersioning.GitContext.Create(path, committish, writable: false); + [Fact] + public void CreateTest() + { + this.InitializeSourceControl(); + this.AddCommits(1); - [Fact] - public void CreateTest() + using (var repository = GitRepository.Create(this.RepoPath)) { - this.InitializeSourceControl(); - this.AddCommits(1); - - using (var repository = GitRepository.Create(this.RepoPath)) - { - AssertPath(Path.Combine(this.RepoPath, ".git"), repository.CommonDirectory); - AssertPath(Path.Combine(this.RepoPath, ".git"), repository.GitDirectory); - AssertPath(this.RepoPath, repository.WorkingDirectory); - AssertPath(Path.Combine(this.RepoPath, ".git", "objects"), repository.ObjectDirectory); - } + AssertPath(Path.Combine(this.RepoPath, ".git"), repository.CommonDirectory); + AssertPath(Path.Combine(this.RepoPath, ".git"), repository.GitDirectory); + AssertPath(this.RepoPath, repository.WorkingDirectory); + AssertPath(Path.Combine(this.RepoPath, ".git", "objects"), repository.ObjectDirectory); } + } - [Fact] - public void CreateWorkTreeTest() - { - this.InitializeSourceControl(); - this.AddCommits(2); - - string workTreePath = this.CreateDirectoryForNewRepo(); - Directory.Delete(workTreePath); - this.LibGit2Repository.Worktrees.Add("HEAD~1", "myworktree", workTreePath, isLocked: false); - - using (var repository = GitRepository.Create(workTreePath)) - { - AssertPath(Path.Combine(this.RepoPath, ".git"), repository.CommonDirectory); - AssertPath(Path.Combine(this.RepoPath, ".git", "worktrees", "myworktree"), repository.GitDirectory); - AssertPath(workTreePath, repository.WorkingDirectory); - AssertPath(Path.Combine(this.RepoPath, ".git", "objects"), repository.ObjectDirectory); - } - } + [Fact] + public void CreateWorkTreeTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); - [Fact] - public void CreateNotARepoTest() + string workTreePath = this.CreateDirectoryForNewRepo(); + Directory.Delete(workTreePath); + this.LibGit2Repository.Worktrees.Add("HEAD~1", "myworktree", workTreePath, isLocked: false); + + using (var repository = GitRepository.Create(workTreePath)) { - Assert.Null(GitRepository.Create(null)); - Assert.Null(GitRepository.Create("")); - Assert.Null(GitRepository.Create("/A/Path/To/A/Directory/Which/Does/Not/Exist")); - Assert.Null(GitRepository.Create(this.RepoPath)); + AssertPath(Path.Combine(this.RepoPath, ".git"), repository.CommonDirectory); + AssertPath(Path.Combine(this.RepoPath, ".git", "worktrees", "myworktree"), repository.GitDirectory); + AssertPath(workTreePath, repository.WorkingDirectory); + AssertPath(Path.Combine(this.RepoPath, ".git", "objects"), repository.ObjectDirectory); } + } - // A "normal" repository, where a branch is currently checked out. - [Fact] - public void GetHeadAsReferenceTest() - { - this.InitializeSourceControl(); - this.AddCommits(2); + [Fact] + public void CreateNotARepoTest() + { + Assert.Null(GitRepository.Create(null)); + Assert.Null(GitRepository.Create(string.Empty)); + Assert.Null(GitRepository.Create("/A/Path/To/A/Directory/Which/Does/Not/Exist")); + Assert.Null(GitRepository.Create(this.RepoPath)); + } - var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); + // A "normal" repository, where a branch is currently checked out. + [Fact] + public void GetHeadAsReferenceTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); + + var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); - using (var repository = GitRepository.Create(this.RepoPath)) - { - var head = repository.GetHeadAsReferenceOrSha(); - var reference = Assert.IsType(head); - Assert.Equal("refs/heads/master", reference); + using (var repository = GitRepository.Create(this.RepoPath)) + { + object head = repository.GetHeadAsReferenceOrSha(); + string reference = Assert.IsType(head); + Assert.Equal("refs/heads/master", reference); - Assert.Equal(headObjectId, repository.GetHeadCommitSha()); + Assert.Equal(headObjectId, repository.GetHeadCommitSha()); - var headCommit = repository.GetHeadCommit(); - Assert.NotNull(headCommit); - Assert.Equal(headObjectId, headCommit.Value.Sha); - } + GitCommit? headCommit = repository.GetHeadCommit(); + Assert.NotNull(headCommit); + Assert.Equal(headObjectId, headCommit.Value.Sha); } + } - // A repository with a detached HEAD. - [Fact] - public void GetHeadAsShaTest() - { - this.InitializeSourceControl(); - this.AddCommits(2); + // A repository with a detached HEAD. + [Fact] + public void GetHeadAsShaTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); - var newHead = this.LibGit2Repository.Head.Tip.Parents.Single(); - var newHeadObjectId = GitObjectId.Parse(newHead.Sha); - Commands.Checkout(this.LibGit2Repository, this.LibGit2Repository.Head.Tip.Parents.Single()); + Commit newHead = this.LibGit2Repository.Head.Tip.Parents.Single(); + var newHeadObjectId = GitObjectId.Parse(newHead.Sha); + Commands.Checkout(this.LibGit2Repository, this.LibGit2Repository.Head.Tip.Parents.Single()); - using (var repository = GitRepository.Create(this.RepoPath)) - { - var detachedHead = repository.GetHeadAsReferenceOrSha(); - var reference = Assert.IsType(detachedHead); - Assert.Equal(newHeadObjectId, reference); + using (var repository = GitRepository.Create(this.RepoPath)) + { + object detachedHead = repository.GetHeadAsReferenceOrSha(); + GitObjectId reference = Assert.IsType(detachedHead); + Assert.Equal(newHeadObjectId, reference); - Assert.Equal(newHeadObjectId, repository.GetHeadCommitSha()); + Assert.Equal(newHeadObjectId, repository.GetHeadCommitSha()); - var headCommit = repository.GetHeadCommit(); - Assert.NotNull(headCommit); - Assert.Equal(newHeadObjectId, headCommit.Value.Sha); - } + GitCommit? headCommit = repository.GetHeadCommit(); + Assert.NotNull(headCommit); + Assert.Equal(newHeadObjectId, headCommit.Value.Sha); } + } - // A fresh repository with no commits yet. - [Fact] - public void GetHeadMissingTest() - { - this.InitializeSourceControl(withInitialCommit: false); + // A fresh repository with no commits yet. + [Fact] + public void GetHeadMissingTest() + { + this.InitializeSourceControl(withInitialCommit: false); - using (var repository = GitRepository.Create(this.RepoPath)) - { - var head = repository.GetHeadAsReferenceOrSha(); - var reference = Assert.IsType(head); - Assert.Equal("refs/heads/master", reference); + using (var repository = GitRepository.Create(this.RepoPath)) + { + object head = repository.GetHeadAsReferenceOrSha(); + string reference = Assert.IsType(head); + Assert.Equal("refs/heads/master", reference); - Assert.Equal(GitObjectId.Empty, repository.GetHeadCommitSha()); + Assert.Equal(GitObjectId.Empty, repository.GetHeadCommitSha()); - Assert.Null(repository.GetHeadCommit()); - } + Assert.Null(repository.GetHeadCommit()); } + } - // Fetch a commit from the object store - [Fact] - public void GetCommitTest() - { - this.InitializeSourceControl(); - this.AddCommits(2); + // Fetch a commit from the object store + [Fact] + public void GetCommitTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); - var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); + var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); - using (var repository = GitRepository.Create(this.RepoPath)) - { - var commit = repository.GetCommit(headObjectId); - Assert.Equal(headObjectId, commit.Sha); - } + using (var repository = GitRepository.Create(this.RepoPath)) + { + GitCommit commit = repository.GetCommit(headObjectId); + Assert.Equal(headObjectId, commit.Sha); } + } - [Fact] - public void GetInvalidCommitTest() - { - this.InitializeSourceControl(); - this.AddCommits(2); + [Fact] + public void GetInvalidCommitTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); - var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); + var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); - using (var repository = GitRepository.Create(this.RepoPath)) - { - Assert.Throws(() => repository.GetCommit(GitObjectId.Empty)); - } + using (var repository = GitRepository.Create(this.RepoPath)) + { + Assert.Throws(() => repository.GetCommit(GitObjectId.Empty)); } + } - [Fact] - public void GetTreeEntryTest() + [Fact] + public void GetTreeEntryTest() + { + this.InitializeSourceControl(); + File.WriteAllText(Path.Combine(this.RepoPath, "hello.txt"), "Hello, World"); + Commands.Stage(this.LibGit2Repository, "hello.txt"); + this.AddCommits(); + + using (var repository = GitRepository.Create(this.RepoPath)) { - this.InitializeSourceControl(); - File.WriteAllText(Path.Combine(this.RepoPath, "hello.txt"), "Hello, World"); - Commands.Stage(this.LibGit2Repository, "hello.txt"); - this.AddCommits(); - - using (var repository = GitRepository.Create(this.RepoPath)) - { - var headCommit = repository.GetHeadCommit(); - Assert.NotNull(headCommit); - - var helloBlobId = repository.GetTreeEntry(headCommit.Value.Tree, Encoding.UTF8.GetBytes("hello.txt")); - Assert.Equal("1856e9be02756984c385482a07e42f42efd5d2f3", helloBlobId.ToString()); - } + GitCommit? headCommit = repository.GetHeadCommit(); + Assert.NotNull(headCommit); + + GitObjectId helloBlobId = repository.GetTreeEntry(headCommit.Value.Tree, Encoding.UTF8.GetBytes("hello.txt")); + Assert.Equal("1856e9be02756984c385482a07e42f42efd5d2f3", helloBlobId.ToString()); } + } - [Fact] - public void GetInvalidTreeEntryTest() + [Fact] + public void GetInvalidTreeEntryTest() + { + this.InitializeSourceControl(); + File.WriteAllText(Path.Combine(this.RepoPath, "hello.txt"), "Hello, World"); + Commands.Stage(this.LibGit2Repository, "hello.txt"); + this.AddCommits(); + + using (var repository = GitRepository.Create(this.RepoPath)) { - this.InitializeSourceControl(); - File.WriteAllText(Path.Combine(this.RepoPath, "hello.txt"), "Hello, World"); - Commands.Stage(this.LibGit2Repository, "hello.txt"); - this.AddCommits(); - - using (var repository = GitRepository.Create(this.RepoPath)) - { - var headCommit = repository.GetHeadCommit(); - Assert.NotNull(headCommit); - - Assert.Equal(GitObjectId.Empty, repository.GetTreeEntry(headCommit.Value.Tree, Encoding.UTF8.GetBytes("goodbye.txt"))); - } + GitCommit? headCommit = repository.GetHeadCommit(); + Assert.NotNull(headCommit); + + Assert.Equal(GitObjectId.Empty, repository.GetTreeEntry(headCommit.Value.Tree, Encoding.UTF8.GetBytes("goodbye.txt"))); } + } - [Fact] - public void GetObjectByShaTest() - { - this.InitializeSourceControl(); - this.AddCommits(2); + [Fact] + public void GetObjectByShaTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); - var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); + var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); - using (var repository = GitRepository.Create(this.RepoPath)) - { - var commitStream = repository.GetObjectBySha(headObjectId, "commit"); - Assert.NotNull(commitStream); + using (var repository = GitRepository.Create(this.RepoPath)) + { + Stream commitStream = repository.GetObjectBySha(headObjectId, "commit"); + Assert.NotNull(commitStream); - var objectStream = Assert.IsType(commitStream); - Assert.Equal("commit", objectStream.ObjectType); - Assert.Equal(186, objectStream.Length); - } + GitObjectStream objectStream = Assert.IsType(commitStream); + Assert.Equal("commit", objectStream.ObjectType); + Assert.Equal(186, objectStream.Length); } + } - // This test runs on netcoreapp only; netstandard/netfx don't support Path.GetRelativePath + // This test runs on netcoreapp only; netstandard/netfx don't support Path.GetRelativePath #if NETCOREAPP - [Fact] - public void GetObjectFromAlternateTest() + [Fact] + public void GetObjectFromAlternateTest() + { + // Add 2 alternates for this repository, each with their own commit. + // Make sure that commits from the current repository and the alternates + // can be found. + // + // Alternate1 Alternate2 + // | | + // +-----+ +-----+ + // | + // Repo + this.InitializeSourceControl(); + + Commit localCommit = this.LibGit2Repository.Commit("Local", this.Signer, this.Signer, new CommitOptions() { AllowEmptyCommit = true }); + + string alternate1Path = this.CreateDirectoryForNewRepo(); + this.InitializeSourceControl(alternate1Path).Dispose(); + var alternate1 = new Repository(alternate1Path); + Commit alternate1Commit = alternate1.Commit("Alternate 1", this.Signer, this.Signer, new CommitOptions() { AllowEmptyCommit = true }); + + string alternate2Path = this.CreateDirectoryForNewRepo(); + this.InitializeSourceControl(alternate2Path).Dispose(); + var alternate2 = new Repository(alternate2Path); + Commit alternate2Commit = alternate2.Commit("Alternate 2", this.Signer, this.Signer, new CommitOptions() { AllowEmptyCommit = true }); + + string objectDatabasePath = Path.Combine(this.RepoPath, ".git", "objects"); + + Directory.CreateDirectory(Path.Combine(this.RepoPath, ".git", "objects", "info")); + File.WriteAllText( + Path.Combine(this.RepoPath, ".git", "objects", "info", "alternates"), + $"{Path.GetRelativePath(objectDatabasePath, Path.Combine(alternate1Path, ".git", "objects"))}:{Path.GetRelativePath(objectDatabasePath, Path.Combine(alternate2Path, ".git", "objects"))}:"); + + using (GitRepository repository = GitRepository.Create(this.RepoPath)) { - // Add 2 alternates for this repository, each with their own commit. - // Make sure that commits from the current repository and the alternates - // can be found. - // - // Alternate1 Alternate2 - // | | - // +-----+ +-----+ - // | - // Repo - this.InitializeSourceControl(); - - var localCommit = this.LibGit2Repository.Commit("Local", this.Signer, this.Signer, new CommitOptions() { AllowEmptyCommit = true }); - - var alternate1Path = this.CreateDirectoryForNewRepo(); - this.InitializeSourceControl(alternate1Path).Dispose(); - var alternate1 = new Repository(alternate1Path); - var alternate1Commit = alternate1.Commit("Alternate 1", this.Signer, this.Signer, new CommitOptions() { AllowEmptyCommit = true }); - - var alternate2Path = this.CreateDirectoryForNewRepo(); - this.InitializeSourceControl(alternate2Path).Dispose(); - var alternate2 = new Repository(alternate2Path); - var alternate2Commit = alternate2.Commit("Alternate 2", this.Signer, this.Signer, new CommitOptions() { AllowEmptyCommit = true }); - - var objectDatabasePath = Path.Combine(this.RepoPath, ".git", "objects"); - - Directory.CreateDirectory(Path.Combine(this.RepoPath, ".git", "objects", "info")); - File.WriteAllText( - Path.Combine(this.RepoPath, ".git", "objects", "info", "alternates"), - $"{Path.GetRelativePath(objectDatabasePath, Path.Combine(alternate1Path, ".git", "objects"))}:{Path.GetRelativePath(objectDatabasePath, Path.Combine(alternate2Path, ".git", "objects"))}:"); - - using (GitRepository repository = GitRepository.Create(this.RepoPath)) - { - Assert.Equal(localCommit.Sha, repository.GetCommit(GitObjectId.Parse(localCommit.Sha)).Sha.ToString()); - Assert.Equal(alternate1Commit.Sha, repository.GetCommit(GitObjectId.Parse(alternate1Commit.Sha)).Sha.ToString()); - Assert.Equal(alternate2Commit.Sha, repository.GetCommit(GitObjectId.Parse(alternate2Commit.Sha)).Sha.ToString()); - } + Assert.Equal(localCommit.Sha, repository.GetCommit(GitObjectId.Parse(localCommit.Sha)).Sha.ToString()); + Assert.Equal(alternate1Commit.Sha, repository.GetCommit(GitObjectId.Parse(alternate1Commit.Sha)).Sha.ToString()); + Assert.Equal(alternate2Commit.Sha, repository.GetCommit(GitObjectId.Parse(alternate2Commit.Sha)).Sha.ToString()); } + } #endif - [Fact] - public void GetObjectByShaAndWrongTypeTest() - { - this.InitializeSourceControl(); - this.AddCommits(2); + [Fact] + public void GetObjectByShaAndWrongTypeTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); - var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); + var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); - using (var repository = GitRepository.Create(this.RepoPath)) - { - Assert.Throws(() => repository.GetObjectBySha(headObjectId, "tree")); - } - } - - [Fact] - public void GetMissingObjectByShaTest() + using (var repository = GitRepository.Create(this.RepoPath)) { - this.InitializeSourceControl(); - this.AddCommits(2); + Assert.Throws(() => repository.GetObjectBySha(headObjectId, "tree")); + } + } - var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); + [Fact] + public void GetMissingObjectByShaTest() + { + this.InitializeSourceControl(); + this.AddCommits(2); - using (var repository = GitRepository.Create(this.RepoPath)) - { - Assert.Throws(() => repository.GetObjectBySha(GitObjectId.Parse("7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9"), "commit")); - Assert.Null(repository.GetObjectBySha(GitObjectId.Empty, "commit")); - } - } + var headObjectId = GitObjectId.Parse(this.LibGit2Repository.Head.Tip.Sha); - [Fact] - public void ParseAlternates_SingleValue_Test() + using (var repository = GitRepository.Create(this.RepoPath)) { - var alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("/home/git/nbgv/.git/objects\n")); - Assert.Collection( - alternates, - a => Assert.Equal("/home/git/nbgv/.git/objects", a)); + Assert.Throws(() => repository.GetObjectBySha(GitObjectId.Parse("7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9"), "commit")); + Assert.Null(repository.GetObjectBySha(GitObjectId.Empty, "commit")); } + } - [Fact] - public void ParseAlternates_SingleValue_NoTrailingNewline_Test() - { - var alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("../repo/.git/objects")); - Assert.Collection( - alternates, - a => Assert.Equal("../repo/.git/objects", a)); - } + [Fact] + public void ParseAlternates_SingleValue_Test() + { + List alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("/home/git/nbgv/.git/objects\n")); + Assert.Collection( + alternates, + a => Assert.Equal("/home/git/nbgv/.git/objects", a)); + } - [Fact] - public void ParseAlternates_TwoValues_Test() - { - var alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("/home/git/nbgv/.git/objects:../../clone/.git/objects\n")); - Assert.Collection( - alternates, - a => Assert.Equal("/home/git/nbgv/.git/objects", a), - a => Assert.Equal("../../clone/.git/objects", a)); - } + [Fact] + public void ParseAlternates_SingleValue_NoTrailingNewline_Test() + { + List alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("../repo/.git/objects")); + Assert.Collection( + alternates, + a => Assert.Equal("../repo/.git/objects", a)); + } - [Fact] - public void ParseAlternates_PathWithColon_Test() - { - var alternates = GitRepository.ParseAlternates( - Encoding.UTF8.GetBytes("C:/Users/nbgv/objects:C:/Users/nbgv2/objects/:../../clone/.git/objects\n"), - 2); - Assert.Collection( - alternates, - a => Assert.Equal("C:/Users/nbgv/objects", a), - a => Assert.Equal("C:/Users/nbgv2/objects/", a), - a => Assert.Equal("../../clone/.git/objects", a)); - } + [Fact] + public void ParseAlternates_TwoValues_Test() + { + List alternates = GitRepository.ParseAlternates(Encoding.UTF8.GetBytes("/home/git/nbgv/.git/objects:../../clone/.git/objects\n")); + Assert.Collection( + alternates, + a => Assert.Equal("/home/git/nbgv/.git/objects", a), + a => Assert.Equal("../../clone/.git/objects", a)); + } - private static void AssertPath(string expected, string actual) - { - Assert.Equal( - Path.GetFullPath(expected), - Path.GetFullPath(actual)); - } + [Fact] + public void ParseAlternates_PathWithColon_Test() + { + List alternates = GitRepository.ParseAlternates( + Encoding.UTF8.GetBytes("C:/Users/nbgv/objects:C:/Users/nbgv2/objects/:../../clone/.git/objects\n"), + 2); + Assert.Collection( + alternates, + a => Assert.Equal("C:/Users/nbgv/objects", a), + a => Assert.Equal("C:/Users/nbgv2/objects/", a), + a => Assert.Equal("../../clone/.git/objects", a)); + } + + /// + protected override Nerdbank.GitVersioning.GitContext CreateGitContext(string path, string committish = null) + => Nerdbank.GitVersioning.GitContext.Create(path, committish, writable: false); + + private static void AssertPath(string expected, string actual) + { + Assert.Equal( + Path.GetFullPath(expected), + Path.GetFullPath(actual)); } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs index b476e3e1..9e94fc36 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs @@ -1,30 +1,32 @@ -using System.IO; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; using System.Text; using Nerdbank.GitVersioning.ManagedGit; using Xunit; -namespace ManagedGit +namespace ManagedGit; + +public class GitTreeStreamingReaderTests { - public class GitTreeStreamingReaderTests + [Fact] + public void FindBlobTest() { - [Fact] - public void FindBlobTest() + using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\tree.bin")) { - using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\tree.bin")) - { - var blobObjectId = GitTreeStreamingReader.FindNode(stream, Encoding.UTF8.GetBytes("version.json")); - Assert.Equal("59552a5eed6779aa4e5bb4dc96e80f36bb6e7380", blobObjectId.ToString()); - } + GitObjectId blobObjectId = GitTreeStreamingReader.FindNode(stream, Encoding.UTF8.GetBytes("version.json")); + Assert.Equal("59552a5eed6779aa4e5bb4dc96e80f36bb6e7380", blobObjectId.ToString()); } + } - [Fact] - public void FindTreeTest() + [Fact] + public void FindTreeTest() + { + using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\tree.bin")) { - using (Stream stream = TestUtilities.GetEmbeddedResource(@"ManagedGit\tree.bin")) - { - var blobObjectId = GitTreeStreamingReader.FindNode(stream, Encoding.UTF8.GetBytes("tools")); - Assert.Equal("ec8e91fc4ad13d6a214584330f26d7a05495c8cc", blobObjectId.ToString()); - } + GitObjectId blobObjectId = GitTreeStreamingReader.FindNode(stream, Encoding.UTF8.GetBytes("tools")); + Assert.Equal("ec8e91fc4ad13d6a214584330f26d7a05495c8cc", blobObjectId.ToString()); } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs index c0b1c6ec..881e9450 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs @@ -1,20 +1,22 @@ -using System.IO; -using Xunit; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; using Nerdbank.GitVersioning.ManagedGit; +using Xunit; -namespace ManagedGit +namespace ManagedGit; + +public class StreamExtensionsTests { - public class StreamExtensionsTests + [Fact] + public void ReadTest() { - [Fact] - public void ReadTest() - { - byte[] data = new byte[] { 0b10010001, 0b00101110 }; + byte[] data = new byte[] { 0b10010001, 0b00101110 }; - using (MemoryStream stream = new MemoryStream(data)) - { - Assert.Equal(5905, stream.ReadMbsInt()); - } + using (MemoryStream stream = new MemoryStream(data)) + { + Assert.Equal(5905, stream.ReadMbsInt()); } } } diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs b/test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs index e75ef3ca..70d087e9 100644 --- a/test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs +++ b/test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.IO.Compression; using System.Security.Cryptography; @@ -18,11 +21,11 @@ public void ReadTest() using (ZLibStream stream = new ZLibStream(rawStream, -1)) using (var sha = SHA1.Create()) { - var deflateStream = Assert.IsType(stream.BaseStream); + DeflateStream deflateStream = Assert.IsType(stream.BaseStream); Assert.Same(rawStream, deflateStream.BaseStream); Assert.Equal(0, stream.Position); - var hash = sha.ComputeHash(stream); + byte[] hash = sha.ComputeHash(stream); Assert.Equal("NZb/5ZiYEDomdVR9RZfnQuHyOJw=", Convert.ToBase64String(hash)); Assert.Equal(148, stream.Position); @@ -37,7 +40,7 @@ public void SeekTest() { // Seek past the commit 137 header, and make sure we can read the 'tree' word Assert.Equal(11, stream.Seek(11, SeekOrigin.Begin)); - var tree = new byte[4]; + byte[] tree = new byte[4]; stream.Read(tree); Assert.Equal("tree", Encoding.UTF8.GetString(tree)); diff --git a/test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index 77e52925..b2f3a59a 100644 --- a/test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -9,7 +9,7 @@ true - + @@ -18,7 +18,7 @@ - + @@ -28,25 +28,23 @@ - - + + - - - + - - - - + + + + - - all - runtime; build; native; contentfiles; analyzers - + + + + - + diff --git a/test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs b/test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs index fb3e248c..3218f371 100644 --- a/test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs +++ b/test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.Linq; using LibGit2Sharp; @@ -14,6 +17,9 @@ using ReleaseVersionIncrement = Nerdbank.GitVersioning.VersionOptions.ReleaseVersionIncrement; using Version = System.Version; +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable SA1649 // File name should match first type name + [Trait("Engine", "Managed")] public class ReleaseManagerManagedTests : ReleaseManagerTests { @@ -22,6 +28,7 @@ public ReleaseManagerManagedTests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: false); } @@ -34,6 +41,7 @@ public ReleaseManagerLibGit2Tests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); } @@ -59,7 +67,7 @@ public void PrepareRelease_DirtyWorkingDirecotory() this.InitializeSourceControl(); // create a file - File.WriteAllText(Path.Combine(this.RepoPath, "file1.txt"), ""); + File.WriteAllText(Path.Combine(this.RepoPath, "file1.txt"), string.Empty); // running PrepareRelease should result in an error // because there is a new file not under version control @@ -72,8 +80,8 @@ public void PrepareRelease_DirtyIndex() this.InitializeSourceControl(); // create a file and stage it - var filePath = Path.Combine(this.RepoPath, "file1.txt"); - File.WriteAllText(filePath, ""); + string filePath = Path.Combine(this.RepoPath, "file1.txt"); + File.WriteAllText(filePath, string.Empty); Commands.Stage(this.LibGit2Repository, filePath); // running PrepareRelease should result in an error @@ -103,7 +111,7 @@ public void PrepareRelease_InvalidBranchNameSetting() Release = new ReleaseOptions() { BranchName = "nameWithoutPlaceholder", - } + }, }; this.WriteVersionFile(versionOptions); @@ -124,7 +132,7 @@ public void PrepareRelease_ReleaseBranchAlreadyExists() Release = new ReleaseOptions() { BranchName = "release/v{version}", - } + }, }; this.WriteVersionFile(versionOptions); @@ -159,8 +167,8 @@ public void PrepareRelease_ReleaseBranch(string initialVersion, string releaseOp Version = SemanticVersion.Parse(initialVersion), Release = new ReleaseOptions() { - BranchName = releaseOptionsBranchName - } + BranchName = releaseOptionsBranchName, + }, }; var expectedVersionOptions = new VersionOptions() @@ -168,18 +176,18 @@ public void PrepareRelease_ReleaseBranch(string initialVersion, string releaseOp Version = SemanticVersion.Parse(resultingVersion), Release = new ReleaseOptions() { - BranchName = releaseOptionsBranchName - } + BranchName = releaseOptionsBranchName, + }, }; // create version.json this.WriteVersionFile(initialVersionOptions); // switch to release branch - var branchName = releaseBranchName; + string branchName = releaseBranchName; Commands.Checkout(this.LibGit2Repository, this.LibGit2Repository.CreateBranch(branchName)); - var tipBeforePrepareRelease = this.LibGit2Repository.Head.Tip; + Commit tipBeforePrepareRelease = this.LibGit2Repository.Head.Tip; // run PrepareRelease var releaseManager = new ReleaseManager(); @@ -187,7 +195,7 @@ public void PrepareRelease_ReleaseBranch(string initialVersion, string releaseOp // Check if a commit was created { - var updateVersionCommit = this.LibGit2Repository.Head.Tip; + Commit updateVersionCommit = this.LibGit2Repository.Head.Tip; Assert.NotEqual(tipBeforePrepareRelease.Id, updateVersionCommit.Id); Assert.Single(updateVersionCommit.Parents); Assert.Equal(updateVersionCommit.Parents.Single().Id, tipBeforePrepareRelease.Id); @@ -195,7 +203,7 @@ public void PrepareRelease_ReleaseBranch(string initialVersion, string releaseOp // check version on release branch { - var actualVersionOptions = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[branchName].Tip.Sha); + VersionOptions actualVersionOptions = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[branchName].Tip.Sha); Assert.Equal(expectedVersionOptions, actualVersionOptions); } } @@ -220,7 +228,7 @@ public void PrepeareRelease_ReleaseBranchWithVersionDecrement(string initialVers this.AssertError(() => new ReleaseManager().PrepareRelease(this.RepoPath, releaseUnstableTag), ReleasePreparationError.VersionDecrement); } - +#pragma warning disable SA1114 // Parameter list should follow declaration [Theory] // base test cases [InlineData("1.2-beta", null, null, null, null, null, null, "v1.2", "1.2", "1.3-alpha")] @@ -259,7 +267,7 @@ public void PrepeareRelease_ReleaseBranchWithVersionDecrement(string initialVers [InlineData("1.2-beta", null, null, null, null, "4.5", null, "v1.2", "1.2", "4.5-alpha")] [InlineData("1.2-beta.{height}", null, null, null, null, "4.5", null, "v1.2", "1.2", "4.5-alpha.{height}")] [InlineData("1.2-beta.{height}", null, null, "pre", null, "4.5.6", null, "v1.2", "1.2", "4.5.6-pre.{height}")] - // explicitly set version increment overriding the setting from ReleaseOptions + // explicitly set version increment overriding the setting from ReleaseOptions [InlineData("1.2-beta", null, ReleaseVersionIncrement.Minor, null, null, null, ReleaseVersionIncrement.Major, "v1.2", "1.2", "2.0-alpha")] [InlineData("1.2.3-beta", null, ReleaseVersionIncrement.Minor, null, null, null, ReleaseVersionIncrement.Build, "v1.2.3", "1.2.3", "1.2.4-alpha")] public void PrepareRelease_Master( @@ -277,6 +285,7 @@ public void PrepareRelease_Master( string resultingReleaseVersion, string resultingMainVersion) { +#pragma warning restore SA1114 // Parameter list should follow declaration // create and configure repository this.InitializeSourceControl(); @@ -288,8 +297,8 @@ public void PrepareRelease_Master( { VersionIncrement = releaseOptionsVersionIncrement, BranchName = releaseOptionsBranchName, - FirstUnstableTag = releaseOptionsFirstUnstableTag - } + FirstUnstableTag = releaseOptionsFirstUnstableTag, + }, }; this.WriteVersionFile(initialVersionOptions); @@ -300,8 +309,8 @@ public void PrepareRelease_Master( { VersionIncrement = releaseOptionsVersionIncrement, BranchName = releaseOptionsBranchName, - FirstUnstableTag = releaseOptionsFirstUnstableTag - } + FirstUnstableTag = releaseOptionsFirstUnstableTag, + }, }; var expectedVersionOptionsCurrentBrach = new VersionOptions() @@ -311,16 +320,16 @@ public void PrepareRelease_Master( { VersionIncrement = releaseOptionsVersionIncrement, BranchName = releaseOptionsBranchName, - FirstUnstableTag = releaseOptionsFirstUnstableTag - } + FirstUnstableTag = releaseOptionsFirstUnstableTag, + }, }; - var initialBranchName = this.LibGit2Repository.Head.FriendlyName; - var tipBeforePrepareRelease = this.LibGit2Repository.Head.Tip; + string initialBranchName = this.LibGit2Repository.Head.FriendlyName; + Commit tipBeforePrepareRelease = this.LibGit2Repository.Head.Tip; // prepare release var releaseManager = new ReleaseManager(); - releaseManager.PrepareRelease(this.RepoPath, releaseUnstableTag, (nextVersion is null ? null : Version.Parse(nextVersion)), parameterVersionIncrement); + releaseManager.PrepareRelease(this.RepoPath, releaseUnstableTag, nextVersion is null ? null : Version.Parse(nextVersion), parameterVersionIncrement); // check if a branch was created Assert.Contains(this.LibGit2Repository.Branches, branch => branch.FriendlyName == expectedBranchName); @@ -330,7 +339,7 @@ public void PrepareRelease_Master( // check if release branch contains a new commit // parent of new commit must be the commit before preparing the release - var releaseBranch = this.LibGit2Repository.Branches[expectedBranchName]; + Branch releaseBranch = this.LibGit2Repository.Branches[expectedBranchName]; { // If the original branch had no -prerelease tag, the release branch has no commit to author. if (string.IsNullOrEmpty(initialVersionOptions.Version.Prerelease)) @@ -347,7 +356,7 @@ public void PrepareRelease_Master( if (string.IsNullOrEmpty(initialVersionOptions.Version.Prerelease)) { // Verify that one commit was authored. - var incrementCommit = this.LibGit2Repository.Head.Tip; + Commit incrementCommit = this.LibGit2Repository.Head.Tip; Assert.Single(incrementCommit.Parents); Assert.Equal(tipBeforePrepareRelease.Id, incrementCommit.Parents.Single().Id); } @@ -356,24 +365,24 @@ public void PrepareRelease_Master( // check if current branch contains new commits // - one commit that updates the version (parent must be the commit before preparing the release) // - one commit merging the release branch back to master and resolving the conflict - var mergeCommit = this.LibGit2Repository.Head.Tip; + Commit mergeCommit = this.LibGit2Repository.Head.Tip; Assert.Equal(2, mergeCommit.Parents.Count()); Assert.Equal(releaseBranch.Tip.Id, mergeCommit.Parents.Skip(1).First().Id); - var updateVersionCommit = mergeCommit.Parents.First(); + Commit updateVersionCommit = mergeCommit.Parents.First(); Assert.Single(updateVersionCommit.Parents); Assert.Equal(tipBeforePrepareRelease.Id, updateVersionCommit.Parents.First().Id); } // check version on release branch { - var releaseBranchVersion = this.GetVersionOptions(committish: releaseBranch.Tip.Sha); + VersionOptions releaseBranchVersion = this.GetVersionOptions(committish: releaseBranch.Tip.Sha); Assert.Equal(expectedVersionOptionsReleaseBranch, releaseBranchVersion); } // check version on master branch { - var currentBranchVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Head.Tip.Sha); + VersionOptions currentBranchVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Head.Tip.Sha); Assert.Equal(expectedVersionOptionsCurrentBrach, currentBranchVersion); } } @@ -394,7 +403,7 @@ public void PrepareRelease_MasterWithVersionDecrement(string initialVersion, str // running PrepareRelease should result in an error // because we're setting the version on master to a lower version this.AssertError( - () => new ReleaseManager().PrepareRelease(this.RepoPath, releaseUnstableTag, (nextVersion is null ? null : Version.Parse(nextVersion))), + () => new ReleaseManager().PrepareRelease(this.RepoPath, releaseUnstableTag, nextVersion is null ? null : Version.Parse(nextVersion)), ReleasePreparationError.VersionDecrement); } @@ -412,7 +421,7 @@ public void PrepareRelease_MasterWithoutVersionIncrement(string initialVersion, // running PrepareRelease should result in an error // because we're trying to set master to the version it already has this.AssertError( - () => new ReleaseManager().PrepareRelease(this.RepoPath, null, (nextVersion is null ? null : Version.Parse(nextVersion))), + () => new ReleaseManager().PrepareRelease(this.RepoPath, null, nextVersion is null ? null : Version.Parse(nextVersion)), ReleasePreparationError.NoVersionIncrement); } @@ -422,7 +431,7 @@ public void PrepareRelease_DetachedHead() this.InitializeSourceControl(); this.WriteVersionFile("1.0", "-alpha"); Commands.Checkout(this.LibGit2Repository, this.LibGit2Repository.Head.Commits.First()); - var ex = Assert.Throws(() => new ReleaseManager().PrepareRelease(this.RepoPath)); + ReleasePreparationException ex = Assert.Throws(() => new ReleaseManager().PrepareRelease(this.RepoPath)); Assert.Equal(ReleasePreparationError.DetachedHead, ex.Error); } @@ -436,7 +445,7 @@ public void PrepareRelease_InvalidVersionIncrement() var versionOptions = new VersionOptions() { Version = SemanticVersion.Parse("1.2"), - Release = new ReleaseOptions() { VersionIncrement = ReleaseVersionIncrement.Build } + Release = new ReleaseOptions() { VersionIncrement = ReleaseVersionIncrement.Build }, }; this.WriteVersionFile(versionOptions); @@ -476,20 +485,19 @@ public void PrepareRelease_JsonOutput() Release = new ReleaseOptions() { BranchName = "v{version}", - VersionIncrement = ReleaseVersionIncrement.Minor - } + VersionIncrement = ReleaseVersionIncrement.Minor, + }, }; this.WriteVersionFile(versionOptions); - var currentBranchName = this.LibGit2Repository.Head.FriendlyName; - var releaseBranchName = "v1.0"; + string currentBranchName = this.LibGit2Repository.Head.FriendlyName; + string releaseBranchName = "v1.0"; // run release preparation var stdout = new StringWriter(); var releaseManager = new ReleaseManager(stdout); releaseManager.PrepareRelease(this.RepoPath, outputMode: ReleaseManager.ReleaseManagerOutputMode.Json); - // Expected output: // { // "CurrentBranch" : { @@ -503,13 +511,12 @@ public void PrepareRelease_JsonOutput() // "Version" : "", // } // } - var jsonOutput = JObject.Parse(stdout.ToString()); // check "CurrentBranch" output { - var expectedCommitId = this.LibGit2Repository.Branches[currentBranchName].Tip.Sha; - var expectedVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[currentBranchName].Tip.Sha).Version.ToString(); + string expectedCommitId = this.LibGit2Repository.Branches[currentBranchName].Tip.Sha; + string expectedVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[currentBranchName].Tip.Sha).Version.ToString(); var currentBranchOutput = jsonOutput.Property("CurrentBranch")?.Value as JObject; Assert.NotNull(currentBranchOutput); @@ -517,13 +524,12 @@ public void PrepareRelease_JsonOutput() Assert.Equal(currentBranchName, currentBranchOutput.GetValue("Name")?.ToString()); Assert.Equal(expectedCommitId, currentBranchOutput.GetValue("Commit")?.ToString()); Assert.Equal(expectedVersion, currentBranchOutput.GetValue("Version")?.ToString()); - } // Check "NewBranch" output { - var expectedCommitId = this.LibGit2Repository.Branches[releaseBranchName].Tip.Sha; - var expectedVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[releaseBranchName].Tip.Sha).Version.ToString(); + string expectedCommitId = this.LibGit2Repository.Branches[releaseBranchName].Tip.Sha; + string expectedVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[releaseBranchName].Tip.Sha).Version.ToString(); var newBranchOutput = jsonOutput.Property("NewBranch")?.Value as JObject; Assert.NotNull(newBranchOutput); @@ -547,11 +553,11 @@ public void PrepareRelease_JsonOutputWhenUpdatingReleaseBranch() Release = new ReleaseOptions() { BranchName = "v{version}", - VersionIncrement = ReleaseVersionIncrement.Minor - } + VersionIncrement = ReleaseVersionIncrement.Minor, + }, }; this.WriteVersionFile(versionOptions); - var branchName = "v1.0"; + string branchName = "v1.0"; // switch to release branch Commands.Checkout(this.LibGit2Repository, this.LibGit2Repository.CreateBranch(branchName)); @@ -561,7 +567,6 @@ public void PrepareRelease_JsonOutputWhenUpdatingReleaseBranch() var releaseManager = new ReleaseManager(stdout); releaseManager.PrepareRelease(this.RepoPath, outputMode: ReleaseManager.ReleaseManagerOutputMode.Json); - // Expected output: // { // "CurrentBranch" : { @@ -571,13 +576,12 @@ public void PrepareRelease_JsonOutputWhenUpdatingReleaseBranch() // }, // "NewBranch" : null // } - var jsonOutput = JObject.Parse(stdout.ToString()); // check "CurrentBranch" output { - var expectedCommitId = this.LibGit2Repository.Branches[branchName].Tip.Sha; - var expectedVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[branchName].Tip.Sha).Version.ToString(); + string expectedCommitId = this.LibGit2Repository.Branches[branchName].Tip.Sha; + string expectedVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Branches[branchName].Tip.Sha).Version.ToString(); var currentBranchOutput = jsonOutput.Property("CurrentBranch")?.Value as JObject; Assert.NotNull(currentBranchOutput); @@ -585,8 +589,8 @@ public void PrepareRelease_JsonOutputWhenUpdatingReleaseBranch() Assert.Equal(branchName, currentBranchOutput.GetValue("Name")?.ToString()); Assert.Equal(expectedCommitId, currentBranchOutput.GetValue("Commit")?.ToString()); Assert.Equal(expectedVersion, currentBranchOutput.GetValue("Version")?.ToString()); - } + // Check "NewBranch" output { // no new branch was created, so "NewBranch" should be null @@ -621,19 +625,20 @@ public void PrepareRelease_ResetsVersionHeightOffset() // create version.json this.WriteVersionFile(initialVersionOptions); - var tipBeforePrepareRelease = this.LibGit2Repository.Head.Tip; + Commit tipBeforePrepareRelease = this.LibGit2Repository.Head.Tip; var releaseManager = new ReleaseManager(); releaseManager.PrepareRelease(this.RepoPath); this.SetContextToHead(); - var newVersion = this.Context.VersionFile.GetVersion(); + VersionOptions newVersion = this.Context.VersionFile.GetVersion(); Assert.Equal(expectedMainVersionOptions, newVersion); VersionOptions releaseVersion = this.GetVersionOptions(committish: this.LibGit2Repository.Branches["v1.0"].Tip.Sha); Assert.Equal(expectedReleaseVersionOptions, releaseVersion); } + /// protected override void InitializeSourceControl(bool withInitialCommit = true) { base.InitializeSourceControl(withInitialCommit); @@ -642,7 +647,7 @@ protected override void InitializeSourceControl(bool withInitialCommit = true) private void AssertError(Action testCode, ReleasePreparationError expectedError) { - var ex = Assert.Throws(testCode); + ReleasePreparationException ex = Assert.Throws(testCode); Assert.Equal(expectedError, ex.Error); } } diff --git a/test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs b/test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs index 09ba29d4..8918cd28 100644 --- a/test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs +++ b/test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs @@ -1,4 +1,7 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable using System; using System.Collections.Generic; @@ -11,9 +14,9 @@ public partial class RepoTestBase /// /// Gets the number of commits in the longest single path between /// the specified commit and the most distant ancestor (inclusive) - /// that set the version to the value at . + /// that set the version to the value at . /// - /// The commit, branch or tag to measure the height of. Leave as null to check HEAD. + /// The commit, branch or tag to measure the height of. Leave as null to check HEAD. /// The repo-relative project directory for which to calculate the version. /// The height of the commit. Always a positive integer. protected int GetVersionHeight(string? committish, string? repoRelativeProjectDirectory = null) => this.GetVersionOracle(repoRelativeProjectDirectory, committish).VersionHeight; diff --git a/test/NerdBank.GitVersioning.Tests/RepoTestBase.cs b/test/NerdBank.GitVersioning.Tests/RepoTestBase.cs index 5cc81647..135bab9a 100644 --- a/test/NerdBank.GitVersioning.Tests/RepoTestBase.cs +++ b/test/NerdBank.GitVersioning.Tests/RepoTestBase.cs @@ -1,4 +1,7 @@ -#nullable enable +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +#nullable enable using System; using System.Collections.Generic; @@ -33,6 +36,7 @@ public RepoTestBase(ITestOutputHelper logger) protected Repository? LibGit2Repository { get; private set; } + /// public void Dispose() { this.Dispose(true); @@ -47,13 +51,13 @@ public void Dispose() { Debug.Assert(path?.Length != 40, "commit passed as path"); - using var context = this.CreateGitContext(path is null ? this.RepoPath : Path.Combine(this.RepoPath, path), committish); + using GitContext? context = this.CreateGitContext(path is null ? this.RepoPath : Path.Combine(this.RepoPath, path), committish); return context.VersionFile.GetVersion(); } protected VersionOracle GetVersionOracle(string? path = null, string? committish = null) { - using var context = this.CreateGitContext(path is null ? this.RepoPath : Path.Combine(this.RepoPath, path), committish); + using GitContext? context = this.CreateGitContext(path is null ? this.RepoPath : Path.Combine(this.RepoPath, path), committish); return new VersionOracle(context); } @@ -65,7 +69,8 @@ protected string CreateDirectoryForNewRepo() do { repoPath = Path.Combine(Path.GetTempPath(), this.GetType().Name + "_" + Path.GetRandomFileName()); - } while (Directory.Exists(repoPath)); + } + while (Directory.Exists(repoPath)); Directory.CreateDirectory(repoPath); this.repoDirectories.Add(repoPath); @@ -105,7 +110,7 @@ protected virtual GitContext InitializeSourceControl(string repoPath, bool withI var repo = new Repository(repoPath); repo.Config.Set("user.name", this.Signer.Name, ConfigurationLevel.Local); repo.Config.Set("user.email", this.Signer.Email, ConfigurationLevel.Local); - foreach (var file in repo.RetrieveStatus().Untracked) + foreach (StatusEntry? file in repo.RetrieveStatus().Untracked) { if (!Path.GetFileName(file.FilePath).StartsWith("_git2_", StringComparison.Ordinal)) { @@ -169,7 +174,7 @@ protected void AddCommits(int count = 1) } bool localContextCreated = this.Context is null; - var context = this.Context ?? GitContext.Create(this.RepoPath, writable: true); + GitContext? context = this.Context ?? GitContext.Create(this.RepoPath, writable: true); try { string versionFilePath = context.VersionFile.SetVersion(Path.Combine(this.RepoPath, relativeDirectory), versionData); @@ -192,7 +197,7 @@ protected void AddCommits(int count = 1) if (this.LibGit2Repository is object) { Assumes.True(versionFilePath.StartsWith(this.RepoPath, StringComparison.OrdinalIgnoreCase)); - var relativeFilePath = versionFilePath.Substring(this.RepoPath.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + string? relativeFilePath = versionFilePath.Substring(this.RepoPath.Length).TrimStart(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); Commands.Stage(this.LibGit2Repository, relativeFilePath); if (Path.GetExtension(relativeFilePath) == ".json") { diff --git a/test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs index 1631c65a..2213809b 100644 --- a/test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs +++ b/test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.Generic; using System.Reflection; using Nerdbank.GitVersioning; @@ -8,7 +11,7 @@ using static Nerdbank.GitVersioning.VersionOptions; /// -/// Tests for +/// Tests for . /// public class SemanticVersionExtensionsTests { @@ -38,7 +41,7 @@ public void Increment(string currentVersionString, ReleaseVersionIncrement incre var currentVersion = SemanticVersion.Parse(currentVersionString); var expectedVersion = SemanticVersion.Parse(expectedVersionString); - var actualVersion = currentVersion.Increment(increment); + SemanticVersion actualVersion = currentVersion.Increment(increment); Assert.Equal(expectedVersion, actualVersion); } @@ -67,7 +70,7 @@ public void Increment_InvalidIncrement(string currentVersionString, ReleaseVersi // multiple prerelease tags [InlineData("1.2-alpha.preview", "beta", "1.2-beta.preview")] [InlineData("1.2-alpha.preview", "-beta", "1.2-beta.preview")] - [InlineData("1.2-alpha.preview+metadata", "beta", "1.2-beta.preview+metadata")] + [InlineData("1.2-alpha.preview+metadata", "beta", "1.2-beta.preview+metadata")] [InlineData("1.2.3-alpha.preview", "beta", "1.2.3-beta.preview")] [InlineData("1.2-alpha.{height}", "beta", "1.2-beta.{height}")] // remove tag @@ -77,9 +80,8 @@ public void SetFirstPrereleaseTag(string currentVersionString, string newTag, st var currentVersion = SemanticVersion.Parse(currentVersionString); var expectedVersion = SemanticVersion.Parse(expectedVersionString); - var actualVersion = currentVersion.SetFirstPrereleaseTag(newTag); + SemanticVersion actualVersion = currentVersion.SetFirstPrereleaseTag(newTag); Assert.Equal(expectedVersion, actualVersion); } } - diff --git a/test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs b/test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs index bde7b5d4..a22feb7a 100644 --- a/test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs +++ b/test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -50,7 +53,6 @@ public void TryParse() Assert.Equal(2, result.Version.Minor); Assert.Equal("-pre.5.8-foo", result.Prerelease); Assert.Equal("+build-metadata.id1.2", result.BuildMetadata); - } [Fact] @@ -156,6 +158,5 @@ public void ToStringTests() Assert.Equal("1.2+buildInfo", vb.ToString()); var vpb = new SemanticVersion(new Version(1, 2), "-pre", "+buildInfo"); Assert.Equal("1.2-pre+buildInfo", vpb.ToString()); - } } diff --git a/test/NerdBank.GitVersioning.Tests/TestUtilities.cs b/test/NerdBank.GitVersioning.Tests/TestUtilities.cs index 6ea6efc3..35640944 100644 --- a/test/NerdBank.GitVersioning.Tests/TestUtilities.cs +++ b/test/NerdBank.GitVersioning.Tests/TestUtilities.cs @@ -1,4 +1,5 @@ -using Validation; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. using System; using System.Collections.Generic; @@ -8,6 +9,7 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; +using Validation; /// /// Test utility methods. @@ -52,10 +54,10 @@ internal static void ExtractEmbeddedResource(string resourcePath, string extract Requires.NotNullOrEmpty(resourcePath, nameof(resourcePath)); Requires.NotNullOrEmpty(extractedFilePath, nameof(extractedFilePath)); - using (var stream = GetEmbeddedResource(resourcePath)) + using (Stream stream = GetEmbeddedResource(resourcePath)) { Requires.Argument(stream is not null, nameof(resourcePath), "Resource not found."); - using (var extractedFile = File.OpenWrite(extractedFilePath)) + using (FileStream extractedFile = File.OpenWrite(extractedFilePath)) { stream.CopyTo(extractedFile); } @@ -93,6 +95,7 @@ internal ExpandedRepo(string repoPath) public string RepoPath { get; private set; } + /// public void Dispose() { if (Directory.Exists(this.RepoPath)) diff --git a/test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs b/test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs index 66347dd8..9be24c67 100644 --- a/test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs +++ b/test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -11,7 +14,7 @@ public class VersionExtensionsTests [Fact] public void EnsureNonNegativeComponents_NoValues() { - var version = new Version().EnsureNonNegativeComponents(); + Version version = new Version().EnsureNonNegativeComponents(); Assert.Equal(0, version.Major); Assert.Equal(0, version.Minor); Assert.Equal(0, version.Build); @@ -21,7 +24,7 @@ public void EnsureNonNegativeComponents_NoValues() [Fact] public void EnsureNonNegativeComponents_2Values() { - var version = new Version(1, 2).EnsureNonNegativeComponents(); + Version version = new Version(1, 2).EnsureNonNegativeComponents(); Assert.Equal(1, version.Major); Assert.Equal(2, version.Minor); Assert.Equal(0, version.Build); @@ -31,7 +34,7 @@ public void EnsureNonNegativeComponents_2Values() [Fact] public void EnsureNonNegativeComponents_3Values() { - var version = new Version(1, 2, 3).EnsureNonNegativeComponents(); + Version version = new Version(1, 2, 3).EnsureNonNegativeComponents(); Assert.Equal(1, version.Major); Assert.Equal(2, version.Minor); Assert.Equal(3, version.Build); @@ -42,7 +45,7 @@ public void EnsureNonNegativeComponents_3Values() public void EnsureNonNegativeComponents_4Values() { var original = new Version(1, 2, 3, 4); - var version = original.EnsureNonNegativeComponents(); + Version version = original.EnsureNonNegativeComponents(); Assert.Same(original, version); } diff --git a/test/NerdBank.GitVersioning.Tests/VersionFileTests.cs b/test/NerdBank.GitVersioning.Tests/VersionFileTests.cs index afeedc2a..071a2287 100644 --- a/test/NerdBank.GitVersioning.Tests/VersionFileTests.cs +++ b/test/NerdBank.GitVersioning.Tests/VersionFileTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -11,6 +14,9 @@ using Xunit.Abstractions; using Version = System.Version; +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable SA1649 // File name should match first type name + [Trait("Engine", "Managed")] public class VersionFileManagedTests : VersionFileTests { @@ -19,6 +25,7 @@ public VersionFileManagedTests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: false); } @@ -31,6 +38,7 @@ public VersionFileLibGit2Tests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); } @@ -58,8 +66,8 @@ public void IsVersionDefined_Commit() // Verify that we can find the version.txt file in the most recent commit, // But not in the initial commit. - using var tipContext = this.CreateGitContext(this.RepoPath, this.LibGit2Repository.Head.Commits.First().Sha); - using var initialContext = this.CreateGitContext(this.RepoPath, this.LibGit2Repository.Head.Commits.Last().Sha); + using GitContext tipContext = this.CreateGitContext(this.RepoPath, this.LibGit2Repository.Head.Commits.First().Sha); + using GitContext initialContext = this.CreateGitContext(this.RepoPath, this.LibGit2Repository.Head.Commits.Last().Sha); Assert.True(tipContext.VersionFile.IsVersionDefined()); Assert.False(initialContext.VersionFile.IsVersionDefined()); } @@ -80,9 +88,9 @@ public void IsVersionDefined_String_ConsiderAncestorFolders() Directory.CreateDirectory(subDirABC); this.Context.VersionFile.SetVersion(subDirAB, new Version(1, 1)); - using var subDirABCContext = this.CreateGitContext(subDirABC); - using var subDirABContext = this.CreateGitContext(subDirAB); - using var subDirAContext = this.CreateGitContext(subDirA); + using GitContext subDirABCContext = this.CreateGitContext(subDirABC); + using GitContext subDirABContext = this.CreateGitContext(subDirAB); + using GitContext subDirAContext = this.CreateGitContext(subDirA); Assert.True(subDirABCContext.VersionFile.IsVersionDefined()); Assert.True(subDirABContext.VersionFile.IsVersionDefined()); Assert.True(subDirAContext.VersionFile.IsVersionDefined()); @@ -102,7 +110,7 @@ public void GetVersion_JsonCompatibility(string version, string assemblyVersion, { File.WriteAllText(Path.Combine(this.RepoPath, VersionFile.JsonFileName), json); - var options = this.Context.VersionFile.GetVersion(); + VersionOptions options = this.Context.VersionFile.GetVersion(); Assert.NotNull(options); Assert.Equal(version, options.Version?.ToString()); Assert.Equal(assemblyVersion, options.AssemblyVersion?.Version?.ToString()); @@ -162,8 +170,8 @@ public void SetVersion_PathFilters_OutsideGitRepo() Version = SemanticVersion.Parse("1.2"), PathFilters = new[] { - new FilterPath("./foo", ""), - } + new FilterPath("./foo", string.Empty), + }, }; this.Context.VersionFile.SetVersion(this.RepoPath, versionOptions); @@ -181,15 +189,15 @@ public void SetVersion_PathFilters_DifferentRelativePaths() { new FilterPath("./foo", "bar"), new FilterPath("/absolute", "bar"), - } + }, }; var expected = versionOptions.PathFilters.Select(x => x.RepoRelativePath).ToList(); - var projectDirectory = Path.Combine(this.RepoPath, "quux"); + string projectDirectory = Path.Combine(this.RepoPath, "quux"); this.Context.VersionFile.SetVersion(projectDirectory, versionOptions); - using var projectContext = this.CreateGitContext(projectDirectory); - var actualVersionOptions = projectContext.VersionFile.GetVersion(); + using GitContext projectContext = this.CreateGitContext(projectDirectory); + VersionOptions actualVersionOptions = projectContext.VersionFile.GetVersion(); var actual = actualVersionOptions.PathFilters.Select(x => x.RepoRelativePath).ToList(); Assert.Equal(expected, actual); } @@ -204,24 +212,24 @@ public void SetVersion_PathFilters_InheritRelativePaths() Version = SemanticVersion.Parse("1.2"), PathFilters = new[] { - new FilterPath("./root-file.txt", ""), - new FilterPath("/absolute", ""), - } + new FilterPath("./root-file.txt", string.Empty), + new FilterPath("/absolute", string.Empty), + }, }; this.Context.VersionFile.SetVersion(this.RepoPath, rootVersionOptions); var versionOptions = new VersionOptions { Version = SemanticVersion.Parse("1.2"), - Inherit = true + Inherit = true, }; - var projectDirectory = Path.Combine(this.RepoPath, "quux"); + string projectDirectory = Path.Combine(this.RepoPath, "quux"); this.Context.VersionFile.SetVersion(projectDirectory, versionOptions); var expected = rootVersionOptions.PathFilters.Select(x => x.RepoRelativePath).ToList(); - using var projectContext = this.CreateGitContext(projectDirectory); - var actualVersionOptions = projectContext.VersionFile.GetVersion(); + using GitContext projectContext = this.CreateGitContext(projectDirectory); + VersionOptions actualVersionOptions = projectContext.VersionFile.GetVersion(); var actual = actualVersionOptions.PathFilters.Select(x => x.RepoRelativePath).ToList(); Assert.Equal(expected, actual); } @@ -236,9 +244,9 @@ public void SetVersion_PathFilters_InheritOverride() Version = SemanticVersion.Parse("1.2"), PathFilters = new[] { - new FilterPath("./root-file.txt", ""), - new FilterPath("/absolute", ""), - } + new FilterPath("./root-file.txt", string.Empty), + new FilterPath("/absolute", string.Empty), + }, }; this.Context.VersionFile.SetVersion(this.RepoPath, rootVersionOptions); @@ -250,15 +258,15 @@ public void SetVersion_PathFilters_InheritOverride() { new FilterPath("./project-file.txt", "quux"), new FilterPath("/absolute", "quux"), - } + }, }; - var projectDirectory = Path.Combine(this.RepoPath, "quux"); + string projectDirectory = Path.Combine(this.RepoPath, "quux"); this.Context.VersionFile.SetVersion(projectDirectory, versionOptions); var expected = versionOptions.PathFilters.Select(x => x.RepoRelativePath).ToList(); - using var projectContext = this.CreateGitContext(projectDirectory); - var actualVersionOptions = projectContext.VersionFile.GetVersion(); + using GitContext projectContext = this.CreateGitContext(projectDirectory); + VersionOptions actualVersionOptions = projectContext.VersionFile.GetVersion(); var actual = actualVersionOptions.PathFilters.Select(x => x.RepoRelativePath).ToList(); Assert.Equal(expected, actual); } @@ -283,12 +291,12 @@ public void SetVersion_PathFilters_InheritOverride() [InlineData(@"{""release"":{""branchName"":""someName"",""versionIncrement"":""major"",""firstUnstableTag"":""pre""}}", @"{""release"":{""branchName"":""someName"",""versionIncrement"":""major"",""firstUnstableTag"":""pre""}}")] public void JsonMinification(string full, string minimal) { - var settings = VersionOptions.GetJsonSettings(); + JsonSerializerSettings settings = VersionOptions.GetJsonSettings(); settings.Formatting = Formatting.None; // Assert that the two representations are equivalent. - var fullVersion = JsonConvert.DeserializeObject(full, settings); - var minimalVersion = JsonConvert.DeserializeObject(minimal, settings); + VersionOptions fullVersion = JsonConvert.DeserializeObject(full, settings); + VersionOptions minimalVersion = JsonConvert.DeserializeObject(minimal, settings); Assert.Equal(fullVersion, minimalVersion); string fullVersionSerialized = JsonConvert.SerializeObject(fullVersion, settings); @@ -368,7 +376,7 @@ public void GetVersion_String_FindsNearestFileInAncestorDirectories() Directory.CreateDirectory(subDirABC); this.Context.VersionFile.SetVersion(subDirAB, new Version(1, 1)); this.InitializeSourceControl(); - var commit = this.LibGit2Repository.Head.Commits.First().Sha; + string commit = this.LibGit2Repository.Head.Commits.First().Sha; this.AssertPathHasVersion(commit, subDirABC, subdirVersionSpec); this.AssertPathHasVersion(commit, subDirAB, subdirVersionSpec); @@ -399,7 +407,7 @@ public void GetVersion_String_FindsNearestFileInAncestorDirectories_WithAssembly Directory.CreateDirectory(subDirABC); this.Context.VersionFile.SetVersion(subDirAB, subdirVersionSpec); this.InitializeSourceControl(); - var commit = this.LibGit2Repository.Head.Commits.First().Sha; + string commit = this.LibGit2Repository.Head.Commits.First().Sha; this.AssertPathHasVersion(commit, subDirABC, subdirVersionSpec); this.AssertPathHasVersion(commit, subDirAB, subdirVersionSpec); @@ -407,15 +415,14 @@ public void GetVersion_String_FindsNearestFileInAncestorDirectories_WithAssembly this.AssertPathHasVersion(commit, this.RepoPath, rootVersionSpec); } - [Fact] public void GetVersion_ReadReleaseSettings_VersionIncrement() { - var json = @"{ ""version"" : ""1.2"", ""release"" : { ""versionIncrement"" : ""major"" } }"; - var path = Path.Combine(this.RepoPath, "version.json"); + string json = @"{ ""version"" : ""1.2"", ""release"" : { ""versionIncrement"" : ""major"" } }"; + string path = Path.Combine(this.RepoPath, "version.json"); File.WriteAllText(path, json); - var versionOptions = this.Context.VersionFile.GetVersion(); + VersionOptions versionOptions = this.Context.VersionFile.GetVersion(); Assert.NotNull(versionOptions.Release); Assert.NotNull(versionOptions.Release.VersionIncrement); @@ -425,11 +432,11 @@ public void GetVersion_ReadReleaseSettings_VersionIncrement() [Fact] public void GetVersion_ReadReleaseSettings_FirstUnstableTag() { - var json = @"{ ""version"" : ""1.2"", ""release"" : { ""firstUnstableTag"" : ""preview"" } }"; - var path = Path.Combine(this.RepoPath, "version.json"); + string json = @"{ ""version"" : ""1.2"", ""release"" : { ""firstUnstableTag"" : ""preview"" } }"; + string path = Path.Combine(this.RepoPath, "version.json"); File.WriteAllText(path, json); - var versionOptions = this.Context.VersionFile.GetVersion(); + VersionOptions versionOptions = this.Context.VersionFile.GetVersion(); Assert.NotNull(versionOptions.Release); Assert.NotNull(versionOptions.Release.FirstUnstableTag); @@ -439,11 +446,11 @@ public void GetVersion_ReadReleaseSettings_FirstUnstableTag() [Fact] public void GetVersion_ReadReleaseSettings_BranchName() { - var json = @"{ ""version"" : ""1.2"", ""release"" : { ""branchName"" : ""someValue{version}"" } }"; - var path = Path.Combine(this.RepoPath, "version.json"); + string json = @"{ ""version"" : ""1.2"", ""release"" : { ""branchName"" : ""someValue{version}"" } }"; + string path = Path.Combine(this.RepoPath, "version.json"); File.WriteAllText(path, json); - var versionOptions = this.Context.VersionFile.GetVersion(); + VersionOptions versionOptions = this.Context.VersionFile.GetVersion(); Assert.NotNull(versionOptions.Release); Assert.NotNull(versionOptions.Release.BranchName); @@ -455,12 +462,12 @@ public void GetVersion_ReadPathFilters() { this.InitializeSourceControl(); - var json = @"{ ""version"" : ""1.2"", ""pathFilters"" : [ "":/root.txt"", ""./hello"" ] }"; - var path = Path.Combine(this.RepoPath, "version.json"); + string json = @"{ ""version"" : ""1.2"", ""pathFilters"" : [ "":/root.txt"", ""./hello"" ] }"; + string path = Path.Combine(this.RepoPath, "version.json"); File.WriteAllText(path, json); - var repoRelativeBaseDirectory = "."; - var versionOptions = this.Context.VersionFile.GetVersion(); + string repoRelativeBaseDirectory = "."; + VersionOptions versionOptions = this.Context.VersionFile.GetVersion(); Assert.NotNull(versionOptions.PathFilters); Assert.Equal(new[] { "/root.txt", "./hello" }, versionOptions.PathFilters.Select(fp => fp.ToPathSpec(repoRelativeBaseDirectory))); @@ -469,8 +476,8 @@ public void GetVersion_ReadPathFilters() [Fact] public void GetVersion_WithPathFiltersOutsideOfGitRepo() { - var json = @"{ ""version"" : ""1.2"", ""pathFilters"" : [ ""."" ] }"; - var path = Path.Combine(this.RepoPath, "version.json"); + string json = @"{ ""version"" : ""1.2"", ""pathFilters"" : [ ""."" ] }"; + string path = Path.Combine(this.RepoPath, "version.json"); File.WriteAllText(path, json); this.Context.VersionFile.GetVersion(); @@ -553,20 +560,20 @@ public void VersionJson_Inheritance(bool commitInSourceControl) VersionOptions GetOption(string path) { - using var context = this.CreateGitContext(Path.Combine(this.RepoPath, path)); + using GitContext context = this.CreateGitContext(Path.Combine(this.RepoPath, path)); return context.VersionFile.GetVersion(); } - - var level1Options = GetOption(string.Empty); + + VersionOptions level1Options = GetOption(string.Empty); Assert.False(level1Options.Inherit); - var level2Options = GetOption("foo"); + VersionOptions level2Options = GetOption("foo"); Assert.Equal(level1.Version.Version.Major, level2Options.Version.Version.Major); Assert.Equal(level1.Version.Version.Minor, level2Options.Version.Version.Minor); Assert.Equal(level2.AssemblyVersion.Precision, level2Options.AssemblyVersion.Precision); Assert.True(level2Options.Inherit); - var level3Options = GetOption("foo/bar"); + VersionOptions level3Options = GetOption("foo/bar"); Assert.Equal(level1.Version.Version.Major, level3Options.Version.Version.Major); Assert.Equal(level1.Version.Version.Minor, level3Options.Version.Version.Minor); Assert.Equal(level2.AssemblyVersion.Precision, level3Options.AssemblyVersion.Precision); @@ -574,12 +581,12 @@ VersionOptions GetOption(string path) Assert.Equal(level3.VersionHeightOffset, level3Options.VersionHeightOffset); Assert.True(level3Options.Inherit); - var level2NoInheritOptions = GetOption("noInherit"); + VersionOptions level2NoInheritOptions = GetOption("noInherit"); Assert.Equal(level2NoInherit.Version, level2NoInheritOptions.Version); Assert.Equal(VersionOptions.DefaultVersionPrecision, level2NoInheritOptions.AssemblyVersionOrDefault.PrecisionOrDefault); Assert.False(level2NoInheritOptions.Inherit); - var level2InheritButResetVersionOptions = GetOption("inheritWithVersion"); + VersionOptions level2InheritButResetVersionOptions = GetOption("inheritWithVersion"); Assert.Equal(level2InheritButResetVersion.Version, level2InheritButResetVersionOptions.Version); Assert.True(level2InheritButResetVersionOptions.Inherit); @@ -608,17 +615,16 @@ public void GetVersion_ProducesAbsolutePath() Assert.True(Path.IsPathRooted(actualDirectory)); } - [Theory] [InlineData(1)] [InlineData(2)] public void GetVersion_ReadNuGetPackageVersionSettings_SemVer(int semVer) { - var json = $@"{{ ""version"" : ""1.0"", ""nugetPackageVersion"" : {{ ""semVer"" : {semVer} }} }}"; - var path = Path.Combine(this.RepoPath, "version.json"); + string json = $@"{{ ""version"" : ""1.0"", ""nugetPackageVersion"" : {{ ""semVer"" : {semVer} }} }}"; + string path = Path.Combine(this.RepoPath, "version.json"); File.WriteAllText(path, json); - var versionOptions = this.Context.VersionFile.GetVersion(); + VersionOptions versionOptions = this.Context.VersionFile.GetVersion(); Assert.NotNull(versionOptions.NuGetPackageVersion); Assert.NotNull(versionOptions.NuGetPackageVersion.SemVer); @@ -629,11 +635,11 @@ public void GetVersion_ReadNuGetPackageVersionSettings_SemVer(int semVer) [CombinatorialData] public void GetVersion_ReadNuGetPackageVersionSettings_Precision(VersionOptions.VersionPrecision precision) { - var json = $@"{{ ""version"" : ""1.0"", ""nugetPackageVersion"" : {{ ""precision"" : ""{precision}"" }} }}"; - var path = Path.Combine(this.RepoPath, "version.json"); + string json = $@"{{ ""version"" : ""1.0"", ""nugetPackageVersion"" : {{ ""precision"" : ""{precision}"" }} }}"; + string path = Path.Combine(this.RepoPath, "version.json"); File.WriteAllText(path, json); - var versionOptions = this.Context.VersionFile.GetVersion(); + VersionOptions versionOptions = this.Context.VersionFile.GetVersion(); Assert.NotNull(versionOptions.NuGetPackageVersion); Assert.NotNull(versionOptions.NuGetPackageVersion.Precision); @@ -642,7 +648,7 @@ public void GetVersion_ReadNuGetPackageVersionSettings_Precision(VersionOptions. private void AssertPathHasVersion(string committish, string absolutePath, VersionOptions expected) { - var actual = this.GetVersionOptions(absolutePath, committish); + VersionOptions actual = this.GetVersionOptions(absolutePath, committish); Assert.Equal(expected, this.GetVersionOptions(absolutePath, committish)); } } diff --git a/test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs b/test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs index 603f02fe..233e2fdc 100644 --- a/test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs +++ b/test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; @@ -184,7 +187,6 @@ public void CannotWriteToDefaultInstances() Assert.Throws(() => options.ReleaseOrDefault.FirstUnstableTag = "-tag"); } - [Fact] public void ReleaseOptions_Equality() { @@ -193,12 +195,12 @@ public void ReleaseOptions_Equality() var ro3 = new VersionOptions.ReleaseOptions() { BranchName = "branchName", - VersionIncrement = VersionOptions.ReleaseVersionIncrement.Major + VersionIncrement = VersionOptions.ReleaseVersionIncrement.Major, }; var ro4 = new VersionOptions.ReleaseOptions() { BranchName = "branchName", - VersionIncrement = VersionOptions.ReleaseVersionIncrement.Major + VersionIncrement = VersionOptions.ReleaseVersionIncrement.Major, }; var ro5 = new VersionOptions.ReleaseOptions() { @@ -209,13 +211,13 @@ public void ReleaseOptions_Equality() { BranchName = "branchName", VersionIncrement = VersionOptions.ReleaseVersionIncrement.Minor, - FirstUnstableTag = "tag" + FirstUnstableTag = "tag", }; var ro7 = new VersionOptions.ReleaseOptions() { BranchName = "branchName", VersionIncrement = VersionOptions.ReleaseVersionIncrement.Minor, - FirstUnstableTag = "tag" + FirstUnstableTag = "tag", }; Assert.Equal(ro1, ro2); @@ -237,19 +239,19 @@ public void NuGetPackageVersionOptions_Equality() var npvo2a = new VersionOptions.NuGetPackageVersionOptions { - SemVer = 2 + SemVer = 2, }; Assert.NotEqual(npvo2a, npvo1a); var npvo3a = new VersionOptions.NuGetPackageVersionOptions { - Precision = VersionOptions.VersionPrecision.Revision + Precision = VersionOptions.VersionPrecision.Revision, }; Assert.NotEqual(npvo3a, npvo1a); var npvo4a = new VersionOptions.NuGetPackageVersionOptions { - Precision = VersionOptions.VersionPrecision.Build + Precision = VersionOptions.VersionPrecision.Build, }; Assert.Equal(npvo4a, npvo1a); // Equal because we haven't changed defaults. } diff --git a/test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs index 1b121956..16fd63d7 100644 --- a/test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs +++ b/test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.IO; using System.Linq; using LibGit2Sharp; @@ -8,6 +11,9 @@ using Xunit.Abstractions; using Version = System.Version; +#pragma warning disable SA1402 // File may only contain a single type +#pragma warning disable SA1649 // File name should match first type name + [Trait("Engine", "Managed")] public class VersionOracleManagedTests : VersionOracleTests { @@ -16,6 +22,7 @@ public VersionOracleManagedTests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: false); } @@ -28,6 +35,7 @@ public VersionOracleLibGit2Tests(ITestOutputHelper logger) { } + /// protected override GitContext CreateGitContext(string path, string committish = null) => GitContext.Create(path, committish, writable: true); } @@ -45,7 +53,7 @@ public VersionOracleTests(ITestOutputHelper logger) public void NotRepo() { // Seems safe to assume a temporary path is not a Git directory. - var context = this.CreateGitContext(Path.GetTempPath()); + GitContext context = this.CreateGitContext(Path.GetTempPath()); var oracle = new VersionOracle(context); Assert.Equal(0, oracle.VersionHeight); } @@ -53,7 +61,7 @@ public void NotRepo() [Fact] public void Submodule_RecognizedWithCorrectVersion() { - using (var expandedRepo = TestUtilities.ExtractRepoArchive("submodules")) + using (TestUtilities.ExpandedRepo expandedRepo = TestUtilities.ExtractRepoArchive("submodules")) { this.Context = this.CreateGitContext(Path.Combine(expandedRepo.RepoPath, "a")); var oracleA = new VersionOracle(this.Context); @@ -161,9 +169,9 @@ public void VersionHeightResetsWithVersionSpecChanges(string initial, string nex if (this.Context is Nerdbank.GitVersioning.LibGit2.LibGit2Context libgit2Context) { - foreach (var commit in libgit2Context.Repository.Head.Commits) + foreach (Commit commit in libgit2Context.Repository.Head.Commits) { - var versionFromId = this.GetVersion(committish: commit.Sha); + Version versionFromId = this.GetVersion(committish: commit.Sha); Assert.Contains(commit, Nerdbank.GitVersioning.LibGit2.LibGit2GitExtensions.GetCommitsFromVersion(libgit2Context, versionFromId)); } } @@ -272,7 +280,7 @@ public void SemVerStableNonPublicVersionShortened() var workingCopyVersion = new VersionOptions { Version = SemanticVersion.Parse("2.3"), - GitCommitIdShortFixedLength = 7 + GitCommitIdShortFixedLength = 7, }; this.WriteVersionFile(workingCopyVersion); this.InitializeSourceControl(); @@ -346,7 +354,7 @@ public void NpmPackageVersionIsSemVer2() VersionOptions workingCopyVersion = new VersionOptions { Version = SemanticVersion.Parse("7.8.9-foo.25"), - SemVer1NumericIdentifierPadding = 2 + SemVer1NumericIdentifierPadding = 2, }; this.WriteVersionFile(workingCopyVersion); this.InitializeSourceControl(); @@ -364,7 +372,7 @@ public void CanSetSemVer2ForNuGetPackageVersionPublicRelease() NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions { SemVer = 2, - } + }, }; this.WriteVersionFile(workingCopyVersion); this.InitializeSourceControl(); @@ -374,98 +382,98 @@ public void CanSetSemVer2ForNuGetPackageVersionPublicRelease() } [Theory] - // - // SemVer 1 - // - // 2 version fields configured in version.json + //// + //// SemVer 1 + //// + //// 2 version fields configured in version.json [InlineData(1, "1.2", VersionOptions.VersionPrecision.Major, "1.0.0")] [InlineData(1, "1.2", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(1, "1.2", VersionOptions.VersionPrecision.Build, "1.2.1")] [InlineData(1, "1.2", VersionOptions.VersionPrecision.Revision, "1.2.1.")] - // 2 version fields and a static prerelease tag configured in version.json + //// 2 version fields and a static prerelease tag configured in version.json [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Build, "1.2.1-alpha")] [InlineData(1, "1.2-alpha", VersionOptions.VersionPrecision.Revision, "1.2.1.-alpha")] - // 2 version fields with git height in prerelease tag configured in version.json + //// 2 version fields with git height in prerelease tag configured in version.json [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.0-alpha-0001")] [InlineData(1, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.0.0-alpha-0001")] - // 3 version fields configured in version.json + //// 3 version fields configured in version.json [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] [InlineData(1, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] - // 3 version fields and a static prerelease tag configured in version.json + //// 3 version fields and a static prerelease tag configured in version.json [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] [InlineData(1, "1.2.3-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.1-alpha")] - // 3 version fields with git height in prerelease tag configured in version.json + //// 3 version fields with git height in prerelease tag configured in version.json [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha-0001")] [InlineData(1, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.0-alpha-0001")] - // 4 version fields configured in version.json + //// 4 version fields configured in version.json [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] [InlineData(1, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] - // 4 version fields and a static prerelease tag configured in version.json + //// 4 version fields and a static prerelease tag configured in version.json [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] [InlineData(1, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.4-alpha")] - // 4 version fields with git height in prerelease tag configured in version.json + //// 4 version fields with git height in prerelease tag configured in version.json [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha-0001")] [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha-0001")] [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha-0001")] [InlineData(1, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.4-alpha-0001")] - // - // SemVer 2 - // - // 2 version fields configured in version.json + //// + //// SemVer 2 + //// + //// 2 version fields configured in version.json [InlineData(2, "1.2", VersionOptions.VersionPrecision.Major, "1.0.0")] [InlineData(2, "1.2", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(2, "1.2", VersionOptions.VersionPrecision.Build, "1.2.1")] [InlineData(2, "1.2", VersionOptions.VersionPrecision.Revision, "1.2.1.")] - // 2 version fields and a static prerelease tag configured in version.json + //// 2 version fields and a static prerelease tag configured in version.json [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Build, "1.2.1-alpha")] [InlineData(2, "1.2-alpha", VersionOptions.VersionPrecision.Revision, "1.2.1.-alpha")] - // 2 version fields with git height in prerelease tag configured in version.json + //// 2 version fields with git height in prerelease tag configured in version.json [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.0-alpha.1")] [InlineData(2, "1.2-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.0.0-alpha.1")] - // 3 version fields configured in version.json + //// 3 version fields configured in version.json [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Major, "1.0.0")] [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Build, "1.2.3")] [InlineData(2, "1.2.3", VersionOptions.VersionPrecision.Revision, "1.2.3.1")] - // 3 version fields and a static prerelease tag configured in version.json + //// 3 version fields and a static prerelease tag configured in version.json [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] [InlineData(2, "1.2.3-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.1-alpha")] - // 3 version fields with git height in prerelease tag configured in version.json + //// 3 version fields with git height in prerelease tag configured in version.json [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha.1")] [InlineData(2, "1.2.3-alpha.{height}", VersionOptions.VersionPrecision.Revision, "1.2.3.0-alpha.1")] - // 4 version fields configured in version.json + //// 4 version fields configured in version.json [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Major, "1.0.0")] [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Minor, "1.2.0")] [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Build, "1.2.3")] [InlineData(2, "1.2.3.4", VersionOptions.VersionPrecision.Revision, "1.2.3.4")] - // 4 version fields and a static prerelease tag configured in version.json + //// 4 version fields and a static prerelease tag configured in version.json [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Major, "1.0.0-alpha")] [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha")] [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Build, "1.2.3-alpha")] [InlineData(2, "1.2.3.4-alpha", VersionOptions.VersionPrecision.Revision, "1.2.3.4-alpha")] - // 4 version fields with git height in prerelease tag configured in version.json + //// 4 version fields with git height in prerelease tag configured in version.json [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Major, "1.0.0-alpha.1")] [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Minor, "1.2.0-alpha.1")] [InlineData(2, "1.2.3.4-alpha.{height}", VersionOptions.VersionPrecision.Build, "1.2.3-alpha.1")] @@ -478,8 +486,8 @@ public void CanSetPrecisionForNuGetPackageVersion(int semVer, string version, Ve NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions { SemVer = semVer, - Precision = precision - } + Precision = precision, + }, }; this.WriteVersionFile(workingCopyVersion); this.InitializeSourceControl(); @@ -498,7 +506,7 @@ public void CanSetSemVer2ForNuGetPackageVersionNonPublicRelease() NuGetPackageVersion = new VersionOptions.NuGetPackageVersionOptions { SemVer = 2, - } + }, }; this.WriteVersionFile(workingCopyVersion); this.InitializeSourceControl(); @@ -576,7 +584,7 @@ public void VersionJsonWithSingleIntegerForVersion() { File.WriteAllText(Path.Combine(this.RepoPath, VersionFile.JsonFileName), @"{""version"":""3""}"); this.InitializeSourceControl(); - var ex = Assert.Throws(() => new VersionOracle(this.Context)); + FormatException ex = Assert.Throws(() => new VersionOracle(this.Context)); Assert.Contains(this.Context.GitCommitId, ex.Message); Assert.Contains("\"3\"", ex.InnerException.Message); this.Logger.WriteLine(ex.ToString()); @@ -606,7 +614,7 @@ public void Worktree_Support(bool detachedHead) this.LibGit2Repository.Worktrees.Add("wtbranch", "myworktree", workTreePath, isLocked: false); } - var context = this.CreateGitContext(workTreePath); + GitContext context = this.CreateGitContext(workTreePath); var oracleWorkTree = new VersionOracle(context); Assert.Equal(oracleOriginal.Version, oracleWorkTree.Version); @@ -619,10 +627,10 @@ public void GetVersionHeight_Test() { this.InitializeSourceControl(); - var first = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); - var second = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Commit first = this.LibGit2Repository.Commit("First", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Commit second = this.LibGit2Repository.Commit("Second", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); this.WriteVersionFile(); - var third = this.LibGit2Repository.Commit("Third", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); + Commit third = this.LibGit2Repository.Commit("Third", this.Signer, this.Signer, new CommitOptions { AllowEmptyCommit = true }); Assert.Equal(2, this.GetVersionHeight()); } @@ -707,14 +715,14 @@ public void GetVersionHeight_IncludeFilter(string includeFilter) Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Expect commit outside of project tree to not affect version height - var otherFilePath = Path.Combine(this.RepoPath, "my-file.txt"); + string otherFilePath = Path.Combine(this.RepoPath, "my-file.txt"); File.WriteAllText(otherFilePath, "hello"); Commands.Stage(this.LibGit2Repository, otherFilePath); this.LibGit2Repository.Commit("Add other file outside of project root", this.Signer, this.Signer); Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Expect commit inside project tree to affect version height - var containedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); + string containedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); File.WriteAllText(containedFilePath, "hello"); Commands.Stage(this.LibGit2Repository, containedFilePath); this.LibGit2Repository.Commit("Add file within project root", this.Signer, this.Signer); @@ -733,20 +741,20 @@ public void GetVersionHeight_IncludeExcludeFilter() { new FilterPath("./", relativeDirectory), new FilterPath(":^/some-sub-dir/ignore.txt", relativeDirectory), - new FilterPath(":^excluded-dir", relativeDirectory) + new FilterPath(":^excluded-dir", relativeDirectory), }; this.WriteVersionFile(versionData, relativeDirectory); Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Commit touching excluded path does not affect version height - var ignoredFilePath = Path.Combine(this.RepoPath, relativeDirectory, "ignore.txt"); + string ignoredFilePath = Path.Combine(this.RepoPath, relativeDirectory, "ignore.txt"); File.WriteAllText(ignoredFilePath, "hello"); Commands.Stage(this.LibGit2Repository, ignoredFilePath); this.LibGit2Repository.Commit("Add excluded file", this.Signer, this.Signer); Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Commit touching both excluded and included path does affect height - var includedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); + string includedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); File.WriteAllText(includedFilePath, "hello"); File.WriteAllText(ignoredFilePath, "changed"); Commands.Stage(this.LibGit2Repository, includedFilePath); @@ -755,7 +763,7 @@ public void GetVersionHeight_IncludeExcludeFilter() Assert.Equal(2, this.GetVersionHeight(relativeDirectory)); // Commit touching excluded directory does not affect version height - var fileInExcludedDirPath = Path.Combine(this.RepoPath, relativeDirectory, "excluded-dir", "ignore.txt"); + string fileInExcludedDirPath = Path.Combine(this.RepoPath, relativeDirectory, "excluded-dir", "ignore.txt"); Directory.CreateDirectory(Path.GetDirectoryName(fileInExcludedDirPath)); File.WriteAllText(fileInExcludedDirPath, "hello"); Commands.Stage(this.LibGit2Repository, fileInExcludedDirPath); @@ -773,13 +781,13 @@ public void GetVersionHeight_IncludeExcludeFilter_NoProjectDirectory() { new FilterPath("./", "."), new FilterPath(":^/some-sub-dir/ignore.txt", "."), - new FilterPath(":^/excluded-dir", ".") + new FilterPath(":^/excluded-dir", "."), }; this.WriteVersionFile(versionData); Assert.Equal(1, this.GetVersionHeight()); // Commit touching excluded path does not affect version height - var ignoredFilePath = Path.Combine(this.RepoPath, "some-sub-dir", "ignore.txt"); + string ignoredFilePath = Path.Combine(this.RepoPath, "some-sub-dir", "ignore.txt"); Directory.CreateDirectory(Path.GetDirectoryName(ignoredFilePath)); File.WriteAllText(ignoredFilePath, "hello"); Commands.Stage(this.LibGit2Repository, ignoredFilePath); @@ -787,7 +795,7 @@ public void GetVersionHeight_IncludeExcludeFilter_NoProjectDirectory() Assert.Equal(1, this.GetVersionHeight()); // Commit touching both excluded and included path does affect height - var includedFilePath = Path.Combine(this.RepoPath, "some-sub-dir", "another-file.txt"); + string includedFilePath = Path.Combine(this.RepoPath, "some-sub-dir", "another-file.txt"); File.WriteAllText(includedFilePath, "hello"); File.WriteAllText(ignoredFilePath, "changed"); Commands.Stage(this.LibGit2Repository, includedFilePath); @@ -796,7 +804,7 @@ public void GetVersionHeight_IncludeExcludeFilter_NoProjectDirectory() Assert.Equal(2, this.GetVersionHeight()); // Commit touching excluded directory does not affect version height - var fileInExcludedDirPath = Path.Combine(this.RepoPath, "excluded-dir", "ignore.txt"); + string fileInExcludedDirPath = Path.Combine(this.RepoPath, "excluded-dir", "ignore.txt"); Directory.CreateDirectory(Path.GetDirectoryName(fileInExcludedDirPath)); File.WriteAllText(fileInExcludedDirPath, "hello"); Commands.Stage(this.LibGit2Repository, fileInExcludedDirPath); @@ -818,7 +826,7 @@ public void GetVersionHeight_AddingExcludeDoesNotLowerHeight(string excludePathF Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Commit a file which will later be ignored - var ignoredFilePath = Path.Combine(this.RepoPath, "excluded-dir", "ignore.txt"); + string ignoredFilePath = Path.Combine(this.RepoPath, "excluded-dir", "ignore.txt"); Directory.CreateDirectory(Path.GetDirectoryName(ignoredFilePath)); File.WriteAllText(ignoredFilePath, "hello"); Commands.Stage(this.LibGit2Repository, ignoredFilePath); @@ -849,14 +857,14 @@ public void GetVersionHeight_IncludeRoot() Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Expect commit outside of project tree to affect version height - var otherFilePath = Path.Combine(this.RepoPath, "my-file.txt"); + string otherFilePath = Path.Combine(this.RepoPath, "my-file.txt"); File.WriteAllText(otherFilePath, "hello"); Commands.Stage(this.LibGit2Repository, otherFilePath); this.LibGit2Repository.Commit("Add other file outside of project root", this.Signer, this.Signer); Assert.Equal(2, this.GetVersionHeight(relativeDirectory)); // Expect commit inside project tree to affect version height - var containedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); + string containedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); File.WriteAllText(containedFilePath, "hello"); Commands.Stage(this.LibGit2Repository, containedFilePath); this.LibGit2Repository.Commit("Add file within project root", this.Signer, this.Signer); @@ -880,7 +888,7 @@ public void GetVersionHeight_IncludeRootExcludeSome() Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Expect commit in an excluded directory to not affect version height - var ignoredFilePath = Path.Combine(this.RepoPath, "excluded-dir", "my-file.txt"); + string ignoredFilePath = Path.Combine(this.RepoPath, "excluded-dir", "my-file.txt"); Directory.CreateDirectory(Path.GetDirectoryName(ignoredFilePath)); File.WriteAllText(ignoredFilePath, "hello"); Commands.Stage(this.LibGit2Repository, ignoredFilePath); @@ -888,7 +896,7 @@ public void GetVersionHeight_IncludeRootExcludeSome() Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Expect commit within another directory to affect version height - var otherFilePath = Path.Combine(this.RepoPath, "another-dir", "another-file.txt"); + string otherFilePath = Path.Combine(this.RepoPath, "another-dir", "another-file.txt"); Directory.CreateDirectory(Path.GetDirectoryName(otherFilePath)); File.WriteAllText(otherFilePath, "hello"); Commands.Stage(this.LibGit2Repository, otherFilePath); @@ -960,13 +968,13 @@ public void GetVersionHeight_ProjectDirectoryDifferentToVersionJsonDirectory() var versionData = VersionOptions.FromVersion(new Version("1.2")); versionData.PathFilters = new[] { - new FilterPath(".", "") + new FilterPath(".", string.Empty), }; - this.WriteVersionFile(versionData, ""); + this.WriteVersionFile(versionData, string.Empty); Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Expect commit in an excluded directory to not affect version height - var ignoredFilePath = Path.Combine(this.RepoPath, "other-dir", "my-file.txt"); + string ignoredFilePath = Path.Combine(this.RepoPath, "other-dir", "my-file.txt"); Directory.CreateDirectory(Path.GetDirectoryName(ignoredFilePath)); File.WriteAllText(ignoredFilePath, "hello"); Commands.Stage(this.LibGit2Repository, ignoredFilePath); @@ -992,14 +1000,14 @@ public void GetVersionHeight_ProjectDirectoryIsMoved() Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Commit touching excluded path does not affect version height - var ignoredFilePath = Path.Combine(this.RepoPath, relativeDirectory, "ignore.txt"); + string ignoredFilePath = Path.Combine(this.RepoPath, relativeDirectory, "ignore.txt"); File.WriteAllText(ignoredFilePath, "hello"); Commands.Stage(this.LibGit2Repository, ignoredFilePath); this.LibGit2Repository.Commit("Add excluded file", this.Signer, this.Signer); Assert.Equal(1, this.GetVersionHeight(relativeDirectory)); // Commit touching both excluded and included path does affect height - var includedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); + string includedFilePath = Path.Combine(this.RepoPath, relativeDirectory, "another-file.txt"); File.WriteAllText(includedFilePath, "hello"); File.WriteAllText(ignoredFilePath, "changed"); Commands.Stage(this.LibGit2Repository, includedFilePath); @@ -1008,7 +1016,7 @@ public void GetVersionHeight_ProjectDirectoryIsMoved() Assert.Equal(2, this.GetVersionHeight(relativeDirectory)); // Commit touching excluded directory does not affect version height - var fileInExcludedDirPath = Path.Combine(this.RepoPath, relativeDirectory, "excluded-dir", "ignore.txt"); + string fileInExcludedDirPath = Path.Combine(this.RepoPath, relativeDirectory, "excluded-dir", "ignore.txt"); Directory.CreateDirectory(Path.GetDirectoryName(fileInExcludedDirPath)); File.WriteAllText(fileInExcludedDirPath, "hello"); Commands.Stage(this.LibGit2Repository, fileInExcludedDirPath); @@ -1098,8 +1106,8 @@ public void GetVersionHeight_VeryLongHistory() [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3.4-alpha", "1.2.3.4-alpha+")] [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3.4-alpha", "1.2.3.4-alpha")] // 4 version fields with git height in prerelease tag configured in version.json - [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3.4-alpha.{height}", "1.2.3.4-alpha.1+")] - [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3.4-alpha.{height}", "1.2.3.4-alpha.1")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.BuildMetadata, "1.2.3.4-alpha.{height}", "1.2.3.4-alpha.1+")] + [InlineData(VersionOptions.CloudBuildNumberCommitWhere.FourthVersionComponent, "1.2.3.4-alpha.{height}", "1.2.3.4-alpha.1")] public void CloudBuildNumber_4thPosition(VersionOptions.CloudBuildNumberCommitWhere where, string version, string expectedCloudBuildNumber) { VersionOptions workingCopyVersion = new VersionOptions @@ -1112,10 +1120,10 @@ public void CloudBuildNumber_4thPosition(VersionOptions.CloudBuildNumberCommitWh IncludeCommitId = new VersionOptions.CloudBuildNumberCommitIdOptions { When = VersionOptions.CloudBuildNumberCommitWhen.Always, - Where = where - } - } - } + Where = where, + }, + }, + }, }; this.WriteVersionFile(workingCopyVersion); this.InitializeSourceControl(); @@ -1123,7 +1131,7 @@ public void CloudBuildNumber_4thPosition(VersionOptions.CloudBuildNumberCommitWh oracle.PublicRelease = true; expectedCloudBuildNumber = expectedCloudBuildNumber.Replace("", GitObjectId.Parse(oracle.GitCommitId).AsUInt16().ToString()); expectedCloudBuildNumber = expectedCloudBuildNumber.Replace("", oracle.GitCommitIdShort); - + Assert.Equal(expectedCloudBuildNumber, oracle.CloudBuildNumber); } } diff --git a/test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs b/test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs index db00a999..50d87f14 100644 --- a/test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs +++ b/test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs @@ -1,4 +1,7 @@ -using System.IO; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.IO; using System.Reflection; using Newtonsoft.Json; using Newtonsoft.Json.Linq; @@ -8,7 +11,7 @@ public class VersionSchemaTests { - private readonly ITestOutputHelper Logger; + private readonly ITestOutputHelper logger; private readonly JSchema schema; @@ -16,7 +19,7 @@ public class VersionSchemaTests public VersionSchemaTests(ITestOutputHelper logger) { - this.Logger = logger; + this.logger = logger; using (var schemaStream = new StreamReader(Assembly.GetExecutingAssembly().GetManifestResourceStream($"{ThisAssembly.RootNamespace}.version.schema.json"))) { this.schema = JSchema.Load(new JsonTextReader(schemaStream)); @@ -97,14 +100,14 @@ public void Inherit_AllowsOmissionOfVersion() public void ReleaseProperty_ValidJson(string json) { this.json = JObject.Parse(json); - Assert.True(this.json.IsValid(this.schema)); + Assert.True(this.json.IsValid(this.schema)); } [Theory] [InlineData(@"{ ""version"": ""2.3"", ""release"": { ""versionIncrement"" : ""revision"" } }")] [InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""formatWithoutPlaceholder"" } }")] [InlineData(@"{ ""version"": ""2.3"", ""release"": { ""branchName"" : ""formatWithoutPlaceholder{0}"" } }")] - [InlineData(@"{ ""version"": ""2.3"", ""release"": { ""unknownProperty"" : ""value"" } }")] + [InlineData(@"{ ""version"": ""2.3"", ""release"": { ""unknownProperty"" : ""value"" } }")] public void ReleaseProperty_InvalidJson(string json) { this.json = JObject.Parse(json); diff --git a/test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs b/test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs index 66639cc6..1a6a379a 100644 --- a/test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs +++ b/test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs @@ -1,9 +1,13 @@ -using System; +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; using System.Runtime.InteropServices; using Xunit; public class WindowsTheoryAttribute : TheoryAttribute { + /// public override string Skip { get @@ -15,6 +19,7 @@ public override string Skip return null; } + set { throw new NotSupportedException(); diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 7dcddc78..76a397f0 100755 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -15,20 +15,28 @@ When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. +.PARAMETER IncludeX86 + Installs a x86 SDK and runtimes in addition to the x64 ones. Only supported on Windows. Ignored on others. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( [ValidateSet('repo','user','machine')] - [string]$InstallLocality='user' + [string]$InstallLocality='user', + [switch]$IncludeX86 ) $DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools" if (!(Test-Path $DotNetInstallScriptRoot)) { New-Item -ItemType Directory -Path $DotNetInstallScriptRoot -WhatIf:$false | Out-Null } $DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot -# Look up actual required .NET Core SDK version from global.json +# Look up actual required .NET SDK version from global.json $sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1" +If ($IncludeX86 -and ($IsMacOS -or $IsLinux)) { + Write-Verbose "Ignoring -IncludeX86 switch because 32-bit runtimes are only supported on Windows." + $IncludeX86 = $false +} + $arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture if (!$arch) { # Windows Powershell leaves this blank $arch = 'x64' @@ -72,7 +80,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile = Join-Path $OutDir $Uri.Segments[-1] if (!(Test-Path $OutFile)) { Write-Verbose "Downloading $Uri..." - if (!(Test-Path $OutDir)) { mkdir $OutDir } + if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir } try { (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) } finally { @@ -83,7 +91,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile } -Function Get-InstallerExe($Version, [switch]$Runtime) { +Function Get-InstallerExe($Version, $Architecture, [switch]$Runtime) { $sdkOrRuntime = 'Sdk' if ($Runtime) { $sdkOrRuntime = 'Runtime' } @@ -116,7 +124,7 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { if ($filesElement) { foreach ($file in $filesElement) { - if ($file.rid -eq "win-$arch") { + if ($file.rid -eq "win-$Architecture") { $url = $file.url Break } @@ -135,22 +143,20 @@ Function Get-InstallerExe($Version, [switch]$Runtime) { } } -Function Install-DotNet($Version, [switch]$Runtime) { +Function Install-DotNet($Version, $Architecture, [switch]$Runtime) { if ($Runtime) { $sdkSubstring = '' } else { $sdkSubstring = 'SDK ' } Write-Host "Downloading .NET Core $sdkSubstring$Version..." - $Installer = Get-InstallerExe -Version $Version -Runtime:$Runtime + $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -Runtime:$Runtime Write-Host "Installing .NET Core $sdkSubstring$Version..." cmd /c start /wait $Installer /install /passive /norestart if ($LASTEXITCODE -eq 3010) { Write-Verbose "Restart required" } elseif ($LASTEXITCODE -ne 0) { - throw "Failure to install .NET Core SDK" + throw "Failure to install .NET SDK" } } -$switches = @( - '-Architecture',$arch -) +$switches = @() $envVars = @{ # For locally installed dotnet, skip first time experience which takes a long time 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' = 'true'; @@ -161,15 +167,25 @@ if ($InstallLocality -eq 'machine') { $DotNetInstallDir = '/usr/share/dotnet' } else { $restartRequired = $false - if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { - Install-DotNet -Version $sdkVersion + 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 + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } } $runtimeVersions | Get-Unique |% { if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - Install-DotNet -Version $_ -Runtime + Install-DotNet -Version $_ -Architecture $arch -Runtime $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + + if ($IncludeX86) { + Install-DotNet -Version $_ -Architecture x86 -Runtime + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } } } @@ -182,20 +198,34 @@ if ($InstallLocality -eq 'machine') { } } elseif ($InstallLocality -eq 'repo') { $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet" + $DotNetX86InstallDir = "$DotNetInstallScriptRoot/x86/.dotnet" } elseif ($env:AGENT_TOOLSDIRECTORY) { $DotNetInstallDir = "$env:AGENT_TOOLSDIRECTORY/dotnet" + $DotNetX86InstallDir = "$env:AGENT_TOOLSDIRECTORY/x86/dotnet" } else { $DotNetInstallDir = Join-Path $HOME .dotnet } -Write-Host "Installing .NET Core SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue - if ($DotNetInstallDir) { - $switches += '-InstallDir',"`"$DotNetInstallDir`"" + if (!(Test-Path $DotNetInstallDir)) { New-Item -ItemType Directory -Path $DotNetInstallDir } + $DotNetInstallDir = Resolve-Path $DotNetInstallDir + Write-Host "Installing .NET SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue $envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0' $envVars['DOTNET_ROOT'] = $DotNetInstallDir } +if ($IncludeX86) { + if ($DotNetX86InstallDir) { + if (!(Test-Path $DotNetX86InstallDir)) { New-Item -ItemType Directory -Path $DotNetX86InstallDir } + $DotNetX86InstallDir = Resolve-Path $DotNetX86InstallDir + Write-Host "Installing x86 .NET SDK and runtimes to $DotNetX86InstallDir" -ForegroundColor Blue + } else { + # Only machine-wide or repo-wide installations can handle two unique dotnet.exe architectures. + Write-Error "The installation location or OS isn't supported for x86 installation. Try a different -InstallLocality value." + return 1 + } +} + if ($IsMacOS -or $IsLinux) { $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" @@ -219,47 +249,89 @@ $DotNetInstallScriptPathExpression = "& '$DotNetInstallScriptPathExpression'" $anythingInstalled = $false $global:LASTEXITCODE = 0 -if ($PSCmdlet.ShouldProcess(".NET Core SDK $sdkVersion", "Install")) { +if ($PSCmdlet.ShouldProcess(".NET SDK $sdkVersion", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion $switches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches -DryRun" +} + +if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET x86 SDK $sdkVersion", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET x86 SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches -DryRun" + } } $dotnetRuntimeSwitches = $switches + '-Runtime','dotnet' $runtimeVersions | Sort-Object -Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET Core $Arch runtime $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $dotnetRuntimeSwitches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $dotnetRuntimeSwitches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $dotnetRuntimeSwitches -DryRun" + } + + if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET Core x86 runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $dotnetRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $dotnetRuntimeSwitches -DryRun" + } } } $windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop' $windowsDesktopRuntimeVersions | Sort-Object -Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop $arch runtime $_", "Install")) { $anythingInstalled = $true - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $windowsDesktopRuntimeSwitches" if ($LASTEXITCODE -ne 0) { Write-Error ".NET SDK installation failure: $LASTEXITCODE" exit $LASTEXITCODE } } else { - Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ $windowsDesktopRuntimeSwitches -DryRun" + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $windowsDesktopRuntimeSwitches -DryRun" + } + + if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop x86 runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $windowsDesktopRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $windowsDesktopRuntimeSwitches -DryRun" + } } } From 78cba24937d03e10c3266e7421b1aef038d0e354 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 5 May 2022 21:07:12 -0600 Subject: [PATCH 470/704] Shift to `using` directives outside the namespace This is a concession from StyleCop defaults, but it's just too hard to paddle upstream with the C# language team, which doesn't consistently test their refactoring features when `using` is inside the namespace. --- stylecop.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/stylecop.json b/stylecop.json index 37918949..6cd45574 100644 --- a/stylecop.json +++ b/stylecop.json @@ -10,6 +10,9 @@ }, "fileNamingConvention": "metadata", "xmlHeader": false + }, + "orderingRules": { + "usingDirectivesPlacement": "outsideNamespace" } } } From c82cc3463cb88e1591401059e127a1d84c4317f9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 5 May 2022 21:07:33 -0600 Subject: [PATCH 471/704] Permit attribute lists with multiple attributes in tests --- test/.editorconfig | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/.editorconfig b/test/.editorconfig index 8aa791be..74dd4a1f 100644 --- a/test/.editorconfig +++ b/test/.editorconfig @@ -50,3 +50,6 @@ dotnet_diagnostic.CA2007.severity = none # SA1401: Fields should be private dotnet_diagnostic.SA1401.severity = silent + +# SA1133: Do not combine attributes +dotnet_diagnostic.SA1133.severity = silent From 0a6f58c3cc425ca7a8612acb9129e730fce8507c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 5 May 2022 21:22:34 -0600 Subject: [PATCH 472/704] Update Nerdbank.GitVersioning dependency --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 834e7457..2e13d76f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,7 +37,7 @@ - + From 9dde17ff42c902d3be0951021e049b7c8fc6fec1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 5 May 2022 21:32:22 -0600 Subject: [PATCH 473/704] Use icons for all task display names --- azure-pipelines/build.yml | 2 +- azure-pipelines/dotnet.yml | 10 +++++----- azure-pipelines/expand-template.yml | 6 +++--- azure-pipelines/install-dependencies.yml | 6 +++--- azure-pipelines/publish-codecoverage.yml | 10 +++++----- azure-pipelines/publish-deployables.yml | 4 ++-- azure-pipelines/publish-symbols.yml | 16 ++++++++-------- azure-pipelines/release.yml | 10 +++++----- 8 files changed, 32 insertions(+), 32 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index f779fd12..5bfd95f5 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -14,7 +14,7 @@ jobs: - template: install-dependencies.yml - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' - displayName: Set build number + displayName: ⚙ Set build number - template: dotnet.yml - template: expand-template.yml diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index a103adfd..1d7d9de7 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -1,23 +1,23 @@ steps: - script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" - displayName: dotnet build + displayName: 🛠 dotnet build - powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults - displayName: dotnet test + displayName: 🧪 dotnet test - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true - displayName: Update pipeline variables based on build outputs + displayName: ⚙ Update pipeline variables based on build outputs condition: succeededOrFailed() - powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" failOnStderr: true - displayName: Publish artifacts + displayName: 📢 Publish artifacts condition: succeededOrFailed() - bash: bash <(curl -s https://codecov.io/bash) - displayName: Publish code coverage results to codecov.io + displayName: 📢 Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') timeoutInMinutes: 3 continueOnError: true diff --git a/azure-pipelines/expand-template.yml b/azure-pipelines/expand-template.yml index ed510de3..d843f1ea 100644 --- a/azure-pipelines/expand-template.yml +++ b/azure-pipelines/expand-template.yml @@ -2,13 +2,13 @@ steps: - script: | dotnet build-server shutdown git clean -fdx - displayName: Cleaning repo for template expansion + displayName: 🧹 Cleaning repo for template expansion - powershell: | git config user.name "test user" git config user.email "andrewarnott@gmail.com" ./Expand-Template.ps1 -LibraryName Calc -Author "Andrew Arnott" - displayName: Expanding template + displayName: 🧪 Expanding template failOnStderr: true # TODO: Verify that all changes are staged to the git index - script: dotnet build - displayName: dotnet build (expanded template) + displayName: 🛠 dotnet build (expanded template) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 4f848b09..3993f104 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -4,7 +4,7 @@ parameters: steps: - task: NuGetAuthenticate@0 - displayName: Authenticate NuGet feeds + displayName: 🔏 Authenticate NuGet feeds inputs: forceReinstallCredentialProvider: true @@ -17,9 +17,9 @@ steps: if (Get-Command mono -ErrorAction SilentlyContinue) { mono --version } - displayName: Install prerequisites + displayName: ⚙ Install prerequisites - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true - displayName: Set pipeline variables based on source + displayName: ⚙ Set pipeline variables based on source name: SetPipelineVariables diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index a0862be3..423e12fc 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -4,15 +4,15 @@ parameters: steps: - download: current artifact: coverageResults-Windows - displayName: Download Windows code coverage results + displayName: 🔻 Download Windows code coverage results continueOnError: true - download: current artifact: coverageResults-Linux - displayName: Download Linux code coverage results + displayName: 🔻 Download Linux code coverage results continueOnError: true - download: current artifact: coverageResults-macOS - displayName: Download macOS code coverage results + displayName: 🔻 Download macOS code coverage results continueOnError: true condition: ${{ parameters.includeMacOS }} - powershell: | @@ -26,9 +26,9 @@ steps: } $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ })) obj/reportgenerator -reports:"$Inputs" -targetdir:coveragereport -reporttypes:Cobertura - displayName: Merge coverage + displayName: ⚙ Merge coverage - task: PublishCodeCoverageResults@1 - displayName: Publish code coverage results to Azure DevOps + displayName: 📢 Publish code coverage results to Azure DevOps inputs: codeCoverageTool: cobertura summaryFileLocation: 'coveragereport/Cobertura.xml' diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index 9ccdc29e..31e80a43 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -1,8 +1,8 @@ steps: - download: current - displayName: Download deployables + displayName: 🔻 Download deployables artifact: deployables-Windows - powershell: dotnet nuget push "$(Resolve-Path '$(Pipeline.Workspace)\deployables-Windows\')*.nupkg" -s $(ci_feed) -k azdo --skip-duplicate - displayName: Push packages to CI feed + displayName: 📦 Push packages to CI feed condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) diff --git a/azure-pipelines/publish-symbols.yml b/azure-pipelines/publish-symbols.yml index c45eff02..00c188fc 100644 --- a/azure-pipelines/publish-symbols.yml +++ b/azure-pipelines/publish-symbols.yml @@ -6,19 +6,19 @@ steps: inputs: artifact: symbols-Windows path: $(Pipeline.Workspace)/symbols/Windows - displayName: Download Windows symbols + displayName: 🔻 Download Windows symbols continueOnError: true - task: DownloadPipelineArtifact@2 inputs: artifact: symbols-Linux path: $(Pipeline.Workspace)/symbols/Linux - displayName: Download Linux symbols + displayName: 🔻 Download Linux symbols continueOnError: true - task: DownloadPipelineArtifact@2 inputs: artifact: symbols-macOS path: $(Pipeline.Workspace)/symbols/macOS - displayName: Download macOS symbols + displayName: 🔻 Download macOS symbols continueOnError: true condition: ${{ parameters.includeMacOS }} @@ -26,19 +26,19 @@ steps: inputs: artifact: test_symbols-Windows path: $(Pipeline.Workspace)/test_symbols/Windows - displayName: Download Windows test symbols + displayName: 🔻 Download Windows test symbols continueOnError: true - task: DownloadPipelineArtifact@2 inputs: artifact: test_symbols-Linux path: $(Pipeline.Workspace)/test_symbols/Linux - displayName: Download Linux test symbols + displayName: 🔻 Download Linux test symbols continueOnError: true - task: DownloadPipelineArtifact@2 inputs: artifact: test_symbols-macOS path: $(Pipeline.Workspace)/test_symbols/macOS - displayName: Download macOS test symbols + displayName: 🔻 Download macOS test symbols continueOnError: true condition: ${{ parameters.includeMacOS }} @@ -48,7 +48,7 @@ steps: SearchPattern: '**/*.pdb' IndexSources: false SymbolServerType: TeamServices - displayName: Publish symbols + displayName: 📢 Publish symbols - task: PublishSymbols@2 inputs: @@ -56,4 +56,4 @@ steps: SearchPattern: '**/*.pdb' IndexSources: false SymbolServerType: TeamServices - displayName: Publish test symbols + displayName: 📢 Publish test symbols diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 6690cccf..2679b24e 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -25,18 +25,18 @@ jobs: } else { Write-Host "##vso[task.setvariable variable=IsPrerelease]false" } - displayName: Set up pipeline + displayName: ⚙ Set up pipeline - task: UseDotNet@2 - displayName: Install .NET SDK + displayName: ⚙ Install .NET SDK inputs: packageType: sdk version: 6.x - download: CI artifact: deployables-Windows - displayName: Download deployables-Windows artifact + displayName: 🔻 Download deployables-Windows artifact patterns: 'deployables-Windows/*' - task: GitHubRelease@1 - displayName: GitHub release (create) + displayName: 📢 GitHub release (create) inputs: gitHubConnection: # TODO: fill in service connection here repositoryName: $(Build.Repository.Name) @@ -55,5 +55,5 @@ jobs: { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } ] - script: dotnet nuget push $(Pipeline.Workspace)/CI/deployables-Windows/*.nupkg -s https://api.nuget.org/v3/index.json --api-key $(NuGetOrgApiKey) --skip-duplicate - displayName: Push packages to nuget.org + displayName: 📦 Push packages to nuget.org condition: and(succeeded(), ne(variables['NuGetOrgApiKey'], '')) From d0b7c362fff25b333b7da3c89d16741af6945f17 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 9 May 2022 09:03:16 -0600 Subject: [PATCH 474/704] Define more empty targets for VSIX projects (#752) * Define an empty BuiltProjectOutputGroupDependencies target * Define an empty DebugSymbolsProjectOutputGroup target Fixes #751 --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 8e6aa161..5d2508d2 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -20,6 +20,8 @@ + + From f53c039e3a2e5a11c2168b2eb9936e978175cd12 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 11 May 2022 20:55:22 -0600 Subject: [PATCH 475/704] Define an empty GetTargetPathWithTargetPlatformMoniker target Closes #754 --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 5d2508d2..157dd6a7 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -22,6 +22,9 @@ + + + From 8f57653736604c48c801ec36a9923a6e6eefa670 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 11 May 2022 21:03:09 -0600 Subject: [PATCH 476/704] Declare an empty _CollectWatchItems target Fixes #732 --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 157dd6a7..16c0d5a1 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -25,6 +25,9 @@ + + + From 9805678248d0fbda63f97982f37e35de71890d2f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:41:05 -0600 Subject: [PATCH 477/704] Fix NUGET_PACKAGES path in pipelines Be default the NUGET_PACKAGES path has a trailing slash. In our override, we should do this as well or the msbuild property that gets generated is missing the slash, which can break some builds. --- .github/workflows/build.yml | 2 +- azure-pipelines.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18ae3e28..4db43f53 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -12,7 +12,7 @@ env: DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BUILDCONFIGURATION: Release codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ - NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages + NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages/ jobs: build: diff --git a/azure-pipelines.yml b/azure-pipelines.yml index b7d86b45..d98ed107 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -24,7 +24,7 @@ variables: BuildConfiguration: Release codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ ci_feed: https://pkgs.dev.azure.com/andrewarnott/_packaging/CI/nuget/v3/index.json # Azure Artifacts feed URL - NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages + NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/ jobs: - template: azure-pipelines/build.yml From a6447c105799eb9337660b14e195976965c856ec Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 3 May 2022 09:06:52 -0600 Subject: [PATCH 478/704] Fixed directory capitalization --- azure-pipelines.yml | 8 ++++---- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 2 +- .../Nerdbank.GitVersioning.Tasks.csproj | 2 +- .../AssemblyVersionOptionsConverter.cs | 0 .../CloudBuild.cs | 0 .../CloudBuildServices/AppVeyor.cs | 0 .../CloudBuildServices/AtlassianBamboo.cs | 0 .../CloudBuildServices/GitHubActions.cs | 0 .../CloudBuildServices/GitLab.cs | 0 .../CloudBuildServices/Jenkins.cs | 0 .../CloudBuildServices/SpaceAutomation.cs | 0 .../CloudBuildServices/TeamCity.cs | 0 .../CloudBuildServices/Travis.cs | 0 .../CloudBuildServices/VisualStudioTeamServices.cs | 0 .../Commands/CloudCommand.cs | 0 .../FilterPath.cs | 0 .../FilterPathJsonConverter.cs | 0 .../GitContext.cs | 0 .../GitException.cs | 0 .../ICloudBuild.cs | 0 .../LibGit2/LibGit2Context.cs | 0 .../LibGit2/LibGit2GitExtensions.cs | 0 .../LibGit2/LibGit2VersionFile.cs | 0 .../Managed/GitExtensions.cs | 0 .../Managed/ManagedGitContext.cs | 0 .../Managed/ManagedVersionFile.cs | 0 .../ManagedGit/DeltaInstruction.cs | 0 .../ManagedGit/DeltaInstructionType.cs | 0 .../ManagedGit/DeltaStreamReader.cs | 0 .../ManagedGit/FileHelpers.cs | 0 .../ManagedGit/GitCommit.cs | 0 .../ManagedGit/GitCommitReader.cs | 0 .../ManagedGit/GitObjectId.cs | 0 .../ManagedGit/GitObjectStream.cs | 0 .../ManagedGit/GitPack.cs | 0 .../ManagedGit/GitPackCache.cs | 0 .../ManagedGit/GitPackDeltafiedStream.cs | 0 .../ManagedGit/GitPackIndexMappedReader.cs | 0 .../ManagedGit/GitPackIndexReader.cs | 0 .../ManagedGit/GitPackMemoryCache.cs | 0 .../ManagedGit/GitPackMemoryCacheStream.cs | 0 .../ManagedGit/GitPackMemoryCacheViewStream.cs | 0 .../ManagedGit/GitPackNullCache.cs | 0 .../ManagedGit/GitPackObjectType.cs | 0 .../ManagedGit/GitPackPooledStream.cs | 0 .../ManagedGit/GitPackReader.cs | 0 .../ManagedGit/GitReferenceReader.cs | 0 .../ManagedGit/GitRepository.cs | 0 .../ManagedGit/GitSignature.cs | 0 .../ManagedGit/GitTree.cs | 0 .../ManagedGit/GitTreeEntry.cs | 0 .../ManagedGit/GitTreeReader.cs | 0 .../ManagedGit/GitTreeStreamingReader.cs | 0 .../ManagedGit/MemoryMappedStream.cs | 0 .../ManagedGit/StreamExtensions.cs | 0 .../ManagedGit/ZLibStream.cs | 0 .../NativeMethods.json | 0 .../NativeMethods.txt | 0 .../Nerdbank.GitVersioning.csproj} | 0 .../NoGit/NoGitContext.cs | 0 .../NoGit/NoGitVersionFile.cs | 0 .../ReleaseManager.cs | 0 .../SemanticVersion.cs | 0 .../SemanticVersionJsonConverter.cs | 0 .../VersionExtensions.cs | 0 .../VersionFile.cs | 0 .../VersionOptions.cs | 2 +- .../VersionOptionsContractResolver.cs | 0 .../VersionOracle.cs | 0 .../version.schema.json | 0 src/nbgv/nbgv.csproj | 2 +- .../Cake.GitVersioning.Tests.csproj | 2 +- .../GetVersionBenchmarks.cs | 2 +- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- .../Program.cs | 0 .../AssemblyInfoTest.cs | 0 .../BuildIntegrationTests.cs | 6 +++--- .../FilterPathTests.cs | 0 .../GitContextTests.cs | 0 .../Keys/keypair.snk | Bin .../Keys/protectedPair.pfx | Bin .../Keys/public.snk | Bin .../LibGit2GitExtensionsTests.cs | 2 +- .../MSBuildExtensions.cs | 0 .../MSBuildFixture.cs | 0 .../ManagedGit/.gitattributes | 0 .../3596ffe59898103a2675547d4597e742e1f2389c.gz | Bin .../ManagedGit/DeltaStreamReaderTests.cs | 0 .../ManagedGit/GitCommitReaderTests.cs | 0 .../ManagedGit/GitCommitTests.cs | 0 .../ManagedGit/GitObjectIdTests.cs | 0 .../ManagedGit/GitObjectStreamTests.cs | 0 .../ManagedGit/GitPackDeltafiedStreamTests.cs | 0 .../ManagedGit/GitPackIndexMappedReaderTests.cs | 0 .../ManagedGit/GitPackMemoryCacheTests.cs | 0 .../ManagedGit/GitPackTests.cs | 0 .../ManagedGit/GitRepositoryTests.cs | 0 .../ManagedGit/GitTreeStreamingReaderTests.cs | 0 .../ManagedGit/StreamExtensionsTests.cs | 0 .../ManagedGit/ZLibStreamTest.cs | 0 .../commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 | 0 .../commit-ab39e8acac105fa0db88514f259341c9f0201b22 | 0 .../commit-d56dc3ed179053abef2097d1120b4507769bcf1a | 0 .../ManagedGit/commit.delta | 0 ...ck-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt | 0 ...ack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx | Bin ...ck-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack | Bin .../tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 | 0 .../tree-f914b48023c7c804a4f3be780d451f31aef74ac1 | 0 .../ManagedGit/tree.bin | Bin .../ManagedGit/tree.delta | 0 .../Nerdbank.GitVersioning.Tests.csproj} | 4 ++-- .../ReleaseManagerTests.cs | 0 .../RepoTestBase.Helpers.cs | 0 .../RepoTestBase.cs | 0 .../SemanticVersionExtensionsTests.cs | 0 .../SemanticVersionTests.cs | 0 .../TestUtilities.cs | 0 .../VersionExtensionsTests.cs | 0 .../VersionFileTests.cs | 0 .../VersionOptionsTests.cs | 0 .../VersionOracleTests.cs | 0 .../VersionSchemaTests.cs | 0 .../WindowsTheoryAttribute.cs | 0 .../repos/PackedHeadRef.zip | Bin .../repos/submodules.zip | Bin .../test.prj | 0 .../test.vcprj | 4 ++-- 128 files changed, 19 insertions(+), 19 deletions(-) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/AssemblyVersionOptionsConverter.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuild.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/AppVeyor.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/AtlassianBamboo.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/GitHubActions.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/GitLab.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/Jenkins.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/SpaceAutomation.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/TeamCity.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/Travis.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/CloudBuildServices/VisualStudioTeamServices.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/Commands/CloudCommand.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/FilterPath.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/FilterPathJsonConverter.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/GitContext.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/GitException.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ICloudBuild.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/LibGit2/LibGit2Context.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/LibGit2/LibGit2GitExtensions.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/LibGit2/LibGit2VersionFile.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/Managed/GitExtensions.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/Managed/ManagedGitContext.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/Managed/ManagedVersionFile.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/DeltaInstruction.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/DeltaInstructionType.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/DeltaStreamReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/FileHelpers.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitCommit.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitCommitReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitObjectId.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitObjectStream.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPack.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackCache.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackDeltafiedStream.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackIndexMappedReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackIndexReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackMemoryCache.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackMemoryCacheStream.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackMemoryCacheViewStream.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackNullCache.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackObjectType.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackPooledStream.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitPackReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitReferenceReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitRepository.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitSignature.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitTree.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitTreeEntry.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitTreeReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/GitTreeStreamingReader.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/MemoryMappedStream.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/StreamExtensions.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ManagedGit/ZLibStream.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/NativeMethods.json (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/NativeMethods.txt (100%) rename src/{NerdBank.GitVersioning/NerdBank.GitVersioning.csproj => Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj} (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/NoGit/NoGitContext.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/NoGit/NoGitVersionFile.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/ReleaseManager.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/SemanticVersion.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/SemanticVersionJsonConverter.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/VersionExtensions.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/VersionFile.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/VersionOptions.cs (99%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/VersionOptionsContractResolver.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/VersionOracle.cs (100%) rename src/{NerdBank.GitVersioning => Nerdbank.GitVersioning}/version.schema.json (100%) rename test/{NerdBank.GitVersioning.Benchmarks => Nerdbank.GitVersioning.Benchmarks}/GetVersionBenchmarks.cs (98%) rename test/{NerdBank.GitVersioning.Benchmarks => Nerdbank.GitVersioning.Benchmarks}/Nerdbank.GitVersioning.Benchmarks.csproj (92%) rename test/{NerdBank.GitVersioning.Benchmarks => Nerdbank.GitVersioning.Benchmarks}/Program.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/AssemblyInfoTest.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/BuildIntegrationTests.cs (99%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/FilterPathTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/GitContextTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/Keys/keypair.snk (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/Keys/protectedPair.pfx (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/Keys/public.snk (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/LibGit2GitExtensionsTests.cs (99%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/MSBuildExtensions.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/MSBuildFixture.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/.gitattributes (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/DeltaStreamReaderTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitCommitReaderTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitCommitTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitObjectIdTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitObjectStreamTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitPackDeltafiedStreamTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitPackIndexMappedReaderTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitPackMemoryCacheTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitPackTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitRepositoryTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/GitTreeStreamingReaderTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/StreamExtensionsTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/ZLibStreamTest.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/commit.delta (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/tree.bin (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ManagedGit/tree.delta (100%) rename test/{NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj => Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj} (95%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/ReleaseManagerTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/RepoTestBase.Helpers.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/RepoTestBase.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/SemanticVersionExtensionsTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/SemanticVersionTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/TestUtilities.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/VersionExtensionsTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/VersionFileTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/VersionOptionsTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/VersionOracleTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/VersionSchemaTests.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/WindowsTheoryAttribute.cs (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/repos/PackedHeadRef.zip (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/repos/submodules.zip (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/test.prj (100%) rename test/{NerdBank.GitVersioning.Tests => Nerdbank.GitVersioning.Tests}/test.vcprj (99%) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 11a4d988..d326cf9a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -104,7 +104,7 @@ stages: git clone https://github.com/xunit/xunit $(repoDir)/xunit git clone https://github.com/gimlichael/Cuemon $(repoDir)/Cuemon git clone https://github.com/kerryjiang/SuperSocket $(repoDir)/SuperSocket - git clone https://github.com/dotnet/NerdBank.GitVersioning $(repoDir)/NerdBank.GitVersioning + git clone https://github.com/dotnet/Nerdbank.GitVersioning $(repoDir)/Nerdbank.GitVersioning displayName: Clone test repositories - script: | dotnet build -c Release @@ -112,7 +112,7 @@ stages: displayName: Build in Release mode - script: | dotnet run -c Release -f netcoreapp3.1 -- --filter GetVersionBenchmarks --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) - workingDirectory: src/NerdBank.GitVersioning.Benchmarks + workingDirectory: src/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (packed) - bash: | cd $(repoDir)/xunit @@ -124,12 +124,12 @@ stages: cd $(repoDir)/SuperSocket git unpack-objects < .git/objects/pack/*.pack - cd $(repoDir)/NerdBank.GitVersioning + cd $(repoDir)/Nerdbank.GitVersioning git unpack-objects < .git/objects/pack/*.pack displayName: Unpack Git repositories - script: | dotnet run -c Release -f netcoreapp3.1 -- --filter GetVersionBenchmarks --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) - workingDirectory: src/NerdBank.GitVersioning.Benchmarks + workingDirectory: src/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (unpacked) - task: PublishBuildArtifacts@1 inputs: diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 40b965fb..3ab5c9cd 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -48,7 +48,7 @@ - + diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj index b03f89ed..f17b6fbc 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj @@ -69,7 +69,7 @@ - + diff --git a/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs b/src/Nerdbank.GitVersioning/AssemblyVersionOptionsConverter.cs similarity index 100% rename from src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs rename to src/Nerdbank.GitVersioning/AssemblyVersionOptionsConverter.cs diff --git a/src/NerdBank.GitVersioning/CloudBuild.cs b/src/Nerdbank.GitVersioning/CloudBuild.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuild.cs rename to src/Nerdbank.GitVersioning/CloudBuild.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/AppVeyor.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/AppVeyor.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/GitHubActions.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/GitHubActions.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/GitLab.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/GitLab.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/Jenkins.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/Jenkins.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/SpaceAutomation.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/SpaceAutomation.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/TeamCity.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/TeamCity.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/Travis.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/Travis.cs diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs b/src/Nerdbank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs similarity index 100% rename from src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs rename to src/Nerdbank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs diff --git a/src/NerdBank.GitVersioning/Commands/CloudCommand.cs b/src/Nerdbank.GitVersioning/Commands/CloudCommand.cs similarity index 100% rename from src/NerdBank.GitVersioning/Commands/CloudCommand.cs rename to src/Nerdbank.GitVersioning/Commands/CloudCommand.cs diff --git a/src/NerdBank.GitVersioning/FilterPath.cs b/src/Nerdbank.GitVersioning/FilterPath.cs similarity index 100% rename from src/NerdBank.GitVersioning/FilterPath.cs rename to src/Nerdbank.GitVersioning/FilterPath.cs diff --git a/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs b/src/Nerdbank.GitVersioning/FilterPathJsonConverter.cs similarity index 100% rename from src/NerdBank.GitVersioning/FilterPathJsonConverter.cs rename to src/Nerdbank.GitVersioning/FilterPathJsonConverter.cs diff --git a/src/NerdBank.GitVersioning/GitContext.cs b/src/Nerdbank.GitVersioning/GitContext.cs similarity index 100% rename from src/NerdBank.GitVersioning/GitContext.cs rename to src/Nerdbank.GitVersioning/GitContext.cs diff --git a/src/NerdBank.GitVersioning/GitException.cs b/src/Nerdbank.GitVersioning/GitException.cs similarity index 100% rename from src/NerdBank.GitVersioning/GitException.cs rename to src/Nerdbank.GitVersioning/GitException.cs diff --git a/src/NerdBank.GitVersioning/ICloudBuild.cs b/src/Nerdbank.GitVersioning/ICloudBuild.cs similarity index 100% rename from src/NerdBank.GitVersioning/ICloudBuild.cs rename to src/Nerdbank.GitVersioning/ICloudBuild.cs diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs b/src/Nerdbank.GitVersioning/LibGit2/LibGit2Context.cs similarity index 100% rename from src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs rename to src/Nerdbank.GitVersioning/LibGit2/LibGit2Context.cs diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/Nerdbank.GitVersioning/LibGit2/LibGit2GitExtensions.cs similarity index 100% rename from src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs rename to src/Nerdbank.GitVersioning/LibGit2/LibGit2GitExtensions.cs diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs b/src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs similarity index 100% rename from src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs rename to src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs diff --git a/src/NerdBank.GitVersioning/Managed/GitExtensions.cs b/src/Nerdbank.GitVersioning/Managed/GitExtensions.cs similarity index 100% rename from src/NerdBank.GitVersioning/Managed/GitExtensions.cs rename to src/Nerdbank.GitVersioning/Managed/GitExtensions.cs diff --git a/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs b/src/Nerdbank.GitVersioning/Managed/ManagedGitContext.cs similarity index 100% rename from src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs rename to src/Nerdbank.GitVersioning/Managed/ManagedGitContext.cs diff --git a/src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs b/src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs similarity index 100% rename from src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs rename to src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs b/src/Nerdbank.GitVersioning/ManagedGit/DeltaInstruction.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs rename to src/Nerdbank.GitVersioning/ManagedGit/DeltaInstruction.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs b/src/Nerdbank.GitVersioning/ManagedGit/DeltaInstructionType.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs rename to src/Nerdbank.GitVersioning/ManagedGit/DeltaInstructionType.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/DeltaStreamReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/DeltaStreamReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs b/src/Nerdbank.GitVersioning/ManagedGit/FileHelpers.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs rename to src/Nerdbank.GitVersioning/ManagedGit/FileHelpers.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitCommit.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitCommit.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitCommitReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitCommitReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitObjectId.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitObjectId.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitObjectStream.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitObjectStream.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPack.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPack.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPack.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackCache.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackCache.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCache.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCache.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackNullCache.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackNullCache.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackObjectType.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackObjectType.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackPooledStream.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackPooledStream.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitPackReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitPackReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitReferenceReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitReferenceReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitRepository.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitRepository.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitSignature.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitSignature.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTree.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitTree.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitTree.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitTree.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitTreeEntry.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitTreeEntry.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitTreeReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitTreeReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs b/src/Nerdbank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs rename to src/Nerdbank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs b/src/Nerdbank.GitVersioning/ManagedGit/MemoryMappedStream.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs rename to src/Nerdbank.GitVersioning/ManagedGit/MemoryMappedStream.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs b/src/Nerdbank.GitVersioning/ManagedGit/StreamExtensions.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs rename to src/Nerdbank.GitVersioning/ManagedGit/StreamExtensions.cs diff --git a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs b/src/Nerdbank.GitVersioning/ManagedGit/ZLibStream.cs similarity index 100% rename from src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs rename to src/Nerdbank.GitVersioning/ManagedGit/ZLibStream.cs diff --git a/src/NerdBank.GitVersioning/NativeMethods.json b/src/Nerdbank.GitVersioning/NativeMethods.json similarity index 100% rename from src/NerdBank.GitVersioning/NativeMethods.json rename to src/Nerdbank.GitVersioning/NativeMethods.json diff --git a/src/NerdBank.GitVersioning/NativeMethods.txt b/src/Nerdbank.GitVersioning/NativeMethods.txt similarity index 100% rename from src/NerdBank.GitVersioning/NativeMethods.txt rename to src/Nerdbank.GitVersioning/NativeMethods.txt diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj similarity index 100% rename from src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj rename to src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj diff --git a/src/NerdBank.GitVersioning/NoGit/NoGitContext.cs b/src/Nerdbank.GitVersioning/NoGit/NoGitContext.cs similarity index 100% rename from src/NerdBank.GitVersioning/NoGit/NoGitContext.cs rename to src/Nerdbank.GitVersioning/NoGit/NoGitContext.cs diff --git a/src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs b/src/Nerdbank.GitVersioning/NoGit/NoGitVersionFile.cs similarity index 100% rename from src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs rename to src/Nerdbank.GitVersioning/NoGit/NoGitVersionFile.cs diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/Nerdbank.GitVersioning/ReleaseManager.cs similarity index 100% rename from src/NerdBank.GitVersioning/ReleaseManager.cs rename to src/Nerdbank.GitVersioning/ReleaseManager.cs diff --git a/src/NerdBank.GitVersioning/SemanticVersion.cs b/src/Nerdbank.GitVersioning/SemanticVersion.cs similarity index 100% rename from src/NerdBank.GitVersioning/SemanticVersion.cs rename to src/Nerdbank.GitVersioning/SemanticVersion.cs diff --git a/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs b/src/Nerdbank.GitVersioning/SemanticVersionJsonConverter.cs similarity index 100% rename from src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs rename to src/Nerdbank.GitVersioning/SemanticVersionJsonConverter.cs diff --git a/src/NerdBank.GitVersioning/VersionExtensions.cs b/src/Nerdbank.GitVersioning/VersionExtensions.cs similarity index 100% rename from src/NerdBank.GitVersioning/VersionExtensions.cs rename to src/Nerdbank.GitVersioning/VersionExtensions.cs diff --git a/src/NerdBank.GitVersioning/VersionFile.cs b/src/Nerdbank.GitVersioning/VersionFile.cs similarity index 100% rename from src/NerdBank.GitVersioning/VersionFile.cs rename to src/Nerdbank.GitVersioning/VersionFile.cs diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/Nerdbank.GitVersioning/VersionOptions.cs similarity index 99% rename from src/NerdBank.GitVersioning/VersionOptions.cs rename to src/Nerdbank.GitVersioning/VersionOptions.cs index 8984d851..f598c379 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/Nerdbank.GitVersioning/VersionOptions.cs @@ -243,7 +243,7 @@ public enum ReleaseVersionIncrement /// Gets the $schema field that should be serialized when writing. /// [JsonProperty(PropertyName = "$schema")] - public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json"; + public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/Nerdbank.GitVersioning/version.schema.json"; /// /// Gets or sets the default version to use. diff --git a/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs b/src/Nerdbank.GitVersioning/VersionOptionsContractResolver.cs similarity index 100% rename from src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs rename to src/Nerdbank.GitVersioning/VersionOptionsContractResolver.cs diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/Nerdbank.GitVersioning/VersionOracle.cs similarity index 100% rename from src/NerdBank.GitVersioning/VersionOracle.cs rename to src/Nerdbank.GitVersioning/VersionOracle.cs diff --git a/src/NerdBank.GitVersioning/version.schema.json b/src/Nerdbank.GitVersioning/version.schema.json similarity index 100% rename from src/NerdBank.GitVersioning/version.schema.json rename to src/Nerdbank.GitVersioning/version.schema.json diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 345cb47f..1a813cc1 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -22,6 +22,6 @@ - + diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 388b19e0..9c8340be 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs similarity index 98% rename from test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs rename to test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs index 3e74e994..be00f97a 100644 --- a/test/NerdBank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs +++ b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs @@ -22,7 +22,7 @@ public class GetVersionBenchmarks "xunit", "Cuemon", "SuperSocket", - "NerdBank.GitVersioning")] + "Nerdbank.GitVersioning")] public string ProjectDirectory; public Version Version { get; set; } diff --git a/test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj similarity index 92% rename from test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj rename to test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index 71e37780..808fa9a2 100644 --- a/test/NerdBank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/NerdBank.GitVersioning.Benchmarks/Program.cs b/test/Nerdbank.GitVersioning.Benchmarks/Program.cs similarity index 100% rename from test/NerdBank.GitVersioning.Benchmarks/Program.cs rename to test/Nerdbank.GitVersioning.Benchmarks/Program.cs diff --git a/test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs b/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs rename to test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs diff --git a/test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs similarity index 99% rename from test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs rename to test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs index 7dbc5400..268abc84 100644 --- a/test/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -83,8 +83,8 @@ protected override void ApplyGlobalProperties(IDictionary global public abstract class BuildIntegrationTests : RepoTestBase, IClassFixture { - private const string GitVersioningPropsFileName = "NerdBank.GitVersioning.props"; - private const string GitVersioningTargetsFileName = "NerdBank.GitVersioning.targets"; + private const string GitVersioningPropsFileName = "Nerdbank.GitVersioning.props"; + private const string GitVersioningTargetsFileName = "Nerdbank.GitVersioning.targets"; private const string UnitTestCloudBuildPrefix = "UnitTest: "; private static readonly string[] ToxicEnvironmentVariablePrefixes = new string[] { @@ -994,7 +994,7 @@ public async Task NativeVersionInfo_CreateNativeResourceDll() Assert.Equal("1.2", fileInfo.FileVersion); Assert.Equal("1.2.0", fileInfo.ProductVersion); Assert.Equal("test", fileInfo.InternalName); - Assert.Equal("NerdBank", fileInfo.CompanyName); + Assert.Equal("Nerdbank", fileInfo.CompanyName); Assert.Equal($"Copyright (c) {DateTime.Now.Year}. All rights reserved.", fileInfo.LegalCopyright); } #endif diff --git a/test/NerdBank.GitVersioning.Tests/FilterPathTests.cs b/test/Nerdbank.GitVersioning.Tests/FilterPathTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/FilterPathTests.cs rename to test/Nerdbank.GitVersioning.Tests/FilterPathTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/GitContextTests.cs b/test/Nerdbank.GitVersioning.Tests/GitContextTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/GitContextTests.cs rename to test/Nerdbank.GitVersioning.Tests/GitContextTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/Keys/keypair.snk b/test/Nerdbank.GitVersioning.Tests/Keys/keypair.snk similarity index 100% rename from test/NerdBank.GitVersioning.Tests/Keys/keypair.snk rename to test/Nerdbank.GitVersioning.Tests/Keys/keypair.snk diff --git a/test/NerdBank.GitVersioning.Tests/Keys/protectedPair.pfx b/test/Nerdbank.GitVersioning.Tests/Keys/protectedPair.pfx similarity index 100% rename from test/NerdBank.GitVersioning.Tests/Keys/protectedPair.pfx rename to test/Nerdbank.GitVersioning.Tests/Keys/protectedPair.pfx diff --git a/test/NerdBank.GitVersioning.Tests/Keys/public.snk b/test/Nerdbank.GitVersioning.Tests/Keys/public.snk similarity index 100% rename from test/NerdBank.GitVersioning.Tests/Keys/public.snk rename to test/Nerdbank.GitVersioning.Tests/Keys/public.snk diff --git a/test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs b/test/Nerdbank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs similarity index 99% rename from test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs rename to test/Nerdbank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs index 8d908bd8..8740e0bf 100644 --- a/test/NerdBank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/LibGit2GitExtensionsTests.cs @@ -467,7 +467,7 @@ public void GetIdAsVersion_MigrationFromVersionTxtToJson() [SkippableFact(Skip = "It fails already.")] // Skippable, only run test on specific machine public void TestBiggerRepo() { - string testBiggerRepoPath = @"D:\git\NerdBank.GitVersioning"; + string testBiggerRepoPath = @"D:\git\Nerdbank.GitVersioning"; Skip.If(!Directory.Exists(testBiggerRepoPath)); using var largeRepo = new Repository(testBiggerRepoPath); diff --git a/test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs b/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/MSBuildExtensions.cs rename to test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs diff --git a/test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs b/test/Nerdbank.GitVersioning.Tests/MSBuildFixture.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/MSBuildFixture.cs rename to test/Nerdbank.GitVersioning.Tests/MSBuildFixture.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/.gitattributes b/test/Nerdbank.GitVersioning.Tests/ManagedGit/.gitattributes similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/.gitattributes rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/.gitattributes diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz b/test/Nerdbank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/3596ffe59898103a2675547d4597e742e1f2389c.gz diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/DeltaStreamReaderTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitCommitReaderTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitCommitTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitObjectIdTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitObjectStreamTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackDeltafiedStreamTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackIndexMappedReaderTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackMemoryCacheTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitPackTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitPackTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitRepositoryTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/GitTreeStreamingReaderTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/StreamExtensionsTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs b/test/Nerdbank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/ZLibStreamTest.cs diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 b/test/Nerdbank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/commit-4497b0eaaa89abf0e6d70961ad5f04fd3a49cbc6 diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 b/test/Nerdbank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/commit-ab39e8acac105fa0db88514f259341c9f0201b22 diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a b/test/Nerdbank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/commit-d56dc3ed179053abef2097d1120b4507769bcf1a diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/commit.delta b/test/Nerdbank.GitVersioning.Tests/ManagedGit/commit.delta similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/commit.delta rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/commit.delta diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt b/test/Nerdbank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9 .txt diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx b/test/Nerdbank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.idx diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack b/test/Nerdbank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/pack-7d6b2c56ffb97eedb92f4e28583c093f7ee4b3d9.pack diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 b/test/Nerdbank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/tree-bb36cf0ca445ccc8e5ce9cc88f7cf74128e96dc9 diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 b/test/Nerdbank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/tree-f914b48023c7c804a4f3be780d451f31aef74ac1 diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/tree.bin b/test/Nerdbank.GitVersioning.Tests/ManagedGit/tree.bin similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/tree.bin rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/tree.bin diff --git a/test/NerdBank.GitVersioning.Tests/ManagedGit/tree.delta b/test/Nerdbank.GitVersioning.Tests/ManagedGit/tree.delta similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ManagedGit/tree.delta rename to test/Nerdbank.GitVersioning.Tests/ManagedGit/tree.delta diff --git a/test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj similarity index 95% rename from test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj rename to test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index b2f3a59a..cbefea7f 100644 --- a/test/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -18,7 +18,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs b/test/Nerdbank.GitVersioning.Tests/ReleaseManagerTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/ReleaseManagerTests.cs rename to test/Nerdbank.GitVersioning.Tests/ReleaseManagerTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs b/test/Nerdbank.GitVersioning.Tests/RepoTestBase.Helpers.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/RepoTestBase.Helpers.cs rename to test/Nerdbank.GitVersioning.Tests/RepoTestBase.Helpers.cs diff --git a/test/NerdBank.GitVersioning.Tests/RepoTestBase.cs b/test/Nerdbank.GitVersioning.Tests/RepoTestBase.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/RepoTestBase.cs rename to test/Nerdbank.GitVersioning.Tests/RepoTestBase.cs diff --git a/test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs b/test/Nerdbank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs rename to test/Nerdbank.GitVersioning.Tests/SemanticVersionExtensionsTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs b/test/Nerdbank.GitVersioning.Tests/SemanticVersionTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/SemanticVersionTests.cs rename to test/Nerdbank.GitVersioning.Tests/SemanticVersionTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/TestUtilities.cs b/test/Nerdbank.GitVersioning.Tests/TestUtilities.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/TestUtilities.cs rename to test/Nerdbank.GitVersioning.Tests/TestUtilities.cs diff --git a/test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs b/test/Nerdbank.GitVersioning.Tests/VersionExtensionsTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/VersionExtensionsTests.cs rename to test/Nerdbank.GitVersioning.Tests/VersionExtensionsTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/VersionFileTests.cs b/test/Nerdbank.GitVersioning.Tests/VersionFileTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/VersionFileTests.cs rename to test/Nerdbank.GitVersioning.Tests/VersionFileTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs b/test/Nerdbank.GitVersioning.Tests/VersionOptionsTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/VersionOptionsTests.cs rename to test/Nerdbank.GitVersioning.Tests/VersionOptionsTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs b/test/Nerdbank.GitVersioning.Tests/VersionOracleTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/VersionOracleTests.cs rename to test/Nerdbank.GitVersioning.Tests/VersionOracleTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs b/test/Nerdbank.GitVersioning.Tests/VersionSchemaTests.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/VersionSchemaTests.cs rename to test/Nerdbank.GitVersioning.Tests/VersionSchemaTests.cs diff --git a/test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs b/test/Nerdbank.GitVersioning.Tests/WindowsTheoryAttribute.cs similarity index 100% rename from test/NerdBank.GitVersioning.Tests/WindowsTheoryAttribute.cs rename to test/Nerdbank.GitVersioning.Tests/WindowsTheoryAttribute.cs diff --git a/test/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip b/test/Nerdbank.GitVersioning.Tests/repos/PackedHeadRef.zip similarity index 100% rename from test/NerdBank.GitVersioning.Tests/repos/PackedHeadRef.zip rename to test/Nerdbank.GitVersioning.Tests/repos/PackedHeadRef.zip diff --git a/test/NerdBank.GitVersioning.Tests/repos/submodules.zip b/test/Nerdbank.GitVersioning.Tests/repos/submodules.zip similarity index 100% rename from test/NerdBank.GitVersioning.Tests/repos/submodules.zip rename to test/Nerdbank.GitVersioning.Tests/repos/submodules.zip diff --git a/test/NerdBank.GitVersioning.Tests/test.prj b/test/Nerdbank.GitVersioning.Tests/test.prj similarity index 100% rename from test/NerdBank.GitVersioning.Tests/test.prj rename to test/Nerdbank.GitVersioning.Tests/test.prj diff --git a/test/NerdBank.GitVersioning.Tests/test.vcprj b/test/Nerdbank.GitVersioning.Tests/test.vcprj similarity index 99% rename from test/NerdBank.GitVersioning.Tests/test.vcprj rename to test/Nerdbank.GitVersioning.Tests/test.vcprj index a3f9e7e7..d0c4915b 100644 --- a/test/NerdBank.GitVersioning.Tests/test.vcprj +++ b/test/Nerdbank.GitVersioning.Tests/test.vcprj @@ -31,7 +31,7 @@ test DynamicLibrary true - NerdBank + Nerdbank @@ -126,4 +126,4 @@ - \ No newline at end of file + From eb9a19cebd5680258b614b0928c95f39a945edb4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:04:53 -0600 Subject: [PATCH 479/704] fix yaml syntax --- azure-pipelines/build.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index cf345336..2c5a1973 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -9,7 +9,8 @@ jobs: - job: Windows pool: ${{ parameters.windowsPool }} variables: - testModifier: + - name: testModifier + value: - ${{ if eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/') }}: - group: dotnetfoundation code signing steps: From 55f93dc7f47aa3eff16b217be5fca9ca0d0673a9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:06:38 -0600 Subject: [PATCH 480/704] Remove macOSX references in YAML --- azure-pipelines/build.yml | 3 --- azure-pipelines/publish-codecoverage.yml | 8 -------- 2 files changed, 11 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 2c5a1973..e3224a74 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -3,7 +3,6 @@ parameters: type: object default: vmImage: windows-2022 -- name: includeMacOS jobs: - job: Windows @@ -54,6 +53,4 @@ jobs: parameters: initArgs: -NoRestore - template: publish-codecoverage.yml - parameters: - includeMacOS: ${{ parameters.includeMacOS }} - template: publish-deployables.yml diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index a0862be3..7be9459e 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -1,6 +1,3 @@ -parameters: - includeMacOS: - steps: - download: current artifact: coverageResults-Windows @@ -10,11 +7,6 @@ steps: artifact: coverageResults-Linux displayName: Download Linux code coverage results continueOnError: true -- download: current - artifact: coverageResults-macOS - displayName: Download macOS code coverage results - continueOnError: true - condition: ${{ parameters.includeMacOS }} - powershell: | dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.8.5 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj From c295221c90af0e2fc127edb961b0720d4b72cec8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:12:20 -0600 Subject: [PATCH 481/704] Fix nuget restore issues --- azure-pipelines.yml | 2 +- nuget.config | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d326cf9a..bb2209c2 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,7 +30,7 @@ variables: BuildConfiguration: Release codecov_token: 92266a45-648d-454e-8fec-beffae2e6553 ci_feed: https://pkgs.dev.azure.com/andrewarnott/OSS/_packaging/PublicCI/nuget/v3/index.json - NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages + NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/ stages: - stage: Build diff --git a/nuget.config b/nuget.config index f1b5445d..b7e3d616 100644 --- a/nuget.config +++ b/nuget.config @@ -15,7 +15,7 @@ - Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer + Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer;Thecentury;sharwell From 0480e1758872ad98bcd04963a28af0e769ef0017 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:17:31 -0600 Subject: [PATCH 482/704] Remove another use of net5.0 --- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index 808fa9a2..92e52069 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;net5.0 + netcoreapp3.1;net6.0 $(TargetFrameworks);net461 Exe true From 21318a67f8c6f87e57de2514b43ebaf78e2eaa3d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:17:54 -0600 Subject: [PATCH 483/704] init should install to repo-location by default This because the user location doesn't support x86 runtime installation. --- init.ps1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/init.ps1 b/init.ps1 index aef7240a..4d66f65b 100755 --- a/init.ps1 +++ b/init.ps1 @@ -33,8 +33,8 @@ #> [CmdletBinding(SupportsShouldProcess = $true)] Param ( - [ValidateSet('repo', 'user', 'machine')] - [string]$InstallLocality = 'user', + [ValidateSet('repo', 'machine')] + [string]$InstallLocality = 'repo', [Parameter()] [switch]$NoPrerequisites, [Parameter()] @@ -88,7 +88,7 @@ try { npm i -g yarn@">=1.22 <2.0" Write-Host "Restoring NPM packages..." -ForegroundColor Yellow if ($PSCmdlet.ShouldProcess("$PSScriptRoot\src\nerdbank-gitversioning.npm", "yarn install")) { - yarn --cwd src/nerdbank-gitversioning.npm --loglevel error + yarn install --cwd src/nerdbank-gitversioning.npm --loglevel error } } From 081492f27e683e7207f6076570e3c0ff7b5ca48c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:26:47 -0600 Subject: [PATCH 484/704] Prepare generated URL for the default branch rename --- src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs | 2 +- src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs | 2 +- src/Nerdbank.GitVersioning/VersionOptions.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs b/src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs index c741328e..d903e216 100644 --- a/src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs +++ b/src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs @@ -84,7 +84,7 @@ internal LibGit2VersionFile(LibGit2Context context) throw new FormatException( $"Failure while reading {JsonFileName} from commit {this.Context.GitCommitId}. " + "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + - "https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/migrating.md", + "https://github.com/dotnet/Nerdbank.GitVersioning/blob/main/doc/migrating.md", ex); } diff --git a/src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs b/src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs index 777a2c18..bce00516 100644 --- a/src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs +++ b/src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs @@ -105,7 +105,7 @@ public ManagedVersionFile(GitContext context) throw new FormatException( $"Failure while reading {JsonFileName} from commit {this.Context.GitCommitId}. " + "Fix this commit with rebase if this is an error, or review this doc on how to migrate to Nerdbank.GitVersioning: " + - "https://github.com/dotnet/Nerdbank.GitVersioning/blob/master/doc/migrating.md", + "https://github.com/dotnet/Nerdbank.GitVersioning/blob/main/doc/migrating.md", ex); } diff --git a/src/Nerdbank.GitVersioning/VersionOptions.cs b/src/Nerdbank.GitVersioning/VersionOptions.cs index f598c379..dd5f6b47 100644 --- a/src/Nerdbank.GitVersioning/VersionOptions.cs +++ b/src/Nerdbank.GitVersioning/VersionOptions.cs @@ -243,7 +243,7 @@ public enum ReleaseVersionIncrement /// Gets the $schema field that should be serialized when writing. /// [JsonProperty(PropertyName = "$schema")] - public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/Nerdbank.GitVersioning/version.schema.json"; + public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/Nerdbank.GitVersioning/version.schema.json"; /// /// Gets or sets the default version to use. From c2d66f5ddb3fba7b16625effbb03ab7326c29c42 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 08:29:40 -0600 Subject: [PATCH 485/704] Update a couple example branch names from master to main --- src/Nerdbank.GitVersioning/GitContext.cs | 2 +- src/Nerdbank.GitVersioning/ReleaseManager.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Nerdbank.GitVersioning/GitContext.cs b/src/Nerdbank.GitVersioning/GitContext.cs index 73df0026..3f481f17 100644 --- a/src/Nerdbank.GitVersioning/GitContext.cs +++ b/src/Nerdbank.GitVersioning/GitContext.cs @@ -96,7 +96,7 @@ public string RepoRelativeProjectDirectory public abstract DateTimeOffset? GitCommitDate { get; } /// - /// Gets the canonical name for HEAD's position (e.g. refs/heads/master). + /// Gets the canonical name for HEAD's position (e.g. refs/heads/main). /// public abstract string? HeadCanonicalName { get; } diff --git a/src/Nerdbank.GitVersioning/ReleaseManager.cs b/src/Nerdbank.GitVersioning/ReleaseManager.cs index fa79f252..594a728c 100644 --- a/src/Nerdbank.GitVersioning/ReleaseManager.cs +++ b/src/Nerdbank.GitVersioning/ReleaseManager.cs @@ -469,7 +469,7 @@ public ReleaseBranchInfo(string name, string commit, SemanticVersion version) } /// - /// Gets the name of the branch, e.g. master. + /// Gets the name of the branch, e.g. main. /// public string Name { get; } From d7166f1212f36e2ea4d273d042bd61e3ee2e2f67 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 09:07:42 -0600 Subject: [PATCH 486/704] Fix test reference to project files --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index cbefea7f..772bf05b 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -12,7 +12,7 @@ - + false Targets\%(FileName)%(Extension) From ff48ec7f3a7dcb6379bc7f0f1cde077792be64f8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 09:36:08 -0600 Subject: [PATCH 487/704] Fix skipped test category to match new pipeline scripts --- test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs index 268abc84..83183298 100644 --- a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -568,7 +568,7 @@ public async Task PublicRelease_RegEx_SatisfiedByCI(IReadOnlyDictionary properties, string expectedMessage, bool setAllVariables) { @@ -906,7 +906,7 @@ public async Task AssemblyInfo_HasKeyData(string keyFile, bool delaySigned) } [Fact] - [Trait("TestCategory", "FailsOnAzurePipelines")] + [Trait("TestCategory", "FailsInCloudTest")] public async Task AssemblyInfo_IncrementalBuild() { this.WriteVersionFile(prerelease: "-beta"); From f6c6afad74ab9fc2b991d535a94e342735d6a048 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 09:36:34 -0600 Subject: [PATCH 488/704] Fix test for linux output --- test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs index 83183298..33f636d3 100644 --- a/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs +++ b/test/Nerdbank.GitVersioning.Tests/BuildIntegrationTests.cs @@ -626,7 +626,9 @@ public async Task CloudBuildVariables_SetInCI(IReadOnlyDictionary string.Equals(e.Message, $"n1=v1", StringComparison.OrdinalIgnoreCase)); + Assert.Contains( + buildResult.LoggedEvents, + e => string.Equals(e.Message, $"n1=v1", StringComparison.OrdinalIgnoreCase) || string.Equals(e.Message, $"n1='v1'", StringComparison.OrdinalIgnoreCase)); versionOptions.CloudBuild.SetVersionVariables = false; this.WriteVersionFile(versionOptions); From 53341c48d97d618208c3f82307c20ecd0950ec0e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 09:40:27 -0600 Subject: [PATCH 489/704] Update test project TFM to work on newer AzP agents --- test/Nerdbank.GitVersioning.Tests/test.prj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/test.prj b/test/Nerdbank.GitVersioning.Tests/test.prj index 984a3367..c7ddcca7 100644 --- a/test/Nerdbank.GitVersioning.Tests/test.prj +++ b/test/Nerdbank.GitVersioning.Tests/test.prj @@ -9,7 +9,7 @@ TestCompany TestCopyright TestConfiguration - v4.5 + v4.7.2 Library bin\ $(NoWarn);1607 From 34c0d23a75a0c1f7e89fffddc14884254d984ecf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 09:44:35 -0600 Subject: [PATCH 490/704] Fix perf analysis stage in pipeline --- azure-pipelines.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index bb2209c2..a37d3a7e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -76,10 +76,10 @@ stages: strategy: matrix: ubuntu: - imageName: ubuntu-18.04 + imageName: ubuntu-20.04 repoDir: '~/git' windows: - imageName: windows-2019 + imageName: windows-2022 repoDir: '${USERPROFILE}/source/repos' macOS: imageName: macOS-10.15 @@ -108,11 +108,10 @@ stages: displayName: Clone test repositories - script: | dotnet build -c Release - workingDirectory: src/ displayName: Build in Release mode - script: | dotnet run -c Release -f netcoreapp3.1 -- --filter GetVersionBenchmarks --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) - workingDirectory: src/Nerdbank.GitVersioning.Benchmarks + workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (packed) - bash: | cd $(repoDir)/xunit @@ -129,7 +128,7 @@ stages: displayName: Unpack Git repositories - script: | dotnet run -c Release -f netcoreapp3.1 -- --filter GetVersionBenchmarks --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) - workingDirectory: src/Nerdbank.GitVersioning.Benchmarks + workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (unpacked) - task: PublishBuildArtifacts@1 inputs: From 4a6e07be6ce195c884b59c01239c3b25b399d8a5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 09:49:42 -0600 Subject: [PATCH 491/704] Fix test run failures when code coverage is measured --- test/Cake.GitVersioning.Tests/app.config | 5 +++++ test/Nerdbank.GitVersioning.Tests/app.config | 5 +++++ 2 files changed, 10 insertions(+) create mode 100644 test/Cake.GitVersioning.Tests/app.config create mode 100644 test/Nerdbank.GitVersioning.Tests/app.config diff --git a/test/Cake.GitVersioning.Tests/app.config b/test/Cake.GitVersioning.Tests/app.config new file mode 100644 index 00000000..61890f05 --- /dev/null +++ b/test/Cake.GitVersioning.Tests/app.config @@ -0,0 +1,5 @@ + + + + + diff --git a/test/Nerdbank.GitVersioning.Tests/app.config b/test/Nerdbank.GitVersioning.Tests/app.config new file mode 100644 index 00000000..61890f05 --- /dev/null +++ b/test/Nerdbank.GitVersioning.Tests/app.config @@ -0,0 +1,5 @@ + + + + + From 07b86d8859abbbb792b7945cb5b5a2f6536559cd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 10:02:06 -0600 Subject: [PATCH 492/704] Skip failing tests on mono --- test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs b/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs index bfc659b6..a7206c76 100644 --- a/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs +++ b/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs @@ -10,9 +10,9 @@ using Nerdbank.GitVersioning.Tasks; using Xunit; -public class AssemblyInfoTest : IClassFixture +public class AssemblyInfoTest : IClassFixture // The MSBuildFixture throws PlatformNotSupportedException when run on mono. { - [Theory] + [SkippableTheory(typeof(PlatformNotSupportedException))] [InlineData(false)] [InlineData(true)] [InlineData(null)] @@ -90,7 +90,7 @@ type internal ThisAssembly() = Assert.Equal(expected, built); } - [Theory] + [SkippableTheory(typeof(PlatformNotSupportedException))] [InlineData(false)] [InlineData(true)] [InlineData(null)] @@ -166,7 +166,7 @@ internal static partial class ThisAssembly {{ Assert.Equal(expected, built); } - [Theory] + [SkippableTheory(typeof(PlatformNotSupportedException))] [InlineData(false)] [InlineData(true)] [InlineData(null)] From e3347ec52f9fa31a226d8fb787f4ec6d812b0d01 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 10:05:58 -0600 Subject: [PATCH 493/704] Fix Code sign step --- nuget.config | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nuget.config b/nuget.config index b7e3d616..59b20b03 100644 --- a/nuget.config +++ b/nuget.config @@ -15,7 +15,7 @@ - Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer;Thecentury;sharwell + Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer;Thecentury;sharwell;dotnetfoundation From d77f00c3ea1894f1cfbc718eebea798d9b97243c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 10:21:33 -0600 Subject: [PATCH 494/704] Add macOS 12 to functional testing matrix --- azure-pipelines.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a37d3a7e..742d5482 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -63,8 +63,14 @@ stages: - template: azure-pipelines/xplattest-pipeline.yml - job: macOS + strategy: + matrix: + macOS_Catalina: + vmImage: macOS-10.15 + macOS_Monterey: + vmImage: macOS-12 pool: - vmImage: macOS-10.15 + vmImage: $[ variables['vmImage'] ] steps: - template: azure-pipelines/xplattest-pipeline.yml From 9af51f473f96cbfbdd6fe00c23f9c21de4b816a5 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 12:14:38 -0600 Subject: [PATCH 495/704] Fix code signing (includes artifact staging enhancement) --- azure-pipelines/artifacts/_all.ps1 | 10 +++---- azure-pipelines/artifacts/_pipelines.ps1 | 35 ++++++++++++++++++++---- azure-pipelines/artifacts/_stage_all.ps1 | 8 +++++- azure-pipelines/dotnet.yml | 9 ++++-- 4 files changed, 49 insertions(+), 13 deletions(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index afe42be3..c9182a45 100644 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -12,7 +12,7 @@ Value = an array of paths (absolute or relative to the BaseDirectory) to files to include in the artifact. FileInfo objects are also allowed. .PARAMETER Force - Executes artifact scripts even if they have already been uploaded. + Executes artifact scripts even if they have already been staged. #> param ( @@ -28,14 +28,14 @@ Function EnsureTrailingSlash($path) { $path.Replace('\', [IO.Path]::DirectorySeparatorChar) } -Function Test-ArtifactUploaded($artifactName) { - $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" +Function Test-ArtifactStaged($artifactName) { + $varName = "ARTIFACTSTAGED_$($artifactName.ToUpper())" Test-Path "env:$varName" } Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { $ArtifactName = $_.BaseName - if ($Force -or !(Test-ArtifactUploaded($ArtifactName + $ArtifactNameSuffix))) { + if ($Force -or !(Test-ArtifactStaged($ArtifactName + $ArtifactNameSuffix))) { $totalFileCount = 0 $fileGroups = & $_ if ($fileGroups) { @@ -65,6 +65,6 @@ Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { Write-Warning "No files found for the `"$ArtifactName`" artifact." } } else { - Write-Host "Skipping $ArtifactName because it has already been uploaded." -ForegroundColor DarkGray + Write-Host "Skipping $ArtifactName because it has already been staged." -ForegroundColor DarkGray } } diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index 73a3af0a..a62d2675 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -2,14 +2,39 @@ # into commands that instruct Azure Pipelines to actually collect those artifacts. param ( - [string]$ArtifactNameSuffix + [string]$ArtifactNameSuffix, + [switch]$StageOnly ) -& "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% { - Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" +Function Set-PipelineVariable($name, $value) { + if ((Test-Path "Env:\$name") -and (Get-Item "Env:\$name").Value -eq $value) { + return # already set + } + + #New-Item -Path "Env:\$name".ToUpper() -Value $value -Force | Out-Null + Write-Host "##vso[task.setvariable variable=$name]$value" +} + +Function Test-ArtifactUploaded($artifactName) { + $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" + Test-Path "env:$varName" +} +& "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% { # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts # will skip this one from a check in the _all.ps1 script. - $varName = "ARTIFACTUPLOADED_$($_.Name.ToUpper())" - Write-Host "##vso[task.setvariable variable=$varName]true" + Set-PipelineVariable "ARTIFACTSTAGED_$($_.Name.ToUpper())" 'true' + Write-Host "Staged artifact $($_.Name) to $($_.Path)" + + if (!$StageOnly) { + if (Test-ArtifactUploaded $_.Name) { + Write-Host "Skipping $($_.Name) because it has already been uploaded." -ForegroundColor DarkGray + } else { + Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" + + # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts + # will skip this one from a check in the _all.ps1 script. + Set-PipelineVariable "ARTIFACTUPLOADED_$($_.Name.ToUpper())" 'true' + } + } } diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index e4954c13..b7166b4e 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -42,7 +42,13 @@ $Artifacts |% { } } -$Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } | Get-Unique |% { +$ArtifactNames = $Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } +$ArtifactNames += Get-ChildItem env:ARTIFACTSTAGED_* |% { + # Return from ALLCAPS to the actual capitalization used for the artifact. + $artifactNameAllCaps = "$($_.Name.Substring('ARTIFACTSTAGED_'.Length))" + (Get-ChildItem $ArtifactStagingFolder\$artifactNameAllCaps* -Filter $artifactNameAllCaps).Name +} +$ArtifactNames | Get-Unique |% { $artifact = New-Object -TypeName PSObject Add-Member -InputObject $artifact -MemberType NoteProperty -Name Name -Value $_ Add-Member -InputObject $artifact -MemberType NoteProperty -Name Path -Value (Join-Path $ArtifactStagingFolder $_) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 7a8082f0..cf596944 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -27,11 +27,16 @@ steps: displayName: dotnet test x86 condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) +- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" -StageOnly + failOnStderr: true + displayName: Stage artifacts + condition: succeededOrFailed() + - pwsh: > dotnet tool install --tool-path obj SignClient obj/SignClient sign - --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables' + --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables-Windows' --input '**/*' --config '$(System.DefaultWorkingDirectory)/azure-pipelines/SignClient.json' --filelist '$(System.DefaultWorkingDirectory)/azure-pipelines/signfiles.txt' @@ -44,7 +49,7 @@ steps: - pwsh: > obj/SignClient sign - --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables-lkg' + --baseDirectory '$(Build.ArtifactStagingDirectory)/deployables-LKG-Windows' --input '**/*' --config '$(System.DefaultWorkingDirectory)/azure-pipelines/SignClient.json' --filelist '$(System.DefaultWorkingDirectory)/azure-pipelines/signfiles.txt' From 4e4a916f8795043e893a5751143c9215a1ccdc91 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 13:53:28 -0600 Subject: [PATCH 496/704] Fix tgz artifact capture --- azure-pipelines/artifacts/deployables.ps1 | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/deployables.ps1 b/azure-pipelines/artifacts/deployables.ps1 index c860a6d4..315a2532 100644 --- a/azure-pipelines/artifacts/deployables.ps1 +++ b/azure-pipelines/artifacts/deployables.ps1 @@ -5,9 +5,11 @@ if (!$BuildConfiguration) { } $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" +$JsRoot = "$RepoRoot/bin/js" if (!(Test-Path $PackagesRoot)) { return } @{ - "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse -Exclude *.LKG.*.nupkg) + "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse -Exclude *.LKG.*.nupkg); + "$JsRoot" = (Get-ChildItem $JsRoot *.tgz); } From 75226d6851232ea41e3c8c13f02f38e804311cb2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 13:54:24 -0600 Subject: [PATCH 497/704] Fix functional testing --- azure-pipelines/xplattest-pipeline.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/azure-pipelines/xplattest-pipeline.yml b/azure-pipelines/xplattest-pipeline.yml index 0841124a..3ddf69e3 100644 --- a/azure-pipelines/xplattest-pipeline.yml +++ b/azure-pipelines/xplattest-pipeline.yml @@ -7,7 +7,7 @@ steps: - task: DownloadBuildArtifacts@0 displayName: Download Build Artifacts inputs: - artifactName: deployables + artifactName: deployables-Windows downloadPath: $(System.DefaultWorkingDirectory) - script: | @@ -17,11 +17,11 @@ steps: displayName: Set up git username and email address - script: > - PkgFileName=$(ls deployables/Nerdbank.GitVersioning.*nupkg) + PkgFileName=$(ls deployables-Windows/Nerdbank.GitVersioning.*nupkg) NBGV_NuGetPackageVersion=$([[ $PkgFileName =~ Nerdbank.GitVersioning\.(.*)\.nupkg ]] && echo "${BASH_REMATCH[1]}") - echo "" > nuget.config && + echo "" > nuget.config && dotnet new classlib -o lib && cd lib && echo '{"version":"42.42"}' > version.json && @@ -55,7 +55,7 @@ steps: echo ".NET Core $DNVERSION" fi - PkgFileName=$(ls deployables/Cake.GitVersioning.*nupkg) + PkgFileName=$(ls deployables-Windows/Cake.GitVersioning.*nupkg) NBGV_NuGetPackageVersion=$([[ $PkgFileName =~ Cake.GitVersioning\.(.*)\.nupkg ]] && echo "${BASH_REMATCH[1]}") @@ -80,11 +80,11 @@ steps: - script: > echo DOTNET_ROOT=$DOTNET_ROOT - PkgFileName=$(ls deployables/Nerdbank.GitVersioning.*nupkg) + PkgFileName=$(ls deployables-Windows/Nerdbank.GitVersioning.*nupkg) NBGV_NuGetPackageVersion=$([[ $PkgFileName =~ Nerdbank.GitVersioning\.(.*)\.nupkg ]] && echo "${BASH_REMATCH[1]}") - dotnet tool install nbgv --tool-path . --version $NBGV_NuGetPackageVersion --add-source deployables && + dotnet tool install nbgv --tool-path . --version $NBGV_NuGetPackageVersion --add-source deployables-Windows && ./nbgv get-version -f json -p lib && ./nbgv get-version -f json -p lib | grep 42.42.1 displayName: Use nbgv dotnet CLI tool From c6bbbac674aefd1cb0e5e9d5938784348a26665c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 14:22:26 -0600 Subject: [PATCH 498/704] Fix NPM package publish --- azure-pipelines.yml | 1 + azure-pipelines/publish-deployables.yml | 10 +++++++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 742d5482..c6e4eeb9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -30,6 +30,7 @@ variables: BuildConfiguration: Release codecov_token: 92266a45-648d-454e-8fec-beffae2e6553 ci_feed: https://pkgs.dev.azure.com/andrewarnott/OSS/_packaging/PublicCI/nuget/v3/index.json + ci_npm_feed: https://pkgs.dev.azure.com/andrewarnott/OSS/_packaging/PublicCI/npm/registry/ NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/ stages: diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml index 14c3f78f..6ad5b38c 100644 --- a/azure-pipelines/publish-deployables.yml +++ b/azure-pipelines/publish-deployables.yml @@ -7,6 +7,14 @@ steps: displayName: Push packages to CI feed condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) +- pwsh: Set-Content -Path "$(Agent.TempDirectory)/.npmrc" -Value "registry=$(ci_npm_feed)`nalways-auth=true" + displayName: Prepare to push to PublicCI + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest')) +- task: npmAuthenticate@0 + displayName: Authenticate to PublicCI + inputs: + workingFile: $(Agent.TempDirectory)/.npmrc + condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'), eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/'), ne(variables['Build.Reason'], 'PullRequest')) - pwsh: | $tgz = (Get-ChildItem "$(Pipeline.Workspace)/deployables-Windows/*.tgz")[0].FullName Write-Host "Will publish $tgz" @@ -14,4 +22,4 @@ steps: workingDirectory: $(Agent.TempDirectory) displayName: npm publish to PublicCI feed continueOnError: true - condition: and(succeeded(), ne(variables['ci_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) + condition: and(succeeded(), ne(variables['ci_npm_feed'], ''), ne(variables['Build.Reason'], 'PullRequest')) From e435ac4a31c490efb753ad0d457d28eae8813e6f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 15:18:45 -0600 Subject: [PATCH 499/704] Fix more capitalization issues --- .vscode/settings.json | 2 +- doc/versionJson.md | 2 +- .../Nerdbank.GitVersioning.nuspec | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 9d58e437..9fccf55b 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,5 @@ { - "dotnet-test-explorer.testProjectPath": "src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj", + "dotnet-test-explorer.testProjectPath": "src/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj", "files.trimTrailingWhitespace": true, "files.insertFinalNewline": true, "files.trimFinalNewlines": true, diff --git a/doc/versionJson.md b/doc/versionJson.md index 910a03e3..9701c541 100644 --- a/doc/versionJson.md +++ b/doc/versionJson.md @@ -10,7 +10,7 @@ Here is the content of a sample version.json file you may start with: ```json { - "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/Nerdbank.GitVersioning/version.schema.json", "version": "1.0-beta" } ``` diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 28b573e0..f6bd8c7a 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -20,7 +20,7 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - + @@ -43,7 +43,7 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - + From da08e901c94c416cbbdfa980020ced9ed9612851 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 12 May 2022 16:08:56 -0600 Subject: [PATCH 500/704] Add ability to split stage and publish artifact steps --- azure-pipelines/artifacts/_all.ps1 | 10 +++---- azure-pipelines/artifacts/_pipelines.ps1 | 35 ++++++++++++++++++++---- azure-pipelines/artifacts/_stage_all.ps1 | 8 +++++- 3 files changed, 42 insertions(+), 11 deletions(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index afe42be3..c9182a45 100755 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -12,7 +12,7 @@ Value = an array of paths (absolute or relative to the BaseDirectory) to files to include in the artifact. FileInfo objects are also allowed. .PARAMETER Force - Executes artifact scripts even if they have already been uploaded. + Executes artifact scripts even if they have already been staged. #> param ( @@ -28,14 +28,14 @@ Function EnsureTrailingSlash($path) { $path.Replace('\', [IO.Path]::DirectorySeparatorChar) } -Function Test-ArtifactUploaded($artifactName) { - $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" +Function Test-ArtifactStaged($artifactName) { + $varName = "ARTIFACTSTAGED_$($artifactName.ToUpper())" Test-Path "env:$varName" } Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { $ArtifactName = $_.BaseName - if ($Force -or !(Test-ArtifactUploaded($ArtifactName + $ArtifactNameSuffix))) { + if ($Force -or !(Test-ArtifactStaged($ArtifactName + $ArtifactNameSuffix))) { $totalFileCount = 0 $fileGroups = & $_ if ($fileGroups) { @@ -65,6 +65,6 @@ Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { Write-Warning "No files found for the `"$ArtifactName`" artifact." } } else { - Write-Host "Skipping $ArtifactName because it has already been uploaded." -ForegroundColor DarkGray + Write-Host "Skipping $ArtifactName because it has already been staged." -ForegroundColor DarkGray } } diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index 73a3af0a..a62d2675 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -2,14 +2,39 @@ # into commands that instruct Azure Pipelines to actually collect those artifacts. param ( - [string]$ArtifactNameSuffix + [string]$ArtifactNameSuffix, + [switch]$StageOnly ) -& "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% { - Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" +Function Set-PipelineVariable($name, $value) { + if ((Test-Path "Env:\$name") -and (Get-Item "Env:\$name").Value -eq $value) { + return # already set + } + + #New-Item -Path "Env:\$name".ToUpper() -Value $value -Force | Out-Null + Write-Host "##vso[task.setvariable variable=$name]$value" +} + +Function Test-ArtifactUploaded($artifactName) { + $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" + Test-Path "env:$varName" +} +& "$PSScriptRoot/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix |% { # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts # will skip this one from a check in the _all.ps1 script. - $varName = "ARTIFACTUPLOADED_$($_.Name.ToUpper())" - Write-Host "##vso[task.setvariable variable=$varName]true" + Set-PipelineVariable "ARTIFACTSTAGED_$($_.Name.ToUpper())" 'true' + Write-Host "Staged artifact $($_.Name) to $($_.Path)" + + if (!$StageOnly) { + if (Test-ArtifactUploaded $_.Name) { + Write-Host "Skipping $($_.Name) because it has already been uploaded." -ForegroundColor DarkGray + } else { + Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" + + # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts + # will skip this one from a check in the _all.ps1 script. + Set-PipelineVariable "ARTIFACTUPLOADED_$($_.Name.ToUpper())" 'true' + } + } } diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index e4954c13..b7166b4e 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -42,7 +42,13 @@ $Artifacts |% { } } -$Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } | Get-Unique |% { +$ArtifactNames = $Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } +$ArtifactNames += Get-ChildItem env:ARTIFACTSTAGED_* |% { + # Return from ALLCAPS to the actual capitalization used for the artifact. + $artifactNameAllCaps = "$($_.Name.Substring('ARTIFACTSTAGED_'.Length))" + (Get-ChildItem $ArtifactStagingFolder\$artifactNameAllCaps* -Filter $artifactNameAllCaps).Name +} +$ArtifactNames | Get-Unique |% { $artifact = New-Object -TypeName PSObject Add-Member -InputObject $artifact -MemberType NoteProperty -Name Name -Value $_ Add-Member -InputObject $artifact -MemberType NoteProperty -Name Path -Value (Join-Path $ArtifactStagingFolder $_) From 946d7442fd857ed56510fa2461fb78efd7474dae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 May 2022 16:51:19 -0600 Subject: [PATCH 501/704] Bump NuGet.PackageManagement from 5.11.0 to 6.2.0 (#759) Bumps [NuGet.PackageManagement](https://github.com/NuGet/NuGet.Client) from 5.11.0 to 6.2.0. - [Release notes](https://github.com/NuGet/NuGet.Client/releases) - [Commits](https://github.com/NuGet/NuGet.Client/commits) --- updated-dependencies: - dependency-name: NuGet.PackageManagement dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/nbgv/nbgv.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 1a813cc1..6bbe7ae5 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -10,7 +10,7 @@ - + From a13adab39afe9d36bba1fd201975cff3ab8ce6d0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 May 2022 16:52:04 -0600 Subject: [PATCH 502/704] Bump @types/node in /src/nerdbank-gitversioning.npm (#760) Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 17.0.30 to 17.0.33. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index fc7e348c..1a0d00c3 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -50,9 +50,9 @@ camel-case "*" "@types/node@^17.0.30": - version "17.0.30" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.30.tgz#2c6e8512acac70815e8176aa30c38025067880ef" - integrity sha512-oNBIZjIqyHYP8VCNAV9uEytXVeXG2oR0w9lgAXro20eugRQfY002qr3CUl6BAe+Yf/z3CRjPdz27Pu6WWtuSRw== + version "17.0.33" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.33.tgz#3c1879b276dc63e73030bb91165e62a4509cd506" + integrity sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ== acorn@^6.4.1: version "6.4.2" From ac0202afeb0e71475007fe64837375270dbaecad Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 May 2022 23:13:12 +0000 Subject: [PATCH 503/704] Bump Newtonsoft.Json.Schema from 3.0.10 to 3.0.14 (#757) --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 64593715..29670ad1 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -40,7 +40,7 @@ - + From fa3bc46e2951ceb674c10707ea8ae61863badee1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 12 May 2022 20:25:28 -0600 Subject: [PATCH 504/704] Bump LibGit2Sharp from 0.27.0-preview-0158 to 0.27.0-preview-0182 (#761) Bumps [LibGit2Sharp](https://github.com/libgit2/libgit2sharp) from 0.27.0-preview-0158 to 0.27.0-preview-0182. - [Release notes](https://github.com/libgit2/libgit2sharp/releases) - [Changelog](https://github.com/libgit2/libgit2sharp/blob/master/CHANGES.md) - [Commits](https://github.com/libgit2/libgit2sharp/commits) --- updated-dependencies: - dependency-name: LibGit2Sharp dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj b/src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj index bd34cec5..30d7438a 100644 --- a/src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj +++ b/src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj @@ -10,7 +10,7 @@ - + From 11e9b5105132b08ef4184300b4f94ed1066d813b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 13 May 2022 09:13:49 -0600 Subject: [PATCH 505/704] Revert some of the path casing change to fix #762 --- Nerdbank.GitVersioning.sln | 2 +- doc/versionJson.md | 2 +- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 2 +- .../AssemblyVersionOptionsConverter.cs | 0 .../CloudBuild.cs | 0 .../CloudBuildServices/AppVeyor.cs | 0 .../CloudBuildServices/AtlassianBamboo.cs | 0 .../CloudBuildServices/GitHubActions.cs | 0 .../CloudBuildServices/GitLab.cs | 0 .../CloudBuildServices/Jenkins.cs | 0 .../CloudBuildServices/SpaceAutomation.cs | 0 .../CloudBuildServices/TeamCity.cs | 0 .../CloudBuildServices/Travis.cs | 0 .../CloudBuildServices/VisualStudioTeamServices.cs | 0 .../Commands/CloudCommand.cs | 0 .../FilterPath.cs | 0 .../FilterPathJsonConverter.cs | 0 .../GitContext.cs | 0 .../GitException.cs | 0 .../ICloudBuild.cs | 0 .../LibGit2/LibGit2Context.cs | 0 .../LibGit2/LibGit2GitExtensions.cs | 0 .../LibGit2/LibGit2VersionFile.cs | 0 .../Managed/GitExtensions.cs | 0 .../Managed/ManagedGitContext.cs | 0 .../Managed/ManagedVersionFile.cs | 0 .../ManagedGit/DeltaInstruction.cs | 0 .../ManagedGit/DeltaInstructionType.cs | 0 .../ManagedGit/DeltaStreamReader.cs | 0 .../ManagedGit/FileHelpers.cs | 0 .../ManagedGit/GitCommit.cs | 0 .../ManagedGit/GitCommitReader.cs | 0 .../ManagedGit/GitObjectId.cs | 0 .../ManagedGit/GitObjectStream.cs | 0 .../ManagedGit/GitPack.cs | 0 .../ManagedGit/GitPackCache.cs | 0 .../ManagedGit/GitPackDeltafiedStream.cs | 0 .../ManagedGit/GitPackIndexMappedReader.cs | 0 .../ManagedGit/GitPackIndexReader.cs | 0 .../ManagedGit/GitPackMemoryCache.cs | 0 .../ManagedGit/GitPackMemoryCacheStream.cs | 0 .../ManagedGit/GitPackMemoryCacheViewStream.cs | 0 .../ManagedGit/GitPackNullCache.cs | 0 .../ManagedGit/GitPackObjectType.cs | 0 .../ManagedGit/GitPackPooledStream.cs | 0 .../ManagedGit/GitPackReader.cs | 0 .../ManagedGit/GitReferenceReader.cs | 0 .../ManagedGit/GitRepository.cs | 0 .../ManagedGit/GitSignature.cs | 0 .../ManagedGit/GitTree.cs | 0 .../ManagedGit/GitTreeEntry.cs | 0 .../ManagedGit/GitTreeReader.cs | 0 .../ManagedGit/GitTreeStreamingReader.cs | 0 .../ManagedGit/MemoryMappedStream.cs | 0 .../ManagedGit/StreamExtensions.cs | 0 .../ManagedGit/ZLibStream.cs | 0 .../NativeMethods.json | 0 .../NativeMethods.txt | 0 .../Nerdbank.GitVersioning.csproj | 0 .../NoGit/NoGitContext.cs | 0 .../NoGit/NoGitVersionFile.cs | 0 .../ReleaseManager.cs | 0 .../SemanticVersion.cs | 0 .../SemanticVersionJsonConverter.cs | 0 .../VersionExtensions.cs | 0 .../VersionFile.cs | 0 .../VersionOptions.cs | 2 +- .../VersionOptionsContractResolver.cs | 0 .../VersionOracle.cs | 0 .../version.schema.json | 0 .../Nerdbank.GitVersioning.Tasks.csproj | 2 +- src/nbgv/nbgv.csproj | 2 +- test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- .../Nerdbank.GitVersioning.Tests.csproj | 4 ++-- version.json | 2 +- 76 files changed, 11 insertions(+), 11 deletions(-) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/AssemblyVersionOptionsConverter.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuild.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/AppVeyor.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/AtlassianBamboo.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/GitHubActions.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/GitLab.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/Jenkins.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/SpaceAutomation.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/TeamCity.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/Travis.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/CloudBuildServices/VisualStudioTeamServices.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/Commands/CloudCommand.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/FilterPath.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/FilterPathJsonConverter.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/GitContext.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/GitException.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ICloudBuild.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/LibGit2/LibGit2Context.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/LibGit2/LibGit2GitExtensions.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/LibGit2/LibGit2VersionFile.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/Managed/GitExtensions.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/Managed/ManagedGitContext.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/Managed/ManagedVersionFile.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/DeltaInstruction.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/DeltaInstructionType.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/DeltaStreamReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/FileHelpers.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitCommit.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitCommitReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitObjectId.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitObjectStream.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPack.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackCache.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackDeltafiedStream.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackIndexMappedReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackIndexReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackMemoryCache.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackMemoryCacheStream.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackMemoryCacheViewStream.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackNullCache.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackObjectType.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackPooledStream.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitPackReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitReferenceReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitRepository.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitSignature.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitTree.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitTreeEntry.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitTreeReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/GitTreeStreamingReader.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/MemoryMappedStream.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/StreamExtensions.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ManagedGit/ZLibStream.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/NativeMethods.json (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/NativeMethods.txt (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/Nerdbank.GitVersioning.csproj (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/NoGit/NoGitContext.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/NoGit/NoGitVersionFile.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/ReleaseManager.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/SemanticVersion.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/SemanticVersionJsonConverter.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/VersionExtensions.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/VersionFile.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/VersionOptions.cs (99%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/VersionOptionsContractResolver.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/VersionOracle.cs (100%) rename src/{Nerdbank.GitVersioning => NerdBank.GitVersioning}/version.schema.json (100%) diff --git a/Nerdbank.GitVersioning.sln b/Nerdbank.GitVersioning.sln index b4c7f06c..658f1c3b 100644 --- a/Nerdbank.GitVersioning.sln +++ b/Nerdbank.GitVersioning.sln @@ -22,7 +22,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Test EndProject Project("{9092AA53-FB77-4645-B42D-1CCCA6BD08BD}") = "nb-gv", "src\nerdbank-gitversioning.npm\nb-gv.njsproj", "{F79DD916-27B3-4CD0-97FF-5021B3CF9934}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning", "src\Nerdbank.GitVersioning\Nerdbank.GitVersioning.csproj", "{C7FA7B7A-0469-4B1C-8657-E274C4CD8ABB}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning", "src\NerdBank.GitVersioning\Nerdbank.GitVersioning.csproj", "{C7FA7B7A-0469-4B1C-8657-E274C4CD8ABB}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Tasks", "src\Nerdbank.GitVersioning.Tasks\Nerdbank.GitVersioning.Tasks.csproj", "{B2454569-6EDC-4FD4-9936-D2B2F2E10409}" EndProject diff --git a/doc/versionJson.md b/doc/versionJson.md index 9701c541..c3e14829 100644 --- a/doc/versionJson.md +++ b/doc/versionJson.md @@ -10,7 +10,7 @@ Here is the content of a sample version.json file you may start with: ```json { - "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/Nerdbank.GitVersioning/version.schema.json", + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", "version": "1.0-beta" } ``` diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 0e4dd4f7..63096476 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -48,7 +48,7 @@ - + diff --git a/src/Nerdbank.GitVersioning/AssemblyVersionOptionsConverter.cs b/src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs similarity index 100% rename from src/Nerdbank.GitVersioning/AssemblyVersionOptionsConverter.cs rename to src/NerdBank.GitVersioning/AssemblyVersionOptionsConverter.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuild.cs b/src/NerdBank.GitVersioning/CloudBuild.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuild.cs rename to src/NerdBank.GitVersioning/CloudBuild.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/AppVeyor.cs b/src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/AppVeyor.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/AppVeyor.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs b/src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/AtlassianBamboo.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/GitHubActions.cs b/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/GitHubActions.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/GitLab.cs b/src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/GitLab.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/GitLab.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/Jenkins.cs b/src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/Jenkins.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/Jenkins.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/SpaceAutomation.cs b/src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/SpaceAutomation.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/SpaceAutomation.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/TeamCity.cs b/src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/TeamCity.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/TeamCity.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/Travis.cs b/src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/Travis.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/Travis.cs diff --git a/src/Nerdbank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs b/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs similarity index 100% rename from src/Nerdbank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs rename to src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs diff --git a/src/Nerdbank.GitVersioning/Commands/CloudCommand.cs b/src/NerdBank.GitVersioning/Commands/CloudCommand.cs similarity index 100% rename from src/Nerdbank.GitVersioning/Commands/CloudCommand.cs rename to src/NerdBank.GitVersioning/Commands/CloudCommand.cs diff --git a/src/Nerdbank.GitVersioning/FilterPath.cs b/src/NerdBank.GitVersioning/FilterPath.cs similarity index 100% rename from src/Nerdbank.GitVersioning/FilterPath.cs rename to src/NerdBank.GitVersioning/FilterPath.cs diff --git a/src/Nerdbank.GitVersioning/FilterPathJsonConverter.cs b/src/NerdBank.GitVersioning/FilterPathJsonConverter.cs similarity index 100% rename from src/Nerdbank.GitVersioning/FilterPathJsonConverter.cs rename to src/NerdBank.GitVersioning/FilterPathJsonConverter.cs diff --git a/src/Nerdbank.GitVersioning/GitContext.cs b/src/NerdBank.GitVersioning/GitContext.cs similarity index 100% rename from src/Nerdbank.GitVersioning/GitContext.cs rename to src/NerdBank.GitVersioning/GitContext.cs diff --git a/src/Nerdbank.GitVersioning/GitException.cs b/src/NerdBank.GitVersioning/GitException.cs similarity index 100% rename from src/Nerdbank.GitVersioning/GitException.cs rename to src/NerdBank.GitVersioning/GitException.cs diff --git a/src/Nerdbank.GitVersioning/ICloudBuild.cs b/src/NerdBank.GitVersioning/ICloudBuild.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ICloudBuild.cs rename to src/NerdBank.GitVersioning/ICloudBuild.cs diff --git a/src/Nerdbank.GitVersioning/LibGit2/LibGit2Context.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs similarity index 100% rename from src/Nerdbank.GitVersioning/LibGit2/LibGit2Context.cs rename to src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs diff --git a/src/Nerdbank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs similarity index 100% rename from src/Nerdbank.GitVersioning/LibGit2/LibGit2GitExtensions.cs rename to src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs diff --git a/src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs similarity index 100% rename from src/Nerdbank.GitVersioning/LibGit2/LibGit2VersionFile.cs rename to src/NerdBank.GitVersioning/LibGit2/LibGit2VersionFile.cs diff --git a/src/Nerdbank.GitVersioning/Managed/GitExtensions.cs b/src/NerdBank.GitVersioning/Managed/GitExtensions.cs similarity index 100% rename from src/Nerdbank.GitVersioning/Managed/GitExtensions.cs rename to src/NerdBank.GitVersioning/Managed/GitExtensions.cs diff --git a/src/Nerdbank.GitVersioning/Managed/ManagedGitContext.cs b/src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs similarity index 100% rename from src/Nerdbank.GitVersioning/Managed/ManagedGitContext.cs rename to src/NerdBank.GitVersioning/Managed/ManagedGitContext.cs diff --git a/src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs b/src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs similarity index 100% rename from src/Nerdbank.GitVersioning/Managed/ManagedVersionFile.cs rename to src/NerdBank.GitVersioning/Managed/ManagedVersionFile.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/DeltaInstruction.cs b/src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/DeltaInstruction.cs rename to src/NerdBank.GitVersioning/ManagedGit/DeltaInstruction.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/DeltaInstructionType.cs b/src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/DeltaInstructionType.cs rename to src/NerdBank.GitVersioning/ManagedGit/DeltaInstructionType.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/DeltaStreamReader.cs b/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/DeltaStreamReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/FileHelpers.cs b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/FileHelpers.cs rename to src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitCommit.cs b/src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitCommit.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitCommit.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitCommitReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitCommitReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitCommitReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitObjectId.cs b/src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitObjectId.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitObjectId.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitObjectStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitObjectStream.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitObjectStream.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPack.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPack.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPack.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPack.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackCache.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackCache.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackCache.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackIndexReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackIndexReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCache.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCache.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCache.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheViewStream.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackNullCache.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackNullCache.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackNullCache.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackObjectType.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackObjectType.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackObjectType.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackPooledStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackPooledStream.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackPooledStream.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitPackReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitPackReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitPackReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitReferenceReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitReferenceReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitReferenceReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitRepository.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitSignature.cs b/src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitSignature.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitSignature.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitTree.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTree.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitTree.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitTree.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitTreeEntry.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitTreeEntry.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitTreeEntry.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitTreeReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitTreeReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitTreeReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs rename to src/NerdBank.GitVersioning/ManagedGit/GitTreeStreamingReader.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/MemoryMappedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/MemoryMappedStream.cs rename to src/NerdBank.GitVersioning/ManagedGit/MemoryMappedStream.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/StreamExtensions.cs b/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/StreamExtensions.cs rename to src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs diff --git a/src/Nerdbank.GitVersioning/ManagedGit/ZLibStream.cs b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ManagedGit/ZLibStream.cs rename to src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs diff --git a/src/Nerdbank.GitVersioning/NativeMethods.json b/src/NerdBank.GitVersioning/NativeMethods.json similarity index 100% rename from src/Nerdbank.GitVersioning/NativeMethods.json rename to src/NerdBank.GitVersioning/NativeMethods.json diff --git a/src/Nerdbank.GitVersioning/NativeMethods.txt b/src/NerdBank.GitVersioning/NativeMethods.txt similarity index 100% rename from src/Nerdbank.GitVersioning/NativeMethods.txt rename to src/NerdBank.GitVersioning/NativeMethods.txt diff --git a/src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj b/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj similarity index 100% rename from src/Nerdbank.GitVersioning/Nerdbank.GitVersioning.csproj rename to src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj diff --git a/src/Nerdbank.GitVersioning/NoGit/NoGitContext.cs b/src/NerdBank.GitVersioning/NoGit/NoGitContext.cs similarity index 100% rename from src/Nerdbank.GitVersioning/NoGit/NoGitContext.cs rename to src/NerdBank.GitVersioning/NoGit/NoGitContext.cs diff --git a/src/Nerdbank.GitVersioning/NoGit/NoGitVersionFile.cs b/src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs similarity index 100% rename from src/Nerdbank.GitVersioning/NoGit/NoGitVersionFile.cs rename to src/NerdBank.GitVersioning/NoGit/NoGitVersionFile.cs diff --git a/src/Nerdbank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs similarity index 100% rename from src/Nerdbank.GitVersioning/ReleaseManager.cs rename to src/NerdBank.GitVersioning/ReleaseManager.cs diff --git a/src/Nerdbank.GitVersioning/SemanticVersion.cs b/src/NerdBank.GitVersioning/SemanticVersion.cs similarity index 100% rename from src/Nerdbank.GitVersioning/SemanticVersion.cs rename to src/NerdBank.GitVersioning/SemanticVersion.cs diff --git a/src/Nerdbank.GitVersioning/SemanticVersionJsonConverter.cs b/src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs similarity index 100% rename from src/Nerdbank.GitVersioning/SemanticVersionJsonConverter.cs rename to src/NerdBank.GitVersioning/SemanticVersionJsonConverter.cs diff --git a/src/Nerdbank.GitVersioning/VersionExtensions.cs b/src/NerdBank.GitVersioning/VersionExtensions.cs similarity index 100% rename from src/Nerdbank.GitVersioning/VersionExtensions.cs rename to src/NerdBank.GitVersioning/VersionExtensions.cs diff --git a/src/Nerdbank.GitVersioning/VersionFile.cs b/src/NerdBank.GitVersioning/VersionFile.cs similarity index 100% rename from src/Nerdbank.GitVersioning/VersionFile.cs rename to src/NerdBank.GitVersioning/VersionFile.cs diff --git a/src/Nerdbank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs similarity index 99% rename from src/Nerdbank.GitVersioning/VersionOptions.cs rename to src/NerdBank.GitVersioning/VersionOptions.cs index dd5f6b47..b3a92cc5 100644 --- a/src/Nerdbank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -243,7 +243,7 @@ public enum ReleaseVersionIncrement /// Gets the $schema field that should be serialized when writing. /// [JsonProperty(PropertyName = "$schema")] - public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/Nerdbank.GitVersioning/version.schema.json"; + public string Schema => "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json"; /// /// Gets or sets the default version to use. diff --git a/src/Nerdbank.GitVersioning/VersionOptionsContractResolver.cs b/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs similarity index 100% rename from src/Nerdbank.GitVersioning/VersionOptionsContractResolver.cs rename to src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs diff --git a/src/Nerdbank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs similarity index 100% rename from src/Nerdbank.GitVersioning/VersionOracle.cs rename to src/NerdBank.GitVersioning/VersionOracle.cs diff --git a/src/Nerdbank.GitVersioning/version.schema.json b/src/NerdBank.GitVersioning/version.schema.json similarity index 100% rename from src/Nerdbank.GitVersioning/version.schema.json rename to src/NerdBank.GitVersioning/version.schema.json diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj index f17b6fbc..b03f89ed 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj @@ -69,7 +69,7 @@ - + diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 6bbe7ae5..91926b5f 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -22,6 +22,6 @@ - + diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 9c8340be..388b19e0 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -12,7 +12,7 @@ - + diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index 92e52069..bda2056b 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 29670ad1..93e7e9ab 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -18,7 +18,7 @@ - + @@ -29,7 +29,7 @@ - + diff --git a/version.json b/version.json index a7001192..04420d35 100644 --- a/version.json +++ b/version.json @@ -1,5 +1,5 @@ { - "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/Nerdbank.GitVersioning/version.schema.json", + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/main/src/NerdBank.GitVersioning/version.schema.json", "version": "3.6-alpha", "assemblyVersion": { "precision": "revision" From c268a9e8d99bfed18778aaecea828720522c6dea Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 18 May 2022 16:18:24 -0600 Subject: [PATCH 506/704] Fix several Install-DotNetSdk issues * Stop popping Windows Explorer dialogs * Stop installing the same .NET runtime versions multiple times. * Install WindowsDesktop too. --- tools/Install-DotNetSdk.ps1 | 57 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 76a397f0..2bac3b9b 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -80,7 +80,7 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile = Join-Path $OutDir $Uri.Segments[-1] if (!(Test-Path $OutFile)) { Write-Verbose "Downloading $Uri..." - if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir } + if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir | Out-Null } try { (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) } finally { @@ -91,35 +91,31 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile } -Function Get-InstallerExe($Version, $Architecture, [switch]$Runtime) { - $sdkOrRuntime = 'Sdk' - if ($Runtime) { $sdkOrRuntime = 'Runtime' } - +Function Get-InstallerExe( + $Version, + $Architecture, + [ValidateSet('Sdk','Runtime','WindowsDesktop')] + [string]$sku +) { # Get the latest/actual version for the specified one $TypedVersion = [Version]$Version if ($TypedVersion.Build -eq -1) { - $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sdkOrRuntime/$Version/latest.version" -UseBasicParsing) + $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sku/$Version/latest.version" -UseBasicParsing) $Version = $versionInfo[-1] } $majorMinor = "$($TypedVersion.Major).$($TypedVersion.Minor)" $ReleasesFile = Join-Path $DotNetInstallScriptRoot "$majorMinor\releases.json" if (!(Test-Path $ReleasesFile)) { - Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile) + Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile) | Out-Null } $releases = Get-Content $ReleasesFile | ConvertFrom-Json $url = $null foreach ($release in $releases.releases) { $filesElement = $null - if ($Runtime) { - if ($release.runtime.version -eq $Version) { - $filesElement = $release.runtime.files - } - } else { - if ($release.sdk.version -eq $Version) { - $filesElement = $release.sdk.files - } + if ($release.$sku.version -eq $Version) { + $filesElement = $release.$sku.files } if ($filesElement) { @@ -139,15 +135,14 @@ Function Get-InstallerExe($Version, $Architecture, [switch]$Runtime) { if ($url) { Get-FileFromWeb -Uri $url -OutDir $DotNetInstallScriptRoot } else { - Write-Error "Unable to find release of $sdkOrRuntime v$Version" + Write-Error "Unable to find release of $sku v$Version" } } -Function Install-DotNet($Version, $Architecture, [switch]$Runtime) { - if ($Runtime) { $sdkSubstring = '' } else { $sdkSubstring = 'SDK ' } - Write-Host "Downloading .NET Core $sdkSubstring$Version..." - $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -Runtime:$Runtime - Write-Host "Installing .NET Core $sdkSubstring$Version..." +Function Install-DotNet($Version, $Architecture, [ValidateSet('Sdk','Runtime','WindowsDesktop')][string]$sku = 'Sdk') { + Write-Host "Downloading .NET Core $sku $Version..." + $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -sku $sku + Write-Host "Installing .NET Core $sku $Version..." cmd /c start /wait $Installer /install /passive /norestart if ($LASTEXITCODE -eq 3010) { Write-Verbose "Restart required" @@ -177,13 +172,25 @@ if ($InstallLocality -eq 'machine') { } } - $runtimeVersions | Get-Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core runtime $_", "Install")) { - Install-DotNet -Version $_ -Architecture $arch -Runtime + $runtimeVersions | Sort-Object | Get-Unique |% { + if ($PSCmdlet.ShouldProcess(".NET runtime $_", "Install")) { + Install-DotNet -Version $_ -sku Runtime -Architecture $arch + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + + if ($IncludeX86) { + Install-DotNet -Version $_ -sku Runtime -Architecture x86 + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } + } + } + + $windowsDesktopRuntimeVersions | Sort-Object | Get-Unique |% { + if ($PSCmdlet.ShouldProcess(".NET Windows Desktop $_", "Install")) { + Install-DotNet -Version $_ -sku WindowsDesktop -Architecture $arch $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) if ($IncludeX86) { - Install-DotNet -Version $_ -Architecture x86 -Runtime + Install-DotNet -Version $_ -sku WindowsDesktop -Architecture x86 $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) } } From 7bf4e22b5ab48ca5b0b3992804f685d9b857dad1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 20 May 2022 14:06:55 -0600 Subject: [PATCH 507/704] Fix Apply-Template merge check --- Apply-Template.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Apply-Template.ps1 b/Apply-Template.ps1 index d659670b..12bfaa12 100644 --- a/Apply-Template.ps1 +++ b/Apply-Template.ps1 @@ -20,7 +20,7 @@ try { # Look for our own initial commit in the target repo's history. # If it's there, they've already switched to using git merge to freshen up. # Using Apply-Template would just complicate future merges, so block it. - git log 05f49ce799c1f9cc696d53eea89699d80f59f833 ^HEAD | Out-Null + git merge-base --is-ancestor 05f49ce799c1f9cc696d53eea89699d80f59f833 HEAD | Out-Null if ($LASTEXITCODE -eq 0) { Write-Error 'The target repo already has Library.Template history merged into it. Use `git merge` instead of this script to freshen your repo. See the README.md file for details.' exit 1 From 5abdd709c599b95cb6f584eef289fe665031116a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 08:24:16 -0600 Subject: [PATCH 508/704] Bump Microsoft.NET.Test.Sdk from 17.1.0 to 17.2.0 (#159) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.1.0 to 17.2.0. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v17.1.0...v17.2.0) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 20108645..7dd444b6 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -11,7 +11,7 @@ - + From 311e766eea33c9ea74f6b6b444fa2cb6463722c6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 14:24:39 +0000 Subject: [PATCH 509/704] Bump Nerdbank.GitVersioning from 3.5.103 to 3.5.107 (#157) --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 2e13d76f..a2da14f6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,7 +37,7 @@ - + From 6a1593c66812b348812be702b41320290839ce0c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 14:24:49 +0000 Subject: [PATCH 510/704] Bump StyleCop.Analyzers.Unstable from 1.2.0.406 to 1.2.0.435 (#156) --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index a2da14f6..22c1b94d 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,7 +40,7 @@ - + From a91a2f1e2331902ab7515f1d317cf105892b9cb9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 14:31:58 +0000 Subject: [PATCH 511/704] Bump xunit.runner.visualstudio from 2.4.3 to 2.4.5 (#158) --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 7dd444b6..402468a8 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -12,7 +12,7 @@ - + From 8f76b654df69515cc173cf971de8251bbd36da4f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 19:32:20 +0000 Subject: [PATCH 512/704] Bump @types/node in /src/nerdbank-gitversioning.npm (#767) --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index 1a0d00c3..3b82dd61 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -50,9 +50,9 @@ camel-case "*" "@types/node@^17.0.30": - version "17.0.33" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.33.tgz#3c1879b276dc63e73030bb91165e62a4509cd506" - integrity sha512-miWq2m2FiQZmaHfdZNcbpp9PuXg34W5JZ5CrJ/BaS70VuhoJENBEQybeiYSaPBRNq6KQGnjfEnc/F3PN++D+XQ== + version "17.0.38" + resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947" + integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g== acorn@^6.4.1: version "6.4.2" From 84796572602c48537c173eda3dd28acaf6ec0237 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 19:35:31 +0000 Subject: [PATCH 513/704] Bump del from 6.0.0 to 6.1.1 in /src/nerdbank-gitversioning.npm (#765) --- src/nerdbank-gitversioning.npm/yarn.lock | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index 3b82dd61..9c13d649 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -627,9 +627,9 @@ define-property@^2.0.2: isobject "^3.0.1" del@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/del/-/del-6.0.0.tgz#0b40d0332cea743f1614f818be4feb717714c952" - integrity sha512-1shh9DQ23L16oXSZKB2JxpL7iMy2E0S9d517ptA1P8iw0alkPtQcrKH7ru31rYtKwF499HkTu+DRzq3TCKDFRQ== + version "6.1.1" + resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" + integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== dependencies: globby "^11.0.1" graceful-fs "^4.2.4" @@ -1057,12 +1057,7 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" -graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: - version "4.2.3" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" - integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== - -graceful-fs@^4.2.4: +graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== From 2bb44eb2637c8cb140b5559b579b8823cbf7828d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 19:45:27 +0000 Subject: [PATCH 514/704] Bump Moq from 4.14.7 to 4.18.1 (#771) --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 93e7e9ab..f3e925f1 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -38,7 +38,7 @@ - + From 9487a056deca3e225473ecb9d4e610420b60c0ba Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Jun 2022 20:07:19 +0000 Subject: [PATCH 515/704] Bump Xunit.Combinatorial from 1.2.7 to 1.4.1 (#773) --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index f3e925f1..25c0a631 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -42,7 +42,7 @@ - + From a39b14e9cd5b2cbaf88fa5e3ae8468392d846308 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 5 Jun 2022 20:47:55 -0600 Subject: [PATCH 516/704] Add empty VSTest target Fixes #774 --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 16c0d5a1..135de8e6 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -28,6 +28,9 @@ + + + From 8f2ed5eaf2436e9e49e741650308c0b45b4a53df Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 7 Jun 2022 15:50:23 -0600 Subject: [PATCH 517/704] Update SDK to 6.0.300 --- .devcontainer/Dockerfile | 2 +- global.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 234db6d1..b13ca0ac 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0.200-focal +FROM mcr.microsoft.com/dotnet/sdk:6.0.300-focal # 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/global.json b/global.json index 6bfbd177..954a92e7 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.200", + "version": "6.0.300", "rollForward": "patch", "allowPrerelease": false } From 8c6b68ecdd6cb98a02bc89e762d4cf8851e0148b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Jun 2022 08:48:38 -0600 Subject: [PATCH 518/704] Add adoption caution about github issues being closed --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 0f9715f3..8cab6b7a 100644 --- a/README.md +++ b/README.md @@ -79,5 +79,9 @@ We create the merge commit with these commands: 1. Run `git commit-tree -p HEAD -p A B -m "Merged latest Library.Template"`, where `A` is the output from `git rev-parse HEAD` that you recorded earlier, and `B` is the output from your prior `git write-tree` command. 1. Run `git merge X` where `X` is the output of the `git commit-tree` command. +**CAUTION**: when merging this for the first time, a github-hosted repo may close issues in your repo with the same number as issues that this repo closed in git commit messages. +Verify after completing your PR by visiting your github closed issues, sorted by recently updated, and reactivate any that were inadvertently closed by this merge. +This shouldn't be a recurring issue because going forward, we will avoid referencing github issues with simple `#123` syntax in this repo's history. + Congratulations. You're all done. Next time you want to sync to latest from Library.Template, you can the simple `git merge` steps given at the start of this section. From f678dd36be37f69272b6346b4ba3acb7472ec418 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Jun 2022 12:12:42 -0600 Subject: [PATCH 519/704] Install the nuget cred provider for .NET 6 and .NET Framework Recently we've only been getting the .NET Core 3.1 plugin, which leaves .NET Framework-based nuget tools un-authenticated. --- tools/Install-NuGetCredProvider.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1 index 6d310034..496049a2 100755 --- a/tools/Install-NuGetCredProvider.ps1 +++ b/tools/Install-NuGetCredProvider.ps1 @@ -33,7 +33,7 @@ if ($IsMacOS -or $IsLinux) { $installerScript = Join-Path $toolsPath $installerScript -if (!(Test-Path $installerScript)) { +if (!(Test-Path $installerScript) -or $Force) { Invoke-WebRequest $sourceUrl -OutFile $installerScript } @@ -43,7 +43,7 @@ if ($IsMacOS -or $IsLinux) { chmod u+x $installerScript } -& $installerScript -Force:$Force +& $installerScript -Force:$Force -AddNetfx -InstallNet6 if ($AccessToken) { $endpoints = @() From d8f567ef793329d7ff8cc09cf43922d2d00316c9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Jun 2022 08:58:02 -0600 Subject: [PATCH 520/704] Avoid truncated code coverage data Apply workaround for microsoft/vstest issue 3724. --- azure-pipelines/artifacts/coverageResults.ps1 | 7 +-- azure-pipelines/dotnet-test-cloud.ps1 | 3 +- azure-pipelines/publish-codecoverage.yml | 7 +-- azure-pipelines/test.runsettings | 44 +++++++++++++++++++ test/Directory.Build.targets | 7 --- test/Library.Tests/Library.Tests.csproj | 1 - 6 files changed, 54 insertions(+), 15 deletions(-) create mode 100644 azure-pipelines/test.runsettings diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 index 8fdb3f72..b3a08891 100644 --- a/azure-pipelines/artifacts/coverageResults.ps1 +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -1,10 +1,11 @@ $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") +$coverageFiles = @(Get-ChildItem "$RepoRoot/test/*.cobertura.xml" -Recurse) + # Prepare code coverage reports for merging on another machine if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) { Write-Host "Substituting $env:SYSTEM_DEFAULTWORKINGDIRECTORY with `"{reporoot}`"" - $reports = Get-ChildItem "$RepoRoot/bin/coverage.*cobertura.xml" -Recurse - $reports |% { + $coverageFiles |% { $content = Get-Content -Path $_ |% { $_ -Replace [regex]::Escape($env:SYSTEM_DEFAULTWORKINGDIRECTORY), "{reporoot}" } Set-Content -Path $_ -Value $content -Encoding UTF8 } @@ -16,7 +17,7 @@ if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } @{ $RepoRoot = ( - @(Get-ChildItem "$RepoRoot\bin\coverage.*cobertura.xml" -Recurse) + + $coverageFiles + (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) ); } diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index 43cdc3e0..24bf812a 100755 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -48,7 +48,8 @@ if ($x86) { --no-build ` -c $Configuration ` --filter "TestCategory!=FailsInCloudTest" ` - -p:CollectCoverage=true ` + --collect "Code Coverage;Format=cobertura" ` + --settings "$PSScriptRoot/test.runsettings" ` --blame-hang-timeout 60s ` --blame-crash ` -bl:"$ArtifactStagingFolder/build_logs/test.binlog" ` diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 423e12fc..4bc1b3bb 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -16,14 +16,15 @@ steps: continueOnError: true condition: ${{ parameters.includeMacOS }} - powershell: | - dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 4.8.5 --configfile azure-pipelines/justnugetorg.nuget.config + dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 5.1.9 --configfile azure-pipelines/justnugetorg.nuget.config Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj Write-Host 'Substituting {reporoot} with $(System.DefaultWorkingDirectory)' - $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/coverage.*cobertura.xml' + $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/*.cobertura.xml' $reports |% { $content = Get-Content -Path $_ |% { $_.Replace('{reporoot}', '$(System.DefaultWorkingDirectory)') } Set-Content -Path $_ -Value $content -Encoding UTF8 } + $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ })) obj/reportgenerator -reports:"$Inputs" -targetdir:coveragereport -reporttypes:Cobertura displayName: ⚙ Merge coverage @@ -31,5 +32,5 @@ steps: displayName: 📢 Publish code coverage results to Azure DevOps inputs: codeCoverageTool: cobertura - summaryFileLocation: 'coveragereport/Cobertura.xml' + summaryFileLocation: coveragereport/Cobertura.xml failIfCoverageEmpty: true diff --git a/azure-pipelines/test.runsettings b/azure-pipelines/test.runsettings new file mode 100644 index 00000000..c69022fc --- /dev/null +++ b/azure-pipelines/test.runsettings @@ -0,0 +1,44 @@ + + + + + + + + + \.dll$ + \.exe$ + + + xunit\..* + + + + + ^System\.Diagnostics\.DebuggerHiddenAttribute$ + ^System\.Diagnostics\.DebuggerNonUserCodeAttribute$ + ^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$ + ^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$ + + + + + True + + True + + True + + False + + True + + True + + True + + + + + + diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index 2faab375..e7edee55 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -1,10 +1,3 @@ - - cobertura - [xunit.*]* - - $(OutputPath)/ - - diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 402468a8..92062dc7 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,6 @@ - From f064b9a150eb529716d393fc0f1f60b55a301eb4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Jun 2022 16:22:01 -0600 Subject: [PATCH 521/704] Normalize slashes in coverage --- azure-pipelines/publish-codecoverage.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 4bc1b3bb..23e88a6e 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -21,7 +21,8 @@ steps: Write-Host 'Substituting {reporoot} with $(System.DefaultWorkingDirectory)' $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/*.cobertura.xml' $reports |% { - $content = Get-Content -Path $_ |% { $_.Replace('{reporoot}', '$(System.DefaultWorkingDirectory)') } + # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. + $content = Get-Content -Path $_ |% { [Regex]::Replace($_, '{reporoot}([^"]+)', { '$(System.DefaultWorkingDirectory)' + $args[0].groups[1].value.replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) }) } Set-Content -Path $_ -Value $content -Encoding UTF8 } From e903112e9ebff59ebad913bf6c89b14f97f707b1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Jun 2022 13:20:10 -0600 Subject: [PATCH 522/704] Include only unique coverage reports in artifact The test runner is creating *two* cobertura.xml files for each test run. Besides doubling the size of the coverageResults artifact, this makes the `publish-codecoverage.yml` pipeline step do much more work which can take *minutes* instead of seconds. --- azure-pipelines/artifacts/coverageResults.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/artifacts/coverageResults.ps1 b/azure-pipelines/artifacts/coverageResults.ps1 index b3a08891..280ff9ae 100644 --- a/azure-pipelines/artifacts/coverageResults.ps1 +++ b/azure-pipelines/artifacts/coverageResults.ps1 @@ -1,6 +1,6 @@ $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") -$coverageFiles = @(Get-ChildItem "$RepoRoot/test/*.cobertura.xml" -Recurse) +$coverageFiles = @(Get-ChildItem "$RepoRoot/test/*.cobertura.xml" -Recurse | Where {$_.FullName -notlike "*/In/*" -and $_.FullName -notlike "*\In\*" }) # Prepare code coverage reports for merging on another machine if ($env:SYSTEM_DEFAULTWORKINGDIRECTORY) { From c881dcad9590e33952a956950d6a2e4c4249c0ef Mon Sep 17 00:00:00 2001 From: Steve Bush Date: Wed, 15 Jun 2022 09:02:52 -0700 Subject: [PATCH 523/704] CodeCov binary uploader Replaces the bash CodeCov uploader with the latest binary version. A PowerShell script downloads the latest codecov binary. Another PowerShell script collects and uploads code coverage artifact files to CodeCov.io. You can pass flags and a coverage report name as parameters. --- .github/workflows/build.yml | 5 ++-- azure-pipelines/Get-CodeCovTool.ps1 | 38 ++++++++++++++++++++++++++ azure-pipelines/dotnet.yml | 5 +++- azure-pipelines/publish-CodeCov.ps1 | 42 +++++++++++++++++++++++++++++ 4 files changed, 87 insertions(+), 3 deletions(-) create mode 100644 azure-pipelines/Get-CodeCovTool.ps1 create mode 100644 azure-pipelines/publish-CodeCov.ps1 diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 4db43f53..cde83cd9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -109,7 +109,8 @@ jobs: path: ${{ runner.temp }}/_artifacts/deployables if: always() - name: Publish code coverage results to codecov.io - run: bash <(curl -s https://codecov.io/bash) - shell: bash + run: ./azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "${{ env.codecov_token }}" -PathToCodeCoverage "${{ runner.temp }}/_artifacts/coverageResults" -Name "${{ runner.os }} Coverage Results" -Flags "${{ runner.os }}Host,${{ env.BUILDCONFIGURATION }}" + shell: pwsh timeout-minutes: 3 continue-on-error: true + if: always() diff --git a/azure-pipelines/Get-CodeCovTool.ps1 b/azure-pipelines/Get-CodeCovTool.ps1 new file mode 100644 index 00000000..d6ca157b --- /dev/null +++ b/azure-pipelines/Get-CodeCovTool.ps1 @@ -0,0 +1,38 @@ +<# +.SYNOPSIS + Downloads the CodeCov.io uploader tool and returns the path to it. +#> +[CmdletBinding()] +Param( +) + +$toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" +$binaryToolsPath = Join-Path $toolsPath codecov +if (!(Test-Path $binaryToolsPath)) { $null = mkdir $binaryToolsPath } + +if ($IsMacOS) +{ + $codeCovPath = Join-Path $binaryToolsPath codecov + $codeCovUrl = "https://uploader.codecov.io/latest/macos/codecov" +} +elseif ($IsLinux) +{ + $codeCovPath = Join-Path $binaryToolsPath codecov + $codeCovUrl = "https://uploader.codecov.io/latest/linux/codecov" +} +else +{ + $codeCovPath = Join-Path $binaryToolsPath codecov.exe + $codeCovUrl = "https://uploader.codecov.io/latest/windows/codecov.exe" +} + +if (!(Test-Path $codeCovPath)) { + Write-Host "Downloading latest codeconv..." -ForegroundColor Yellow + (New-Object System.Net.WebClient).DownloadFile($codeCovUrl, $codeCovPath) +} + +if ($IsMacOS -or $IsLinux) { + chmod u+x $codeCovPath +} + +return (Resolve-Path $codeCovPath).Path diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 1d7d9de7..a461c147 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -16,7 +16,10 @@ steps: displayName: 📢 Publish artifacts condition: succeededOrFailed() -- bash: bash <(curl -s https://codecov.io/bash) +- powershell: | + $ArtifactStagingFolder = & "azure-pipelines/Get-ArtifactsStagingDirectory.ps1" + $CoverageResultsFolder = Join-Path $ArtifactStagingFolder "coverageResults-$(Agent.JobName)" + azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName)Host,$(BuildConfiguration)" displayName: 📢 Publish code coverage results to codecov.io condition: ne(variables['codecov_token'], '') timeoutInMinutes: 3 diff --git a/azure-pipelines/publish-CodeCov.ps1 b/azure-pipelines/publish-CodeCov.ps1 new file mode 100644 index 00000000..ec550e7a --- /dev/null +++ b/azure-pipelines/publish-CodeCov.ps1 @@ -0,0 +1,42 @@ +<# +.SYNOPSIS + Uploads code coverage to codecov.io +.PARAMETER CodeCovToken + Code coverage token to use +.PARAMETER PathToCodeCoverage + Path to root of code coverage files +.PARAMETER Name + Optional name to upload with codecoverge +.PARAMETER Flags + Optional flags to upload with codecoverge +#> +[CmdletBinding()] +Param ( + [string]$CodeCovToken, + [string]$PathToCodeCoverage, + [string]$Name="", + [string]$Flags="" +) + +$RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path +$CodeCoveragePathWildcard = (Join-Path $PathToCodeCoverage "*.cobertura.xml") + +Write-Host "RepoRoot: $RepoRoot" -ForegroundColor Yellow +Write-Host "CodeCoveragePathWildcard: $CodeCoveragePathWildcard" -ForegroundColor Yellow + +Get-ChildItem -Recurse -Path $CodeCoveragePathWildcard | % { + + if ($IsMacOS -or $IsLinux) + { + $relativeFilePath = Resolve-Path -relative $_ + } + else + { + $relativeFilePath = Resolve-Path -relative (Get-ChildItem $_ | Select-Object -ExpandProperty Target) + } + + Write-Host "Uploading: $relativeFilePath" -ForegroundColor Yellow + Write-Host "Flags: $Flags$TargetFrameworkFlag$TestTypeFlag$OSTypeFlag" -ForegroundColor Yellow + + & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t "$CodeCovToken" -f "$relativeFilePath" -R "$RepoRoot" -F "$Flags" -n "$Name" +} From 79a441098f323457a8033a09a843300b00631de3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Jun 2022 13:08:50 -0600 Subject: [PATCH 524/704] Add completions for dotnet-test-cloud script --- azure-pipelines/dotnet-test-cloud.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index 24bf812a..d07f1ad8 100755 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -16,6 +16,7 @@ #> [CmdletBinding()] Param( + [ValidateSet('Debug', 'Release')] [string]$Configuration='Debug', [string]$Agent='Local', [switch]$PublishResults, From 85d970c258bafda482b003ba79f4510a491a570d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 15 Jun 2022 13:09:08 -0600 Subject: [PATCH 525/704] Move coverage merge script to a ps1 that can be locally invoked --- .gitignore | 1 + azure-pipelines/Merge-CodeCoverage.ps1 | 42 ++++++++++++++++++++++++ azure-pipelines/publish-codecoverage.yml | 14 +------- 3 files changed, 44 insertions(+), 13 deletions(-) create mode 100644 azure-pipelines/Merge-CodeCoverage.ps1 diff --git a/.gitignore b/.gitignore index 65f94776..3bb49919 100644 --- a/.gitignore +++ b/.gitignore @@ -140,6 +140,7 @@ _TeamCity* # Visual Studio code coverage results *.coverage *.coveragexml +/coveragereport/ # NCrunch _NCrunch_* diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1 new file mode 100644 index 00000000..6672b94c --- /dev/null +++ b/azure-pipelines/Merge-CodeCoverage.ps1 @@ -0,0 +1,42 @@ +#!/usr/bin/env pwsh + +<# +.SYNOPSIS + Merges code coverage reports. +.PARAMETER Path + The path(s) to search for Cobertura code coverage reports. +.PARAMETER Format + The format for the merged result. The default is Cobertura +.PARAMETER OutputDir + The directory the merged result will be written to. The default is `coveragereport` in the root of this repo. +#> +[CmdletBinding()] +Param( + [Parameter(Mandatory=$true)] + [string[]]$Path, + [ValidateSet('Badges', 'Clover', 'Cobertura', 'CsvSummary', 'Html', 'Html_Dark', 'Html_Light', 'HtmlChart', 'HtmlInline', 'HtmlInline_AzurePipelines', 'HtmlInline_AzurePipelines_Dark', 'HtmlInline_AzurePipelines_Light', 'HtmlSummary', 'JsonSummary', 'Latex', 'LatexSummary', 'lcov', 'MarkdownSummary', 'MHtml', 'PngChart', 'SonarQube', 'TeamCitySummary', 'TextSummary', 'Xml', 'XmlSummary')] + [string]$Format='Cobertura', + [string]$OutputDir=("$PSScriptRoot/../coveragereport") +) + +$RepoRoot = [string](Resolve-Path $PSScriptRoot/..) + +if (!(Test-Path $RepoRoot/obj/reportgenerator*)) { + dotnet tool install --tool-path $RepoRoot/obj dotnet-reportgenerator-globaltool --version 5.1.9 --configfile $PSScriptRoot/justnugetorg.nuget.config +} + +Write-Verbose "Searching $Path for *.cobertura.xml files" +$reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml + +if ($reports) { + $reports |% { $_.FullName } |% { + # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. + $content = Get-Content -Path $_ |% { [Regex]::Replace($_, '{reporoot}([^"]+)', { $RepoRoot + $args[0].groups[1].value.replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) }) } + Set-Content -Path $_ -Value $content -Encoding UTF8 + } + + $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_.FullName })) + & "$RepoRoot/obj/reportgenerator" -reports:"$Inputs" -targetdir:$OutputDir -reporttypes:$Format +} else { + Write-Error "No reports found to merge." +} diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 23e88a6e..6e7ef21b 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -15,19 +15,7 @@ steps: displayName: 🔻 Download macOS code coverage results continueOnError: true condition: ${{ parameters.includeMacOS }} -- powershell: | - dotnet tool install --tool-path obj dotnet-reportgenerator-globaltool --version 5.1.9 --configfile azure-pipelines/justnugetorg.nuget.config - Copy-Item -Recurse $(Pipeline.Workspace)/coverageResults-Windows/obj/* $(System.DefaultWorkingDirectory)/obj - Write-Host 'Substituting {reporoot} with $(System.DefaultWorkingDirectory)' - $reports = Get-ChildItem -Recurse '$(Pipeline.Workspace)/*.cobertura.xml' - $reports |% { - # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. - $content = Get-Content -Path $_ |% { [Regex]::Replace($_, '{reporoot}([^"]+)', { '$(System.DefaultWorkingDirectory)' + $args[0].groups[1].value.replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) }) } - Set-Content -Path $_ -Value $content -Encoding UTF8 - } - - $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_ })) - obj/reportgenerator -reports:"$Inputs" -targetdir:coveragereport -reporttypes:Cobertura +- powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputDir coveragereport -Format Cobertura -Verbose displayName: ⚙ Merge coverage - task: PublishCodeCoverageResults@1 displayName: 📢 Publish code coverage results to Azure DevOps From ac247b8566c88e201f1df92013048ce7f3a30772 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 17 Jun 2022 15:44:22 -0600 Subject: [PATCH 526/704] Revert "Add completions for dotnet-test-cloud script" It was problematic since it disallowed non-default config names. This reverts commit 79a441098f323457a8033a09a843300b00631de3. --- azure-pipelines/dotnet-test-cloud.ps1 | 1 - 1 file changed, 1 deletion(-) diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1 index d07f1ad8..24bf812a 100755 --- a/azure-pipelines/dotnet-test-cloud.ps1 +++ b/azure-pipelines/dotnet-test-cloud.ps1 @@ -16,7 +16,6 @@ #> [CmdletBinding()] Param( - [ValidateSet('Debug', 'Release')] [string]$Configuration='Debug', [string]$Agent='Local', [switch]$PublishResults, From 6156061d6576a32b150393a22787c24629ef1545 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 18 Jun 2022 12:15:07 -0600 Subject: [PATCH 527/704] Touch-up formatting and simplify/correct a bit --- azure-pipelines/Get-CodeCovTool.ps1 | 11 ++++------- azure-pipelines/publish-CodeCov.ps1 | 30 +++++++++-------------------- 2 files changed, 13 insertions(+), 28 deletions(-) diff --git a/azure-pipelines/Get-CodeCovTool.ps1 b/azure-pipelines/Get-CodeCovTool.ps1 index d6ca157b..63b5d3f3 100644 --- a/azure-pipelines/Get-CodeCovTool.ps1 +++ b/azure-pipelines/Get-CodeCovTool.ps1 @@ -10,24 +10,21 @@ $toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" $binaryToolsPath = Join-Path $toolsPath codecov if (!(Test-Path $binaryToolsPath)) { $null = mkdir $binaryToolsPath } -if ($IsMacOS) -{ +if ($IsMacOS) { $codeCovPath = Join-Path $binaryToolsPath codecov $codeCovUrl = "https://uploader.codecov.io/latest/macos/codecov" } -elseif ($IsLinux) -{ +elseif ($IsLinux) { $codeCovPath = Join-Path $binaryToolsPath codecov $codeCovUrl = "https://uploader.codecov.io/latest/linux/codecov" } -else -{ +else { $codeCovPath = Join-Path $binaryToolsPath codecov.exe $codeCovUrl = "https://uploader.codecov.io/latest/windows/codecov.exe" } if (!(Test-Path $codeCovPath)) { - Write-Host "Downloading latest codeconv..." -ForegroundColor Yellow + Write-Host "Downloading latest codecov upload tool..." -ForegroundColor Yellow (New-Object System.Net.WebClient).DownloadFile($codeCovUrl, $codeCovPath) } diff --git a/azure-pipelines/publish-CodeCov.ps1 b/azure-pipelines/publish-CodeCov.ps1 index ec550e7a..1f4d3790 100644 --- a/azure-pipelines/publish-CodeCov.ps1 +++ b/azure-pipelines/publish-CodeCov.ps1 @@ -6,37 +6,25 @@ .PARAMETER PathToCodeCoverage Path to root of code coverage files .PARAMETER Name - Optional name to upload with codecoverge + Name to upload with codecoverge .PARAMETER Flags - Optional flags to upload with codecoverge + Flags to upload with codecoverge #> [CmdletBinding()] Param ( + [Parameter(Mandatory=$true)] [string]$CodeCovToken, + [Parameter(Mandatory=$true)] [string]$PathToCodeCoverage, - [string]$Name="", - [string]$Flags="" + [string]$Name, + [string]$Flags ) $RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path -$CodeCoveragePathWildcard = (Join-Path $PathToCodeCoverage "*.cobertura.xml") -Write-Host "RepoRoot: $RepoRoot" -ForegroundColor Yellow -Write-Host "CodeCoveragePathWildcard: $CodeCoveragePathWildcard" -ForegroundColor Yellow - -Get-ChildItem -Recurse -Path $CodeCoveragePathWildcard | % { - - if ($IsMacOS -or $IsLinux) - { - $relativeFilePath = Resolve-Path -relative $_ - } - else - { - $relativeFilePath = Resolve-Path -relative (Get-ChildItem $_ | Select-Object -ExpandProperty Target) - } +Get-ChildItem -Recurse -Path $PathToCodeCoverage -Filter "*.cobertura.xml" | % { + $relativeFilePath = Resolve-Path -relative $_ Write-Host "Uploading: $relativeFilePath" -ForegroundColor Yellow - Write-Host "Flags: $Flags$TargetFrameworkFlag$TestTypeFlag$OSTypeFlag" -ForegroundColor Yellow - - & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t "$CodeCovToken" -f "$relativeFilePath" -R "$RepoRoot" -F "$Flags" -n "$Name" + & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t $CodeCovToken -f $relativeFilePath -R $RepoRoot -F $Flags -n $Name } From 50d35dfde8113caedeca40f6c14d8b93686b3055 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 18 Jun 2022 15:22:38 -0600 Subject: [PATCH 528/704] fixup --- azure-pipelines/publish-CodeCov.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/publish-CodeCov.ps1 b/azure-pipelines/publish-CodeCov.ps1 index 1f4d3790..9926f018 100644 --- a/azure-pipelines/publish-CodeCov.ps1 +++ b/azure-pipelines/publish-CodeCov.ps1 @@ -23,7 +23,7 @@ Param ( $RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path Get-ChildItem -Recurse -Path $PathToCodeCoverage -Filter "*.cobertura.xml" | % { - $relativeFilePath = Resolve-Path -relative $_ + $relativeFilePath = Resolve-Path -relative $_.FullName Write-Host "Uploading: $relativeFilePath" -ForegroundColor Yellow & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t $CodeCovToken -f $relativeFilePath -R $RepoRoot -F $Flags -n $Name From 8abd437547653f0c2a01eb96dcf75d9945829cf0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 18 Jun 2022 14:54:27 -0600 Subject: [PATCH 529/704] Add signature validation --- azure-pipelines/Get-CodeCovTool.ps1 | 77 ++++++++++++++++++++++++----- 1 file changed, 64 insertions(+), 13 deletions(-) diff --git a/azure-pipelines/Get-CodeCovTool.ps1 b/azure-pipelines/Get-CodeCovTool.ps1 index 63b5d3f3..ca580b4d 100644 --- a/azure-pipelines/Get-CodeCovTool.ps1 +++ b/azure-pipelines/Get-CodeCovTool.ps1 @@ -1,35 +1,86 @@ <# .SYNOPSIS Downloads the CodeCov.io uploader tool and returns the path to it. +.PARAMETER AllowSkipVerify + Allows skipping signature verification of the downloaded tool if gpg is not installed. #> [CmdletBinding()] Param( + [switch]$AllowSkipVerify ) -$toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" -$binaryToolsPath = Join-Path $toolsPath codecov -if (!(Test-Path $binaryToolsPath)) { $null = mkdir $binaryToolsPath } - if ($IsMacOS) { - $codeCovPath = Join-Path $binaryToolsPath codecov $codeCovUrl = "https://uploader.codecov.io/latest/macos/codecov" + $toolName = 'codecov' } elseif ($IsLinux) { - $codeCovPath = Join-Path $binaryToolsPath codecov $codeCovUrl = "https://uploader.codecov.io/latest/linux/codecov" + $toolName = 'codecov' } else { - $codeCovPath = Join-Path $binaryToolsPath codecov.exe $codeCovUrl = "https://uploader.codecov.io/latest/windows/codecov.exe" + $toolName = 'codecov.exe' } -if (!(Test-Path $codeCovPath)) { - Write-Host "Downloading latest codecov upload tool..." -ForegroundColor Yellow - (New-Object System.Net.WebClient).DownloadFile($codeCovUrl, $codeCovPath) +$shaSuffix = ".SHA256SUM" +$sigSuffix = $shaSuffix + ".sig" + +Function Get-FileFromWeb([Uri]$Uri, $OutDir) { + $OutFile = Join-Path $OutDir $Uri.Segments[-1] + 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 + } + } + + $OutFile } -if ($IsMacOS -or $IsLinux) { - chmod u+x $codeCovPath +$toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" +$binaryToolsPath = Join-Path $toolsPath codecov +$testingPath = Join-Path $binaryToolsPath unverified +$finalToolPath = Join-Path $binaryToolsPath $toolName + +if (!(Test-Path $finalToolPath)) { + if (Test-Path $testingPath) { + Remove-Item -Recurse -Force $testingPath # ensure we download all matching files + } + $tool = Get-FileFromWeb $codeCovUrl $testingPath + $sha = Get-FileFromWeb "$codeCovUrl$shaSuffix" $testingPath + $sig = Get-FileFromWeb "$codeCovUrl$sigSuffix" $testingPath + $key = Get-FileFromWeb https://keybase.io/codecovsecurity/pgp_keys.asc $testingPath + + if ((Get-Command gpg -ErrorAction SilentlyContinue)) { + Write-Host "Importing codecov key" -ForegroundColor Yellow + gpg --import $key + Write-Host "Verifying signature on codecov hash" -ForegroundColor Yellow + gpg --verify $sig $sha + } else { + if ($AllowSkipVerify) { + Write-Warning "gpg not found. Unable to verify hash signature." + } else { + throw "gpg not found. Unable to verify hash signature. Install gpg or add -AllowSkipVerify to override." + } + } + + Write-Host "Verifying hash on downloaded tool" -ForegroundColor Yellow + $actualHash = (Get-FileHash -Path $tool -Algorithm SHA256).Hash + $expectedHash = (Get-Content $sha).Split()[0] + if ($actualHash -ne $expectedHash) { + # Validation failed. Delete the tool so we can't execute it. + #Remove-Item $codeCovPath + throw "codecov uploader tool failed signature validation." + } + + Copy-Item $tool $finalToolPath + + if ($IsMacOS -or $IsLinux) { + chmod u+x $finalToolPath + } } -return (Resolve-Path $codeCovPath).Path +return $finalToolPath From d0b0b55b461068eb2b7cc3c5e440880cf5203b75 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 18 Jun 2022 17:57:28 -0600 Subject: [PATCH 530/704] Fix perf scaling issue in merging coverage reports --- azure-pipelines/Merge-CodeCoverage.ps1 | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1 index 6672b94c..91ab67ab 100644 --- a/azure-pipelines/Merge-CodeCoverage.ps1 +++ b/azure-pipelines/Merge-CodeCoverage.ps1 @@ -31,8 +31,12 @@ $reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml if ($reports) { $reports |% { $_.FullName } |% { # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. - $content = Get-Content -Path $_ |% { [Regex]::Replace($_, '{reporoot}([^"]+)', { $RepoRoot + $args[0].groups[1].value.replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) }) } - Set-Content -Path $_ -Value $content -Encoding UTF8 + $xml = [xml](Get-Content -Path $_) + $xml.coverage.packages.package.classes.class |? { $_.filename} |% { + $_.filename = $_.filename.Replace('{reporoot}', $RepoRoot).Replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) + } + + $xml.Save($_) } $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_.FullName })) From fa0ac399504747ba4f8b71bfab31a974698811a6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 20 Jun 2022 08:44:04 -0600 Subject: [PATCH 531/704] Log _pipelines scripts verbosely --- azure-pipelines/artifacts/_all.ps1 | 1 + azure-pipelines/artifacts/_pipelines.ps1 | 8 ++++++-- azure-pipelines/artifacts/_stage_all.ps1 | 10 +++++++--- azure-pipelines/artifacts/testResults.ps1 | 4 ++++ azure-pipelines/dotnet.yml | 2 +- azure-pipelines/variables/_all.ps1 | 11 +++++++++-- azure-pipelines/variables/_pipelines.ps1 | 15 +++++++++++---- 7 files changed, 39 insertions(+), 12 deletions(-) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index c9182a45..033cc87c 100755 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -15,6 +15,7 @@ Executes artifact scripts even if they have already been staged. #> +[CmdletBinding(SupportsShouldProcess = $true)] param ( [string]$ArtifactNameSuffix, [switch]$Force diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1 index a62d2675..2d3338b2 100644 --- a/azure-pipelines/artifacts/_pipelines.ps1 +++ b/azure-pipelines/artifacts/_pipelines.ps1 @@ -1,6 +1,10 @@ -# This script translates all the artifacts described by _all.ps1 -# into commands that instruct Azure Pipelines to actually collect those artifacts. +<# +.SYNOPSIS + This script translates all the artifacts described by _all.ps1 + into commands that instruct Azure Pipelines to actually collect those artifacts. +#> +[CmdletBinding()] param ( [string]$ArtifactNameSuffix, [switch]$StageOnly diff --git a/azure-pipelines/artifacts/_stage_all.ps1 b/azure-pipelines/artifacts/_stage_all.ps1 index b7166b4e..d81d16d4 100644 --- a/azure-pipelines/artifacts/_stage_all.ps1 +++ b/azure-pipelines/artifacts/_stage_all.ps1 @@ -1,6 +1,10 @@ -# This script links all the artifacts described by _all.ps1 -# into a staging directory, reading for uploading to a cloud build artifact store. -# It returns a sequence of objects with Name and Path properties. +<# +.SYNOPSIS + This script links all the artifacts described by _all.ps1 + into a staging directory, reading for uploading to a cloud build artifact store. + It returns a sequence of objects with Name and Path properties. +#> + [CmdletBinding()] param ( [string]$ArtifactNameSuffix diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 index 2f894c97..4fa0fe62 100644 --- a/azure-pipelines/artifacts/testResults.ps1 +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -1,3 +1,7 @@ +[CmdletBinding()] +Param( +) + $result = @{} if ($env:AGENT_TEMPDIRECTORY) { diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index a461c147..ca9fc9b8 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -11,7 +11,7 @@ steps: displayName: ⚙ Update pipeline variables based on build outputs condition: succeededOrFailed() -- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" +- powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" -Verbose failOnStderr: true displayName: 📢 Publish artifacts condition: succeededOrFailed() diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1 index 0407d307..cc6e8810 100755 --- a/azure-pipelines/variables/_all.ps1 +++ b/azure-pipelines/variables/_all.ps1 @@ -1,7 +1,14 @@ #!/usr/bin/env pwsh -# This script returns a hashtable of build variables that should be set -# at the start of a build or release definition's execution. +<# +.SYNOPSIS + This script returns a hashtable of build variables that should be set + at the start of a build or release definition's execution. +#> + +[CmdletBinding(SupportsShouldProcess = $true)] +param ( +) $vars = @{} diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index 867b7fc8..951106d2 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -1,8 +1,15 @@ -# This script translates the variables returned by the _all.ps1 script -# into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume. +<# +.SYNOPSIS + This script translates the variables returned by the _all.ps1 script + into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume. -# The build or release definition may have set these variables to override -# what the build would do. So only set them if they have not already been set. + The build or release definition may have set these variables to override + what the build would do. So only set them if they have not already been set. +#> + +[CmdletBinding()] +param ( +) (& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { # Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive. From cb730eacdd53e4ca06b7f9c74b06da74f44db3a9 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 20 Jun 2022 08:46:30 -0600 Subject: [PATCH 532/704] Collect test results from the right directory The dump files used to be written to an agent TEMP directory. Somewhere along the lines they moved to the TestResults directory within the repo itself. Fixes AArnott/Library.Template#167 --- azure-pipelines/artifacts/testResults.ps1 | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1 index 4fa0fe62..301a4376 100644 --- a/azure-pipelines/artifacts/testResults.ps1 +++ b/azure-pipelines/artifacts/testResults.ps1 @@ -4,17 +4,8 @@ Param( $result = @{} -if ($env:AGENT_TEMPDIRECTORY) { - # The DotNetCoreCLI uses an alternate location to publish these files - $guidRegex = '^[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' - $result[$env:AGENT_TEMPDIRECTORY] = (Get-ChildItem $env:AGENT_TEMPDIRECTORY -Directory |? { $_.Name -match $guidRegex } |% { - Get-ChildItem "$($_.FullName)\dotnet*.dmp","$($_.FullName)\*_crashdump.dmp","$($_.FullName)\testhost*.dmp","$($_.FullName)\Sequence_*.xml" -Recurse - }); -} -else { - $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" - $result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File) -} +$testRoot = Resolve-Path "$PSScriptRoot\..\..\test" +$result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File) $testlogsPath = "$env:BUILD_ARTIFACTSTAGINGDIRECTORY\test_logs" if (Test-Path $testlogsPath) { From 540ea6a9b78c8c2a8e99ffb553ba523defaa7e81 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 20 Jun 2022 16:25:12 -0600 Subject: [PATCH 533/704] Prepare release notes with breaking changes --- azure-pipelines/release.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml index 2679b24e..4c9db860 100644 --- a/azure-pipelines/release.yml +++ b/azure-pipelines/release.yml @@ -51,6 +51,7 @@ jobs: changeLogType: issueBased changeLogLabels: | [ + { "label" : "breaking change", "displayName" : "Breaking changes", "state" : "closed" }, { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } ] From 3618dbecb07d7d0d47ae3dfc596f84dcb0aea21c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 1 Jul 2022 19:11:00 +0000 Subject: [PATCH 534/704] Bump System.CommandLine from 2.0.0-beta1.20574.7 to 2.0.0-beta4.22272.1 Bumps [System.CommandLine](https://github.com/dotnet/command-line-api) from 2.0.0-beta1.20574.7 to 2.0.0-beta4.22272.1. - [Release notes](https://github.com/dotnet/command-line-api/releases) - [Changelog](https://github.com/dotnet/command-line-api/blob/main/docs/History.md) - [Commits](https://github.com/dotnet/command-line-api/commits/2.0.0-beta4.22272.1) --- updated-dependencies: - dependency-name: System.CommandLine dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- src/nbgv/nbgv.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 91926b5f..f03b6b0b 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -11,7 +11,7 @@ - + From 6e793d63d36465b3168cadb9705a301c2ee83df3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 12 Jul 2022 13:36:50 -0600 Subject: [PATCH 535/704] Bump Newtonsoft.Json from 9.0.1 to 13.0.1 in /src/NerdBank.GitVersioning (#777) * Bump Newtonsoft.Json from 9.0.1 to 13.0.1 in /src/NerdBank.GitVersioning Bumps [Newtonsoft.Json](https://github.com/JamesNK/Newtonsoft.Json) from 9.0.1 to 13.0.1. - [Release notes](https://github.com/JamesNK/Newtonsoft.Json/releases) - [Commits](https://github.com/JamesNK/Newtonsoft.Json/compare/9.0.1...13.0.1) --- updated-dependencies: - dependency-name: Newtonsoft.Json dependency-type: direct:production ... Signed-off-by: dependabot[bot] * Fix build warning after Newtonsoft.Json upgrade Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Arnott --- src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj | 2 +- src/NerdBank.GitVersioning/VersionOptions.cs | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj index 465913af..dcda6438 100644 --- a/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/NerdBank.GitVersioning.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index b93bd9d1..b2af20bd 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -10,6 +10,7 @@ namespace Nerdbank.GitVersioning using System.Reflection; using Newtonsoft.Json; using Newtonsoft.Json.Converters; + using Newtonsoft.Json.Serialization; using Validation; using EditorBrowsableAttribute = System.ComponentModel.EditorBrowsableAttribute; using EditorBrowsableState = System.ComponentModel.EditorBrowsableState; @@ -493,7 +494,7 @@ public static JsonSerializerSettings GetJsonSettings(bool includeDefaults = fals new VersionConverter(), new SemanticVersionJsonConverter(), new AssemblyVersionOptionsConverter(includeDefaults), - new StringEnumConverter() { CamelCaseText = true }, + new StringEnumConverter() { NamingStrategy = new CamelCaseNamingStrategy() }, new FilterPathJsonConverter(repoRelativeBaseDirectory), }, ContractResolver = new VersionOptionsContractResolver From c5683bea1c776521445818e010a656a96d58b873 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 21 Jul 2022 21:14:22 -0600 Subject: [PATCH 536/704] Fix symbol file collection when the dll or exe is missing --- azure-pipelines/Get-SymbolFiles.ps1 | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1 index fccb1bb1..9183c340 100644 --- a/azure-pipelines/Get-SymbolFiles.ps1 +++ b/azure-pipelines/Get-SymbolFiles.ps1 @@ -49,8 +49,13 @@ $PDBs |% { $BinaryImagePath = $dllPath } elseif (Test-Path $exePath) { $BinaryImagePath = $exePath + } else { + Write-Warning "`"$_`" found with no matching binary file." + $BinaryImagePath = $null } - Write-Output $BinaryImagePath - Write-Output $_.FullName + if ($BinaryImagePath) { + Write-Output $BinaryImagePath + Write-Output $_.FullName + } } From 0bb373adc92cdaca099a82d4dcdb1d59c8f73ffe Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 27 Jul 2022 13:58:05 -0600 Subject: [PATCH 537/704] Fix WPF workaround This presumably broke when the intermediate directory was changed to include the relative path to the project directory. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 22c1b94d..dcf31a29 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -75,7 +75,7 @@ It's also not necessary to generate these assets. --> - <_WpfTempProjectNuGetFilePathNoExt>$(RepoRootPath)obj\$(_TargetAssemblyProjectName)\$(_TargetAssemblyProjectName)$(MSBuildProjectExtension).nuget.g + <_WpfTempProjectNuGetFilePathNoExt>$(BaseIntermediateOutputPath)..\$(_TargetAssemblyProjectName)\$(_TargetAssemblyProjectName)$(MSBuildProjectExtension).nuget.g false false From 0568520ee17b0579166d71dda701022e85aaf12c Mon Sep 17 00:00:00 2001 From: LoremFooBar Date: Fri, 29 Jul 2022 23:06:09 -0400 Subject: [PATCH 538/704] Add Bitbucket Cloud provider (#789) --- .../GitVersioningCloudProvider.cs | 5 +++ src/NerdBank.GitVersioning/CloudBuild.cs | 1 + .../CloudBuildServices/BitbucketCloud.cs | 42 +++++++++++++++++++ 3 files changed, 48 insertions(+) create mode 100644 src/NerdBank.GitVersioning/CloudBuildServices/BitbucketCloud.cs diff --git a/src/Cake.GitVersioning/GitVersioningCloudProvider.cs b/src/Cake.GitVersioning/GitVersioningCloudProvider.cs index f5c29163..0e9ad07d 100644 --- a/src/Cake.GitVersioning/GitVersioningCloudProvider.cs +++ b/src/Cake.GitVersioning/GitVersioningCloudProvider.cs @@ -52,5 +52,10 @@ public enum GitVersioningCloudProvider /// Use the Jetbrains Space cloud build provider. /// SpaceAutomation, + + /// + /// Use the Bitbucket cloud build provider. + /// + BitbucketCloud, } } diff --git a/src/NerdBank.GitVersioning/CloudBuild.cs b/src/NerdBank.GitVersioning/CloudBuild.cs index b57ac48f..71002d8f 100644 --- a/src/NerdBank.GitVersioning/CloudBuild.cs +++ b/src/NerdBank.GitVersioning/CloudBuild.cs @@ -24,6 +24,7 @@ public static class CloudBuild new GitLab(), new Travis(), new SpaceAutomation(), + new BitbucketCloud(), }; /// diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/BitbucketCloud.cs b/src/NerdBank.GitVersioning/CloudBuildServices/BitbucketCloud.cs new file mode 100644 index 00000000..ea4592fd --- /dev/null +++ b/src/NerdBank.GitVersioning/CloudBuildServices/BitbucketCloud.cs @@ -0,0 +1,42 @@ +// Copyright (c) .NET Foundation and Contributors. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Nerdbank.GitVersioning.CloudBuildServices; + +/// +/// Cloud build handling for Bitbucket Cloud. +/// +/// +/// The Bitbucket-specific properties referenced here are documented here. +/// +public class BitbucketCloud : ICloudBuild +{ + /// + public bool IsApplicable => !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("BITBUCKET_PIPELINE_UUID")) && + !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("BITBUCKET_STEP_UUID")) && + !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("BITBUCKET_STEP_TRIGGERER_UUID")); + + /// + public bool IsPullRequest => !string.IsNullOrWhiteSpace(Environment.GetEnvironmentVariable("BITBUCKET_PR_ID")); + + /// + public string BuildingBranch => Environment.GetEnvironmentVariable("BITBUCKET_BRANCH"); + + /// + public string BuildingTag => Environment.GetEnvironmentVariable("BITBUCKET_TAG"); + + /// + public string GitCommitId => Environment.GetEnvironmentVariable("BITBUCKET_COMMIT"); + + /// + public IReadOnlyDictionary SetCloudBuildNumber(string buildNumber, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } + + /// + public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) + { + return new Dictionary(); + } +} From 85241588765ce921ac50132841dee932fab3956e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 29 Jul 2022 21:12:53 -0600 Subject: [PATCH 539/704] Remove UltimateResourceFallbackLocation property (#791) No idea why this was here. Fixes #790 --- .../build/Nerdbank.GitVersioning.targets | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index a5c5fe58..55abaa97 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -116,7 +116,6 @@ $([MSBuild]::NormalizePath('$(IntermediateOutputPath)', '$(AssemblyName).Version$(DefaultLanguageSourceExtension)')) $(VersionSourceFile).new - UltimateResourceFallbackLocation.MainAssembly Date: Mon, 1 Aug 2022 12:25:45 -0600 Subject: [PATCH 540/704] Bump Nullable from 1.3.0 to 1.3.1 (#172) Bumps [Nullable](https://github.com/manuelroemer/Nullable) from 1.3.0 to 1.3.1. - [Release notes](https://github.com/manuelroemer/Nullable/releases) - [Changelog](https://github.com/manuelroemer/Nullable/blob/master/CHANGELOG.md) - [Commits](https://github.com/manuelroemer/Nullable/commits) --- updated-dependencies: - dependency-name: Nullable dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index dcf31a29..c2b4b004 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -38,7 +38,7 @@ - + From 45948958aece65a9048c74443139f5ce5fed952d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 1 Aug 2022 18:33:20 +0000 Subject: [PATCH 541/704] Bump Nerdbank.GitVersioning from 3.5.107 to 3.5.108 (#171) --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index c2b4b004..d13dbc48 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,7 +37,7 @@ - + From bdfbd7dea640926a059e752fd86e2f3aaaaa887e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 5 Jun 2022 20:47:55 -0600 Subject: [PATCH 542/704] Add empty VSTest target Fixes #774 --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 16c0d5a1..135de8e6 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -28,6 +28,9 @@ + + + From b39494e5d1115a599f4ed01565bc5419a8dace36 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Aug 2022 09:16:02 -0600 Subject: [PATCH 543/704] Make running tests in a pipeline optional --- azure-pipelines.yml | 5 +++++ azure-pipelines/build.yml | 16 +++++++++++++--- azure-pipelines/dotnet.yml | 4 ++++ azure-pipelines/publish-codecoverage.yml | 2 +- 4 files changed, 23 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index d98ed107..2cac17bd 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -17,6 +17,10 @@ parameters: displayName: Build on macOS type: boolean default: false # macOS is often bogged down in Azure Pipelines +- name: RunTests + displayName: Run tests + type: boolean + default: true variables: TreatWarningsAsErrors: true @@ -30,3 +34,4 @@ jobs: - template: azure-pipelines/build.yml parameters: includeMacOS: ${{ parameters.includeMacOS }} + RunTests: ${{ parameters.RunTests }} diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 5bfd95f5..cb489949 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -4,6 +4,9 @@ parameters: default: vmImage: windows-2022 - name: includeMacOS +- name: RunTests + type: boolean + default: true jobs: - job: Windows @@ -17,6 +20,8 @@ jobs: displayName: ⚙ Set build number - template: dotnet.yml + parameters: + RunTests: ${{ parameters.RunTests }} - template: expand-template.yml - job: Linux @@ -27,6 +32,8 @@ jobs: clean: true - template: install-dependencies.yml - template: dotnet.yml + parameters: + RunTests: ${{ parameters.RunTests }} - template: expand-template.yml - job: macOS @@ -38,6 +45,8 @@ jobs: clean: true - template: install-dependencies.yml - template: dotnet.yml + parameters: + RunTests: ${{ parameters.RunTests }} - template: expand-template.yml - job: WrapUp @@ -56,7 +65,8 @@ jobs: - template: publish-symbols.yml parameters: includeMacOS: ${{ parameters.includeMacOS }} - - template: publish-codecoverage.yml - parameters: - includeMacOS: ${{ parameters.includeMacOS }} + - ${{ if parameters.RunTests }}: + - template: publish-codecoverage.yml + parameters: + includeMacOS: ${{ parameters.includeMacOS }} - template: publish-deployables.yml diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index ca9fc9b8..055d44e9 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -1,3 +1,6 @@ +parameters: + RunTests: + steps: - script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" @@ -5,6 +8,7 @@ steps: - powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults displayName: 🧪 dotnet test + condition: and(succeeded(), ${{ parameters.RunTests }}) - powershell: azure-pipelines/variables/_pipelines.ps1 failOnStderr: true diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 6e7ef21b..11de8ffa 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -14,7 +14,7 @@ steps: artifact: coverageResults-macOS displayName: 🔻 Download macOS code coverage results continueOnError: true - condition: ${{ parameters.includeMacOS }} + condition: and(succeeded(), ${{ parameters.includeMacOS }}) - powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputDir coveragereport -Format Cobertura -Verbose displayName: ⚙ Merge coverage - task: PublishCodeCoverageResults@1 From 13d3a5635b19b6c4f7078059ebe042d3b38be9a3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 4 Aug 2022 12:42:45 -0600 Subject: [PATCH 544/704] Detect more test assemblies --- azure-pipelines/Get-SymbolFiles.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Get-SymbolFiles.ps1 b/azure-pipelines/Get-SymbolFiles.ps1 index 9183c340..0ce229fc 100644 --- a/azure-pipelines/Get-SymbolFiles.ps1 +++ b/azure-pipelines/Get-SymbolFiles.ps1 @@ -18,7 +18,7 @@ Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" $PDBs = Get-ChildItem -rec "$Path/*.pdb" # Filter PDBs to product OR test related. -$testregex = "unittest|tests" +$testregex = "unittest|tests|\.test\." Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" $PDBsByHash = @{} From d69d108c08c1e70399920a54e06aa5cfc050dd47 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 5 Aug 2022 08:43:45 -0600 Subject: [PATCH 545/704] Hide the codecov publish task if it won't run Instead of showing it as a skipped task, just hide it if we won't run it because no codecov_token is provided. --- .github/workflows/build.yml | 2 +- azure-pipelines/dotnet.yml | 16 ++++++++-------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index cde83cd9..2c4ba94c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ env: TreatWarningsAsErrors: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BUILDCONFIGURATION: Release - codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ + # codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages/ jobs: diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 055d44e9..79babd4d 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -20,11 +20,11 @@ steps: displayName: 📢 Publish artifacts condition: succeededOrFailed() -- powershell: | - $ArtifactStagingFolder = & "azure-pipelines/Get-ArtifactsStagingDirectory.ps1" - $CoverageResultsFolder = Join-Path $ArtifactStagingFolder "coverageResults-$(Agent.JobName)" - azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName)Host,$(BuildConfiguration)" - displayName: 📢 Publish code coverage results to codecov.io - condition: ne(variables['codecov_token'], '') - timeoutInMinutes: 3 - continueOnError: true +- ${{ if and(ne(variables['codecov_token'], ''), parameters.RunTests) }}: + - powershell: | + $ArtifactStagingFolder = & "azure-pipelines/Get-ArtifactsStagingDirectory.ps1" + $CoverageResultsFolder = Join-Path $ArtifactStagingFolder "coverageResults-$(Agent.JobName)" + azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName)Host,$(BuildConfiguration)" + displayName: 📢 Publish code coverage results to codecov.io + timeoutInMinutes: 3 + continueOnError: true From d36ca82f4437c2c091f2465d5007edb77d8259de Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Aug 2022 08:10:08 -0600 Subject: [PATCH 546/704] Add support for disregarding the GitHub Actions env variables Set the `IGNORE_GITHUB_REF` environment variable to `true` when your GitHub workflow has moved HEAD such that the `GITHUB_REF` and `GITHUB_SHA` environment variables are stale. Fixes https://github.com/dotnet/nbgv/issues/50 --- .../CloudBuildServices/GitHubActions.cs | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs b/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs index e278fc01..d43a885b 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/GitHubActions.cs @@ -18,9 +18,18 @@ internal class GitHubActions : ICloudBuild public string BuildingTag => (BuildingRef?.StartsWith("refs/tags/") ?? false) ? BuildingRef : null; /// - public string GitCommitId => Environment.GetEnvironmentVariable("GITHUB_SHA"); - - private static string BuildingRef => Environment.GetEnvironmentVariable("GITHUB_REF"); + public string GitCommitId => IgnoreGitHubRef ? null : Environment.GetEnvironmentVariable("GITHUB_SHA"); + + private static string BuildingRef => IgnoreGitHubRef ? null : Environment.GetEnvironmentVariable("GITHUB_REF"); + + /// + /// Gets a value indicating whether to ignore GitHub Actions environment variables that indicate where HEAD is. + /// + /// + /// This is useful in a GitHub workflow where HEAD was moved by some prior Action, such that the environment variables are stale. + /// GitHub Actions does not allow these env vars to be changed mid-workflow, so in such cases NB.GV should just use HEAD. + /// + private static bool IgnoreGitHubRef => string.Equals(Environment.GetEnvironmentVariable("IGNORE_GITHUB_REF"), "true", StringComparison.OrdinalIgnoreCase); private static string EnvironmentFile => Environment.GetEnvironmentVariable("GITHUB_ENV"); From 8a51f879f2b71d4fbb557cfb3b497de2318b6e27 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Aug 2022 07:49:13 -0600 Subject: [PATCH 547/704] Update .NET SDK we build with --- .devcontainer/Dockerfile | 2 +- azure-pipelines.yml | 4 ++-- azure-pipelines/build.yml | 2 +- global.json | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 234db6d1..67cafb32 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0.200-focal +FROM mcr.microsoft.com/dotnet/sdk:6.0.301-focal # 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/azure-pipelines.yml b/azure-pipelines.yml index c6e4eeb9..dd346ab8 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -100,10 +100,10 @@ stages: packageType: runtime version: 3.1.x - task: UseDotNet@2 - displayName: Install .NET 6.0.200 SDK + displayName: Install .NET 6.0.301 SDK inputs: packageType: sdk - version: 6.0.200 + version: 6.0.301 - script: dotnet --info displayName: Show dotnet SDK info - bash: | diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index e3224a74..019cb2e3 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -20,7 +20,7 @@ jobs: - pwsh: | Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose -Runtime dotnet - & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.202 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.301 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose displayName: Install 32-bit .NET SDK and runtimes - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' diff --git a/global.json b/global.json index 6bfbd177..7e562337 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.200", + "version": "6.0.301", "rollForward": "patch", "allowPrerelease": false } From 281e5d80e5fbbee9209524a4071e13845137122c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Aug 2022 07:50:56 -0600 Subject: [PATCH 548/704] Fix bad references to solution items --- Nerdbank.GitVersioning.sln | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Nerdbank.GitVersioning.sln b/Nerdbank.GitVersioning.sln index 658f1c3b..69495d50 100644 --- a/Nerdbank.GitVersioning.sln +++ b/Nerdbank.GitVersioning.sln @@ -5,17 +5,18 @@ VisualStudioVersion = 17.0.31411.2 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{4BD1A7CD-6F52-4F5A-825B-50E4D8C3ECFF}" ProjectSection(SolutionItems) = preProject - ..\.editorconfig = ..\.editorconfig - ..\.gitignore = ..\.gitignore - ..\3rdPartyNotices.txt = ..\3rdPartyNotices.txt - ..\azure-pipelines.yml = ..\azure-pipelines.yml - ..\build.ps1 = ..\build.ps1 + .editorconfig = .editorconfig + .gitignore = .gitignore + 3rdPartyNotices.txt = 3rdPartyNotices.txt + azure-pipelines.yml = azure-pipelines.yml + build.ps1 = build.ps1 Directory.Build.props = Directory.Build.props - ..\global.json = ..\global.json - ..\init.ps1 = ..\init.ps1 + Directory.Build.targets = Directory.Build.targets + global.json = global.json + init.ps1 = init.ps1 nuget.config = nuget.config - ..\README.md = ..\README.md - ..\version.json = ..\version.json + README.md = README.md + version.json = version.json EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nerdbank.GitVersioning.Tests", "test\Nerdbank.GitVersioning.Tests\Nerdbank.GitVersioning.Tests.csproj", "{C54F9EC8-FDA7-4D22-BCB2-7D97523BD91E}" From 4295efcd92e2a153da6205a59784349f79328be0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 12 Aug 2022 07:52:13 -0600 Subject: [PATCH 549/704] Move projects around in the solution tree --- Nerdbank.GitVersioning.sln | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/Nerdbank.GitVersioning.sln b/Nerdbank.GitVersioning.sln index 69495d50..78d6ef59 100644 --- a/Nerdbank.GitVersioning.sln +++ b/Nerdbank.GitVersioning.sln @@ -89,6 +89,16 @@ Global GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(NestedProjects) = preSolution + {C54F9EC8-FDA7-4D22-BCB2-7D97523BD91E} = {A603FD3B-1A40-4605-B044-5DDAFDEDCD90} + {F79DD916-27B3-4CD0-97FF-5021B3CF9934} = {0A4BEA3B-268B-464F-9C0F-6DC2EFA884F8} + {C7FA7B7A-0469-4B1C-8657-E274C4CD8ABB} = {0A4BEA3B-268B-464F-9C0F-6DC2EFA884F8} + {B2454569-6EDC-4FD4-9936-D2B2F2E10409} = {0A4BEA3B-268B-464F-9C0F-6DC2EFA884F8} + {EF4DAF23-6CE9-48C5-84C5-80AC80D3D07D} = {0A4BEA3B-268B-464F-9C0F-6DC2EFA884F8} + {1F267A97-DFE3-4166-83B1-9D236B7A09BD} = {0A4BEA3B-268B-464F-9C0F-6DC2EFA884F8} + {B0B7955D-E51F-4091-BF7F-55D07D381D15} = {A603FD3B-1A40-4605-B044-5DDAFDEDCD90} + {D68829FE-24D8-4ADD-8525-17F47C6FE257} = {A603FD3B-1A40-4605-B044-5DDAFDEDCD90} + EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {4CF7AA29-5BBD-4294-9C92-DA689CF57200} EndGlobalSection From 68e3d617808b4558af4f940fe926e45c04715d0f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 22 Aug 2022 08:53:58 -0600 Subject: [PATCH 550/704] Add warning about squashing a Lib.Template update --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 8cab6b7a..d3b5acf0 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,8 @@ We create the merge commit with these commands: 1. Run `git commit-tree -p HEAD -p A B -m "Merged latest Library.Template"`, where `A` is the output from `git rev-parse HEAD` that you recorded earlier, and `B` is the output from your prior `git write-tree` command. 1. Run `git merge X` where `X` is the output of the `git commit-tree` command. +**IMPORTANT**: If using a pull request to get your changes into your repo, you must *merge* your PR. If you *squash* your PR, history will be lost and you will have to repeatedly resolve the same merge conflicts at the next Library.Template update. + **CAUTION**: when merging this for the first time, a github-hosted repo may close issues in your repo with the same number as issues that this repo closed in git commit messages. Verify after completing your PR by visiting your github closed issues, sorted by recently updated, and reactivate any that were inadvertently closed by this merge. This shouldn't be a recurring issue because going forward, we will avoid referencing github issues with simple `#123` syntax in this repo's history. From 8c56d91a1d1967e520e21ce55c87255780b7a798 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 13:25:43 -0600 Subject: [PATCH 551/704] Bump Microsoft.NET.Test.Sdk from 17.2.0 to 17.3.1 (#175) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.2.0 to 17.3.1. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v17.2.0...v17.3.1) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 92062dc7..a707cebe 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From 4dfc0ba9854c87eb8d310cfe337290c9c7bb5aeb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 13:25:57 -0600 Subject: [PATCH 552/704] Bump Nerdbank.GitVersioning from 3.5.108 to 3.5.109 (#174) Bumps [Nerdbank.GitVersioning](https://github.com/dotnet/Nerdbank.GitVersioning) from 3.5.108 to 3.5.109. - [Release notes](https://github.com/dotnet/Nerdbank.GitVersioning/releases) - [Commits](https://github.com/dotnet/Nerdbank.GitVersioning/compare/v3.5.108...v3.5.109) --- updated-dependencies: - dependency-name: Nerdbank.GitVersioning dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index d13dbc48..35f7d62a 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -37,7 +37,7 @@ - + From 2bcf967f7d8f19620077021f61219938478635e9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Sep 2022 13:26:07 -0600 Subject: [PATCH 553/704] Bump xunit from 2.4.1 to 2.4.2 (#173) Bumps [xunit](https://github.com/xunit/xunit) from 2.4.1 to 2.4.2. - [Release notes](https://github.com/xunit/xunit/releases) - [Commits](https://github.com/xunit/xunit/compare/2.4.1...2.4.2) --- updated-dependencies: - dependency-name: xunit dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Library.Tests/Library.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index a707cebe..2c1c3e8e 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -12,7 +12,7 @@ - + From 9b736dbc7185a3d2580cb6e32bbb626ad72d1f1b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 5 Sep 2022 01:40:29 -0600 Subject: [PATCH 554/704] Update testing to macOS-12 See https://github.com/actions/runner-images/issues/5583 --- azure-pipelines.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index dd346ab8..d97544e5 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -67,7 +67,7 @@ stages: strategy: matrix: macOS_Catalina: - vmImage: macOS-10.15 + vmImage: macOS-12 macOS_Monterey: vmImage: macOS-12 pool: @@ -89,7 +89,7 @@ stages: imageName: windows-2022 repoDir: '${USERPROFILE}/source/repos' macOS: - imageName: macOS-10.15 + imageName: macOS-12 repoDir: '~/git' pool: vmImage: $(imageName) From fa719472cccc8cc953fb8f626d5ca93890def926 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 5 Sep 2022 02:15:18 -0600 Subject: [PATCH 555/704] Fix break in tests from VS 17.3 This is a workaround suggested in https://github.com/dotnet/msbuild/issues/7873 --- .../NerdBank.GitVersioning.Tests.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj index f75399d7..14fe5031 100644 --- a/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj +++ b/src/NerdBank.GitVersioning.Tests/NerdBank.GitVersioning.Tests.csproj @@ -36,6 +36,7 @@ + From 3abbce9751eea87853609bc7e37eaa1679460fed Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 09:39:24 +0000 Subject: [PATCH 556/704] Bump typescript from 4.6.4 to 4.8.2 in /src/nerdbank-gitversioning.npm (#798) --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index 9c13d649..afbe67c9 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -2742,9 +2742,9 @@ typedarray@^0.0.6: integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typescript@^4.6.4: - version "4.6.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.6.4.tgz#caa78bbc3a59e6a5c510d35703f6a09877ce45e9" - integrity sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg== + version "4.8.2" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" + integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== unc-path-regex@^0.1.2: version "0.1.2" From da06bd91b54e9a55e8d99193928549d101cfde5b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 09:48:24 +0000 Subject: [PATCH 557/704] Bump @types/node in /src/nerdbank-gitversioning.npm (#799) --- src/nerdbank-gitversioning.npm/package.json | 2 +- src/nerdbank-gitversioning.npm/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/package.json b/src/nerdbank-gitversioning.npm/package.json index 29aca42b..7d80a9f5 100644 --- a/src/nerdbank-gitversioning.npm/package.json +++ b/src/nerdbank-gitversioning.npm/package.json @@ -25,7 +25,7 @@ ], "devDependencies": { "@types/camel-case": "^1.2.1", - "@types/node": "^17.0.30", + "@types/node": "^18.7.14", "del": "^6.0.0", "gulp": "^4.0.2", "gulp-cli": "^2.3.0", diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index afbe67c9..f0acd8ff 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -49,10 +49,10 @@ dependencies: camel-case "*" -"@types/node@^17.0.30": - version "17.0.38" - resolved "https://registry.yarnpkg.com/@types/node/-/node-17.0.38.tgz#f8bb07c371ccb1903f3752872c89f44006132947" - integrity sha512-5jY9RhV7c0Z4Jy09G+NIDTsCZ5G0L5n+Z+p+Y7t5VJHM30bgwzSjVtlcBxqAj+6L/swIlvtOSzr8rBk/aNyV2g== +"@types/node@^18.7.14": + version "18.7.14" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.14.tgz#0fe081752a3333392d00586d815485a17c2cf3c9" + integrity sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA== acorn@^6.4.1: version "6.4.2" From df964e24ec1f98c791dc946d113b43782bbb95db Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 13:52:39 +0000 Subject: [PATCH 558/704] Bump BenchmarkDotNet.Diagnostics.Windows from 0.12.0 to 0.13.1 (#780) --- azure-pipelines.yml | 4 ++-- .../Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs | 3 +-- .../Nerdbank.GitVersioning.Benchmarks.csproj | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index a24b6041..cde3d98e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -126,7 +126,7 @@ stages: dotnet build -c Release displayName: Build in Release mode - script: | - dotnet run -c Release -f netcoreapp3.1 -- --filter GetVersionBenchmarks --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) + dotnet run -c Release -f netcoreapp3.1 -- --filter *GetVersionBenchmarks* --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (packed) - bash: | @@ -143,7 +143,7 @@ stages: git unpack-objects < .git/objects/pack/*.pack displayName: Unpack Git repositories - script: | - dotnet run -c Release -f netcoreapp3.1 -- --filter GetVersionBenchmarks --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) + dotnet run -c Release -f netcoreapp3.1 -- --filter '*GetVersionBenchmarks*' --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (unpacked) - task: PublishBuildArtifacts@1 diff --git a/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs index be00f97a..214ab17b 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs +++ b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs @@ -10,8 +10,7 @@ namespace Nerdbank.GitVersioning.Benchmarks { [SimpleJob(RuntimeMoniker.NetCoreApp31, baseline: true)] - [SimpleJob(RuntimeMoniker.NetCoreApp21)] - [SimpleJob(RuntimeMoniker.NetCoreApp50)] + [SimpleJob(RuntimeMoniker.Net60)] [SimpleJob(RuntimeMoniker.Net461)] public class GetVersionBenchmarks { diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index bda2056b..bda92426 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -10,8 +10,8 @@ - - + + From acb09af72ef0f27ee127b85f36622614db8d1331 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 08:10:30 -0600 Subject: [PATCH 559/704] Bump del from 6.1.1 to 7.0.0 in /src/nerdbank-gitversioning.npm (#793) * Bump del from 6.1.1 to 7.0.0 in /src/nerdbank-gitversioning.npm Bumps [del](https://github.com/sindresorhus/del) from 6.1.1 to 7.0.0. - [Release notes](https://github.com/sindresorhus/del/releases) - [Commits](https://github.com/sindresorhus/del/compare/v6.1.1...v7.0.0) --- updated-dependencies: - dependency-name: del dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Fix del import Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Arnott --- src/nerdbank-gitversioning.npm/gulpfile.js | 2 +- src/nerdbank-gitversioning.npm/package.json | 2 +- src/nerdbank-gitversioning.npm/yarn.lock | 123 ++++++++++---------- 3 files changed, 64 insertions(+), 63 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/gulpfile.js b/src/nerdbank-gitversioning.npm/gulpfile.js index 62c52cbd..ff05ca9f 100644 --- a/src/nerdbank-gitversioning.npm/gulpfile.js +++ b/src/nerdbank-gitversioning.npm/gulpfile.js @@ -5,7 +5,7 @@ var ts = require('gulp-typescript'); var sourcemaps = require('gulp-sourcemaps'); var merge = require('merge2'); // var tslint = require('gulp-tslint'); -var del = require('del'); +var del = import('del'); var path = require('path'); const outDir = 'out'; diff --git a/src/nerdbank-gitversioning.npm/package.json b/src/nerdbank-gitversioning.npm/package.json index 7d80a9f5..fc834dee 100644 --- a/src/nerdbank-gitversioning.npm/package.json +++ b/src/nerdbank-gitversioning.npm/package.json @@ -26,7 +26,7 @@ "devDependencies": { "@types/camel-case": "^1.2.1", "@types/node": "^18.7.14", - "del": "^6.0.0", + "del": "^7.0.0", "gulp": "^4.0.2", "gulp-cli": "^2.3.0", "gulp-sourcemaps": "3.0.0", diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index f0acd8ff..ed67f839 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -59,13 +59,13 @@ acorn@^6.4.1: resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.2.tgz#35866fd710528e92de10cf06016498e47e39e1e6" integrity sha512-XtGIhXwF8YM8bJhGxG5kXgjkEuNGLTkoYqVE+KMR+aspr4KGYmKYg7yUe3KghyQ9yheNwLnjmzh/7+gfDBmHCQ== -aggregate-error@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.0.1.tgz#db2fe7246e536f40d9b5442a39e117d7dd6a24e0" - integrity sha512-quoaXsZ9/BLNae5yiNoUz+Nhkwz83GhWwtYFglcjEQB2NDHCIpApbqXxIFnm4Pq/Nvhrsq5sYJFyohrrxnTGAA== +aggregate-error@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-4.0.1.tgz#25091fe1573b9e0be892aeda15c7c66a545f758e" + integrity sha512-0poP0T7el6Vq3rstR8Mn4V/IQrpBLO6POkUSrN7RhyY+GF/InCFShQzsQ39T25gkHhLgSLByyAz+Kjb+c2L98w== dependencies: - clean-stack "^2.0.0" - indent-string "^4.0.0" + clean-stack "^4.0.0" + indent-string "^5.0.0" ansi-colors@^1.0.1: version "1.1.0" @@ -189,11 +189,6 @@ array-sort@^1.0.0: get-value "^2.0.6" kind-of "^5.0.2" -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - array-uniq@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" @@ -403,10 +398,12 @@ class-utils@^0.3.5: isobject "^3.0.0" static-extend "^0.1.1" -clean-stack@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" - integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== +clean-stack@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-4.2.0.tgz#c464e4cde4ac789f4e0735c5d75beb49d7b30b31" + integrity sha512-LYv6XPxoyODi36Dp976riBtSY27VmFo+MKqEU9QCCWyTrdEPDog+RWA7xQWHi6Vbp61j5c4cdzzX1NidnwtUWg== + dependencies: + escape-string-regexp "5.0.0" cliui@^3.2.0: version "3.2.0" @@ -626,19 +623,19 @@ define-property@^2.0.2: is-descriptor "^1.0.2" isobject "^3.0.1" -del@^6.0.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/del/-/del-6.1.1.tgz#3b70314f1ec0aa325c6b14eb36b95786671edb7a" - integrity sha512-ua8BhapfP0JUJKC/zV9yHHDW/rDoDxP4Zhn3AkA6/xT6gY7jYXJiaeyBZznYVujhZZET+UgcbZiQ7sN3WqcImg== - dependencies: - globby "^11.0.1" - graceful-fs "^4.2.4" - is-glob "^4.0.1" - is-path-cwd "^2.2.0" - is-path-inside "^3.0.2" - p-map "^4.0.0" +del@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/del/-/del-7.0.0.tgz#79db048bec96f83f344b46c1a66e35d9c09fe8ac" + integrity sha512-tQbV/4u5WVB8HMJr08pgw0b6nG4RGt/tj+7Numvq+zqcvUFeMaIWWOUFltiU+6go8BSO2/ogsB4EasDaj0y68Q== + dependencies: + globby "^13.1.2" + graceful-fs "^4.2.10" + is-glob "^4.0.3" + is-path-cwd "^3.0.0" + is-path-inside "^4.0.0" + p-map "^5.5.0" rimraf "^3.0.2" - slash "^3.0.0" + slash "^4.0.0" detect-file@^1.0.0: version "1.0.0" @@ -732,6 +729,11 @@ es6-weak-map@^2.0.1, es6-weak-map@^2.0.2: es6-iterator "^2.0.3" es6-symbol "^3.1.1" +escape-string-regexp@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz#4683126b500b61762f2dbebace1806e8be31b1c8" + integrity sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw== + escape-string-regexp@^1.0.2: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -816,7 +818,7 @@ fancy-log@^1.1.0, fancy-log@^1.3.2: parse-node-version "^1.0.0" time-stamp "^1.0.0" -fast-glob@^3.2.9: +fast-glob@^3.2.11: version "3.2.11" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" integrity sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew== @@ -1038,17 +1040,16 @@ global-prefix@^1.0.1: is-windows "^1.0.1" which "^1.2.14" -globby@^11.0.1: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== +globby@^13.1.2: + version "13.1.2" + resolved "https://registry.yarnpkg.com/globby/-/globby-13.1.2.tgz#29047105582427ab6eca4f905200667b056da515" + integrity sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ== dependencies: - array-union "^2.1.0" dir-glob "^3.0.1" - fast-glob "^3.2.9" + fast-glob "^3.2.11" ignore "^5.2.0" merge2 "^1.4.1" - slash "^3.0.0" + slash "^4.0.0" glogg@^1.0.0: version "1.0.2" @@ -1057,7 +1058,7 @@ glogg@^1.0.0: dependencies: sparkles "^1.0.0" -graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.4: +graceful-fs@^4.0.0, graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.2.10: version "4.2.10" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.10.tgz#147d3a006da4ca3ce14728c7aefc287c367d7a6c" integrity sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA== @@ -1247,10 +1248,10 @@ ignore@^5.2.0: resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.2.0.tgz#6d3bac8fa7fe0d45d9f9be7bac2fc279577e345a" integrity sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ== -indent-string@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" - integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== +indent-string@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-5.0.0.tgz#4fd2980fccaf8622d14c64d694f4cf33c81951a5" + integrity sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg== inflight@^1.0.4: version "1.0.6" @@ -1392,10 +1393,10 @@ is-glob@^3.1.0: dependencies: is-extglob "^2.1.0" -is-glob@^4.0.0, is-glob@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" - integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" @@ -1421,15 +1422,15 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-path-cwd@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb" - integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ== +is-path-cwd@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-3.0.0.tgz#889b41e55c8588b1eb2a96a61d05740a674521c7" + integrity sha512-kyiNFFLU0Ampr6SDZitD/DwUo4Zs1nSdnygUBqsu3LooL00Qvb5j+UnvApUn/TTj1J3OuE6BTdQ5rudKmU2ZaA== -is-path-inside@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== +is-path-inside@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-4.0.0.tgz#805aeb62c47c1b12fc3fd13bfb3ed1e7430071db" + integrity sha512-lJJV/5dYS+RcL8uQdBDW9c9uWFLLBNRyFhnAKXw5tVqLlKZ4RMGZKv+YQ/IA3OhD+RpbJa1LLFM1FQPGyIXvOA== is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" @@ -2011,12 +2012,12 @@ os-locale@^1.4.0: dependencies: lcid "^1.0.0" -p-map@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" - integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== +p-map@^5.5.0: + version "5.5.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-5.5.0.tgz#054ca8ca778dfa4cf3f8db6638ccb5b937266715" + integrity sha512-VFqfGDHlx87K66yZrNdI4YGtD70IRyd+zSvgks6mzHPRNkoKy+9EKP4SFC77/vTTQYmRmti7dvqC+m5jBrBAcg== dependencies: - aggregate-error "^3.0.0" + aggregate-error "^4.0.0" parse-filepath@^1.0.1: version "1.0.2" @@ -2430,10 +2431,10 @@ set-value@^2.0.0, set-value@^2.0.1: is-plain-object "^2.0.3" split-string "^3.0.1" -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== +slash@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-4.0.0.tgz#2422372176c4c6c5addb5e2ada885af984b396a7" + integrity sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew== snapdragon-node@^2.0.1: version "2.1.1" From 2d7762adce6c99b7767959437b96bec68ddf07ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 09:24:16 -0600 Subject: [PATCH 560/704] Bump Microsoft.NET.Test.Sdk from 17.1.0 to 17.3.1 (#808) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.1.0 to 17.3.1. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v17.1.0...v17.3.1) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 388b19e0..4930a607 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 5c048256..3ea29de5 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -37,7 +37,7 @@ - + From 4ecd0d99fd6c60cde10255cf90f52947f4b7e675 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 15:27:49 +0000 Subject: [PATCH 561/704] Bump CSharpIsNullAnalyzer from 0.1.300 to 0.1.329 (#807) --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 762d2dd0..76a75cbf 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,7 +40,7 @@ 2.0.315-alpha.0.9 - + From 62389ed1feb4c01a33c4ca4ee928549ef3db1d35 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 5 Sep 2022 09:31:36 -0600 Subject: [PATCH 562/704] Compensate for new System.CommandLine API --- src/nbgv/Program.cs | 304 ++++++++++++++++++++++++-------------------- 1 file changed, 163 insertions(+), 141 deletions(-) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index fd4407b0..321ea6e4 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -89,107 +89,147 @@ public static int Main(string[] args) private static Parser BuildCommandLine() { - var install = new Command("install", "Prepares a project to have version stamps applied using Nerdbank.GitVersioning.") +#pragma warning disable IDE0008 + Command install; { - new Option(new[] { "--path", "-p" }, "The path to the directory that should contain the version.json file. The default is the root of the git repo.").LegalFilePathsOnly(), - new Option(new[] { "--version", "-v" }, () => DefaultVersionSpec, $"The initial version to set."), - new Option(new[] { "--source", "-s" }, $"The URI(s) of the NuGet package source(s) used to determine the latest stable version of the {PackageId} package. This setting overrides all of the sources specified in the NuGet.Config files.") + var path = new Option(new[] { "--path", "-p" }, "The path to the directory that should contain the version.json file. The default is the root of the git repo.").LegalFilePathsOnly(); + var version = new Option(new[] { "--version", "-v" }, () => DefaultVersionSpec, $"The initial version to set."); + var source = new Option(new[] { "--source", "-s" }, () => Array.Empty(), $"The URI(s) of the NuGet package source(s) used to determine the latest stable version of the {PackageId} package. This setting overrides all of the sources specified in the NuGet.Config files.") { - Argument = new Argument(() => Array.Empty()) - { - Arity = ArgumentArity.OneOrMore, - }, - }, - }; - - install.Handler = CommandHandler.Create>(OnInstallCommand); + Arity = ArgumentArity.OneOrMore, + AllowMultipleArgumentsPerToken = true, + }; + install = new Command("install", "Prepares a project to have version stamps applied using Nerdbank.GitVersioning.") + { + path, + version, + source, + }; + install.SetHandler(OnInstallCommand, path, version, source); + } - var getVersion = new Command("get-version", "Gets the version information for a project.") + Command getVersion; { - new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the current directory.").LegalFilePathsOnly(), - new Option("--metadata", "Adds an identifier to the build metadata part of a semantic version.") + var project = new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the current directory.").LegalFilePathsOnly(); + var metadata = new Option("--metadata", () => Array.Empty(), "Adds an identifier to the build metadata part of a semantic version.") { - Argument = new Argument(() => Array.Empty()) - { - Arity = ArgumentArity.OneOrMore, - }, - }, - new Option(new[] { "--format", "-f" }, $"The format to write the version information. Allowed values are: {string.Join(", ", SupportedFormats)}. The default is {DefaultOutputFormat}.").FromAmong(SupportedFormats), - new Option(new[] { "--variable", "-v" }, "The name of just one version property to print to stdout. When specified, the output is always in raw text. Useful in scripts."), - new Argument("commit-ish", () => DefaultRef, $"The commit/ref to get the version information for.") + Arity = ArgumentArity.OneOrMore, + AllowMultipleArgumentsPerToken = true, + }; + var format = new Option(new[] { "--format", "-f" }, $"The format to write the version information. Allowed values are: {string.Join(", ", SupportedFormats)}. The default is {DefaultOutputFormat}.").FromAmong(SupportedFormats); + var variable = new Option(new[] { "--variable", "-v" }, "The name of just one version property to print to stdout. When specified, the output is always in raw text. Useful in scripts."); + var commit = new Argument("commit-ish", () => DefaultRef, $"The commit/ref to get the version information for.") { Arity = ArgumentArity.ZeroOrOne, - }, - }; + }; + getVersion = new Command("get-version", "Gets the version information for a project.") + { + project, + metadata, + format, + variable, + commit, + }; - getVersion.Handler = CommandHandler.Create, string, string, string>(OnGetVersionCommand); + getVersion.SetHandler(OnGetVersionCommand, project, metadata, format, variable, commit); + } - var setVersion = new Command("set-version", "Updates the version stamp that is applied to a project.") + Command setVersion; { - new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the root directory of the repo that spans the current directory, or an existing version.json file, if applicable.").LegalFilePathsOnly(), - new Argument("version", "The version to set."), - }; + var project = new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the root directory of the repo that spans the current directory, or an existing version.json file, if applicable.").LegalFilePathsOnly(); + var version = new Argument("version", "The version to set."); + setVersion = new Command("set-version", "Updates the version stamp that is applied to a project.") + { + project, + version, + }; - setVersion.Handler = CommandHandler.Create(OnSetVersionCommand); + setVersion.SetHandler(OnSetVersionCommand, project, version); + } - var tag = new Command("tag", "Creates a git tag to mark a version.") + Command tag; { - new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the root directory of the repo that spans the current directory, or an existing version.json file, if applicable.").LegalFilePathsOnly(), - new Argument("versionOrRef", () => DefaultRef, $"The a.b.c[.d] version or git ref to be tagged.") + var project = new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the root directory of the repo that spans the current directory, or an existing version.json file, if applicable.").LegalFilePathsOnly(); + var versionOrRef = new Argument("versionOrRef", () => DefaultRef, $"The a.b.c[.d] version or git ref to be tagged.") { Arity = ArgumentArity.ZeroOrOne, - }, - }; + }; + tag = new Command("tag", "Creates a git tag to mark a version.") + { + project, + versionOrRef, + }; - tag.Handler = CommandHandler.Create(OnTagCommand); + tag.SetHandler(OnTagCommand, project, versionOrRef); + } - var getCommits = new Command("get-commits", "Gets the commit(s) that match a given version.") + Command getCommits; { - new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the root directory of the repo that spans the current directory, or an existing version.json file, if applicable.").LegalFilePathsOnly(), - new Option(new[] { "--quiet", "-q" }, "Use minimal output."), - new Argument("version", "The a.b.c[.d] version to find."), - }; + var project = new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the root directory of the repo that spans the current directory, or an existing version.json file, if applicable.").LegalFilePathsOnly(); + var quiet = new Option(new[] { "--quiet", "-q" }, "Use minimal output."); + var version = new Argument("version", "The a.b.c[.d] version to find."); + getCommits = new Command("get-commits", "Gets the commit(s) that match a given version.") + { + project, + quiet, + version, + }; - getCommits.Handler = CommandHandler.Create(OnGetCommitsCommand); + getCommits.SetHandler(OnGetCommitsCommand, project, quiet, version); + } - var cloud = new Command("cloud", "Communicates with the ambient cloud build to set the build number and/or other cloud build variables.") + Command cloud; { - new Option(new[] { "--project", "-p" }, "The path to the project or project directory used to calculate the version. The default is the current directory. Ignored if the -v option is specified.").LegalFilePathsOnly(), - new Option("--metadata", "Adds an identifier to the build metadata part of a semantic version.") + var project = new Option(new[] { "--project", "-p" }, "The path to the project or project directory used to calculate the version. The default is the current directory. Ignored if the -v option is specified.").LegalFilePathsOnly(); + var metadata = new Option("--metadata", () => Array.Empty(), "Adds an identifier to the build metadata part of a semantic version.") { - Argument = new Argument(() => Array.Empty()) - { - Arity = ArgumentArity.OneOrMore, - }, - }, - new Option(new[] { "--version", "-v" }, "The string to use for the cloud build number. If not specified, the computed version will be used."), - new Option(new[] { "--ci-system", "-s" }, "Force activation for a particular CI system. If not specified, auto-detection will be used. Supported values are: " + string.Join(", ", CloudProviderNames)).FromAmong(CloudProviderNames), - new Option(new[] { "--all-vars", "-a" }, "Defines ALL version variables as cloud build variables, with a \"NBGV_\" prefix."), - new Option(new[] { "--common-vars", "-c" }, "Defines a few common version variables as cloud build variables, with a \"Git\" prefix (e.g. GitBuildVersion, GitBuildVersionSimple, GitAssemblyInformationalVersion)."), - new Option(new[] { "--define", "-d" }, "Additional cloud build variables to define. Each should be in the NAME=VALUE syntax.") + Arity = ArgumentArity.OneOrMore, + AllowMultipleArgumentsPerToken = true, + }; + var version = new Option(new[] { "--version", "-v" }, "The string to use for the cloud build number. If not specified, the computed version will be used."); + var ciSystem = new Option(new[] { "--ci-system", "-s" }, "Force activation for a particular CI system. If not specified, auto-detection will be used. Supported values are: " + string.Join(", ", CloudProviderNames)).FromAmong(CloudProviderNames); + var allVars = new Option(new[] { "--all-vars", "-a" }, "Defines ALL version variables as cloud build variables, with a \"NBGV_\" prefix."); + var commonVars = new Option(new[] { "--common-vars", "-c" }, "Defines a few common version variables as cloud build variables, with a \"Git\" prefix (e.g. GitBuildVersion, GitBuildVersionSimple, GitAssemblyInformationalVersion)."); + var define = new Option(new[] { "--define", "-d" }, () => Array.Empty(), "Additional cloud build variables to define. Each should be in the NAME=VALUE syntax.") { - Argument = new Argument(() => Array.Empty()) - { - Arity = ArgumentArity.OneOrMore, - }, - }, - }; + Arity = ArgumentArity.OneOrMore, + AllowMultipleArgumentsPerToken = true, + }; + cloud = new Command("cloud", "Communicates with the ambient cloud build to set the build number and/or other cloud build variables.") + { + project, + metadata, + version, + ciSystem, + allVars, + commonVars, + define, + }; - cloud.Handler = CommandHandler.Create, string, string, bool, bool, IReadOnlyList>(OnCloudCommand); + cloud.SetHandler(OnCloudCommand, project, metadata, version, ciSystem, allVars, commonVars, define); + } - var prepareRelease = new Command("prepare-release", "Prepares a release by creating a release branch for the current version and adjusting the version on the current branch.") + Command prepareRelease; { - new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the current directory.").LegalFilePathsOnly(), - new Option("--nextVersion", "The version to set for the current branch. If omitted, the next version is determined automatically by incrementing the current version."), - new Option("--versionIncrement", "Overrides the 'versionIncrement' setting set in version.json for determining the next version of the current branch."), - new Option(new[] { "--format", "-f" }, $"The format to write information about the release. Allowed values are: {string.Join(", ", SupportedFormats)}. The default is {DefaultOutputFormat}.").FromAmong(SupportedFormats), - new Argument("tag", "The prerelease tag to apply on the release branch (if any). If not specified, any existing prerelease tag will be removed. The preceding hyphen may be omitted.") + var project = new Option(new[] { "--project", "-p" }, "The path to the project or project directory. The default is the current directory.").LegalFilePathsOnly(); + var nextVersion = new Option("--nextVersion", "The version to set for the current branch. If omitted, the next version is determined automatically by incrementing the current version."); + var versionIncrement = new Option("--versionIncrement", "Overrides the 'versionIncrement' setting set in version.json for determining the next version of the current branch."); + var format = new Option(new[] { "--format", "-f" }, $"The format to write information about the release. Allowed values are: {string.Join(", ", SupportedFormats)}. The default is {DefaultOutputFormat}.").FromAmong(SupportedFormats); + var tagArgument = new Argument("tag", "The prerelease tag to apply on the release branch (if any). If not specified, any existing prerelease tag will be removed. The preceding hyphen may be omitted.") { Arity = ArgumentArity.ZeroOrOne, - }, - }; + }; + prepareRelease = new Command("prepare-release", "Prepares a release by creating a release branch for the current version and adjusting the version on the current branch.") + { + project, + nextVersion, + versionIncrement, + format, + tagArgument, + }; - prepareRelease.Handler = CommandHandler.Create(OnPrepareReleaseCommand); + prepareRelease.SetHandler(OnPrepareReleaseCommand, project, nextVersion, versionIncrement, format, tagArgument); + } var root = new RootCommand($"{ThisAssembly.AssemblyTitle} v{ThisAssembly.AssemblyInformationalVersion}") { @@ -204,27 +244,9 @@ private static Parser BuildCommandLine() return new CommandLineBuilder(root) .UseDefaults() - .UseMiddleware( - context => - { - // System.CommandLine 0.1 parsed arguments after optional --. Restore that behavior for compatibility. - // TODO: Remove this middleware when https://github.com/dotnet/command-line-api/issues/1238 is resolved. - if (context.ParseResult.UnparsedTokens.Count > 0) - { - IEnumerable arguments = context.ParseResult.CommandResult.Command.Arguments; - if (arguments.Count() == context.ParseResult.UnparsedTokens.Count) - { - context.ParseResult = context.Parser.Parse( - context.ParseResult.Tokens - .Where(token => token.Type != TokenType.EndOfArguments) - .Select(token => token.Value) - .ToArray()); - } - } - }, - (MiddlewareOrder)(-3000)) // MiddlewareOrderInternal.ExceptionHandler so [parse] directive is accurate. .UseExceptionHandler((ex, context) => PrintException(ex, context)) .Build(); +#pragma warning restore IDE0008 } private static void PrintException(Exception ex, InvocationContext context) @@ -260,7 +282,7 @@ private static int MainInner(string[] args) return (int)exitCode; } - private static int OnInstallCommand(string path, string version, IReadOnlyList source) + private static async Task OnInstallCommand(string path, string version, string[] source) { if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out SemanticVersion semver)) { @@ -308,7 +330,7 @@ private static int OnInstallCommand(string path, string version, IReadOnlyList metadata, string format, string variable, string commitish) + private static Task OnGetVersionCommand(string project, string[] metadata, string format, string variable, string commitish) { if (string.IsNullOrEmpty(format)) { @@ -397,13 +419,13 @@ private static int OnGetVersionCommand(string project, IReadOnlyList met if (!context.IsRepository) { Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath); - return (int)ExitCodes.NoGitRepo; + return Task.FromResult((int)ExitCodes.NoGitRepo); } if (!context.TrySelectCommit(commitish)) { Console.Error.WriteLine("rev-parse produced no commit for {0}", commitish); - return (int)ExitCodes.BadGitRef; + return Task.FromResult((int)ExitCodes.BadGitRef); } var oracle = new VersionOracle(context, CloudBuild.Active); @@ -438,7 +460,7 @@ private static int OnGetVersionCommand(string project, IReadOnlyList met break; default: Console.Error.WriteLine("Unsupported format: {0}", format); - return (int)ExitCodes.UnsupportedFormat; + return Task.FromResult((int)ExitCodes.UnsupportedFormat); } } else @@ -446,28 +468,28 @@ private static int OnGetVersionCommand(string project, IReadOnlyList met if (format != "text") { Console.Error.WriteLine("Format must be \"text\" when querying for an individual variable's value."); - return (int)ExitCodes.UnsupportedFormat; + return Task.FromResult((int)ExitCodes.UnsupportedFormat); } PropertyInfo property = oracle.GetType().GetProperty(variable, CaseInsensitiveFlags); if (property is null) { Console.Error.WriteLine("Variable \"{0}\" not a version property.", variable); - return (int)ExitCodes.BadVariable; + return Task.FromResult((int)ExitCodes.BadVariable); } Console.WriteLine(property.GetValue(oracle)); } - return (int)ExitCodes.OK; + return Task.FromResult((int)ExitCodes.OK); } - private static int OnSetVersionCommand(string project, string version) + private static Task OnSetVersionCommand(string project, string version) { if (!SemanticVersion.TryParse(string.IsNullOrEmpty(version) ? DefaultVersionSpec : version, out SemanticVersion semver)) { Console.Error.WriteLine($"\"{version}\" is not a semver-compliant version spec."); - return (int)ExitCodes.InvalidVersionSpec; + return Task.FromResult((int)ExitCodes.InvalidVersionSpec); } var defaultOptions = new VersionOptions @@ -489,7 +511,7 @@ private static int OnSetVersionCommand(string project, string version) if (!context.IsRepository) { Console.Error.WriteLine("No version file and no git repo found at or above: \"{0}\"", searchPath); - return (int)ExitCodes.NoGitRepo; + return Task.FromResult((int)ExitCodes.NoGitRepo); } versionJsonPath = context.VersionFile.SetVersion(context.WorkingTreePath, defaultOptions); @@ -504,10 +526,10 @@ private static int OnSetVersionCommand(string project, string version) context.Stage(versionJsonPath); } - return (int)ExitCodes.OK; + return Task.FromResult((int)ExitCodes.OK); } - private static int OnTagCommand(string project, string versionOrRef) + private static Task OnTagCommand(string project, string versionOrRef) { if (string.IsNullOrEmpty(versionOrRef)) { @@ -520,7 +542,7 @@ private static int OnTagCommand(string project, string versionOrRef) if (context is null) { Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath); - return (int)ExitCodes.NoGitRepo; + return Task.FromResult((int)ExitCodes.NoGitRepo); } LibGit2Sharp.Repository repository = context.Repository; @@ -529,7 +551,7 @@ private static int OnTagCommand(string project, string versionOrRef) if (!Version.TryParse(versionOrRef, out Version parsedVersion)) { Console.Error.WriteLine($"\"{versionOrRef}\" is not a simple a.b.c[.d] version spec or git reference."); - return (int)ExitCodes.InvalidVersionSpec; + return Task.FromResult((int)ExitCodes.InvalidVersionSpec); } string repoRelativeProjectDir = GetRepoRelativePath(searchPath, repository); @@ -537,7 +559,7 @@ private static int OnTagCommand(string project, string versionOrRef) if (candidateCommits.Count == 0) { Console.Error.WriteLine("No commit with that version found."); - return (int)ExitCodes.NoMatchingVersion; + return Task.FromResult((int)ExitCodes.NoMatchingVersion); } else if (candidateCommits.Count > 1) { @@ -560,7 +582,7 @@ private static int OnTagCommand(string project, string versionOrRef) if (!oracle.VersionFileFound) { Console.Error.WriteLine("No version.json file found in or above \"{0}\" in commit {1}.", searchPath, context.GitCommitId); - return (int)ExitCodes.NoVersionJsonFound; + return Task.FromResult((int)ExitCodes.NoVersionJsonFound); } oracle.PublicRelease = true; // assume a public release so we don't get a redundant -gCOMMITID in the tag name @@ -574,21 +596,21 @@ private static int OnTagCommand(string project, string versionOrRef) var taggedCommit = repository.Tags[tagName].Target as LibGit2Sharp.Commit; bool correctTag = taggedCommit?.Sha == context.GitCommitId; Console.Error.WriteLine("The tag {0} is already defined ({1}).", tagName, correctTag ? "to the right commit" : $"expected {context.GitCommitId} but was on {taggedCommit.Sha}"); - return (int)(correctTag ? ExitCodes.OK : ExitCodes.TagConflict); + return Task.FromResult((int)(correctTag ? ExitCodes.OK : ExitCodes.TagConflict)); } Console.WriteLine("{0} tag created at {1}.", tagName, context.GitCommitId); Console.WriteLine("Remember to push to a remote: git push origin {0}", tagName); - return (int)ExitCodes.OK; + return Task.FromResult((int)ExitCodes.OK); } - private static int OnGetCommitsCommand(string project, bool quiet, string version) + private static Task OnGetCommitsCommand(string project, bool quiet, string version) { if (!Version.TryParse(version, out Version parsedVersion)) { Console.Error.WriteLine($"\"{version}\" is not a simple a.b.c[.d] version spec."); - return (int)ExitCodes.InvalidVersionSpec; + return Task.FromResult((int)ExitCodes.InvalidVersionSpec); } string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); @@ -597,22 +619,22 @@ private static int OnGetCommitsCommand(string project, bool quiet, string versio if (!context.IsRepository) { Console.Error.WriteLine("No git repo found at or above: \"{0}\"", searchPath); - return (int)ExitCodes.NoGitRepo; + return Task.FromResult((int)ExitCodes.NoGitRepo); } IEnumerable candidateCommits = LibGit2GitExtensions.GetCommitsFromVersion(context, parsedVersion); PrintCommits(quiet, context, candidateCommits); - return (int)ExitCodes.OK; + return Task.FromResult((int)ExitCodes.OK); } - private static int OnCloudCommand(string project, IReadOnlyList metadata, string version, string ciSystem, bool allVars, bool commonVars, IReadOnlyList define) + private static Task OnCloudCommand(string project, string[] metadata, string version, string ciSystem, bool allVars, bool commonVars, string[] define) { string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); if (!Directory.Exists(searchPath)) { Console.Error.WriteLine("\"{0}\" is not an existing directory.", searchPath); - return (int)ExitCodes.NoGitRepo; + return Task.FromResult((int)ExitCodes.NoGitRepo); } var additionalVariables = new Dictionary(); @@ -624,13 +646,13 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata if (split.Length < 2) { Console.Error.WriteLine($"\"{def}\" is not in the NAME=VALUE syntax required for cloud variables."); - return (int)ExitCodes.BadCloudVariable; + return Task.FromResult((int)ExitCodes.BadCloudVariable); } if (additionalVariables.ContainsKey(split[0])) { Console.Error.WriteLine($"Cloud build variable \"{split[0]}\" specified more than once."); - return (int)ExitCodes.DuplicateCloudVariable; + return Task.FromResult((int)ExitCodes.DuplicateCloudVariable); } additionalVariables[split[0]] = split[1]; @@ -650,35 +672,35 @@ private static int OnCloudCommand(string project, IReadOnlyList metadata switch (ex.Error) { case CloudCommand.CloudCommandError.NoCloudBuildProviderMatch: - return (int)ExitCodes.NoCloudBuildProviderMatch; + return Task.FromResult((int)ExitCodes.NoCloudBuildProviderMatch); case CloudCommand.CloudCommandError.DuplicateCloudVariable: - return (int)ExitCodes.DuplicateCloudVariable; + return Task.FromResult((int)ExitCodes.DuplicateCloudVariable); case CloudCommand.CloudCommandError.NoCloudBuildEnvDetected: - return (int)ExitCodes.NoCloudBuildEnvDetected; + return Task.FromResult((int)ExitCodes.NoCloudBuildEnvDetected); default: Report.Fail($"{nameof(CloudCommand.CloudCommandError)}: {ex.Error}"); - return -1; + return Task.FromResult(-1); } } - return (int)ExitCodes.OK; + return Task.FromResult((int)ExitCodes.OK); } - private static int OnPrepareReleaseCommand(string project, string nextVersion, string versionIncrement, string format, string tag) + private static Task OnPrepareReleaseCommand(string project, string nextVersion, string versionIncrement, string format, string tag) { // validate project path property string searchPath = GetSpecifiedOrCurrentDirectoryPath(project); if (!Directory.Exists(searchPath)) { Console.Error.WriteLine($"\"{searchPath}\" is not an existing directory."); - return (int)ExitCodes.NoGitRepo; + return Task.FromResult((int)ExitCodes.NoGitRepo); } // nextVersion and versionIncrement parameters cannot be combined if (!string.IsNullOrEmpty(nextVersion) && !string.IsNullOrEmpty(versionIncrement)) { Console.Error.WriteLine("Options 'nextVersion' and 'versionIncrement' cannot be used at the same time."); - return (int)ExitCodes.InvalidParameters; + return Task.FromResult((int)ExitCodes.InvalidParameters); } // parse versionIncrement if parameter was specified @@ -688,7 +710,7 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s if (!Enum.TryParse(versionIncrement, true, out VersionOptions.ReleaseVersionIncrement parsed)) { Console.Error.WriteLine($"\"{versionIncrement}\" is not a valid version increment"); - return (int)ExitCodes.InvalidVersionIncrement; + return Task.FromResult((int)ExitCodes.InvalidVersionIncrement); } versionIncrementParsed = parsed; @@ -701,7 +723,7 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s if (!Version.TryParse(nextVersion, out nextVersionParsed)) { Console.Error.WriteLine($"\"{nextVersion}\" is not a valid version spec."); - return (int)ExitCodes.InvalidVersionSpec; + return Task.FromResult((int)ExitCodes.InvalidVersionSpec); } } @@ -714,7 +736,7 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s if (!Enum.TryParse(format, true, out ReleaseManager.ReleaseManagerOutputMode outputMode)) { Console.Error.WriteLine($"Unsupported format: {format}"); - return (int)ExitCodes.UnsupportedFormat; + return Task.FromResult((int)ExitCodes.UnsupportedFormat); } // run prepare-release @@ -722,7 +744,7 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s { var releaseManager = new ReleaseManager(Console.Out, Console.Error); releaseManager.PrepareRelease(searchPath, tag, nextVersionParsed, versionIncrementParsed, outputMode); - return (int)ExitCodes.OK; + return Task.FromResult((int)ExitCodes.OK); } catch (ReleaseManager.ReleasePreparationException ex) { @@ -730,27 +752,27 @@ private static int OnPrepareReleaseCommand(string project, string nextVersion, s switch (ex.Error) { case ReleaseManager.ReleasePreparationError.NoGitRepo: - return (int)ExitCodes.NoGitRepo; + return Task.FromResult((int)ExitCodes.NoGitRepo); case ReleaseManager.ReleasePreparationError.UncommittedChanges: - return (int)ExitCodes.UncommittedChanges; + return Task.FromResult((int)ExitCodes.UncommittedChanges); case ReleaseManager.ReleasePreparationError.InvalidBranchNameSetting: - return (int)ExitCodes.InvalidBranchNameSetting; + return Task.FromResult((int)ExitCodes.InvalidBranchNameSetting); case ReleaseManager.ReleasePreparationError.NoVersionFile: - return (int)ExitCodes.NoVersionJsonFound; + return Task.FromResult((int)ExitCodes.NoVersionJsonFound); case ReleaseManager.ReleasePreparationError.VersionDecrement: case ReleaseManager.ReleasePreparationError.NoVersionIncrement: - return (int)ExitCodes.InvalidVersionSpec; + return Task.FromResult((int)ExitCodes.InvalidVersionSpec); case ReleaseManager.ReleasePreparationError.BranchAlreadyExists: - return (int)ExitCodes.BranchAlreadyExists; + return Task.FromResult((int)ExitCodes.BranchAlreadyExists); case ReleaseManager.ReleasePreparationError.UserNotConfigured: - return (int)ExitCodes.UserNotConfigured; + return Task.FromResult((int)ExitCodes.UserNotConfigured); case ReleaseManager.ReleasePreparationError.DetachedHead: - return (int)ExitCodes.DetachedHead; + return Task.FromResult((int)ExitCodes.DetachedHead); case ReleaseManager.ReleasePreparationError.InvalidVersionIncrementSetting: - return (int)ExitCodes.InvalidVersionIncrementSetting; + return Task.FromResult((int)ExitCodes.InvalidVersionIncrementSetting); default: Report.Fail($"{nameof(ReleaseManager.ReleasePreparationError)}: {ex.Error}"); - return -1; + return Task.FromResult(-1); } } } From 6d240be921a071b8e920fc71837eb90125ace72a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 17:05:32 +0000 Subject: [PATCH 563/704] Bump Microsoft.CodeAnalysis.CSharp from 4.1.0 to 4.3.0 (#806) --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 3ea29de5..df8b63a1 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -36,7 +36,7 @@ - + From 3a368c7d66d617bc22762e3573f05cbc7058c5fc Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 5 Sep 2022 11:22:06 -0600 Subject: [PATCH 564/704] Consolidate BenchmarkDotNet versions into one property This should allow dependabot to upgrade these with a PR that actually validates. --- .../Nerdbank.GitVersioning.Benchmarks.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index bda92426..b6cd5b6f 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -7,11 +7,12 @@ true AnyCPU false + 0.13.1 - - + + From 21077e6e64e3dbc459c846a6af3d074871c038c3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 11:57:26 -0600 Subject: [PATCH 565/704] Bump BenchmarkDotNetVersion from 0.13.1 to 0.13.2 (#812) * Bump BenchmarkDotNetVersion from 0.13.1 to 0.13.2 Bumps `BenchmarkDotNetVersion` from 0.13.1 to 0.13.2. Updates `BenchmarkDotNet` from 0.13.1 to 0.13.2 - [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases) - [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.1...v0.13.2) Updates `BenchmarkDotNet.Diagnostics.Windows` from 0.13.1 to 0.13.2 - [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases) - [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.1...v0.13.2) --- updated-dependencies: - dependency-name: BenchmarkDotNet dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: BenchmarkDotNet.Diagnostics.Windows dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] * Trust another package author Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Arnott --- nuget.config | 2 +- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nuget.config b/nuget.config index 59b20b03..e61343aa 100644 --- a/nuget.config +++ b/nuget.config @@ -15,7 +15,7 @@ - Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer;Thecentury;sharwell;dotnetfoundation + Microsoft;aarnott;xunit;kzu;castleproject;patrickb8man;jamesnk;ethomson;AndreyAkinshin;MarcoRossignoli;cake-build;ericnewton76;0xd4d;manuel.roemer;Thecentury;sharwell;dotnetfoundation;wtfsck diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index b6cd5b6f..f1a27424 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -7,7 +7,7 @@ true AnyCPU false - 0.13.1 + 0.13.2 From 400f0da4f48afd87277b096f357bbbd383637c55 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Sep 2022 18:02:43 +0000 Subject: [PATCH 566/704] Bump Cake.Core from 1.1.0 to 2.2.0 (#770) * Bump Cake.Core from 1.1.0 to 2.2.0 Bumps [Cake.Core](https://github.com/cake-build/cake) from 1.1.0 to 2.2.0. - [Release notes](https://github.com/cake-build/cake/releases) - [Changelog](https://github.com/cake-build/cake/blob/develop/ReleaseNotes.md) - [Commits](https://github.com/cake-build/cake/compare/v1.1.0...v2.2.0) --- updated-dependencies: - dependency-name: Cake.Core dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] * Fix Cake build * Fix TFM * Fix pack error Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Andrew Arnott --- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 16 ++++++++-------- .../Cake.GitVersioning.Tests.csproj | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 63096476..8ba3f177 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -1,7 +1,7 @@  - netstandard2.0 + netcoreapp3.1 true Chris Crutchfield, Andrew Arnott andarno @@ -28,7 +28,7 @@ - + @@ -37,14 +37,14 @@ - + - - - - - + + + + + diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 4930a607..9e8814b2 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -1,7 +1,7 @@ - net6.0;net461 + netcoreapp3.1;net6.0 false true false From e16106d6686cf153c57064d2d55b77a9484f29d6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 6 Sep 2022 13:38:06 -0600 Subject: [PATCH 567/704] Update doc links --- CONTRIBUTING.md | 4 ++-- README.md | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 36424c42..e56631dd 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -25,7 +25,7 @@ You should install the version specified in `global.json` or a later version wit the same major.minor.Bxx "hundreds" band. For example if 2.2.300 is specified, you may install 2.2.300, 2.2.301, or 2.2.310 while the 2.2.400 version would not be considered compatible by .NET SDK. -See [.NET Core Versioning](https://docs.microsoft.com/en-us/dotnet/core/versions/) for more information. +See [.NET Core Versioning](https://docs.microsoft.com/dotnet/core/versions/) for more information. ## Package restore @@ -39,4 +39,4 @@ This repository can be built on Windows, Linux, and OSX. Building, testing, and packing this repository can be done by using the standard dotnet CLI commands (e.g. `dotnet build`, `dotnet test`, `dotnet pack`, etc.). -[pwsh]: https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell?view=powershell-6 +[pwsh]: https://docs.microsoft.com/powershell/scripting/install/installing-powershell?view=powershell-6 diff --git a/README.md b/README.md index d3b5acf0..33ddbfab 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ * Follow the best and simplest patterns of build, pack and test with dotnet CLI. * Init script that installs prerequisites and auth helpers, supporting both non-elevation and elevation modes. -* Static analyzers: [FxCop](https://docs.microsoft.com/en-us/visualstudio/code-quality/fxcop-analyzers?view=vs-2019) and [StyleCop](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) +* Static analyzers: default [Code Analysis](https://docs.microsoft.com/dotnet/fundamentals/code-analysis/overview) and [StyleCop](https://github.com/DotNetAnalyzers/StyleCopAnalyzers) * Read-only source tree (builds to top-level bin/obj folders) * Auto-versioning (via [Nerdbank.GitVersioning](https://github.com/dotnet/nerdbank.gitversioning)) * Builds with a "pinned" .NET Core SDK to ensure reproducible builds across machines and across time. From b73d62cfd3b2a8dff97fb924bbaa916cb420596f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 7 Sep 2022 13:33:32 -0600 Subject: [PATCH 568/704] Publish OSS security policy --- SECURITY.md | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 SECURITY.md diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..b35d55b5 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,32 @@ +# Security + +The maintainers of this project take security seriously, and the reporting of potential security issues. If you believe you have found a security vulnerability in code from this repository that meets [Microsoft's definition of a security vulnerability](https://docs.microsoft.com/previous-versions/tn-archive/cc751383(v=technet.10)), please report it to us as described below. + +We are using Microsoft's vulnerability definition as it is public and familiar to .NET users. + +## Reporting Security Issues + +**Please do not report security vulnerabilities through public GitHub issues.** + +Instead, please report them to the project maintainers using [keybase](https://keybase.io/aarnott) or [email](mailto:andrewarnott@live.com?subject=OSS%20project%20vulnerability). +You will typically receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. + +Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue: + +* Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) +* Full paths of source file(s) related to the manifestation of the issue +* The location of the affected source code (tag/branch/commit or direct URL) +* Any special configuration required to reproduce the issue +* Step-by-step instructions to reproduce the issue +* Proof-of-concept or exploit code (if possible) +* Impact of the issue, including how an attacker might exploit the issue + +This information will help us triage your report more quickly. + +## Preferred Languages + +We prefer all communications to be in English. + +## Policy + +This project follows the [GitHub CVD process](https://github.blog/2022-02-09-coordinated-vulnerability-disclosure-cvd-open-source-projects/) and will use [GHSA](https://docs.github.com/code-security/security-advisories/about-github-security-advisories) to manage discussion of the vulnerability and fixes, and create a public CVE advisory through github if applicable. From 5d14d2cecbb3fd3caa6a421da1525d8480baef8b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 13 Sep 2022 09:47:18 -0600 Subject: [PATCH 569/704] Force non-shallow clones Fixes issue 176 --- azure-pipelines/build.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index cb489949..23b31221 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -13,6 +13,7 @@ jobs: pool: ${{ parameters.windowsPool }} steps: - checkout: self + fetchDepth: 0 # avoid shallow clone so nbgv can do its work. clean: true - template: install-dependencies.yml @@ -29,6 +30,7 @@ jobs: vmImage: Ubuntu 20.04 steps: - checkout: self + fetchDepth: 0 # avoid shallow clone so nbgv can do its work. clean: true - template: install-dependencies.yml - template: dotnet.yml @@ -42,6 +44,7 @@ jobs: vmImage: macOS-10.15 steps: - checkout: self + fetchDepth: 0 # avoid shallow clone so nbgv can do its work. clean: true - template: install-dependencies.yml - template: dotnet.yml @@ -58,6 +61,7 @@ jobs: condition: succeededOrFailed() steps: - checkout: self + fetchDepth: 0 # avoid shallow clone so nbgv can do its work. clean: true - template: install-dependencies.yml parameters: From efc3b4c6f005530d0576d79f16ae93b3bb62d512 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 13 Sep 2022 10:00:13 -0600 Subject: [PATCH 570/704] Document non-shallow cloning step for Azure Pipelines --- doc/cloudbuild.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/doc/cloudbuild.md b/doc/cloudbuild.md index 9230c4c0..d4746331 100644 --- a/doc/cloudbuild.md +++ b/doc/cloudbuild.md @@ -22,6 +22,22 @@ But `actions/checkout@v2` checks out a shallow clone by default, so you'll have fetch-depth: 0 # avoid shallow clone so nbgv can do its work. ``` +### Azure Pipelines + +[Azure Pipelines behavior has changed][AzpDepthChange] for *new* pipelines created after around Jan 2022 +such that build agents now default to creating shallow clones. +You can defeat this, thereby forcing a full history clone by adding this to the top of your `steps` list: + +```yml +steps: +- checkout: self + fetchDepth: 0 +``` + +In particular, setting `fetchDepth: 0` will cause Azure Pipelines to *not* do shallow clones. + +See this [example change](https://github.com/AArnott/Library.Template/commit/5d14d2cecbb3fd3caa6a421da1525d8480baef8b). + ## Optional features By specifying certain `cloudBuild` options in your `version.json` file, @@ -177,3 +193,4 @@ When building inside a docker container, special considerations may apply: When using `docker run` yourself in your build script, you can add `--env BUILD_SOURCEBRANCH --env SYSTEM_TEAMPROJECTID` to your command line to pass-through those environment variables to your container. [Issue37]: https://github.com/dotnet/Nerdbank.GitVersioning/issues/37 +[AzpDepthChange]: https://github.com/MicrosoftDocs/azure-devops-yaml-schema/issues/32 From 34f4c9f3058c9757647f61869bd7f226a32b7d14 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 13 Sep 2022 10:56:39 -0600 Subject: [PATCH 571/704] Switch to using dotnet-coverage Now that the merge bug has been fixed, this should provide a better report than `dotnet-reportgenerator-globaltool` because methods with `#if` blocks will now still be merged in the report instead of being listed multiple times. --- azure-pipelines/Merge-CodeCoverage.ps1 | 15 ++++++++++----- azure-pipelines/publish-codecoverage.yml | 4 ++-- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1 index 91ab67ab..9fe925cf 100644 --- a/azure-pipelines/Merge-CodeCoverage.ps1 +++ b/azure-pipelines/Merge-CodeCoverage.ps1 @@ -16,13 +16,13 @@ Param( [string[]]$Path, [ValidateSet('Badges', 'Clover', 'Cobertura', 'CsvSummary', 'Html', 'Html_Dark', 'Html_Light', 'HtmlChart', 'HtmlInline', 'HtmlInline_AzurePipelines', 'HtmlInline_AzurePipelines_Dark', 'HtmlInline_AzurePipelines_Light', 'HtmlSummary', 'JsonSummary', 'Latex', 'LatexSummary', 'lcov', 'MarkdownSummary', 'MHtml', 'PngChart', 'SonarQube', 'TeamCitySummary', 'TextSummary', 'Xml', 'XmlSummary')] [string]$Format='Cobertura', - [string]$OutputDir=("$PSScriptRoot/../coveragereport") + [string]$OutputFile=("$PSScriptRoot/../coveragereport/merged.cobertura.xml") ) $RepoRoot = [string](Resolve-Path $PSScriptRoot/..) -if (!(Test-Path $RepoRoot/obj/reportgenerator*)) { - dotnet tool install --tool-path $RepoRoot/obj dotnet-reportgenerator-globaltool --version 5.1.9 --configfile $PSScriptRoot/justnugetorg.nuget.config +if (!(Test-Path $RepoRoot/obj/dotnet-coverage*)) { + dotnet tool install --tool-path $RepoRoot/obj dotnet-coverage --version 17.4.3 --configfile $PSScriptRoot/justnugetorg.nuget.config } Write-Verbose "Searching $Path for *.cobertura.xml files" @@ -39,8 +39,13 @@ if ($reports) { $xml.Save($_) } - $Inputs = [string]::join(';', ($reports |% { Resolve-Path -relative $_.FullName })) - & "$RepoRoot/obj/reportgenerator" -reports:"$Inputs" -targetdir:$OutputDir -reporttypes:$Format + $Inputs = $reports |% { Resolve-Path -relative $_.FullName } + + if (Split-Path $OutputFile) { + New-Item -Type Directory -Path (Split-Path $OutputFile) | Out-Null + } + + & "$RepoRoot/obj/dotnet-coverage" merge $Inputs -o $OutputFile -f cobertura } else { Write-Error "No reports found to merge." } diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml index 11de8ffa..fbb6a39a 100644 --- a/azure-pipelines/publish-codecoverage.yml +++ b/azure-pipelines/publish-codecoverage.yml @@ -15,11 +15,11 @@ steps: displayName: 🔻 Download macOS code coverage results continueOnError: true condition: and(succeeded(), ${{ parameters.includeMacOS }}) -- powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputDir coveragereport -Format Cobertura -Verbose +- powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputFile coveragereport/merged.cobertura.xml -Format Cobertura -Verbose displayName: ⚙ Merge coverage - task: PublishCodeCoverageResults@1 displayName: 📢 Publish code coverage results to Azure DevOps inputs: codeCoverageTool: cobertura - summaryFileLocation: coveragereport/Cobertura.xml + summaryFileLocation: coveragereport/merged.cobertura.xml failIfCoverageEmpty: true From 16f2a9a766f476d402fb4ba5ffa491b8f9df7661 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 14 Sep 2022 09:41:37 -0600 Subject: [PATCH 572/704] Update NuGetAuthenticate task version --- azure-pipelines/install-dependencies.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 3993f104..81782668 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -3,7 +3,7 @@ parameters: steps: -- task: NuGetAuthenticate@0 +- task: NuGetAuthenticate@1 displayName: 🔏 Authenticate NuGet feeds inputs: forceReinstallCredentialProvider: true From 292694b529ef31e4936b80a07aa5f5391fe9bf00 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 19 Sep 2022 21:03:37 -0600 Subject: [PATCH 573/704] Fix `Stream.Seek` implementations to reliably shift position as required The bug is that `Stream.Read` was assumed to always fill the provided buffer, but in fact only a non-zero movement is contractually guaranteed. --- .../ManagedGit/GitPackDeltafiedStream.cs | 6 +---- .../ManagedGit/GitPackMemoryCacheStream.cs | 8 ++---- .../ManagedGit/StreamExtensions.cs | 27 +++++++++++++++++++ .../ManagedGit/ZLibStream.cs | 6 +---- 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs index 9b73a7bb..3dae2a4d 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackDeltafiedStream.cs @@ -135,11 +135,7 @@ public override long Seek(long offset, SeekOrigin origin) if (origin == SeekOrigin.Begin && offset > this.position) { // We can optimise this by skipping over instructions rather than executing them - int length = (int)(offset - this.position); - - byte[] buffer = ArrayPool.Shared.Rent(length); - this.Read(buffer, 0, length); - ArrayPool.Shared.Return(buffer); + this.ReadExactly(checked((int)(offset - this.position))); return this.position; } else diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs index 66fa2f04..4b0a9191 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackMemoryCacheStream.cs @@ -73,13 +73,9 @@ public override long Seek(long offset, SeekOrigin origin) if (offset > this.cacheStream.Length) { - var toRead = (int)(offset - this.cacheStream.Length); - byte[] buffer = ArrayPool.Shared.Rent(toRead); - int read = this.stream.Read(buffer, 0, toRead); this.cacheStream.Seek(0, SeekOrigin.End); - this.cacheStream.Write(buffer, 0, read); - ArrayPool.Shared.Return(buffer); - + int toRead = (int)(offset - this.cacheStream.Length); + this.stream.ReadExactly(toRead, this.cacheStream); this.DisposeStreamIfRead(); return this.cacheStream.Position; } diff --git a/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs b/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs index 550431c8..df84ebdd 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/StreamExtensions.cs @@ -150,5 +150,32 @@ internal static bool TryAdd(this System.Collections.Generic.IDicti return true; } #endif + + /// + /// Reads the specified number of bytes from a stream, or until the end of the stream. + /// + /// The stream to read from. + /// The number of bytes to be read. + /// The stream to copy the read bytes to, if required. + /// The number of bytes actually read. This will be less than only if the end of is reached. + internal static int ReadExactly(this Stream readFrom, int length, Stream? copyTo = null) + { + int bytesRemaining = length; + byte[] buffer = ArrayPool.Shared.Rent(Math.Min(50 * 1024, bytesRemaining)); + while (bytesRemaining > 0) + { + int read = readFrom.Read(buffer, 0, Math.Min(buffer.Length, bytesRemaining)); + if (read == 0) + { + break; + } + + copyTo?.Write(buffer, 0, read); + bytesRemaining -= read; + } + + ArrayPool.Shared.Return(buffer); + return length - bytesRemaining; + } } } diff --git a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs index 4a350e30..d09e0b34 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/ZLibStream.cs @@ -151,11 +151,7 @@ public override long Seek(long offset, SeekOrigin origin) if (origin == SeekOrigin.Begin && offset > this.position) { // We may be able to optimize this by skipping over the compressed data - int length = (int)(offset - this.position); - - byte[] buffer = ArrayPool.Shared.Rent(length); - this.Read(buffer, 0, length); - ArrayPool.Shared.Return(buffer); + this.ReadExactly(checked((int)(offset - this.position))); return this.position; } else From 448dd8c1d0fbbd91960069404eb2e1507102f949 Mon Sep 17 00:00:00 2001 From: Marcin Krystianc Date: Tue, 20 Sep 2022 12:48:31 +0200 Subject: [PATCH 574/704] DeltaStreamReader should interpret 0 size as 0x10000 https://git-scm.com/docs/pack-format/2.31.0#_instruction_to_copy_from_base_object: "In its most compact form, this instruction only takes up one byte (0x80) with both offset and size omitted, which will have default values zero. There is another exception: size zero is automatically converted to 0x10000." --- src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs b/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs index 08ee301e..a23020a9 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/DeltaStreamReader.cs @@ -84,6 +84,12 @@ public static class DeltaStreamReader { value.Size |= ((byte)stream.ReadByte() << 16); } + + // Size zero is automatically converted to 0x10000. + if (value.Size == 0) + { + value.Size = 0x10000; + } } return value; From bb04eec825ce72b67892f9d0d636232ac2ad8f3d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 20 Sep 2022 12:13:48 -0600 Subject: [PATCH 575/704] Add GetTargetPath target for SqlServer projects Fixes #820 --- .../build/PrivateP2PCaching.proj | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 135de8e6..1beb338f 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -22,15 +22,18 @@ - + - + - + + + + From 12bda8587b4e368ff2417711f6c2d29928c00b12 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 20 Sep 2022 17:21:42 -0600 Subject: [PATCH 576/704] Update macOS agent to OS12 --- azure-pipelines/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 23b31221..c8687859 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -41,7 +41,7 @@ jobs: - job: macOS condition: ${{ parameters.includeMacOS }} pool: - vmImage: macOS-10.15 + vmImage: macOS-12 steps: - checkout: self fetchDepth: 0 # avoid shallow clone so nbgv can do its work. From 34412f06a0e3a69eed70eedd8e8323d75e2d338b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 21 Sep 2022 10:36:48 -0600 Subject: [PATCH 577/704] Add more analyzers --- .editorconfig | 9 +++++++++ Directory.Build.props | 2 ++ 2 files changed, 11 insertions(+) diff --git a/.editorconfig b/.editorconfig index 0d75b34a..c8b5de9a 100644 --- a/.editorconfig +++ b/.editorconfig @@ -167,5 +167,14 @@ dotnet_diagnostic.SA1130.severity = silent # IDE1006: Naming Styles - StyleCop handles these for us dotnet_diagnostic.IDE1006.severity = none +dotnet_diagnostic.DOC100.severity = silent +dotnet_diagnostic.DOC104.severity = warning +dotnet_diagnostic.DOC105.severity = warning +dotnet_diagnostic.DOC106.severity = warning +dotnet_diagnostic.DOC107.severity = warning +dotnet_diagnostic.DOC108.severity = warning +dotnet_diagnostic.DOC200.severity = warning +dotnet_diagnostic.DOC202.severity = warning + [*.sln] indent_style = tab diff --git a/Directory.Build.props b/Directory.Build.props index 35f7d62a..f13158c0 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -41,6 +41,8 @@ + + From 503fbf99f418a1a87670ea049c87560bba549836 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 21 Sep 2022 10:43:08 -0600 Subject: [PATCH 578/704] Fix doc issues found by new analyzers --- src/NerdBank.GitVersioning/CloudBuild.cs | 2 +- .../LibGit2/LibGit2Context.cs | 8 ++++---- .../LibGit2/LibGit2GitExtensions.cs | 10 +++++----- .../Managed/GitExtensions.cs | 6 +++--- src/NerdBank.GitVersioning/ReleaseManager.cs | 8 ++++---- src/NerdBank.GitVersioning/SemanticVersion.cs | 10 +++++----- src/NerdBank.GitVersioning/VersionFile.cs | 6 +++--- src/NerdBank.GitVersioning/VersionOptions.cs | 14 +++++++------- src/NerdBank.GitVersioning/VersionOracle.cs | 8 ++++---- src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs | 2 +- 10 files changed, 37 insertions(+), 37 deletions(-) diff --git a/src/NerdBank.GitVersioning/CloudBuild.cs b/src/NerdBank.GitVersioning/CloudBuild.cs index 71002d8f..0c7c8a25 100644 --- a/src/NerdBank.GitVersioning/CloudBuild.cs +++ b/src/NerdBank.GitVersioning/CloudBuild.cs @@ -52,6 +52,6 @@ internal static string ShouldStartWith(string value, string prefix) /// /// The value to return. /// The prefix to check for. - /// if it starts with ; otherwise null. + /// if it starts with ; otherwise . internal static string IfStartsWith(string value, string prefix) => value is object && value.StartsWith(prefix, StringComparison.Ordinal) ? value : null; } diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs index 583d4cd1..1aa804c1 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2Context.cs @@ -101,16 +101,16 @@ public override bool TrySelectCommit(string committish) /// /// Specifies whether to use default settings for looking up global and system settings. /// - /// By default ( == false), the repository will be configured to only + /// By default ( == ), the repository will be configured to only /// use the repository-level configuration ignoring system or user-level configuration (set using git config --global. /// Thus only settings explicitly set for the repo will be available. /// /// /// For example using Repository.Configuration.Get{string}("user.name") to get the user's name will - /// return the value set in the repository config or null if the user name has not been explicitly set for the repository. + /// return the value set in the repository config or if the user name has not been explicitly set for the repository. /// /// - /// When the caller specifies to use the default configuration search paths ( == true) + /// When the caller specifies to use the default configuration search paths ( == ) /// both repository level and global configuration will be available to the repo as well. /// /// @@ -119,7 +119,7 @@ public override bool TrySelectCommit(string committish) /// matching the behavior of the git command. /// /// - /// The found for the specified path, or null if no git repo is found. + /// The found for the specified path, or if no git repo is found. internal static Repository OpenGitRepo(string path, bool useDefaultConfigSearchPaths = false) { if (useDefaultConfigSearchPaths) diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 09b2438b..4c65d76d 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -47,7 +47,7 @@ public static class LibGit2GitExtensions /// /// The git context to read from. /// - /// A function that returns false when we reach a commit that + /// A function that returns when we reach a commit that /// should not be included in the height calculation. /// May be null to count the height to the original commit. /// @@ -76,7 +76,7 @@ public static ushort GetTruncatedCommitIdAsUInt16(this Commit commit) /// /// The git context to read from. /// The version previously obtained from . - /// The matching commit, or null if no match is found. + /// The matching commit, or if no match is found. /// /// Thrown in the very rare situation that more than one matching commit is found. /// @@ -245,7 +245,7 @@ private static IRepository GetRepository(this IBelongToARepository repositoryMem /// The version to test for in the commit. /// The last component of the version to include in the comparison. /// The caching tracker for storing or fetching version information per commit. - /// true if the matches the major and minor components of . + /// if the matches the major and minor components of . private static bool CommitMatchesVersion(this Commit commit, SemanticVersion expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) { Requires.NotNull(commit, nameof(commit)); @@ -274,7 +274,7 @@ private static bool CommitMatchesVersion(this Commit commit, SemanticVersion exp /// The version to test for in the commit. /// The last component of the version to include in the comparison. /// The caching tracker for storing or fetching version information per commit. - /// true if the matches the major and minor components of . + /// if the matches the major and minor components of . private static bool CommitMatchesVersion(this Commit commit, Version expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) { Requires.NotNull(commit, nameof(commit)); @@ -393,7 +393,7 @@ private static string EncodeAsHex(byte[] buffer) /// The commit to measure the height of. /// The caching tracker for storing or fetching version information per commit. /// - /// A function that returns false when we reach a commit that + /// A function that returns when we reach a commit that /// should not be included in the height calculation. /// May be null to count the height to the original commit. /// diff --git a/src/NerdBank.GitVersioning/Managed/GitExtensions.cs b/src/NerdBank.GitVersioning/Managed/GitExtensions.cs index 6d97eee0..173ffaf3 100644 --- a/src/NerdBank.GitVersioning/Managed/GitExtensions.cs +++ b/src/NerdBank.GitVersioning/Managed/GitExtensions.cs @@ -21,7 +21,7 @@ internal static class GitExtensions /// /// The git context. /// - /// A function that returns false when we reach a commit that + /// A function that returns when we reach a commit that /// should not be included in the height calculation. /// May be null to count the height to the original commit. /// @@ -89,7 +89,7 @@ internal static int GetVersionHeight(ManagedGitContext context, Version? baseVer /// The commit to measure the height of. /// The caching tracker for storing or fetching version information per commit. /// - /// A function that returns false when we reach a commit that + /// A function that returns when we reach a commit that /// should not be included in the height calculation. /// May be null to count the height to the original commit. /// @@ -286,7 +286,7 @@ private static bool IsRelevantCommit(GitRepository repository, GitTree tree, Git /// The version to test for in the commit. /// The last component of the version to include in the comparison. /// The caching tracker for storing or fetching version information per commit. - /// true if the matches the major and minor components of . + /// if the matches the major and minor components of . private static bool CommitMatchesVersion(GitCommit commit, SemanticVersion expectedVersion, SemanticVersion.Position comparisonPrecision, GitWalkTracker tracker) { Requires.NotNull(expectedVersion, nameof(expectedVersion)); diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index 594a728c..d6fd752a 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -111,12 +111,12 @@ public enum ReleaseManagerOutputMode /// The path to the directory which may (or its ancestors may) define the version file. /// /// - /// The prerelease tag to add to the version on the release branch. Pass null to omit/remove the prerelease tag. + /// The prerelease tag to add to the version on the release branch. Pass to omit/remove the prerelease tag. /// The leading hyphen may be specified or omitted. /// /// - /// The next version to save to the version file on the current branch. Pass null to automatically determine the next - /// version based on the current version and the versionIncrement setting in version.json. + /// The next version to save to the version file on the current branch. Pass to automatically determine the next + /// version based on the current version and the setting in version.json. /// Parameter will be ignored if the current branch is a release branch. /// /// @@ -440,7 +440,7 @@ public ReleaseInfo(ReleaseBranchInfo currentBranch, ReleaseBranchInfo newBranch) /// Gets information on the new branch created by . /// /// - /// Information on the newly created branch as instance of or null, if no new branch was created. + /// Information on the newly created branch as instance of or , if no new branch was created. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Include)] public ReleaseBranchInfo NewBranch { get; } diff --git a/src/NerdBank.GitVersioning/SemanticVersion.cs b/src/NerdBank.GitVersioning/SemanticVersion.cs index dc267302..572a54b3 100644 --- a/src/NerdBank.GitVersioning/SemanticVersion.cs +++ b/src/NerdBank.GitVersioning/SemanticVersion.cs @@ -191,7 +191,7 @@ internal SemanticVersion.Position? GitCommitIdPosition /// /// The value which must wholly constitute a semantic version to succeed. /// Receives the semantic version, if found. - /// true if a semantic version is found; false otherwise. + /// if a semantic version is found; otherwise. public static bool TryParse(string semanticVersion, out SemanticVersion version) { Requires.NotNullOrEmpty(semanticVersion, nameof(semanticVersion)); @@ -232,7 +232,7 @@ public static SemanticVersion Parse(string semanticVersion) /// Checks equality against another object. /// /// The other instance. - /// true if the instances have equal values; false otherwise. + /// if the instances have equal values; otherwise. public override bool Equals(object obj) { return this.Equals(obj as SemanticVersion); @@ -260,7 +260,7 @@ public override string ToString() /// Checks equality against another instance of this class. /// /// The other instance. - /// true if the instances have equal values; false otherwise. + /// if the instances have equal values; otherwise. public bool Equals(SemanticVersion other) { if (other is null) @@ -280,7 +280,7 @@ public bool Equals(SemanticVersion other) /// The first semantic version. /// The second semantic version. /// The position within the version where height is tracked. - /// true if transitioning from one version to the next should reset the version height; false otherwise. + /// if transitioning from one version to the next should reset the version height; otherwise. internal static bool WillVersionChangeResetVersionHeight(SemanticVersion first, SemanticVersion second, SemanticVersion.Position versionHeightPosition) { Requires.NotNull(first, nameof(first)); @@ -355,7 +355,7 @@ internal bool IsMatchingVersion(Version version) /// belongs to the set of versions represented by this semantic version spec. /// /// A version, with major and minor components, and possibly build and/or revision components. - /// true if may have been produced by this semantic version; false otherwise. + /// if may have been produced by this semantic version; otherwise. internal bool Contains(Version version) { return diff --git a/src/NerdBank.GitVersioning/VersionFile.cs b/src/NerdBank.GitVersioning/VersionFile.cs index 0d3b85f3..90347d50 100644 --- a/src/NerdBank.GitVersioning/VersionFile.cs +++ b/src/NerdBank.GitVersioning/VersionFile.cs @@ -40,7 +40,7 @@ protected VersionFile(GitContext context) /// /// Checks whether a version file is defined. /// - /// true if the version file is found; otherwise false. + /// if the version file is found; otherwise . public bool IsVersionDefined() => this.GetVersion() is object; /// @@ -50,7 +50,7 @@ protected VersionFile(GitContext context) /// Reads the version file from the working tree and returns the deserialized from it. /// /// Set to the actual directory that the version file was found in, which may be or one of its ancestors. - /// The version information read from the file, or null if the file wasn't found. + /// The version information read from the file, or if the file wasn't found. public VersionOptions? GetWorkingCopyVersion(out string? actualDirectory) => this.GetWorkingCopyVersion(this.Context.AbsoluteProjectDirectory, out actualDirectory); /// @@ -144,7 +144,7 @@ public string SetVersion(string projectDirectory, VersionOptions version, bool i /// Reads the version.txt file and returns the and prerelease tag from it. /// /// The content of the version.txt file to read. - /// The version information read from the file; or null if a deserialization error occurs. + /// The version information read from the file; or if a deserialization error occurs. protected static VersionOptions TryReadVersionFile(TextReader versionTextContent) { string? versionLine = versionTextContent.ReadLine(); diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index 501a8868..b631b39e 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -260,7 +260,7 @@ public SemanticVersion? Version /// Gets or sets the version to use particularly for the /// instead of the default . /// - /// An instance of or null to simply use the default . + /// An instance of or to simply use the default . [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public AssemblyVersionOptions? AssemblyVersion { @@ -271,7 +271,7 @@ public AssemblyVersionOptions? AssemblyVersion /// /// Gets or sets the prefix for git commit id in version. /// Because of semver rules the prefix must lead with a [A-z_] character (not a number) and it cannot be the empty string. - /// If null 'g' will be used. + /// If 'g' will be used. /// /// A prefix for git commit id. [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] @@ -299,7 +299,7 @@ public string? GitCommitIdPrefix /// Gets the version to use particularly for the /// instead of the default . /// - /// An instance of or null to simply use the default . + /// An instance of or to simply use the default . [JsonIgnore] public AssemblyVersionOptions AssemblyVersionOrDefault => this.AssemblyVersion ?? AssemblyVersionOptions.DefaultInstance; @@ -488,7 +488,7 @@ public IReadOnlyList? PathFilters /// Gets or sets a value indicating whether this options object should inherit from an ancestor any settings that are not explicitly set in this one. /// /// - /// When this is true, this object may not completely describe the options to be applied. + /// When this is , this object may not completely describe the options to be applied. /// [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] public bool Inherit @@ -583,7 +583,7 @@ public static VersionOptions FromVersion(Version version, string? unstableTag = /// filters should be relative to. /// This should be the directory where the version.json file resides. /// An empty string represents the root of the repository. - /// Passing null will mean path filters cannot be serialized. + /// Passing will mean path filters cannot be serialized. /// /// The serializer settings to use. public static JsonSerializerSettings GetJsonSettings(bool includeDefaults = false, bool includeSchemaProperty = false, string? repoRelativeBaseDirectory = null) @@ -611,7 +611,7 @@ public static JsonSerializerSettings GetJsonSettings(bool includeDefaults = fals /// Checks equality against another object. /// /// The other instance. - /// true if the instances have equal values; false otherwise. + /// if the instances have equal values; otherwise. public override bool Equals(object? obj) { return this.Equals(obj as VersionOptions); @@ -627,7 +627,7 @@ public override bool Equals(object? obj) /// Checks equality against another instance of this class. /// /// The other instance. - /// true if the instances have equal values; false otherwise. + /// if the instances have equal values; otherwise. public bool Equals(VersionOptions? other) => EqualWithDefaultsComparer.Singleton.Equals(this, other); /// diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 23927c71..297da93c 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -369,14 +369,14 @@ public IDictionary CloudBuildVersionVars /// /// Gets a SemVer 1.0 compliant string that represents this version, including the -COMMITID suffix - /// when is false. + /// when is . /// public string SemVer1 => $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersionSemVer1}{this.SemVer1BuildMetadata}"; /// /// Gets a SemVer 2.0 compliant string that represents this version, including a +COMMITID suffix - /// when is false. + /// when is . /// public string SemVer2 => $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersion}{this.SemVer2BuildMetadata}"; @@ -421,7 +421,7 @@ public IDictionary CloudBuildVersionVars /// /// Gets a SemVer 1.0 compliant string that represents this version, including the -gCOMMITID suffix - /// when is false. + /// when is . /// private string NuGetSemVer1 { @@ -440,7 +440,7 @@ private string NuGetSemVer1 /// /// Gets a SemVer 2.0 compliant string that represents this version, including the -gCOMMITID suffix - /// when is false. + /// when is . /// private string NuGetSemVer2 { diff --git a/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs b/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs index 51c86547..04b0d87a 100644 --- a/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs +++ b/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs @@ -53,7 +53,7 @@ public override bool Execute() /// /// The source path. /// The dest path. - /// true if the files are the same; false if the files are different. + /// if the files are the same; if the files are different. internal static bool FastFileEqualityCheck(string sourcePath, string destPath) { FileInfo sourceInfo = new FileInfo(sourcePath); From 549d6460e1981db3e0ef24e51549e16e6fa658e4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 25 Sep 2022 09:07:54 -0600 Subject: [PATCH 579/704] Fix `CompareFiles` task It's a cheap fix, in that it gives up streaming during the compare, but it's far more likely to be accurate than if I tried to maintain streaming while fixing the original bug of assuming that `Stream.Read` will always fill the buffer. Fixes #825 --- .../CompareFiles.cs | 64 ++++--------------- 1 file changed, 11 insertions(+), 53 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs b/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs index aa0a62d7..f32d5485 100644 --- a/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs +++ b/src/Nerdbank.GitVersioning.Tasks/CompareFiles.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.IO; + using System.IO.MemoryMappedFiles; using System.Linq; using System.Text; using Microsoft.Build.Framework; @@ -64,66 +65,23 @@ private bool IsContentOfFilesTheSame(string file1, string file2) if (File.Exists(file1) ^ File.Exists(file2)) return false; // If both are missing, that's the same. if (!File.Exists(file1)) return true; - // If both are present, we need to do a content comparison. - using (FileStream fileStream1 = File.OpenRead(file1)) - { - using (FileStream fileStream2 = File.OpenRead(file2)) - { - if (fileStream1.Length != fileStream2.Length) return false; - byte[] buffer1 = new byte[4096]; - byte[] buffer2 = new byte[buffer1.Length]; - int bytesRead; - do - { - bytesRead = fileStream1.Read(buffer1, 0, buffer1.Length); - if (fileStream2.Read(buffer2, 0, buffer2.Length) != bytesRead) - { - // We should never get here since we compared file lengths, but - // this is a sanity check. - return false; - } - for (int i = 0; i < bytesRead; i++) - { - if (buffer1[i] != buffer2[i]) - { - return false; - } - } - } while (bytesRead == buffer1.Length); - } - } - return true; - } + if (new FileInfo(file1).Length != new FileInfo(file2).Length) return false; - /// - /// Tests whether a file is up to date with respect to another, - /// based on existence, last write time and file size. - /// - /// The source path. - /// The dest path. - /// true if the files are the same; false if the files are different - internal static bool FastFileEqualityCheck(string sourcePath, string destPath) - { - FileInfo sourceInfo = new FileInfo(sourcePath); - FileInfo destInfo = new FileInfo(destPath); + // If both are present, we need to do a content comparison. + // Keep our comparison simple by loading both in memory. + byte[] file1Content = File.ReadAllBytes(file1); + byte[] file2Content = File.ReadAllBytes(file2); - if (sourceInfo.Exists ^ destInfo.Exists) - { - // Either the source file or the destination file is missing. - return false; - } + // One more sanity check. + if (file1Content.Length != file2Content.Length) return false; - if (!sourceInfo.Exists) + for (int i = 0; i < file1Content.Length; i++) { - // Neither file exists. - return true; + if (file1Content[i] != file2Content[i]) return false; } - // We'll say the files are the same if their modification date and length are the same. - return - sourceInfo.LastWriteTimeUtc == destInfo.LastWriteTimeUtc && - sourceInfo.Length == destInfo.Length; + return true; } } } From 2678ec5fa3e3d854140405cd980f241df8da617e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 28 Sep 2022 08:39:19 -0600 Subject: [PATCH 580/704] Use static graph restore It's faster, and the future. --- Directory.Build.props | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Directory.Build.props b/Directory.Build.props index f13158c0..3170d14b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -16,6 +16,9 @@ true + + true + $(MSBuildThisFileDirectory) From 0552ddca8b22548fe1e331a64ebe430fe6a80008 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 30 Sep 2022 22:48:21 -0600 Subject: [PATCH 581/704] Update dependencies --- Directory.Build.props | 2 +- test/Library.Tests/Library.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 3170d14b..8cada6c7 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,7 +40,7 @@ - + diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 2c1c3e8e..4e9a7a4c 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,7 @@ - + From 32300919860464d15555188a8cacbb1cca260618 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 1 Oct 2022 21:06:20 -0600 Subject: [PATCH 582/704] Bump Microsoft.NET.Test.Sdk from 17.3.1 to 17.3.2 (#833) Bumps [Microsoft.NET.Test.Sdk](https://github.com/microsoft/vstest) from 17.3.1 to 17.3.2. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/compare/v17.3.1...v17.3.2) --- updated-dependencies: - dependency-name: Microsoft.NET.Test.Sdk dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 9e8814b2..ed89cdc7 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -16,7 +16,7 @@ - + diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index df8b63a1..af6354db 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -37,7 +37,7 @@ - + From 5e4d1380a5fdc42be1b3c62c6772ef7ddadd8690 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 1 Oct 2022 21:17:08 -0600 Subject: [PATCH 583/704] Drop support for .NET Framework 4.6.1 net461 support from Microsoft ended on April 26, 2022 per https://dotnet.microsoft.com/en-us/platform/support/policy/dotnet-framework --- .../AssemblyVersionInfo.cs | 8 +++---- .../NativeVersionInfo.cs | 2 +- .../Nerdbank.GitVersioning.Tasks.csproj | 6 ++--- .../Nerdbank.GitVersioning.nuspec | 24 +++++++++---------- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 6 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs index 8c619600..32794b03 100644 --- a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs @@ -37,7 +37,7 @@ the code is regenerated. ------------------------------------------------------------------------------ "; -#if NET461 +#if NET462 private static readonly CodeGeneratorOptions CodeGeneratorOptions = new CodeGeneratorOptions { BlankLinesBetweenMembers = false, @@ -133,7 +133,7 @@ public string BuildCode() return null; } -#if NET461 +#if NET462 /// public override bool Execute() { @@ -183,7 +183,7 @@ public override bool Execute() } #endif -#if !NET461 +#if !NET462 /// public override bool Execute() { @@ -230,7 +230,7 @@ private static byte[] GetPublicKeyFromKeyPair(byte[] keyPair) } } -#if NET461 +#if NET462 private static CodeMemberField CreateField(string name, T value) { return new CodeMemberField(typeof(T), name) diff --git a/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs index 08fd4669..e6d9530f 100644 --- a/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/NativeVersionInfo.cs @@ -177,7 +177,7 @@ private void CreateDefines() { if (!int.TryParse(this.AssemblyLanguage, out lcid)) { -#if NET461 +#if NET462 try { var cultureInfo = new CultureInfo(this.AssemblyLanguage); diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj index b03f89ed..8406f285 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj @@ -1,6 +1,6 @@  - net461;netcoreapp3.1 + net462;netcoreapp3.1 true Nerdbank.GitVersioning.nuspec @@ -27,7 +27,7 @@ MSBuildCore\ - MSBuildFull\ + MSBuildFull\ @@ -71,7 +71,7 @@ - + diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index f6bd8c7a..92b4ed91 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -17,18 +17,18 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - - - - - - - - - - - - + + + + + + + + + + + + diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index f1a27424..08742ab1 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -2,7 +2,7 @@ netcoreapp3.1;net6.0 - $(TargetFrameworks);net461 + $(TargetFrameworks);net462 Exe true AnyCPU diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index df8b63a1..91dc6a40 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -1,6 +1,6 @@  - net6.0;net461 + net6.0;net462 true true full From a9dc956a32d4f48da5dd74af8083e86920a64920 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 2 Oct 2022 03:32:30 +0000 Subject: [PATCH 584/704] Bump Microsoft.CodeAnalysis.CSharp from 4.3.0 to 4.3.1 (#834) --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index af6354db..e0fa9449 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -36,7 +36,7 @@ - + From 3d1afd6ce0378b4074f15d918fc14827f21da769 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 2 Oct 2022 03:50:54 +0000 Subject: [PATCH 585/704] Bump xunit from 2.4.1 to 2.4.2 (#832) --- test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index ed89cdc7..02ca0fd3 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -19,7 +19,7 @@ - + diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 18b998de..d2ed91ff 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -46,6 +46,6 @@ - + From cd0d71548c78a2c92c4b06060e5353c66bbe7da1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 2 Oct 2022 04:17:18 +0000 Subject: [PATCH 586/704] Bump xunit.runner.visualstudio from 2.4.3 to 2.4.5 (#831) --- test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 02ca0fd3..e3f72de2 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -18,7 +18,7 @@ - + diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index d2ed91ff..79e5d825 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -44,7 +44,7 @@ - + From 2eaf0fb8f261f978f6d60bef5fde8c87d5eb8640 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 5 Oct 2022 11:48:02 -0600 Subject: [PATCH 587/704] Update .NET SDK to 6.0.401 --- .devcontainer/Dockerfile | 2 +- global.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index b13ca0ac..5c1bdc7a 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0.300-focal +FROM mcr.microsoft.com/dotnet/sdk:6.0.401-focal # 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/global.json b/global.json index 954a92e7..7bf6fc99 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.300", + "version": "6.0.401", "rollForward": "patch", "allowPrerelease": false } From dc0a8cfe732e7e589836225666b81e1b7ef58d82 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 6 Oct 2022 06:35:17 -0600 Subject: [PATCH 588/704] Link to Microsoft docs for Azure Pipelines shallow clone --- doc/cloudbuild.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/cloudbuild.md b/doc/cloudbuild.md index d4746331..ae8fbb2b 100644 --- a/doc/cloudbuild.md +++ b/doc/cloudbuild.md @@ -24,7 +24,7 @@ But `actions/checkout@v2` checks out a shallow clone by default, so you'll have ### Azure Pipelines -[Azure Pipelines behavior has changed][AzpDepthChange] for *new* pipelines created after around Jan 2022 +[Azure Pipelines behavior has changed][AzpDepthChange] for *new* pipelines such that build agents now default to creating shallow clones. You can defeat this, thereby forcing a full history clone by adding this to the top of your `steps` list: @@ -38,6 +38,8 @@ In particular, setting `fetchDepth: 0` will cause Azure Pipelines to *not* do sh See this [example change](https://github.com/AArnott/Library.Template/commit/5d14d2cecbb3fd3caa6a421da1525d8480baef8b). +[Read more about this and how to configure shallow cloning when not using YAML files in Microsoft documentation](https://learn.microsoft.com/azure/devops/pipelines/repos/azure-repos-git?view=azure-devops&tabs=yaml#shallow-fetch). + ## Optional features By specifying certain `cloudBuild` options in your `version.json` file, From 5782246fff526e006f5cf3979d0f05baa4d84003 Mon Sep 17 00:00:00 2001 From: Amadeusz Sadowski Date: Fri, 14 Oct 2022 14:50:54 +0200 Subject: [PATCH 589/704] fix: remove BOM from version.schema.json, #839 --- src/NerdBank.GitVersioning/version.schema.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/version.schema.json b/src/NerdBank.GitVersioning/version.schema.json index 3d50d72f..14863b3c 100644 --- a/src/NerdBank.GitVersioning/version.schema.json +++ b/src/NerdBank.GitVersioning/version.schema.json @@ -1,4 +1,4 @@ -{ +{ "$schema": "http://json-schema.org/draft-04/schema", "title": "Nerdbank.GitVersioning version.json schema", "type": "object", From 5a1f25c7d6455bf9cd9edb829908142e13c5ef9c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 17 Oct 2022 09:18:20 -0600 Subject: [PATCH 590/704] Add emoji to Azure Pipelines step --- azure-pipelines/dotnet.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 8e341525..1ca99490 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -33,7 +33,7 @@ steps: - powershell: azure-pipelines/artifacts/_pipelines.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" -StageOnly failOnStderr: true - displayName: Stage artifacts + displayName: 🗃️ Stage artifacts condition: succeededOrFailed() - pwsh: > From 5e1adb525ffafaa91f3ae54cc86e10efcdf710b7 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 18 Oct 2022 10:00:50 -0600 Subject: [PATCH 591/704] Drop BuildMetadata from NPM package version NPM doesn't support it anyway. It just silently drops it. --- src/NerdBank.GitVersioning/VersionOracle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 297da93c..26868a61 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -365,7 +365,7 @@ public IDictionary CloudBuildVersionVars /// /// Gets the version to use for NPM packages. /// - public string NpmPackageVersion => this.SemVer2; + public string NpmPackageVersion => $"{this.Version.ToStringSafe(3)}{this.PrereleaseVersion}"; /// /// Gets a SemVer 1.0 compliant string that represents this version, including the -COMMITID suffix From abab1d849933ee85cb6f026026f28e481db1bc64 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 20 Oct 2022 16:06:44 -0600 Subject: [PATCH 592/704] Fix variable detection on linux Linux can have empty values for environment variables. Windows evidently doesn't tend to have those. --- azure-pipelines/variables/_pipelines.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/variables/_pipelines.ps1 b/azure-pipelines/variables/_pipelines.ps1 index 951106d2..11748b81 100644 --- a/azure-pipelines/variables/_pipelines.ps1 +++ b/azure-pipelines/variables/_pipelines.ps1 @@ -14,7 +14,7 @@ param ( (& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { # Always use ALL CAPS for env var names since Azure Pipelines converts variable names to all caps and on non-Windows OS, env vars are case sensitive. $keyCaps = $_.Key.ToUpper() - if (Test-Path -Path "env:$keyCaps") { + if ((Test-Path "env:$keyCaps") -and (Get-Content "env:$keyCaps")) { Write-Host "Skipping setting $keyCaps because variable is already set to '$(Get-Content env:$keyCaps)'." -ForegroundColor Cyan } else { Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow From e54acf10cc421b9b986820ef8df39238cabff970 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 22 Oct 2022 08:47:10 -0600 Subject: [PATCH 593/704] Remove inner project from ProjectReference items by default This should avoid the vast majority of the P2P problems introduced by trying to work in `msbuild -graph -isolate`. --- .../build/MSBuildTargetCaching.targets | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets index 8f864fc5..3f367900 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/MSBuildTargetCaching.targets @@ -18,8 +18,7 @@ - - + GetBuildVersion_Properties;GetBuildVersion_CloudBuildVersionVars $(NBGV_InnerGlobalProperties)BuildMetadata=@(BuildMetadata, ','); Configuration=Release @@ -31,8 +30,14 @@ false true false - true all + + + + + true @@ -41,19 +46,17 @@ - - From 51cf091064fcc00682a3aa7f89792e52816874ac Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 22 Oct 2022 09:03:53 -0600 Subject: [PATCH 594/704] Add Microsoft.NETFramework.ReferenceAssemblies to resolve net462 targeting framework error --- Directory.Build.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Build.props b/Directory.Build.props index 595cbcf0..46896a51 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,6 +40,7 @@ 2.0.315-alpha.0.9 + From 334b9dc16780034b3d72614e43ef80726976de34 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 22 Oct 2022 12:40:12 -0600 Subject: [PATCH 595/704] Set application version properties for Maui projects Closes #828 --- .../build/Nerdbank.GitVersioning.targets | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 55abaa97..dcf476b3 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -219,6 +219,56 @@ + + + + + + + + + + <_NBGV_Major_Shifted>$([MSBuild]::Multiply($([System.Version]::Parse('$(BuildVersion)').Major), 16777216)) + <_NBGV_Minor_Shifted>$([MSBuild]::Multiply($([System.Version]::Parse('$(BuildVersion)').Minor), 65536)) + + $([MSBuild]::Add($([MSBuild]::Add($(_NBGV_Major_Shifted), $(_NBGV_Minor_Shifted))), $(BuildNumber))) + $(Version) + + + + + + + $(BuildVersionSimple) + + $(BuildVersionSimple) + + + + + + + + + $(BuildVersion) + + Date: Mon, 24 Oct 2022 06:48:12 -0600 Subject: [PATCH 596/704] Update NuGet.PackageManagement to 6.3.1 --- src/nbgv/nbgv.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index 29b376ce..ea5c3399 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -10,7 +10,7 @@ - + From 1d3750a546f268798d7fd64bbb8787d282f0c61f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 24 Oct 2022 06:43:08 -0600 Subject: [PATCH 597/704] Update Cake.Core to 2.3.0 --- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 8ba3f177..3f65b074 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -28,7 +28,7 @@ - + From 5e9916bb1d0f9edcf28417453f59df4e19572879 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 24 Oct 2022 06:46:23 -0600 Subject: [PATCH 598/704] Upgrade Microsoft.Build dependencies to 15.9.20 in test project --- .../Nerdbank.GitVersioning.Tests.csproj | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 79e5d825..9e2f85aa 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -7,6 +7,7 @@ false false true + 15.9.20 @@ -34,8 +35,8 @@ - - + + From 703b51dfe833b8b8eb3acb4dfd6c26c7e357ebc2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 24 Oct 2022 06:47:05 -0600 Subject: [PATCH 599/704] Update other test dependencies --- .../Nerdbank.GitVersioning.Tests.csproj | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 9e2f85aa..34df0e3d 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -39,14 +39,14 @@ - + - + - + From cffffa4afb7b44d45896d8138d6464bc92650fbe Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 24 Oct 2022 14:17:43 -0600 Subject: [PATCH 600/704] Update Nerdbank.GitVersioning version --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8cada6c7..abdb9d8b 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -40,7 +40,7 @@ - + From 2a5a528133ac007b2facba8b53cfbdb86f0f0b67 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 31 Oct 2022 08:51:51 -0600 Subject: [PATCH 601/704] Improve verbose output of artifact collection --- azure-pipelines/artifacts/_all.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/azure-pipelines/artifacts/_all.ps1 b/azure-pipelines/artifacts/_all.ps1 index 033cc87c..9a22a1d0 100755 --- a/azure-pipelines/artifacts/_all.ps1 +++ b/azure-pipelines/artifacts/_all.ps1 @@ -38,6 +38,7 @@ Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { $ArtifactName = $_.BaseName if ($Force -or !(Test-ArtifactStaged($ArtifactName + $ArtifactNameSuffix))) { $totalFileCount = 0 + Write-Verbose "Collecting file list for artifact $($_.BaseName)" $fileGroups = & $_ if ($fileGroups) { $fileGroups.GetEnumerator() | % { From 77fcd3de2d9f7c6368cc0baeb6cf6e23a204bdaa Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Nov 2022 08:16:02 -0600 Subject: [PATCH 602/704] Switch to NuGet's central package versioning --- Directory.Build.props | 13 ++++++------- Directory.Packages.props | 17 +++++++++++++++++ test/Library.Tests/Library.Tests.csproj | 6 +++--- 3 files changed, 26 insertions(+), 10 deletions(-) create mode 100644 Directory.Packages.props diff --git a/Directory.Build.props b/Directory.Build.props index abdb9d8b..8f186a7c 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -39,13 +39,12 @@ - - - - - - - + + + + + + diff --git a/Directory.Packages.props b/Directory.Packages.props new file mode 100644 index 00000000..8bec0397 --- /dev/null +++ b/Directory.Packages.props @@ -0,0 +1,17 @@ + + + + true + + + + + + + + + + + + + diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 4e9a7a4c..39650b7d 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,9 +10,9 @@ - - - + + + From b894b8a9901dfcbec1030860da30bf6c7507bd19 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Nov 2022 08:22:12 -0600 Subject: [PATCH 603/704] Update to the .NET 7.0.100-rc.2 SDK This removes the warning about using NuGet CPVM, "a preview feature". --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 7bf6fc99..01e689ed 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.401", + "version": "7.0.100-rc.2.22477.23", "rollForward": "patch", "allowPrerelease": false } From ab4fb10d210dd404d8d04aa14c706af271129d0e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Nov 2022 08:29:15 -0600 Subject: [PATCH 604/704] Switch to using GlobalPackageReference --- Directory.Build.props | 9 --------- Directory.Packages.props | 14 ++++++++------ 2 files changed, 8 insertions(+), 15 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 8f186a7c..301047d1 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -38,15 +38,6 @@ snupkg - - - - - - - - - diff --git a/Directory.Packages.props b/Directory.Packages.props index 8bec0397..2b94d74d 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -4,14 +4,16 @@ true - - - - - - + + + + + + + + From 318aaadd6dc4f2b674e5f7c18e9940550a1b3e43 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Nov 2022 08:45:31 -0600 Subject: [PATCH 605/704] Move GitHub-specific package ref to its own group This is to reduce merge conflicts with the microbuild branch where nearby lines change a lot. --- Directory.Packages.props | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 2b94d74d..c33a3beb 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,9 +11,11 @@ - + + + From 253e62c08488d57a5b740fb68475501353713cdd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Nov 2022 12:02:25 -0600 Subject: [PATCH 606/704] Simplify parent import pattern --- src/Directory.Build.props | 2 +- src/Directory.Build.targets | 2 +- test/Directory.Build.props | 2 +- test/Directory.Build.targets | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Directory.Build.props b/src/Directory.Build.props index 77d94765..052fe3ef 100644 --- a/src/Directory.Build.props +++ b/src/Directory.Build.props @@ -1,3 +1,3 @@ - + diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets index 566ab4fc..c1d929a5 100644 --- a/src/Directory.Build.targets +++ b/src/Directory.Build.targets @@ -3,5 +3,5 @@ - + diff --git a/test/Directory.Build.props b/test/Directory.Build.props index 449a06e4..ad4a4b6c 100644 --- a/test/Directory.Build.props +++ b/test/Directory.Build.props @@ -1,5 +1,5 @@ - + false diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets index e7edee55..052fe3ef 100644 --- a/test/Directory.Build.targets +++ b/test/Directory.Build.targets @@ -1,3 +1,3 @@ - + From f91a0e871d9f794cc36020341f358718d6b07f83 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 4 Nov 2022 14:19:46 -0600 Subject: [PATCH 607/704] Avoid .NET 7 SDK till it's stable Otherwise, msbuild.exe fails on VS 17.3, which is the latest stable release. We need to wait till folks can use VS 17.4 to use the .NET 7 SDK. --- Directory.Packages.props | 24 ++++++++++++++++++------ global.json | 2 +- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index c33a3beb..8c1e8f80 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -8,14 +8,26 @@ + - - - - - + + + + + - + + + + + + + + + + + diff --git a/global.json b/global.json index 01e689ed..3ce46e09 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.100-rc.2.22477.23", + "version": "6.0.402", "rollForward": "patch", "allowPrerelease": false } From c32551d1365873cdf6c26bec81c07481fa2b28fe Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 7 Nov 2022 08:59:40 -0700 Subject: [PATCH 608/704] Add Directory.Packages.props as a solution item --- Library.sln | 1 + 1 file changed, 1 insertion(+) diff --git a/Library.sln b/Library.sln index 606811aa..638efb56 100644 --- a/Library.sln +++ b/Library.sln @@ -12,6 +12,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig Directory.Build.props = Directory.Build.props Directory.Build.targets = Directory.Build.targets + Directory.Packages.props = Directory.Packages.props global.json = global.json nuget.config = nuget.config README.md = README.md From d700fe26671ade828854293c5c1b49a28953997c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 9 Nov 2022 12:56:02 -0700 Subject: [PATCH 609/704] Allow use of `NBGV_SetMauiVersionProperties` to suppress new behavior --- .../build/Nerdbank.GitVersioning.targets | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index dcf476b3..c25fe0fd 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -219,11 +219,11 @@ - + False - True + False - True + False True + True + False diff --git a/nuget.config b/nuget.config index 22f7b809..9454ec02 100644 --- a/nuget.config +++ b/nuget.config @@ -7,6 +7,7 @@ + diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 39650b7d..2eb4afe1 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,6 +10,7 @@ + From 49ff64cbb5ca94d2bca9ee23cb7c96a9c6707c5f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 9 Nov 2022 14:00:23 -0700 Subject: [PATCH 612/704] Drop .NET Core 3.1 support It falls out of its LTS support early next month. --- .devcontainer/Dockerfile | 2 +- azure-pipelines.yml | 45 ++++++++----------- azure-pipelines/build.yml | 3 +- azure-pipelines/dotnet.yml | 2 +- azure-pipelines/xplattest-pipeline.yml | 14 +----- global.json | 2 +- .../Cake.GitVersioning.csproj | 14 +++--- .../LibGit2/LibGit2GitExtensions.cs | 6 +-- .../ManagedGit/FileHelpers.cs | 13 +++++- .../Nerdbank.GitVersioning.csproj | 2 +- src/NerdBank.GitVersioning/VersionFile.cs | 2 +- .../ContextAwareTask.cs | 4 +- .../Nerdbank.GitVersioning.Tasks.csproj | 6 +-- .../Nerdbank.GitVersioning.nuspec | 13 +++--- src/nbgv/Program.cs | 2 +- src/nbgv/nbgv.csproj | 2 +- src/nerdbank-gitversioning.npm/ts/core.ts | 2 +- .../Cake.GitVersioning.Tests.csproj | 2 +- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- 19 files changed, 63 insertions(+), 75 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 67cafb32..be43e284 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,4 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0.301-focal +FROM mcr.microsoft.com/dotnet/sdk:6.0.403-focal # 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/azure-pipelines.yml b/azure-pipelines.yml index cde3d98e..c67d1364 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -21,14 +21,14 @@ parameters: resources: containers: - - container: xenial - image: andrewarnott/linux-buildagent - - container: bionic - image: mcr.microsoft.com/dotnet/core/sdk:3.1-bionic - container: focal - image: mcr.microsoft.com/dotnet/core/sdk:3.1-focal - - container: archlinux - image: andrewarnott/archlinux + image: mcr.microsoft.com/dotnet/sdk:6.0-focal + - container: jammy60 + image: mcr.microsoft.com/dotnet/sdk:6.0-jammy + - container: jammy70 + image: mcr.microsoft.com/dotnet/sdk:7.0-jammy + - container: debian + image: mcr.microsoft.com/dotnet/sdk:latest variables: TreatWarningsAsErrors: true @@ -53,18 +53,16 @@ stages: - job: linux strategy: matrix: - # xenial: - # containerImage: xenial - # configureContainerCommand: 'sudo apt update && sudo apt-get install -y git' - Ubuntu_Bionic: - containerImage: bionic Ubuntu_Focal: containerImage: focal - # Arch_Linux: - # containerImage: archlinux - # configureContainerCommand: 'sudo pacman -Sy --noconfirm git dotnet-sdk openssl-1.0' + Ubuntu_Jammy_60: + containerImage: jammy60 + Ubuntu_Jammy_70: + containerImage: jammy70 + Debian: + containerImage: debian pool: - vmImage: ubuntu-20.04 + vmImage: ubuntu-22.04 container: $[ variables['containerImage'] ] steps: - bash: $(configureContainerCommand) @@ -92,7 +90,7 @@ stages: strategy: matrix: ubuntu: - imageName: ubuntu-20.04 + imageName: ubuntu-22.04 repoDir: '~/git' windows: imageName: windows-2022 @@ -104,15 +102,10 @@ stages: vmImage: $(imageName) steps: - task: UseDotNet@2 - displayName: Install .NET Core 3.1 runtime - inputs: - packageType: runtime - version: 3.1.x - - task: UseDotNet@2 - displayName: Install .NET 6.0.301 SDK + displayName: Install .NET 6.0.403 SDK inputs: packageType: sdk - version: 6.0.301 + version: 6.0.403 - script: dotnet --info displayName: Show dotnet SDK info - bash: | @@ -126,7 +119,7 @@ stages: dotnet build -c Release displayName: Build in Release mode - script: | - dotnet run -c Release -f netcoreapp3.1 -- --filter *GetVersionBenchmarks* --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) + dotnet run -c Release -f net6.0 -- --filter *GetVersionBenchmarks* --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (packed) - bash: | @@ -143,7 +136,7 @@ stages: git unpack-objects < .git/objects/pack/*.pack displayName: Unpack Git repositories - script: | - dotnet run -c Release -f netcoreapp3.1 -- --filter '*GetVersionBenchmarks*' --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) + dotnet run -c Release -f net6.0 -- --filter '*GetVersionBenchmarks*' --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (unpacked) - task: PublishBuildArtifacts@1 diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 88e6f3d2..1070ad61 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -23,8 +23,7 @@ jobs: - template: install-dependencies.yml - pwsh: | Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 - & .\dotnet-install.ps1 -Architecture x86 -Channel 3.1 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose -Runtime dotnet - & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.301 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + & .\dotnet-install.ps1 -Architecture x86 -Version 6.0.403 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose displayName: ⚙ Install 32-bit .NET SDK and runtimes - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 1ca99490..3fe2e61b 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -15,7 +15,7 @@ steps: displayName: Build LKG package workingDirectory: src/Nerdbank.GitVersioning.Tasks -- script: dotnet publish -c $(BuildConfiguration) -o ../nerdbank-gitversioning.npm/out/nbgv.cli/tools/netcoreapp3.1/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog" +- script: dotnet publish -c $(BuildConfiguration) -o ../nerdbank-gitversioning.npm/out/nbgv.cli/tools/net6.0/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog" displayName: Publish nbgv tool workingDirectory: src/nbgv diff --git a/azure-pipelines/xplattest-pipeline.yml b/azure-pipelines/xplattest-pipeline.yml index 92fe5c36..0b2e29f9 100644 --- a/azure-pipelines/xplattest-pipeline.yml +++ b/azure-pipelines/xplattest-pipeline.yml @@ -43,18 +43,6 @@ steps: failOnStderr: true - script: > - # Uses dotnet commands that require at least 3.x - - DNVERSION=$(dotnet --version) - - if [[ $DNVERSION == 2.* ]] ; - then - echo "Skipping .NET Core $DNVERSION" - exit 0 - else - echo ".NET Core $DNVERSION" - fi - PkgFileName=$(ls deployables-Windows/Cake.GitVersioning.*nupkg) NBGV_NuGetPackageVersion=$([[ $PkgFileName =~ Cake.GitVersioning\.(.*)\.nupkg ]] && echo "${BASH_REMATCH[1]}") @@ -65,7 +53,7 @@ steps: cd caketest && git init && dotnet new tool-manifest && - dotnet tool install Cake.Tool --version 2.3.0 + dotnet tool install Cake.Tool echo "#addin nuget:?package=Cake.GitVersioning&version=${NBGV_NuGetPackageVersion}&prerelease=true" diff --git a/global.json b/global.json index 7e562337..7b09693c 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.301", + "version": "6.0.403", "rollForward": "patch", "allowPrerelease": false } diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 3f65b074..117a2753 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1 + net6.0 true Chris Crutchfield, Andrew Arnott andarno @@ -37,14 +37,14 @@ - + - - - - - + + + + + diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 4c65d76d..5a5e67d4 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -80,7 +80,7 @@ public static ushort GetTruncatedCommitIdAsUInt16(this Commit commit) /// /// Thrown in the very rare situation that more than one matching commit is found. /// - public static Commit GetCommitFromVersion(LibGit2Context context, Version version) + public static Commit? GetCommitFromVersion(LibGit2Context context, Version version) { // Note we'll accept no match, or one match. But we throw if there is more than one match. return GetCommitsFromVersion(context, version).SingleOrDefault(); @@ -455,7 +455,7 @@ bool ContainsRelevantChanges(IEnumerable changes) => ? changes.Any() //// If there is a single change that isn't excluded, //// then this commit is relevant. - : changes.Any(change => !excludePaths.Any(exclude => exclude.Excludes(change.Path, ignoreCase))); + : changes.Any(change => !excludePaths!.Any(exclude => exclude.Excludes(change.Path, ignoreCase))); int height = 1; @@ -465,7 +465,7 @@ bool ContainsRelevantChanges(IEnumerable changes) => // paths refer to the root of the repository, then do not // filter the diff at all. List? diffInclude = - includePaths.Count == 0 || pathFilters.Any(filter => filter.IsRoot) + includePaths.Count == 0 || pathFilters!.Any(filter => filter.IsRoot) ? null : includePaths; diff --git a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs index 5d2cf46a..7ddafd62 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs @@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; +using System.Runtime.Versioning; using Microsoft.Win32.SafeHandles; using Windows.Win32; using Windows.Win32.Storage.FileSystem; @@ -24,7 +25,11 @@ internal static class FileHelpers /// if the file exists; otherwise . internal static bool TryOpen(string path, out FileStream? stream) { - if (IsWindows) +#if NET5_0_OR_GREATER + if (OperatingSystem.IsWindowsVersionAtLeast(5, 1, 2600)) +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) +#endif { SafeFileHandle? handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); @@ -62,7 +67,11 @@ internal static bool TryOpen(string path, out FileStream? stream) /// if the file exists; otherwise . internal static unsafe bool TryOpen(ReadOnlySpan path, [NotNullWhen(true)] out FileStream? stream) { - if (IsWindows) +#if NET5_0_OR_GREATER + if (OperatingSystem.IsWindowsVersionAtLeast(5, 1, 2600)) +#else + if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) +#endif { HANDLE handle; fixed (char* pPath = &path[0]) diff --git a/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj b/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj index 8214e81c..645345d5 100644 --- a/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj @@ -1,6 +1,6 @@  - netstandard2.0;netcoreapp3.1 + netstandard2.0;net6.0 true Full false diff --git a/src/NerdBank.GitVersioning/VersionFile.cs b/src/NerdBank.GitVersioning/VersionFile.cs index 90347d50..c2ba6e05 100644 --- a/src/NerdBank.GitVersioning/VersionFile.cs +++ b/src/NerdBank.GitVersioning/VersionFile.cs @@ -88,7 +88,7 @@ public string SetVersion(string projectDirectory, VersionOptions version, bool i { File.WriteAllLines( versionTxtPath, - new[] { version.Version?.Version.ToString(), version.Version?.Prerelease }); + new[] { version.Version?.Version.ToString() ?? string.Empty, version.Version?.Prerelease ?? string.Empty }); return versionTxtPath; } else diff --git a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs index 9d3beb3e..b20499a0 100644 --- a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs +++ b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs @@ -16,7 +16,7 @@ namespace MSBuildExtensionTask { public abstract class ContextAwareTask : Microsoft.Build.Utilities.Task { - protected virtual string ManagedDllDirectory => Path.GetDirectoryName(new Uri(this.GetType().GetTypeInfo().Assembly.CodeBase).LocalPath); + protected virtual string ManagedDllDirectory => Path.GetDirectoryName(this.GetType().GetTypeInfo().Assembly.Location); protected virtual string UnmanagedDllDirectory => null; @@ -24,7 +24,7 @@ public abstract class ContextAwareTask : Microsoft.Build.Utilities.Task public override bool Execute() { #if NETCOREAPP - string taskAssemblyPath = new Uri(this.GetType().GetTypeInfo().Assembly.CodeBase).LocalPath; + string taskAssemblyPath = this.GetType().GetTypeInfo().Assembly.Location; Assembly inContextAssembly = GitLoaderContext.Instance.LoadFromAssemblyPath(taskAssemblyPath); Type innerTaskType = inContextAssembly.GetType(this.GetType().FullName); diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj index 8406f285..c8154c95 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj @@ -1,6 +1,6 @@  - net462;netcoreapp3.1 + net462;net6.0 true Nerdbank.GitVersioning.nuspec @@ -26,7 +26,7 @@ - MSBuildCore\ + MSBuildCore\ MSBuildFull\ @@ -74,7 +74,7 @@ - + diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 92b4ed91..faa85a85 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -41,13 +41,12 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - - - - - - - + + + + + + diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 321ea6e4..03d372b8 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -76,7 +76,7 @@ private enum ExitCodes public static int Main(string[] args) { - string thisAssemblyPath = new Uri(typeof(Program).GetTypeInfo().Assembly.CodeBase).LocalPath; + string thisAssemblyPath = typeof(Program).GetTypeInfo().Assembly.Location; Assembly inContextAssembly = GitLoaderContext.Instance.LoadFromAssemblyPath(thisAssemblyPath); Type innerProgramType = inContextAssembly.GetType(typeof(Program).FullName); diff --git a/src/nbgv/nbgv.csproj b/src/nbgv/nbgv.csproj index f914b672..4042b198 100644 --- a/src/nbgv/nbgv.csproj +++ b/src/nbgv/nbgv.csproj @@ -4,7 +4,7 @@ nbgv True Exe - netcoreapp3.1 + net6.0 Nerdbank.GitVersioning.Tool A .NET Core Tool that can install, read and set version information based on git history, using Nerdbank.GitVersioning. diff --git a/src/nerdbank-gitversioning.npm/ts/core.ts b/src/nerdbank-gitversioning.npm/ts/core.ts index 9fcddeea..10c78675 100644 --- a/src/nerdbank-gitversioning.npm/ts/core.ts +++ b/src/nerdbank-gitversioning.npm/ts/core.ts @@ -5,6 +5,6 @@ const nbgvPath = 'nbgv.cli'; export function getNbgvCommand(dotnetCommand?: string): string { var command = dotnetCommand || 'dotnet'; - const nbgvDll = path.join(__dirname, nbgvPath, "tools", "netcoreapp3.1", "any", "nbgv.dll"); + const nbgvDll = path.join(__dirname, nbgvPath, "tools", "net6.0", "any", "nbgv.dll"); return `${command} "${nbgvDll}"`; } diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index e3f72de2..44c7e219 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -1,7 +1,7 @@ - netcoreapp3.1;net6.0 + net6.0 false true false diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index 08742ab1..caef93e7 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -1,7 +1,7 @@  - netcoreapp3.1;net6.0 + net6.0 $(TargetFrameworks);net462 Exe true From ad6e2422bed202dfd0e95a567635809eb9b3a2f3 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 11 Nov 2022 15:19:51 +0000 Subject: [PATCH 613/704] Resolve NU1507 warning --- nuget.config | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nuget.config b/nuget.config index 9454ec02..6ce7cfd0 100644 --- a/nuget.config +++ b/nuget.config @@ -13,4 +13,12 @@ + + + + + + + + From 66a302c4e7c60633ad09c232f0b8cd105ab1f795 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 14 Nov 2022 12:17:50 -0700 Subject: [PATCH 614/704] Update Microsoft.NET.Test.Sdk --- Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index d1226691..924f4b4e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ - + @@ -31,4 +31,4 @@ - + \ No newline at end of file From 8ebf3f27b25adbe6d266bc07fbdd01bc94d82a48 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 21 Nov 2022 09:37:48 -0700 Subject: [PATCH 615/704] Use `MSBuildTreatWarningsAsErrors` in pipeline This is more comprehensive than `TreatWarningsAsErrors` because it changes the behavior of the MSBuild logging system itself instead of relying on individual tasks and targets to honor the property and elevate their own warnings. --- .github/workflows/build.yml | 2 +- azure-pipelines.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 2c4ba94c..a56a6dda 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -8,7 +8,7 @@ on: pull_request: env: - TreatWarningsAsErrors: true + MSBuildTreatWarningsAsErrors: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BUILDCONFIGURATION: Release # codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2cac17bd..521d4ce6 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -23,7 +23,7 @@ parameters: default: true variables: - TreatWarningsAsErrors: true + MSBuildTreatWarningsAsErrors: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true BuildConfiguration: Release codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ From 73ef446ccb46cf39b434ef004007681624bffc89 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 21 Nov 2022 09:40:20 -0700 Subject: [PATCH 616/704] Avoid static graph restore This until the fix for https://github.com/NuGet/Home/issues/12177 is broadly available. --- Directory.Build.props | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 301047d1..e78128b9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -17,7 +17,8 @@ true - true + + false $(MSBuildThisFileDirectory) From ae66da74a2e324d3fc73753c691cfeb882d18daf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 8 Nov 2022 22:24:14 -0700 Subject: [PATCH 617/704] Update to the .NET 7 SDK --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index 3ce46e09..e5187f36 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.402", + "version": "7.0.100", "rollForward": "patch", "allowPrerelease": false } From ca3ab7d086ec1559228a26e454f6dc71e920066e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 21 Nov 2022 20:06:18 -0700 Subject: [PATCH 618/704] Enable NuGet CPVM transitive pinning --- Directory.Packages.props | 1 + 1 file changed, 1 insertion(+) diff --git a/Directory.Packages.props b/Directory.Packages.props index 924f4b4e..5ce5b0f0 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -2,6 +2,7 @@ true + true From 6bcec4372bd8508a7513aa6653712b2388a94a9a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 22 Nov 2022 09:05:12 -0700 Subject: [PATCH 619/704] Fix build on machines with Visual Studio 2022 Update 3 This is a workaround for Azure Pipelines Hosted agents, which haven't upgraded to Dev17.4 yet. --- Directory.Packages.props | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 5ce5b0f0..e9475f7c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -15,6 +15,7 @@ + @@ -25,6 +26,7 @@ + @@ -32,4 +34,4 @@ - \ No newline at end of file + From 6a34c4f283848ed96447f3ce5fde429309112fe0 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 22 Nov 2022 09:23:41 -0700 Subject: [PATCH 620/704] Switch back to `GlobalPackageReference` --- Directory.Packages.props | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index e9475f7c..5996640f 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -10,28 +10,15 @@ - - - - - - - + + + + + + - - - - - - - - - - - - + From fb2b395fce67a75e5be07443e204fc5b905b6983 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 24 Nov 2022 13:21:22 -0700 Subject: [PATCH 621/704] Drop the .NET compilers toolset pin This reverts "Fix build on machines with Visual Studio 2022 Update 3" since Azure Pipelines now has Update 4 installed. This reverts commit 6bcec4372bd8508a7513aa6653712b2388a94a9a. --- Directory.Packages.props | 1 - 1 file changed, 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 5996640f..8e696a7e 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -13,7 +13,6 @@ - From a32f820b0f145106b6a7182079a59adf7e9554a3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 10:45:54 -0700 Subject: [PATCH 622/704] Bump Microsoft.CodeCoverage (#182) Bumps [Microsoft.CodeCoverage](https://github.com/microsoft/vstest) from 17.5.0-preview-20221109-01 to 17.5.0-preview-20221201-01. - [Release notes](https://github.com/microsoft/vstest/releases) - [Commits](https://github.com/microsoft/vstest/commits) --- updated-dependencies: - dependency-name: Microsoft.CodeCoverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 8e696a7e..056c5349 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ true - + From 87aa2ac8f32c3663644e522c1b84211aa950b33e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 1 Dec 2022 13:30:40 -0700 Subject: [PATCH 623/704] Bump System.Threading.Tasks.Dataflow from 6.0.0 to 7.0.0 (#866) Bumps [System.Threading.Tasks.Dataflow](https://github.com/dotnet/runtime) from 6.0.0 to 7.0.0. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/compare/v6.0.0...v7.0.0) --- updated-dependencies: - dependency-name: System.Threading.Tasks.Dataflow dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 34df0e3d..80cffc79 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -43,7 +43,7 @@ - + From e7ed3b30668a893d23584ecf05294d7b14f6b445 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 1 Dec 2022 14:46:40 -0700 Subject: [PATCH 624/704] Bump Microsoft.CodeCoverage from 17.5.0-preview-20221201-01 to 17.5.0-preview-20221201-06 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 056c5349..f19a9842 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ true - + From 12210c3a74230cad864e950a79445bbf229d3c38 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sat, 3 Dec 2022 09:40:42 -0700 Subject: [PATCH 625/704] Bump decode-uri-component in /src/nerdbank-gitversioning.npm (#869) Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2. - [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases) - [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2) --- updated-dependencies: - dependency-name: decode-uri-component dependency-type: indirect ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index ed67f839..f7bab7dd 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -578,9 +578,9 @@ decamelize@^1.1.1: integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= decode-uri-component@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" - integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= + version "0.2.2" + resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.2.tgz#e69dbe25d37941171dd540e024c444cd5188e1e9" + integrity sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ== default-compare@^1.0.0: version "1.0.0" From 1c45336d90a13462576608148687352d6426c893 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 5 Dec 2022 13:19:04 -0700 Subject: [PATCH 626/704] Fix ArgumentNullException thrown when reading empty strings from git database Fixes #870 --- src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs index c079b951..43f02885 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitRepository.cs @@ -719,6 +719,11 @@ private static bool TryConvertHexStringToByteArray(string hexString, Span /// public static unsafe string GetString(ReadOnlySpan bytes) { + if (bytes.Length == 0) + { + return string.Empty; + } + fixed (byte* pBytes = bytes) { return Encoding.GetString(pBytes, bytes.Length); From 0f6370085ca9b61c96e315a47f526a5e0c5b0eba Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 15 Dec 2022 16:54:35 +0100 Subject: [PATCH 627/704] Add tag name option --- src/NerdBank.GitVersioning/VersionOptions.cs | 28 +++++++++++++++++++ .../version.schema.json | 10 +++++-- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index b631b39e..2d779160 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -46,6 +46,11 @@ public class VersionOptions : IEquatable /// private const int DefaultSemVer1NumericIdentifierPadding = 4; + /// + /// The default value for the property. + /// + private const string DefaultTagName = "v{version}"; + /// /// A value indicating whether mutations of this instance are not allowed. /// @@ -109,6 +114,12 @@ public class VersionOptions : IEquatable [DebuggerBrowsable(DebuggerBrowsableState.Never)] private CloudBuildOptions? cloudBuild; + /// + /// Backing field for the property. + /// + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string? tagName; + /// /// Backing field for the property. /// @@ -153,6 +164,7 @@ public VersionOptions(VersionOptions copyFrom) this.publicReleaseRefSpec = copyFrom.publicReleaseRefSpec?.ToList(); this.cloudBuild = copyFrom.cloudBuild is object ? new CloudBuildOptions(copyFrom.cloudBuild) : null; this.release = copyFrom.release is object ? new ReleaseOptions(copyFrom.release) : null; + this.tagName = copyFrom.tagName; this.pathFilters = copyFrom.pathFilters?.ToList(); } @@ -472,6 +484,22 @@ public ReleaseOptions? Release [JsonIgnore] public ReleaseOptions ReleaseOrDefault => this.Release ?? ReleaseOptions.DefaultInstance; + /// + /// Gets or sets the tag name template for tagging. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? TagName + { + get => this.tagName; + set => this.SetIfNotReadOnly(ref this.tagName, value); + } + + /// + /// Gets the tag name template for tagging. + /// + [JsonIgnore] + public string? TagNameOrDefault => this.TagName ?? DefaultTagName; + /// /// Gets or sets a list of paths to use to filter commits when calculating version height. /// If a given commit does not affect any paths in this filter, it is ignored for version height calculations. diff --git a/src/NerdBank.GitVersioning/version.schema.json b/src/NerdBank.GitVersioning/version.schema.json index 14863b3c..efc3afa2 100644 --- a/src/NerdBank.GitVersioning/version.schema.json +++ b/src/NerdBank.GitVersioning/version.schema.json @@ -176,7 +176,7 @@ "type": "object", "properties": { "branchName": { - "description": "Defines the format of release branch names. Format must include a placeholder '{version}' for the version", + "description": "Defines the format of release branch names. Format must include a placeholder '{version}' for the version.", "type": "string", "pattern": ".*\\{version\\}.*", "default": "v{version}" @@ -188,13 +188,19 @@ "default": "minor" }, "firstUnstableTag": { - "description": "Specifies the first/default prerelease tag for new versions", + "description": "Specifies the first/default prerelease tag for new versions.", "type": "string", "default": "alpha" } }, "additionalProperties": false }, + "tagName": { + "description": "Defines the format of tag names. Format must include a placeholder '{version}' for the version.", + "type": "string", + "pattern": ".*\\{version\\}.*", + "default": "v{version}" + }, "pathFilters": { "type": "array", "description": "An array of pathspec-like strings that are used to filter commits when calculating the version height. A commit will not increment the version height if its changed files are not included by these filters.\nPaths are relative to this file. Paths relative to the root of the repository can be specified with the `:/` prefix.\nExclusions can be specified with a `:^` prefix for relative paths, or a `:^/` prefix for paths relative to the root of the repository.\nAfter a path matches any non-exclude filter, it will be run through all exclude filters. If it matches, the path is ignored.", From 0c947f2abd18d319f878129a6d912ab93c7182a2 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Thu, 15 Dec 2022 16:56:03 +0100 Subject: [PATCH 628/704] Use tag name format --- src/nbgv/Program.cs | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 03d372b8..2590553a 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -68,6 +68,7 @@ private enum ExitCodes PackageIdNotFound, ShallowClone, InternalError, + InvalidTagNameSetting, } private static bool AlwaysUseLibGit2 => string.Equals(Environment.GetEnvironmentVariable("NBGV_GitEngine"), "LibGit2", StringComparison.Ordinal); @@ -545,6 +546,24 @@ private static Task OnTagCommand(string project, string versionOrRef) return Task.FromResult((int)ExitCodes.NoGitRepo); } + // get tag name format + VersionOptions versionOptions = context.VersionFile.GetVersion(); + if (versionOptions is null) + { + Console.Error.WriteLine($"Failed to load version file for directory '{searchPath}'."); + return Task.FromResult((int)ExitCodes.NoVersionJsonFound); + } + + string tagNameFormat = versionOptions.TagNameOrDefault; + + // ensure there is a '{version}' placeholder in the tag name + if (string.IsNullOrEmpty(tagNameFormat) || !tagNameFormat.Contains("{version}")) + { + Console.Error.WriteLine($"Invalid 'tagName' setting '{tagNameFormat}'. Missing version placeholder '{{version}}'."); + return Task.FromResult((int)ExitCodes.InvalidTagNameSetting); + } + + // get commit to tag LibGit2Sharp.Repository repository = context.Repository; if (!context.TrySelectCommit(versionOrRef)) { @@ -585,8 +604,12 @@ private static Task OnTagCommand(string project, string versionOrRef) return Task.FromResult((int)ExitCodes.NoVersionJsonFound); } - oracle.PublicRelease = true; // assume a public release so we don't get a redundant -gCOMMITID in the tag name - string tagName = $"v{oracle.SemVer2}"; + // assume a public release so we don't get a redundant -gCOMMITID in the tag name + oracle.PublicRelease = true; + + // replace the "{version}" placeholder with the actual version + string tagName = tagNameFormat.Replace("{version}", oracle.SemVer2); + try { context.ApplyTag(tagName); From a24d8a1e51e439376edc8cf3753f4460c2044204 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 15 Dec 2022 09:05:55 -0700 Subject: [PATCH 629/704] Drop netcoreapp3.1 targeting Also update the .NET SDK to 7.0.101 --- .devcontainer/Dockerfile | 3 ++- global.json | 2 +- test/Library.Tests/CalculatorTests.cs | 2 +- test/Library.Tests/Library.Tests.csproj | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 5c1bdc7a..7ffd07ef 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,4 +1,5 @@ -FROM mcr.microsoft.com/dotnet/sdk:6.0.401-focal +# Refer to https://hub.docker.com/_/microsoft-dotnet-sdk for available versions +FROM mcr.microsoft.com/dotnet/sdk:7.0.101-jammy # 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/global.json b/global.json index e5187f36..cc08211e 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.100", + "version": "7.0.101", "rollForward": "patch", "allowPrerelease": false } diff --git a/test/Library.Tests/CalculatorTests.cs b/test/Library.Tests/CalculatorTests.cs index 042e7d94..0e7e8339 100644 --- a/test/Library.Tests/CalculatorTests.cs +++ b/test/Library.Tests/CalculatorTests.cs @@ -14,7 +14,7 @@ public CalculatorTests() public void AddOrSubtract() { // This tests aggregation of code coverage across test runs. -#if NETCOREAPP3_1 +#if NET6_0_OR_GREATER Assert.Equal(3, Calculator.Add(1, 2)); #else Assert.Equal(-1, Calculator.Subtract(1, 2)); diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index 2eb4afe1..d557e4c7 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -1,7 +1,7 @@ - net6.0;netcoreapp3.1;net472 + net6.0;net472 From 2da647834cdc78b9399967a813a4d2ef6461c437 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 15 Dec 2022 09:22:45 -0700 Subject: [PATCH 630/704] Multitarget the library .NET Standard 2.0 is still relevant because it's the last TFM that works on all .NET runtimes. But it's also very old, depriving the developer of the nullable ref annotations that are in later versions of .NET that can help reduce bugs. There are also newer APIs that can be *automatically* consumed by the compiler based on newer TFMs even without using `#if` in your code that can improve runtime performance of the code. --- src/Library/Library.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Library/Library.csproj b/src/Library/Library.csproj index a7547da1..b6b926ab 100644 --- a/src/Library/Library.csproj +++ b/src/Library/Library.csproj @@ -1,6 +1,6 @@ - netstandard2.0 + net6.0;netstandard2.0 README.md From dfd69e0a9d0062a445e6bd4c2c0131d41f588a77 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 15 Dec 2022 09:26:42 -0700 Subject: [PATCH 631/704] Avoid System.Net.Http compile error when targeting net472 --- Directory.Build.targets | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Directory.Build.targets b/Directory.Build.targets index 65a15bfc..cbe19ca0 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -4,5 +4,10 @@ false + + + + + From 8121dad9b92d083ef3500956182a84f4674ea2b4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 15 Dec 2022 09:48:06 -0700 Subject: [PATCH 632/704] Drop obsolete WPF workarounds --- Directory.Build.props | 8 -------- Directory.Build.targets | 2 -- 2 files changed, 10 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index e78128b9..7980f528 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -62,23 +62,15 @@ - <_WpfTempProjectNuGetFilePathNoExt>$(BaseIntermediateOutputPath)..\$(_TargetAssemblyProjectName)\$(_TargetAssemblyProjectName)$(MSBuildProjectExtension).nuget.g - false false false false - - - diff --git a/Directory.Build.targets b/Directory.Build.targets index cbe19ca0..ea7b6e6f 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -8,6 +8,4 @@ - - From 435bda683b3d32c46261684af3c5291e81ed5acd Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 15 Dec 2022 09:03:17 -0700 Subject: [PATCH 633/704] Add emoticons to github workflows --- .github/workflows/build.yml | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a56a6dda..7718f84a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -30,7 +30,7 @@ jobs: - uses: actions/checkout@v2 with: fetch-depth: 0 # avoid shallow clone so nbgv can do its work. - - name: Install prerequisites + - name: ⚙ Install prerequisites run: | ./init.ps1 -UpgradePrerequisites dotnet --info @@ -40,75 +40,75 @@ jobs: mono --version } shell: pwsh - - name: Set pipeline variables based on source + - name: ⚙️ Set pipeline variables based on source run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh - - name: build + - name: 🛠 build run: dotnet build -t:build,pack --no-restore -c ${{ env.BUILDCONFIGURATION }} /v:m /bl:"${{ runner.temp }}/_artifacts/build_logs/build.binlog" - - name: test + - name: 🧪 test run: azure-pipelines/dotnet-test-cloud.ps1 -Configuration ${{ env.BUILDCONFIGURATION }} -Agent ${{ runner.os }} shell: pwsh - - name: Update pipeline variables based on build outputs + - name: ⚙ Update pipeline variables based on build outputs run: azure-pipelines/variables/_pipelines.ps1 shell: pwsh - - name: Collect artifacts + - name: 📥 Collect artifacts run: azure-pipelines/artifacts/_stage_all.ps1 shell: pwsh if: always() - - name: Upload project.assets.json files + - name: 📢 Upload project.assets.json files if: always() uses: actions/upload-artifact@v1 with: name: projectAssetsJson-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/projectAssetsJson continue-on-error: true - - name: Upload variables + - name: 📢 Upload variables uses: actions/upload-artifact@v1 with: name: variables-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/Variables continue-on-error: true - - name: Upload build_logs + - name: 📢 Upload build_logs if: always() uses: actions/upload-artifact@v1 with: name: build_logs-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/build_logs continue-on-error: true - - name: Upload test_logs + - name: 📢 Upload test_logs if: always() uses: actions/upload-artifact@v1 with: name: test_logs-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/test_logs continue-on-error: true - - name: Upload testResults + - name: 📢 Upload testResults if: always() uses: actions/upload-artifact@v1 with: name: testResults-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/testResults continue-on-error: true - - name: Upload coverageResults + - name: 📢 Upload coverageResults if: always() uses: actions/upload-artifact@v1 with: name: coverageResults-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/coverageResults continue-on-error: true - - name: Upload symbols + - name: 📢 Upload symbols uses: actions/upload-artifact@v1 with: name: symbols-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/symbols continue-on-error: true - - name: Upload deployables + - name: 📢 Upload deployables uses: actions/upload-artifact@v1 with: name: deployables-${{ runner.os }} path: ${{ runner.temp }}/_artifacts/deployables if: always() - - name: Publish code coverage results to codecov.io + - name: 📢 Publish code coverage results to codecov.io run: ./azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "${{ env.codecov_token }}" -PathToCodeCoverage "${{ runner.temp }}/_artifacts/coverageResults" -Name "${{ runner.os }} Coverage Results" -Flags "${{ runner.os }}Host,${{ env.BUILDCONFIGURATION }}" shell: pwsh timeout-minutes: 3 From 2107c6a84526544f8c00f4f86bc6390f234a4036 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 17 Dec 2022 16:40:56 -0700 Subject: [PATCH 634/704] Bump C# language version to 11 Just use `latest` so it'll be whatever the SDK version permits. Dropping the property altogether would use the formally recommended version for the TFM, which is less desirable. --- Directory.Build.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Build.props b/Directory.Build.props index 7980f528..d722f5e4 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -5,7 +5,7 @@ $(RepoRootPath)obj\$([MSBuild]::MakeRelative($(RepoRootPath), $(MSBuildProjectDirectory)))\ $(RepoRootPath)bin\$(MSBuildProjectName)\ $(RepoRootPath)bin\Packages\$(Configuration)\ - 10.0 + latest enable enable latest From 7e26321035767c832e5205ad71be7e666b4d8d2a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 17 Dec 2022 17:14:19 -0700 Subject: [PATCH 635/704] Bump Microsoft.NET.Test.Sdk to 17.4.1 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index f19a9842..9ec9d10c 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -6,7 +6,7 @@ - + From 78104ee5ca30657c44d76d851f3f4192ec504770 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Mon, 19 Dec 2022 17:29:50 +0100 Subject: [PATCH 636/704] Move tag name option to release object --- src/NerdBank.GitVersioning/VersionOptions.cs | 59 +++++++++---------- .../VersionOptionsContractResolver.cs | 5 ++ .../version.schema.json | 22 +++---- src/nbgv/Program.cs | 2 +- 4 files changed, 44 insertions(+), 44 deletions(-) diff --git a/src/NerdBank.GitVersioning/VersionOptions.cs b/src/NerdBank.GitVersioning/VersionOptions.cs index 2d779160..7e47f06c 100644 --- a/src/NerdBank.GitVersioning/VersionOptions.cs +++ b/src/NerdBank.GitVersioning/VersionOptions.cs @@ -46,11 +46,6 @@ public class VersionOptions : IEquatable /// private const int DefaultSemVer1NumericIdentifierPadding = 4; - /// - /// The default value for the property. - /// - private const string DefaultTagName = "v{version}"; - /// /// A value indicating whether mutations of this instance are not allowed. /// @@ -114,12 +109,6 @@ public class VersionOptions : IEquatable [DebuggerBrowsable(DebuggerBrowsableState.Never)] private CloudBuildOptions? cloudBuild; - /// - /// Backing field for the property. - /// - [DebuggerBrowsable(DebuggerBrowsableState.Never)] - private string? tagName; - /// /// Backing field for the property. /// @@ -164,7 +153,6 @@ public VersionOptions(VersionOptions copyFrom) this.publicReleaseRefSpec = copyFrom.publicReleaseRefSpec?.ToList(); this.cloudBuild = copyFrom.cloudBuild is object ? new CloudBuildOptions(copyFrom.cloudBuild) : null; this.release = copyFrom.release is object ? new ReleaseOptions(copyFrom.release) : null; - this.tagName = copyFrom.tagName; this.pathFilters = copyFrom.pathFilters?.ToList(); } @@ -484,22 +472,6 @@ public ReleaseOptions? Release [JsonIgnore] public ReleaseOptions ReleaseOrDefault => this.Release ?? ReleaseOptions.DefaultInstance; - /// - /// Gets or sets the tag name template for tagging. - /// - [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] - public string? TagName - { - get => this.tagName; - set => this.SetIfNotReadOnly(ref this.tagName, value); - } - - /// - /// Gets the tag name template for tagging. - /// - [JsonIgnore] - public string? TagNameOrDefault => this.TagName ?? DefaultTagName; - /// /// Gets or sets a list of paths to use to filter commits when calculating version height. /// If a given commit does not affect any paths in this filter, it is ignored for version height calculations. @@ -1470,7 +1442,7 @@ public int GetHashCode(CloudBuildNumberCommitIdOptions? obj) } /// - /// Encapsulates settings for the "prepare-release" command. + /// Encapsulates settings for the "prepare-release" and "tag" commands. /// public class ReleaseOptions : IEquatable { @@ -1480,6 +1452,7 @@ public class ReleaseOptions : IEquatable internal static readonly ReleaseOptions DefaultInstance = new ReleaseOptions() { isFrozen = true, + tagName = "v{version}", branchName = "v{version}", versionIncrement = ReleaseVersionIncrement.Minor, firstUnstableTag = "alpha", @@ -1488,6 +1461,9 @@ public class ReleaseOptions : IEquatable [DebuggerBrowsable(DebuggerBrowsableState.Never)] private bool isFrozen; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] + private string? tagName; + [DebuggerBrowsable(DebuggerBrowsableState.Never)] private string? branchName; @@ -1510,11 +1486,28 @@ public ReleaseOptions() /// The existing instance to copy from. public ReleaseOptions(ReleaseOptions copyFrom) { + this.tagName = copyFrom.tagName; this.branchName = copyFrom.branchName; this.versionIncrement = copyFrom.versionIncrement; this.firstUnstableTag = copyFrom.firstUnstableTag; } + /// + /// Gets or sets the tag name template for tagging. + /// + [JsonProperty(DefaultValueHandling = DefaultValueHandling.Ignore)] + public string? TagName + { + get => this.tagName; + set => this.SetIfNotReadOnly(ref this.tagName, value); + } + + /// + /// Gets the tag name template for tagging. + /// + [JsonIgnore] + public string TagNameOrDefault => this.TagName ?? DefaultInstance.TagName!; + /// /// Gets or sets the branch name template for release branches. /// @@ -1526,7 +1519,7 @@ public string? BranchName } /// - /// Gets the set branch name template for release branches. + /// Gets the branch name template for release branches. /// [JsonIgnore] public string BranchNameOrDefault => this.BranchName ?? DefaultInstance.BranchName!; @@ -1621,7 +1614,8 @@ public bool Equals(ReleaseOptions? x, ReleaseOptions? y) return false; } - return StringComparer.Ordinal.Equals(x.BranchNameOrDefault, y.BranchNameOrDefault) && + return StringComparer.Ordinal.Equals(x.TagNameOrDefault, y.TagNameOrDefault) && + StringComparer.Ordinal.Equals(x.BranchNameOrDefault, y.BranchNameOrDefault) && x.VersionIncrementOrDefault == y.VersionIncrementOrDefault && StringComparer.Ordinal.Equals(x.FirstUnstableTagOrDefault, y.FirstUnstableTagOrDefault); } @@ -1636,7 +1630,8 @@ public int GetHashCode(ReleaseOptions? obj) unchecked { - int hash = StringComparer.Ordinal.GetHashCode(obj.BranchNameOrDefault) * 397; + int hash = StringComparer.Ordinal.GetHashCode(obj.TagNameOrDefault) * 397; + hash ^= StringComparer.Ordinal.GetHashCode(obj.BranchNameOrDefault); hash ^= (int)obj.VersionIncrementOrDefault; hash ^= StringComparer.Ordinal.GetHashCode(obj.FirstUnstableTagOrDefault); return hash; diff --git a/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs b/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs index 4975daa3..5b0355fa 100644 --- a/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs +++ b/src/NerdBank.GitVersioning/VersionOptionsContractResolver.cs @@ -126,6 +126,11 @@ protected override JsonProperty CreateProperty(MemberInfo member, MemberSerializ property.ShouldSerialize = instance => !((VersionOptions)instance).ReleaseOrDefault.IsDefault; } + if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.TagName)) + { + property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).TagNameOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.TagName; + } + if (property.DeclaringType == typeof(VersionOptions.ReleaseOptions) && member.Name == nameof(VersionOptions.ReleaseOptions.BranchName)) { property.ShouldSerialize = instance => ((VersionOptions.ReleaseOptions)instance).BranchNameOrDefault != VersionOptions.ReleaseOptions.DefaultInstance.BranchName; diff --git a/src/NerdBank.GitVersioning/version.schema.json b/src/NerdBank.GitVersioning/version.schema.json index efc3afa2..44a0bb72 100644 --- a/src/NerdBank.GitVersioning/version.schema.json +++ b/src/NerdBank.GitVersioning/version.schema.json @@ -119,7 +119,7 @@ }, "publicReleaseRefSpec": { "type": "array", - "description": "An array of regular expressions that may match a ref (branch or tag) that should be built with PublicRelease=true as the default value. The ref matched against is in its canonical form (e.g. refs/heads/master)", + "description": "An array of regular expressions that may match a ref (branch or tag) that should be built with PublicRelease=true as the default value. The ref matched against is in its canonical form (e.g. refs/heads/master).", "items": { "type": "string", "format": "regex" @@ -128,12 +128,12 @@ }, "cloudBuild": { "type": "object", - "description": "Options that are applicable specifically to cloud builds (e.g. VSTS, AppVeyor, TeamCity)", + "description": "Options that are applicable specifically to cloud builds (e.g. VSTS, AppVeyor, TeamCity).", "properties": { "setAllVariables": { "type": "boolean", "default": false, - "description": "Elevates all build properties to cloud build variables prefaced with \"NBGV_\"" + "description": "Elevates all build properties to cloud build variables prefaced with \"NBGV_\"." }, "setVersionVariables": { "type": "boolean", @@ -172,13 +172,19 @@ } }, "release": { - "description": "Settings for the prepare-release command", + "description": "Settings for the prepare-release and tag commands.", "type": "object", "properties": { + "tagName": { + "description": "Defines the format of tag names. Format must include a placeholder '{version}' for the version.", + "type": "string", + "pattern": "\\{version\\}", + "default": "v{version}" + }, "branchName": { "description": "Defines the format of release branch names. Format must include a placeholder '{version}' for the version.", "type": "string", - "pattern": ".*\\{version\\}.*", + "pattern": "\\{version\\}", "default": "v{version}" }, "versionIncrement": { @@ -195,12 +201,6 @@ }, "additionalProperties": false }, - "tagName": { - "description": "Defines the format of tag names. Format must include a placeholder '{version}' for the version.", - "type": "string", - "pattern": ".*\\{version\\}.*", - "default": "v{version}" - }, "pathFilters": { "type": "array", "description": "An array of pathspec-like strings that are used to filter commits when calculating the version height. A commit will not increment the version height if its changed files are not included by these filters.\nPaths are relative to this file. Paths relative to the root of the repository can be specified with the `:/` prefix.\nExclusions can be specified with a `:^` prefix for relative paths, or a `:^/` prefix for paths relative to the root of the repository.\nAfter a path matches any non-exclude filter, it will be run through all exclude filters. If it matches, the path is ignored.", diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 2590553a..19457436 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -554,7 +554,7 @@ private static Task OnTagCommand(string project, string versionOrRef) return Task.FromResult((int)ExitCodes.NoVersionJsonFound); } - string tagNameFormat = versionOptions.TagNameOrDefault; + string tagNameFormat = versionOptions.ReleaseOrDefault.TagNameOrDefault; // ensure there is a '{version}' placeholder in the tag name if (string.IsNullOrEmpty(tagNameFormat) || !tagNameFormat.Contains("{version}")) From edb2d5f3b821c3b9b73e87b3dcaeb1cfdaccc329 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Mon, 19 Dec 2022 22:07:39 +0100 Subject: [PATCH 637/704] Update documentation --- doc/nbgv-cli.md | 38 ++++++++++++++++++++++++++++++++++++++ doc/versionJson.md | 1 + 2 files changed, 39 insertions(+) diff --git a/doc/nbgv-cli.md b/doc/nbgv-cli.md index 3c9f46af..ac48a69b 100644 --- a/doc/nbgv-cli.md +++ b/doc/nbgv-cli.md @@ -164,6 +164,44 @@ For each branch, the following properties are provided: **Note:** When the current branch is already the release branch for the current version, no new branch will be created. In that case, the `NewBranch` property will be `null`. +## Creating a version tag + +The `tag` command automates the task of tagging a commit with a version. + +To create a version tag, run: + +```ps1 +nbgv tag +``` + +This will: + +1. Read version.json to ascertain the version under development, and the naming convention of tag names. +1. Create a new tag for that version. + +You can optionally include a version or commit id to create a new tag for an older version/commit, e.g.: + +```ps1 +nbgv tag 1.0.0 +``` + +### Customizing the behaviour of `tag` + +The behaviour of the `tag` command can be customized in `version.json`: + +```json +{ + "version": "1.0", + "release": { + "tagName" : "v{version}" + } +} +``` + +| Property | Default value | Description | +|----------|---------------|-------------------------------------------------------------------------------------------------| +| tagName | `v{version}` | Defines the format of tag names. Format must include a placeholder '{version}' for the version. | + ## Learn more There are several more sub-commands and switches to each to help you build and maintain your projects, find a commit that built a particular version later on, create tags, etc. diff --git a/doc/versionJson.md b/doc/versionJson.md index c3e14829..a56adb55 100644 --- a/doc/versionJson.md +++ b/doc/versionJson.md @@ -59,6 +59,7 @@ The content of the version.json file is a JSON serialized object with these prop } }, "release" : { + "tagName" : "v{version}", "branchName" : "v{version}", "versionIncrement" : "minor", "firstUnstableTag" : "alpha" From 73ed0f8cc96286dc9a188662178e64e2aaf2ee73 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 3 Jan 2023 09:47:36 -0700 Subject: [PATCH 638/704] Bump Microsoft.CodeCoverage (#187) Bumps [Microsoft.CodeCoverage](https://github.com/microsoft/vstest) from 17.5.0-preview-20221201-06 to 17.5.0-release-20221220-01. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/commits) --- updated-dependencies: - dependency-name: Microsoft.CodeCoverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 9ec9d10c..bfa98614 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ true - + From 03e988325666cd92193afb2ce5b10688276d9ee3 Mon Sep 17 00:00:00 2001 From: Ronald Barendse Date: Wed, 4 Jan 2023 10:22:10 +0100 Subject: [PATCH 639/704] Fix CloudBuildAllVars value formatting --- src/NerdBank.GitVersioning/VersionOracle.cs | 29 +++++++++++++++------ 1 file changed, 21 insertions(+), 8 deletions(-) diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 297da93c..9a6c9fc5 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -170,6 +170,7 @@ public IEnumerable BuildMetadataWithCommitId /// /// Gets the version options used to initialize this instance. /// + [Ignore] public VersionOptions? VersionOptions { get; } /// @@ -296,17 +297,29 @@ public IDictionary CloudBuildAllVars { var variables = new Dictionary(StringComparer.OrdinalIgnoreCase); - PropertyInfo[]? properties = this.GetType().GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); - foreach (PropertyInfo? property in properties) + PropertyInfo[] properties = this.GetType().GetTypeInfo().GetProperties(BindingFlags.Public | BindingFlags.DeclaredOnly | BindingFlags.Instance); + foreach (PropertyInfo property in properties) { - if (property.GetCustomAttribute() is null) + if (property.GetCustomAttribute() is not null) + { + continue; + } + + object? propertyValue = property.GetValue(this); + if (propertyValue is null) { - object? value = property.GetValue(this); - if (value is object) - { - variables.Add($"NBGV_{property.Name}", value.ToString() ?? string.Empty); - } + continue; } + + const string isoDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; + + string value = propertyValue switch + { + DateTimeOffset dateTimeOffset => dateTimeOffset.ToString(isoDateTimeFormat, CultureInfo.InvariantCulture), + _ => Convert.ToString(propertyValue, CultureInfo.InvariantCulture) ?? string.Empty, + }; + + variables.Add($"NBGV_{property.Name}", value); } return variables; From 1d09284ec92f9a50dc84d7c15a009688a22c889d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 4 Jan 2023 09:23:52 -0700 Subject: [PATCH 640/704] Switch code coverage from static to dynamic instrumentation --- azure-pipelines/test.runsettings | 2 -- 1 file changed, 2 deletions(-) diff --git a/azure-pipelines/test.runsettings b/azure-pipelines/test.runsettings index 975b7123..4e24a0a6 100644 --- a/azure-pipelines/test.runsettings +++ b/azure-pipelines/test.runsettings @@ -36,8 +36,6 @@ False True - True - False From c36559cdfe5273db85685f965919b7ee86452571 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 5 Jan 2023 13:44:09 -0700 Subject: [PATCH 641/704] Upgrade Microsoft.CodeCoverage --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index bfa98614..1acbd174 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ true - + From 77e4b5106dd74aa25564ba0631212146184a1f2d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 6 Jan 2023 09:30:23 -0700 Subject: [PATCH 642/704] Fix merge coverage error when output directory already exists --- azure-pipelines/Merge-CodeCoverage.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1 index 9fe925cf..02ff12b0 100644 --- a/azure-pipelines/Merge-CodeCoverage.ps1 +++ b/azure-pipelines/Merge-CodeCoverage.ps1 @@ -41,7 +41,7 @@ if ($reports) { $Inputs = $reports |% { Resolve-Path -relative $_.FullName } - if (Split-Path $OutputFile) { + if ((Split-Path $OutputFile) -and -not (Test-Path (Split-Path $OutputFile))) { New-Item -Type Directory -Path (Split-Path $OutputFile) | Out-Null } From b5ac6c12bb439b807fed51a0775b384adf5bdd88 Mon Sep 17 00:00:00 2001 From: clyvari Date: Tue, 10 Jan 2023 23:50:10 +0100 Subject: [PATCH 643/704] Improved error message in prepare-release when uncommited changes are present --- src/NerdBank.GitVersioning/ReleaseManager.cs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/ReleaseManager.cs b/src/NerdBank.GitVersioning/ReleaseManager.cs index d6fd752a..af5f9fd1 100644 --- a/src/NerdBank.GitVersioning/ReleaseManager.cs +++ b/src/NerdBank.GitVersioning/ReleaseManager.cs @@ -324,9 +324,12 @@ private LibGit2Context GetRepository(string projectDirectory) RepositoryStatus status = libgit2context.Repository.RetrieveStatus(); if (status.IsDirty) { - var changedFiles = status.OfType().ToList(); + // This filter copies the internal logic used by LibGit2 behind RepositoryStatus.IsDirty to tell if + // a repo is dirty or not + // Could be simplified if https://github.com/libgit2/libgit2sharp/pull/2004 is ever merged + var changedFiles = status.Where(file => file.State != FileStatus.Ignored && file.State != FileStatus.Unaltered).ToList(); string changesFilesFormatted = string.Join(Environment.NewLine, changedFiles.Select(t => $"- {t.FilePath} changed with {nameof(FileStatus)} {t.State}")); - this.stderr.WriteLine($"Uncommitted changes ({changedFiles.Count}) in directory '{projectDirectory}':"); + this.stderr.WriteLine($"No uncommitted changes are allowed, but {changedFiles.Count} are present in directory '{projectDirectory}':"); this.stderr.WriteLine(changesFilesFormatted); throw new ReleasePreparationException(ReleasePreparationError.UncommittedChanges); } From 9786b3c2cdf9abbedd4815b5db5d0a1f14befb21 Mon Sep 17 00:00:00 2001 From: clyvari Date: Wed, 11 Jan 2023 00:13:32 +0100 Subject: [PATCH 644/704] Modified nbgv-cli doc to mention uncommited change --- doc/nbgv-cli.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/doc/nbgv-cli.md b/doc/nbgv-cli.md index 3c9f46af..69b295a9 100644 --- a/doc/nbgv-cli.md +++ b/doc/nbgv-cli.md @@ -22,8 +22,9 @@ It will also add/modify your `Directory.Build.props` file in the root of your re If scripting for running in a CI build where global impact from installing a tool is undesirable, you can localize the tool installation: ```ps1 -dotnet tool install --tool-path . nbgv +dotnet tool install --tool-path my/path nbgv ``` +> Ensure your custom path is outside of your git repository, as the `nbgv` tool doesn't support uncommited changes At this point you can launch the tool using `./nbgv` in your build script. @@ -41,7 +42,7 @@ The `prepare-release` command automates the task of branching off the main devel The `prepare-release` command supports this working model by taking care of creating the release branch and updating `version.json` on both branches. -To prepare a release, run: +To prepare a release, first ensure there is no uncommited changes in your repository then run: ```ps1 nbgv prepare-release From eb847be2bae977a110c44d683d43e253cea8ec8c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 13 Jan 2023 06:54:39 -0700 Subject: [PATCH 645/704] .gitignore .DS_Store --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index 3bb49919..69599b87 100644 --- a/.gitignore +++ b/.gitignore @@ -349,3 +349,6 @@ MigrationBackup/ # dotnet tool local install directory .store/ + +# mac-created file to track user view preferences for a directory +.DS_Store From f4034853e251f6f9f221cceaf2fad81b7a08465c Mon Sep 17 00:00:00 2001 From: Sam Goldmann Date: Thu, 19 Jan 2023 22:12:05 -0500 Subject: [PATCH 646/704] write variables as both output and non-output in VSTS. --- .../CloudBuildServices/VisualStudioTeamServices.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs b/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs index f94bb8ea..f9ed964c 100644 --- a/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs +++ b/src/NerdBank.GitVersioning/CloudBuildServices/VisualStudioTeamServices.cs @@ -39,7 +39,11 @@ public IReadOnlyDictionary SetCloudBuildNumber(string buildNumbe public IReadOnlyDictionary SetCloudBuildVariable(string name, string value, TextWriter stdout, TextWriter stderr) { Utilities.FileOperationWithRetry(() => - (stdout ?? Console.Out).WriteLine($"##vso[task.setvariable variable={name};]{value}")); + { + TextWriter output = stdout ?? Console.Out; + output.WriteLine($"##vso[task.setvariable variable={name};]{value}"); + output.WriteLine($"##vso[task.setvariable variable={name};isOutput=true;]{value}"); + }); return GetDictionaryFor(name, value); } From 4f415c1cdc9b55f766523312b51e176002556866 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 20 Jan 2023 08:43:19 -0700 Subject: [PATCH 647/704] Use 'o' format specifier for DateTimeOffset --- src/NerdBank.GitVersioning/VersionOracle.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/NerdBank.GitVersioning/VersionOracle.cs b/src/NerdBank.GitVersioning/VersionOracle.cs index 9a6c9fc5..8f43f8c5 100644 --- a/src/NerdBank.GitVersioning/VersionOracle.cs +++ b/src/NerdBank.GitVersioning/VersionOracle.cs @@ -311,11 +311,9 @@ public IDictionary CloudBuildAllVars continue; } - const string isoDateTimeFormat = "yyyy'-'MM'-'dd'T'HH':'mm':'ss.FFFFFFFK"; - string value = propertyValue switch { - DateTimeOffset dateTimeOffset => dateTimeOffset.ToString(isoDateTimeFormat, CultureInfo.InvariantCulture), + DateTimeOffset dateTimeOffset => dateTimeOffset.ToString("o", CultureInfo.InvariantCulture), _ => Convert.ToString(propertyValue, CultureInfo.InvariantCulture) ?? string.Empty, }; From c4d099cb455f118c23cd10a2b53553fc38aba490 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 22 Jan 2023 09:06:39 -0700 Subject: [PATCH 648/704] Increase likelihood that folks set PackageProjectUrl property --- .editorconfig | 6 +++--- Directory.Build.props | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.editorconfig b/.editorconfig index c8b5de9a..07868777 100644 --- a/.editorconfig +++ b/.editorconfig @@ -19,12 +19,12 @@ indent_size = 4 insert_final_newline = true trim_trailing_whitespace = true -# Xml project files -[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj}] +# MSBuild project files +[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,props,targets}] indent_size = 2 # Xml config files -[*.{props,targets,ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}] +[*.{ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}] indent_size = 2 # JSON files diff --git a/Directory.Build.props b/Directory.Build.props index d722f5e4..35fd4f69 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -29,6 +29,7 @@ true $(MSBuildThisFileDirectory)strongname.snk + COMPANY-PLACEHOLDER COMPANY-PLACEHOLDER © COMPANY-PLACEHOLDER. All rights reserved. @@ -50,8 +51,7 @@ - - + $(PackageProjectUrl)/releases/tag/v$(Version) From 07df47ef04adb71c6d6a3e6bf8b560e5ff4c96db Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 22 Jan 2023 13:29:41 -0700 Subject: [PATCH 649/704] Bump Microsoft.CodeCoverage to 17.5.0-release-20230106-01 --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 1acbd174..02f1d707 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ true - + From f7f6ed362751d7a3fd9d11026a0a42ec10e1cf0b Mon Sep 17 00:00:00 2001 From: Kartheek Penagamuri <52756182+kartheekp-ms@users.noreply.github.com> Date: Tue, 31 Jan 2023 17:32:49 -0800 Subject: [PATCH 650/704] Use latest NuGet.exe version (#188) * Use latest NuGet.exe version * Use 6.4.0 NuGet.exe version --- azure-pipelines/Get-NuGetTool.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/azure-pipelines/Get-NuGetTool.ps1 b/azure-pipelines/Get-NuGetTool.ps1 index 4431adb9..3097c873 100644 --- a/azure-pipelines/Get-NuGetTool.ps1 +++ b/azure-pipelines/Get-NuGetTool.ps1 @@ -6,7 +6,7 @@ #> Param( [Parameter()] - [string]$NuGetVersion='5.2.0' + [string]$NuGetVersion='6.4.0' ) $toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" From 4de45d4b12398d099da69b59a2a18dcb4782ba87 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 1 Feb 2023 10:39:21 -0700 Subject: [PATCH 651/704] Bump Microsoft.CodeCoverage (#189) Bumps [Microsoft.CodeCoverage](https://github.com/microsoft/vstest) from 17.5.0-release-20230106-01 to 17.5.0-release-20230131-04. - [Release notes](https://github.com/microsoft/vstest/releases) - [Changelog](https://github.com/microsoft/vstest/blob/main/docs/releases.md) - [Commits](https://github.com/microsoft/vstest/commits) --- updated-dependencies: - dependency-name: Microsoft.CodeCoverage dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index 02f1d707..a46323fa 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,7 @@ true - + From 074684d303c83e0f4d8ef152a41045e6f74e8add Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 7 Feb 2023 20:38:47 -0700 Subject: [PATCH 652/704] Declare empty `_GetCopyToOutputDirectoryItemsFromThisProject` target --- src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj index 1beb338f..93d1906e 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj +++ b/src/Nerdbank.GitVersioning.Tasks/build/PrivateP2PCaching.proj @@ -9,6 +9,7 @@ + From 9cf6efb5b8b5fe82009d4ba8bf7aa8480945783c Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 7 Feb 2023 20:47:48 -0700 Subject: [PATCH 653/704] Refine `#if` conditions around use of attributes --- src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs | 2 +- test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs index 32794b03..d5d05d5a 100644 --- a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs @@ -25,7 +25,7 @@ public class AssemblyVersionInfo : Microsoft.Build.Utilities.Task /// /// private const string CompilerDefinesAroundGeneratedCodeAttribute = "NETSTANDARD || NETFRAMEWORK || NETCOREAPP"; - private const string CompilerDefinesAroundExcludeFromCodeCoverageAttribute = "NETFRAMEWORK || NETCOREAPP || NETSTANDARD2_0 || NETSTANDARD2_1"; + private const string CompilerDefinesAroundExcludeFromCodeCoverageAttribute = "NET40_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER"; private const string FileHeaderComment = @"------------------------------------------------------------------------------ This code was generated by a tool. diff --git a/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs b/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs index a7206c76..7acc991b 100644 --- a/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs +++ b/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs @@ -70,7 +70,7 @@ namespace AssemblyInfo #if NETSTANDARD || NETFRAMEWORK || NETCOREAPP [] #endif -#if NETFRAMEWORK || NETCOREAPP || NETSTANDARD2_0 || NETSTANDARD2_1 +#if NET40_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER [] #endif type internal ThisAssembly() = @@ -146,7 +146,7 @@ public void CSharpGenerator(bool? thisAssemblyClass) {(thisAssemblyClass.GetValueOrDefault(true) ? $@"#if NETSTANDARD || NETFRAMEWORK || NETCOREAPP [System.CodeDom.Compiler.GeneratedCode(""{AssemblyVersionInfo.GeneratorName}"",""{AssemblyVersionInfo.GeneratorVersion}"")] #endif -#if NETFRAMEWORK || NETCOREAPP || NETSTANDARD2_0 || NETSTANDARD2_1 +#if NET40_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER [System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] #endif internal static partial class ThisAssembly {{ @@ -200,7 +200,7 @@ public void VisualBasicGenerator(bool? thisAssemblyClass) -{(thisAssemblyClass.GetValueOrDefault(true) ? $@"#If NETFRAMEWORK Or NETCOREAPP Or NETSTANDARD2_0 Or NETSTANDARD2_1 Then +{(thisAssemblyClass.GetValueOrDefault(true) ? $@"#If NET40_OR_GREATER Or NETCOREAPP2_0_OR_GREATER Or NETSTANDARD2_0_OR_GREATER Then Partial Friend NotInheritable Class ThisAssembly From 196667f6bb050431e195fc24d4e14b96195b999d Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Feb 2023 06:28:22 -0700 Subject: [PATCH 654/704] Build fixes --- Directory.Packages.props | 3 +-- azure-pipelines.yml | 4 ++++ test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index c9e45b59..b3b36dc3 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -11,11 +11,10 @@ - - + diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 876d827b..f3604222 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -101,6 +101,10 @@ stages: pool: vmImage: $(imageName) steps: + - checkout: self + fetchDepth: 0 # avoid shallow clone so nbgv can do its work. + clean: true + submodules: true # keep the warnings quiet about the wiki not being enlisted - task: UseDotNet@2 displayName: Install .NET 7.0.101 SDK inputs: diff --git a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj index 8cc96898..254361be 100644 --- a/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj +++ b/test/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj @@ -15,7 +15,7 @@ - + From 6712b775c619d2aab486b5c0d8afdd09b56460c4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Feb 2023 06:37:11 -0700 Subject: [PATCH 655/704] More perf run fixes --- azure-pipelines.yml | 4 ++-- .../GetVersionBenchmarks.cs | 5 ++--- .../Nerdbank.GitVersioning.Benchmarks.csproj | 2 +- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index f3604222..fff3e430 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -123,7 +123,7 @@ stages: dotnet build -c Release displayName: Build in Release mode - script: | - dotnet run -c Release -f net6.0 -- --filter *GetVersionBenchmarks* --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) + dotnet run -c Release -f net7.0 -- --filter *GetVersionBenchmarks* --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/packed/$(imageName) workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (packed) - bash: | @@ -140,7 +140,7 @@ stages: git unpack-objects < .git/objects/pack/*.pack displayName: Unpack Git repositories - script: | - dotnet run -c Release -f net6.0 -- --filter '*GetVersionBenchmarks*' --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) + dotnet run -c Release -f net7.0 -- --filter '*GetVersionBenchmarks*' --artifacts $(Build.ArtifactStagingDirectory)/benchmarks/unpacked/$(imageName) workingDirectory: test/Nerdbank.GitVersioning.Benchmarks displayName: Run benchmarks (unpacked) - task: PublishBuildArtifacts@1 diff --git a/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs index 214ab17b..7a97daa8 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs +++ b/test/Nerdbank.GitVersioning.Benchmarks/GetVersionBenchmarks.cs @@ -9,9 +9,8 @@ namespace Nerdbank.GitVersioning.Benchmarks { - [SimpleJob(RuntimeMoniker.NetCoreApp31, baseline: true)] - [SimpleJob(RuntimeMoniker.Net60)] - [SimpleJob(RuntimeMoniker.Net461)] + [SimpleJob(RuntimeMoniker.Net70)] + [SimpleJob(RuntimeMoniker.Net462, baseline: true)] public class GetVersionBenchmarks { // You must manually clone these repositories: diff --git a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj index 3a2ea914..6e0ed52a 100644 --- a/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj +++ b/test/Nerdbank.GitVersioning.Benchmarks/Nerdbank.GitVersioning.Benchmarks.csproj @@ -1,7 +1,7 @@  - net6.0 + net7.0 $(TargetFrameworks);net462 Exe true From dd2159511d6cf270578b191b28b7e64afcf428ae Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Feb 2023 06:44:48 -0700 Subject: [PATCH 656/704] Avoid build number warnings, and set the build number earlier by moving to linux agent --- azure-pipelines/build.yml | 5 ++--- version.json | 5 ++++- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 96022d35..ed918468 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -26,9 +26,6 @@ jobs: & .\dotnet-install.ps1 -Architecture x86 -Version 7.0.101 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose displayName: ⚙ Install 32-bit .NET SDK and runtimes - - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' - displayName: ⚙ Set build number - - template: dotnet.yml parameters: RunTests: ${{ parameters.RunTests }} @@ -42,6 +39,8 @@ jobs: clean: true submodules: true # keep the warnings quiet about the wiki not being enlisted - template: install-dependencies.yml + - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' + displayName: ⚙ Set build number - template: dotnet.yml parameters: RunTests: ${{ parameters.RunTests }} diff --git a/version.json b/version.json index 04420d35..f71e8946 100644 --- a/version.json +++ b/version.json @@ -10,6 +10,9 @@ "^refs/heads/v\\d+\\.\\d+$" ], "cloudBuild": { - "setVersionVariables": false + "setVersionVariables": false, + "buildNumber": { + "enabled": false + } } } From 8cde04c964c032cd17a715eda1d43afd2ed75df2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Feb 2023 12:42:38 -0700 Subject: [PATCH 657/704] Add pipeline emoji icons --- azure-pipelines/dotnet.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/azure-pipelines/dotnet.yml b/azure-pipelines/dotnet.yml index 3fe2e61b..92ffd970 100644 --- a/azure-pipelines/dotnet.yml +++ b/azure-pipelines/dotnet.yml @@ -6,21 +6,21 @@ steps: - script: | git config --global user.name ci git config --global user.email me@ci.com - displayName: Configure git commit author for testing + displayName: ⚙️ Configure git commit author for testing - script: dotnet build -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" displayName: 🛠 dotnet build - script: dotnet pack -c $(BuildConfiguration) --no-build -p:PackLKG=true /bl:"$(Build.ArtifactStagingDirectory)/build_logs/msbuild_lkg.binlog" - displayName: Build LKG package + displayName: 🛠️ Build LKG package workingDirectory: src/Nerdbank.GitVersioning.Tasks - script: dotnet publish -c $(BuildConfiguration) -o ../nerdbank-gitversioning.npm/out/nbgv.cli/tools/net6.0/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog" - displayName: Publish nbgv tool + displayName: 📢 Publish nbgv tool workingDirectory: src/nbgv - script: yarn build - displayName: Build nerdbank-gitversioning NPM package + displayName: 🛠️ Build nerdbank-gitversioning NPM package workingDirectory: src/nerdbank-gitversioning.npm - powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults From 395dfa788929224eca785f5ed056da529b496c10 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Wed, 8 Feb 2023 14:37:28 -0700 Subject: [PATCH 658/704] Map only slices of idx files into memory This should help avoid OOMs thrown when operating on repos with very large git database files. More importantly, this fixes a leak where `SafeMemoryMappedViewHandle.ReleasePointer` was not getting called in `GitPackIndexMappedReader`. Without calling this, the native memory just leaks until the msbuild.exe process crashes. --- .../ManagedGit/GitPackIndexMappedReader.cs | 88 +++++++++++++++---- 1 file changed, 70 insertions(+), 18 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs index 34449d82..6136e952 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs @@ -1,6 +1,8 @@ // Copyright (c) .NET Foundation and Contributors. All rights reserved. // Licensed under the MIT license. See LICENSE file in the project root for full license information. +#nullable enable + using System.Buffers.Binary; using System.Diagnostics; using System.IO.MemoryMappedFiles; @@ -14,16 +16,19 @@ namespace Nerdbank.GitVersioning.ManagedGit; public unsafe class GitPackIndexMappedReader : GitPackIndexReader { private readonly MemoryMappedFile file; - private readonly MemoryMappedViewAccessor accessor; // The fanout table consists of // 256 4-byte network byte order integers. // The N-th entry of this table records the number of objects in the corresponding pack, // the first byte of whose object name is less than or equal to N. private readonly int[] fanoutTable = new int[257]; + private readonly ulong fileLength; - private readonly byte* ptr; private bool initialized; + private MemoryMappedViewAccessor? accessor; + private ulong accessorOffset; + private ulong accessorSize; + private byte* accessorPtr; /// /// Initializes a new instance of the class. @@ -38,17 +43,8 @@ public GitPackIndexMappedReader(FileStream stream) throw new ArgumentNullException(nameof(stream)); } + this.fileLength = (ulong)stream.Length; this.file = MemoryMappedFile.CreateFromFile(stream, mapName: null, capacity: 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); - this.accessor = this.file.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); - this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.ptr); - } - - private ReadOnlySpan Value - { - get - { - return new ReadOnlySpan(this.ptr, (int)this.accessor.Capacity); - } } /// @@ -69,7 +65,7 @@ public override (long? Offset, GitObjectId? ObjectId) GetOffset(Span objec int order = 0; int tableSize = 20 * (packEnd - packStart + 1); - ReadOnlySpan table = this.Value.Slice(4 + 4 + (256 * 4) + (20 * packStart), tableSize); + ReadOnlySpan table = this.GetSpan((ulong)(4 + 4 + (256 * 4) + (20 * packStart)), tableSize); int originalPackStart = packStart; @@ -117,7 +113,7 @@ public override (long? Offset, GitObjectId? ObjectId) GetOffset(Span objec // Get the offset value. It's located at: // 4 (header) + 4 (version) + 256 * 4 (fanout table) + 20 * objectCount (SHA1 object name table) + 4 * objectCount (CRC32) + 4 * i (offset values) int offsetTableStart = 4 + 4 + (256 * 4) + (20 * objectCount) + (4 * objectCount); - ReadOnlySpan offsetBuffer = this.Value.Slice(offsetTableStart + (4 * (i + originalPackStart)), 4); + ReadOnlySpan offsetBuffer = this.GetSpan((ulong)(offsetTableStart + (4 * (i + originalPackStart))), 4); uint offset = BinaryPrimitives.ReadUInt32BigEndian(offsetBuffer); if (offsetBuffer[0] < 128) @@ -130,7 +126,7 @@ public override (long? Offset, GitObjectId? ObjectId) GetOffset(Span objec // which follows the table of 4-byte offset entries: "large offsets are encoded as an index into the next table with the msbit set." offset = offset & 0x7FFFFFFF; - offsetBuffer = this.Value.Slice(offsetTableStart + (4 * objectCount) + (8 * (int)offset), 8); + offsetBuffer = this.GetSpan((ulong)(offsetTableStart + (4 * objectCount) + (8 * (int)offset)), 8); long offset64 = BinaryPrimitives.ReadInt64BigEndian(offsetBuffer); return (offset64, GitObjectId.Parse(table.Slice(20 * i, 20))); } @@ -139,22 +135,78 @@ public override (long? Offset, GitObjectId? ObjectId) GetOffset(Span objec /// public override void Dispose() { - this.accessor.Dispose(); + if (this.accessorPtr is not null && this.accessor is not null) + { + this.accessor.SafeMemoryMappedViewHandle.ReleasePointer(); + this.accessorPtr = null; + } + + this.accessor?.Dispose(); + this.accessor = null; this.file.Dispose(); } + private unsafe ReadOnlySpan GetSpan(ulong offset, int length) + { + checked + { + // If the request is for a window that we have not currently mapped, throw away what we have. + if (this.accessor is not null && (this.accessorOffset > offset || this.accessorOffset + this.accessorSize < offset + (ulong)length)) + { + if (this.accessorPtr is not null) + { + this.accessor.SafeMemoryMappedViewHandle.ReleasePointer(); + this.accessorPtr = null; + } + + this.accessor.Dispose(); + this.accessor = null; + } + + if (this.accessor is null) + { + const int minimumLength = 10 * 1024 * 1024; + uint windowSize = (uint)Math.Min((ulong)Math.Max(minimumLength, length), this.fileLength); + + // Push window 'to the left' if our preferred minimum size doesn't fit when we start at the offset requested. + ulong actualOffset = offset + windowSize > this.fileLength ? this.fileLength - windowSize : offset; + + this.accessor = this.file.CreateViewAccessor((long)actualOffset, windowSize, MemoryMappedFileAccess.Read); + + // Record the *actual* offset into the file that the pointer to native memory points at. + // This may be earlier in the file than we requested, and if so, go ahead and take advantage of that. + this.accessorOffset = actualOffset - (ulong)this.accessor.PointerOffset; + + // Also record the *actual* length of the mapped memory, again so we can take full advantage before reallocating the view. + this.accessorSize = this.accessor.SafeMemoryMappedViewHandle.ByteLength; + } + + Debug.Assert(offset >= (ulong)this.accessor.PointerOffset); + byte* ptr = this.accessorPtr; + if (ptr is null) + { + this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.accessorPtr); + ptr = this.accessorPtr; + } + + ptr += offset - this.accessorOffset; + return new ReadOnlySpan(ptr, length); + } + } + private void Initialize() { if (!this.initialized) { - ReadOnlySpan value = this.Value; + const int fanoutTableLength = 256; + ReadOnlySpan value = this.GetSpan(0, 4 + (4 * fanoutTableLength) + 4); ReadOnlySpan header = value.Slice(0, 4); int version = BinaryPrimitives.ReadInt32BigEndian(value.Slice(4, 4)); Debug.Assert(header.SequenceEqual(Header)); Debug.Assert(version == 2); - for (int i = 1; i <= 256; i++) + for (int i = 1; i <= fanoutTableLength; i++) { this.fanoutTable[i] = BinaryPrimitives.ReadInt32BigEndian(value.Slice(4 + (4 * i), 4)); } From 57d6a59dfef27a5249bbef7854666fc709b31f00 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Feb 2023 08:56:36 -0700 Subject: [PATCH 659/704] Add missing crosstargeting import --- src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec | 1 + 1 file changed, 1 insertion(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 28b573e0..531e09dc 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -56,6 +56,7 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj + From f17518be33e4b76fafc8f4b3a6096aa00ca8ceb1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Feb 2023 16:46:32 -0700 Subject: [PATCH 660/704] Update the dotnet-install.ps1 script This enables downloading newer SDK versions. --- tools/Install-DotNetSdk.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 2bac3b9b..a71ff3fd 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -234,10 +234,10 @@ if ($IncludeX86) { } if ($IsMacOS -or $IsLinux) { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.sh" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/88bd34f089b8a023e3523f22c92abd0ab88e4409/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/781752509a890ca7520f1182e8bae71f9a53d754/src/dotnet-install.ps1" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/88bd34f089b8a023e3523f22c92abd0ab88e4409/src/dotnet-install.ps1" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } From 551183c1e900d30e0e8b7623c910be160a690b4e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Feb 2023 16:52:41 -0700 Subject: [PATCH 661/704] Improve error message for unsupported versions --- tools/Install-DotNetSdk.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index a71ff3fd..14f4c8c4 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -98,7 +98,12 @@ Function Get-InstallerExe( [string]$sku ) { # Get the latest/actual version for the specified one - $TypedVersion = [Version]$Version + $TypedVersion = $null + if (![Version]::TryParse($Version, [ref] $TypedVersion)) { + Write-Error "Unable to parse $Version into an a.b.c.d version. This version cannot be installed machine-wide." + exit 1 + } + if ($TypedVersion.Build -eq -1) { $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sku/$Version/latest.version" -UseBasicParsing) $Version = $versionInfo[-1] From 8381192a53608e7a655dfaf4f58a6edf64f8fa76 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Feb 2023 17:00:31 -0700 Subject: [PATCH 662/704] Remove references to "Core" in .NET Core --- tools/Install-DotNetSdk.ps1 | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 14f4c8c4..47ccf22e 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -3,7 +3,7 @@ <# .SYNOPSIS Installs the .NET SDK specified in the global.json file at the root of this repository, - along with supporting .NET Core runtimes used for testing. + along with supporting .NET runtimes used for testing. .DESCRIPTION This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location, unless `-InstallLocality machine` is specified. @@ -43,7 +43,7 @@ if (!$arch) { # Windows Powershell leaves this blank if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' } } -# Search for all .NET Core runtime versions referenced from MSBuild projects and arrange to install them. +# Search for all .NET runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() $windowsDesktopRuntimeVersions = @() Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { @@ -145,9 +145,9 @@ Function Get-InstallerExe( } Function Install-DotNet($Version, $Architecture, [ValidateSet('Sdk','Runtime','WindowsDesktop')][string]$sku = 'Sdk') { - Write-Host "Downloading .NET Core $sku $Version..." + Write-Host "Downloading .NET $sku $Version..." $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -sku $sku - Write-Host "Installing .NET Core $sku $Version..." + Write-Host "Installing .NET $sku $Version..." cmd /c start /wait $Installer /install /passive /norestart if ($LASTEXITCODE -eq 3010) { Write-Verbose "Restart required" @@ -290,7 +290,7 @@ if ($IncludeX86) { $dotnetRuntimeSwitches = $switches + '-Runtime','dotnet' $runtimeVersions | Sort-Object -Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core $Arch runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET $Arch runtime $_", "Install")) { $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $dotnetRuntimeSwitches" @@ -303,7 +303,7 @@ $runtimeVersions | Sort-Object -Unique |% { } if ($IncludeX86) { - if ($PSCmdlet.ShouldProcess(".NET Core x86 runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET x86 runtime $_", "Install")) { $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $dotnetRuntimeSwitches" @@ -320,7 +320,7 @@ $runtimeVersions | Sort-Object -Unique |% { $windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop' $windowsDesktopRuntimeVersions | Sort-Object -Unique |% { - if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop $arch runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET WindowsDesktop $arch runtime $_", "Install")) { $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $windowsDesktopRuntimeSwitches" @@ -333,7 +333,7 @@ $windowsDesktopRuntimeVersions | Sort-Object -Unique |% { } if ($IncludeX86) { - if ($PSCmdlet.ShouldProcess(".NET Core WindowsDesktop x86 runtime $_", "Install")) { + if ($PSCmdlet.ShouldProcess(".NET WindowsDesktop x86 runtime $_", "Install")) { $anythingInstalled = $true Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $windowsDesktopRuntimeSwitches" @@ -352,5 +352,5 @@ if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these } if ($anythingInstalled -and ($InstallLocality -ne 'machine') -and !$env:TF_BUILD -and !$env:GITHUB_ACTIONS) { - Write-Warning ".NET Core runtimes or SDKs were installed to a non-machine location. Perform your builds or open Visual Studio from this same environment in order for tools to discover the location of these dependencies." + Write-Warning ".NET runtimes or SDKs were installed to a non-machine location. Perform your builds or open Visual Studio from this same environment in order for tools to discover the location of these dependencies." } From d19033347c00cf09ef9201a6a4d25a19673d8de4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 9 Feb 2023 17:07:26 -0700 Subject: [PATCH 663/704] Add -SdkOnly switch --- tools/Install-DotNetSdk.ps1 | 53 ++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 24 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 47ccf22e..39e47eb6 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -15,6 +15,8 @@ When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used. Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`. Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it. +.PARAMETER SdkOnly + Skips installing the runtime. .PARAMETER IncludeX86 Installs a x86 SDK and runtimes in addition to the x64 ones. Only supported on Windows. Ignored on others. #> @@ -22,6 +24,7 @@ Param ( [ValidateSet('repo','user','machine')] [string]$InstallLocality='user', + [switch]$SdkOnly, [switch]$IncludeX86 ) @@ -46,34 +49,36 @@ if (!$arch) { # Windows Powershell leaves this blank # Search for all .NET runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() $windowsDesktopRuntimeVersions = @() -Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { - $projXml = [xml](Get-Content -Path $_) - $pg = $projXml.Project.PropertyGroup - if ($pg) { - $targetFrameworks = @() - $tf = $pg.TargetFramework - $targetFrameworks += $tf - $tfs = $pg.TargetFrameworks - if ($tfs) { - $targetFrameworks = $tfs -Split ';' +if (!$SdkOnly) { + Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { + $projXml = [xml](Get-Content -Path $_) + $pg = $projXml.Project.PropertyGroup + if ($pg) { + $targetFrameworks = @() + $tf = $pg.TargetFramework + $targetFrameworks += $tf + $tfs = $pg.TargetFrameworks + if ($tfs) { + $targetFrameworks = $tfs -Split ';' + } } - } - $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% { - $v = $Matches[1] - $runtimeVersions += $v - if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) { - $windowsDesktopRuntimeVersions += $v + $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% { + $v = $Matches[1] + $runtimeVersions += $v + if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) { + $windowsDesktopRuntimeVersions += $v + } } - } - # Add target frameworks of the form: netXX - $targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% { - $v = $Matches[1] - $runtimeVersions += $v - if (-not ($IsMacOS -or $IsLinux)) { - $windowsDesktopRuntimeVersions += $v + # Add target frameworks of the form: netXX + $targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% { + $v = $Matches[1] + $runtimeVersions += $v + if (-not ($IsMacOS -or $IsLinux)) { + $windowsDesktopRuntimeVersions += $v + } } - } + } } Function Get-FileFromWeb([Uri]$Uri, $OutDir) { From 1aa9eca8727b517ef805f7e61ea57d578ccd4e49 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 10 Feb 2023 16:01:08 -0700 Subject: [PATCH 664/704] Bump tests to .NET 7 This is an attempt to get msbuildlocator to work on Azure Pipelines. --- .../Nerdbank.GitVersioning.Tests.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index c84cab46..a79c174d 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -1,6 +1,6 @@  - net6.0;net472 + net7.0;net472 true true full From 8d168d2c5365ee7aaa0c6add02748174bc3ef977 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 10 Feb 2023 16:36:49 -0700 Subject: [PATCH 665/704] Fix tests to find 32-bit MSBuild when required --- .../MSBuildExtensions.cs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs b/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs index 84679522..6cb214b9 100644 --- a/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs +++ b/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs @@ -21,7 +21,20 @@ internal static void LoadMSBuild() { if (!loaded) { +#if NET + if (IntPtr.Size == 4) + { + // 32-bit .NET runtime requires special code to find the x86 SDK (where MSBuild is). + MSBuildLocator.RegisterMSBuildPath(@"C:\Program Files (x86)\dotnet\sdk\7.0.101"); + } + else + { + MSBuildLocator.RegisterDefaults(); + } +#else MSBuildLocator.RegisterDefaults(); +#endif + loaded = true; } } From c01126d8e995b239a17341ecec2e85bd0e02129b Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 13 Feb 2023 16:19:46 -0700 Subject: [PATCH 666/704] Simplify Version cast in ps1 script --- tools/Install-DotNetSdk.ps1 | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 2bac3b9b..a8635f49 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -92,19 +92,18 @@ Function Get-FileFromWeb([Uri]$Uri, $OutDir) { } Function Get-InstallerExe( - $Version, + [Version]$Version, $Architecture, [ValidateSet('Sdk','Runtime','WindowsDesktop')] [string]$sku ) { # Get the latest/actual version for the specified one - $TypedVersion = [Version]$Version - if ($TypedVersion.Build -eq -1) { + if ($Version.Build -eq -1) { $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sku/$Version/latest.version" -UseBasicParsing) $Version = $versionInfo[-1] } - $majorMinor = "$($TypedVersion.Major).$($TypedVersion.Minor)" + $majorMinor = "$($Version.Major).$($Version.Minor)" $ReleasesFile = Join-Path $DotNetInstallScriptRoot "$majorMinor\releases.json" if (!(Test-Path $ReleasesFile)) { Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile) | Out-Null From e11c7860796f7c58b356fed8522e44446aa08db1 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 14 Feb 2023 09:15:07 -0700 Subject: [PATCH 667/704] Fix A/V thrown from while reading the git pack index We had been mapping only parts of the index into memory, and shifting the mapped window with each call to `GetSpan`. The problem was the caller would use `GetSpan` more than once, and hold each result such that it had a pointer/span into both windows when only one existed at any given point. This fixes a regression made in #892 (395dfa788929224eca785f5ed056da529b496c10). In that change, I tried to reduce the mapped file from the whole file to just a window. That was as part of fixing an `OutOfMemoryException`, but ultimately I believe that was due to a memory leak, which that PR also fixed. So in this change I keep the memory leak fix (by releasing the acquired pointer) but revert the smaller, moving window code change. --- .../ManagedGit/GitPackIndexMappedReader.cs | 65 +++---------------- 1 file changed, 8 insertions(+), 57 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs index 6136e952..4f71d023 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/GitPackIndexMappedReader.cs @@ -16,19 +16,16 @@ namespace Nerdbank.GitVersioning.ManagedGit; public unsafe class GitPackIndexMappedReader : GitPackIndexReader { private readonly MemoryMappedFile file; + private readonly MemoryMappedViewAccessor accessor; // The fanout table consists of // 256 4-byte network byte order integers. // The N-th entry of this table records the number of objects in the corresponding pack, // the first byte of whose object name is less than or equal to N. private readonly int[] fanoutTable = new int[257]; - private readonly ulong fileLength; + private byte* ptr; private bool initialized; - private MemoryMappedViewAccessor? accessor; - private ulong accessorOffset; - private ulong accessorSize; - private byte* accessorPtr; /// /// Initializes a new instance of the class. @@ -43,8 +40,9 @@ public GitPackIndexMappedReader(FileStream stream) throw new ArgumentNullException(nameof(stream)); } - this.fileLength = (ulong)stream.Length; this.file = MemoryMappedFile.CreateFromFile(stream, mapName: null, capacity: 0, MemoryMappedFileAccess.Read, HandleInheritability.None, leaveOpen: false); + this.accessor = this.file.CreateViewAccessor(0, 0, MemoryMappedFileAccess.Read); + this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.ptr); } /// @@ -135,64 +133,17 @@ public override (long? Offset, GitObjectId? ObjectId) GetOffset(Span objec /// public override void Dispose() { - if (this.accessorPtr is not null && this.accessor is not null) + if (this.ptr is not null) { this.accessor.SafeMemoryMappedViewHandle.ReleasePointer(); - this.accessorPtr = null; + this.ptr = null; } - this.accessor?.Dispose(); - this.accessor = null; + this.accessor.Dispose(); this.file.Dispose(); } - private unsafe ReadOnlySpan GetSpan(ulong offset, int length) - { - checked - { - // If the request is for a window that we have not currently mapped, throw away what we have. - if (this.accessor is not null && (this.accessorOffset > offset || this.accessorOffset + this.accessorSize < offset + (ulong)length)) - { - if (this.accessorPtr is not null) - { - this.accessor.SafeMemoryMappedViewHandle.ReleasePointer(); - this.accessorPtr = null; - } - - this.accessor.Dispose(); - this.accessor = null; - } - - if (this.accessor is null) - { - const int minimumLength = 10 * 1024 * 1024; - uint windowSize = (uint)Math.Min((ulong)Math.Max(minimumLength, length), this.fileLength); - - // Push window 'to the left' if our preferred minimum size doesn't fit when we start at the offset requested. - ulong actualOffset = offset + windowSize > this.fileLength ? this.fileLength - windowSize : offset; - - this.accessor = this.file.CreateViewAccessor((long)actualOffset, windowSize, MemoryMappedFileAccess.Read); - - // Record the *actual* offset into the file that the pointer to native memory points at. - // This may be earlier in the file than we requested, and if so, go ahead and take advantage of that. - this.accessorOffset = actualOffset - (ulong)this.accessor.PointerOffset; - - // Also record the *actual* length of the mapped memory, again so we can take full advantage before reallocating the view. - this.accessorSize = this.accessor.SafeMemoryMappedViewHandle.ByteLength; - } - - Debug.Assert(offset >= (ulong)this.accessor.PointerOffset); - byte* ptr = this.accessorPtr; - if (ptr is null) - { - this.accessor.SafeMemoryMappedViewHandle.AcquirePointer(ref this.accessorPtr); - ptr = this.accessorPtr; - } - - ptr += offset - this.accessorOffset; - return new ReadOnlySpan(ptr, length); - } - } + private ReadOnlySpan GetSpan(ulong offset, int length) => new ReadOnlySpan(this.ptr + offset, length); private void Initialize() { From b3a68a9e4a6c37996ef969a54ac059ab62eae3d2 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 16 Feb 2023 13:02:03 -0700 Subject: [PATCH 668/704] Use LF line endings for plist files The mac tools that read these files are sticklers for LF endings. --- .gitattributes | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitattributes b/.gitattributes index c22a129e..1f35e683 100644 --- a/.gitattributes +++ b/.gitattributes @@ -7,6 +7,9 @@ *.sh eol=lf *.ps1 eol=lf +# The macOS codesign tool is extremely picky, and requires LF line endings. +*.plist eol=lf + ############################################################################### # Set default behavior for command prompt diff. # From b579c7cabdad15c7b0b86446309f5297bd71cbb4 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 16 Feb 2023 13:04:55 -0700 Subject: [PATCH 669/704] Add `-interactive` switch to init.ps1 --- init.ps1 | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/init.ps1 b/init.ps1 index 774ead58..ad3b4145 100755 --- a/init.ps1 +++ b/init.ps1 @@ -30,6 +30,8 @@ Skips the package restore step. .PARAMETER AccessToken An optional access token for authenticating to Azure Artifacts authenticated feeds. +.PARAMETER Interactive + Runs NuGet restore in interactive mode. This can turn authentication failures into authentication challenges. #> [CmdletBinding(SupportsShouldProcess = $true)] Param ( @@ -44,7 +46,9 @@ Param ( [Parameter()] [switch]$NoRestore, [Parameter()] - [string]$AccessToken + [string]$AccessToken, + [Parameter()] + [switch]$Interactive ) $EnvVars = @{} @@ -76,8 +80,14 @@ try { $HeaderColor = 'Green' if (!$NoRestore -and $PSCmdlet.ShouldProcess("NuGet packages", "Restore")) { + $RestoreArguments = @() + if ($Interactive) + { + $RestoreArguments += '--interactive' + } + Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor - dotnet restore + dotnet restore @RestoreArguments if ($lastexitcode -ne 0) { throw "Failure while restoring packages." } From 066c0db340a54decb7144a7a9a007f6e7318f4ef Mon Sep 17 00:00:00 2001 From: Georg Jung Date: Wed, 22 Feb 2023 16:17:52 +0100 Subject: [PATCH 670/704] Avoid shallow cloning --- azure-pipelines.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index c67d1364..2bac596a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -101,6 +101,8 @@ stages: pool: vmImage: $(imageName) steps: + - checkout: self + fetchDepth: 0 # avoid shallow clone so nbgv can do its work. - task: UseDotNet@2 displayName: Install .NET 6.0.403 SDK inputs: From 91bea7e6e9f82e1d5086429f27efcefa93a04514 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Feb 2023 10:06:33 -0700 Subject: [PATCH 671/704] Use Node.js v16 --- CONTRIBUTING.md | 2 +- azure-pipelines/install-dependencies.yml | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 09656a68..86ea3ae2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ It is highly recommended that anyone contributing to this library use the same software. 1. [Visual Studio 2019][VS] -2. [Node.js][NodeJs] +2. [Node.js][NodeJs] v16 (v18 breaks our build) ### Optional additional software diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml index 81782668..761d1800 100644 --- a/azure-pipelines/install-dependencies.yml +++ b/azure-pipelines/install-dependencies.yml @@ -3,6 +3,11 @@ parameters: steps: +- task: NodeTool@0 + inputs: + versionSpec: 16.x + displayName: ⚙️ Install Node.js + - task: NuGetAuthenticate@1 displayName: 🔏 Authenticate NuGet feeds inputs: From 578ce8fc1f2aebfc5f5fb06422bf90b412bcaf73 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Thu, 23 Feb 2023 10:06:33 -0700 Subject: [PATCH 672/704] Use Node.js v16 --- CONTRIBUTING.md | 2 +- azure-pipelines.yml | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 09656a68..86ea3ae2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,7 +10,7 @@ It is highly recommended that anyone contributing to this library use the same software. 1. [Visual Studio 2019][VS] -2. [Node.js][NodeJs] +2. [Node.js][NodeJs] v16 (v18 breaks our build) ### Optional additional software diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 914908dd..505b16d9 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -72,6 +72,10 @@ stages: packageType: sdk version: 6.0.100 + - task: NodeTool@0 + inputs: + versionSpec: 16.x + displayName: ⚙️ Install Node.js - pwsh: | Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 From 6415323a89947e6d5d2229cd606cb02d18c1c474 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 24 Feb 2023 13:07:15 -0700 Subject: [PATCH 673/704] Bump dependencies to 17.5.0 versions --- Directory.Packages.props | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index a46323fa..b792f3f6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,8 +5,8 @@ true - - + + From 34f1344df70ea081e1875a83bf852c7bc4709954 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 27 Feb 2023 09:28:14 -0700 Subject: [PATCH 674/704] Add msbuild extension for VS Code --- .vscode/extensions.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 4ca01616..ca3a2aa9 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -11,7 +11,8 @@ "davidanson.vscode-markdownlint", "dotjoshjohnson.xml", "ms-vscode-remote.remote-containers", - "ms-azuretools.vscode-docker" + "ms-azuretools.vscode-docker", + "tintoy.msbuild-project-tools" ], // List of extensions recommended by VS Code that should not be recommended for users of this workspace. "unwantedRecommendations": [] From fb2395d9a7cc483f5f1a37a82b104fde93883b34 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 27 Feb 2023 09:46:58 -0700 Subject: [PATCH 675/704] Add dotnet CLI tools --- .config/dotnet-tools.json | 18 ++++++++++++++++++ init.ps1 | 5 +++++ 2 files changed, 23 insertions(+) create mode 100644 .config/dotnet-tools.json diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 00000000..2599e26a --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,18 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "powershell": { + "version": "7.3.3", + "commands": [ + "pwsh" + ] + }, + "dotnet-format": { + "version": "5.1.250801", + "commands": [ + "dotnet-format" + ] + } + } +} \ No newline at end of file diff --git a/init.ps1 b/init.ps1 index ad3b4145..5bace1e6 100755 --- a/init.ps1 +++ b/init.ps1 @@ -91,6 +91,11 @@ try { if ($lastexitcode -ne 0) { throw "Failure while restoring packages." } + + dotnet tool restore @RestoreArguments + if ($lastexitcode -ne 0) { + throw "Failure while restoring dotnet CLI tools." + } } & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars -PrependPath $PrependPath | Out-Null From 1c74cec97e6835dfe6a8e1806bf25251361f91e8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 27 Feb 2023 10:51:56 -0700 Subject: [PATCH 676/704] Avoid build break for msbuild projects that do not set `$(Language)` --- .../build/Nerdbank.GitVersioning.targets | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index c25fe0fd..1a65d0fe 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -112,7 +112,7 @@ - + $([MSBuild]::NormalizePath('$(IntermediateOutputPath)', '$(AssemblyName).Version$(DefaultLanguageSourceExtension)')) $(VersionSourceFile).new From 0bfecd61cceeeb70cbe038c00fd8aac38b7ce32e Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 27 Feb 2023 15:23:55 -0700 Subject: [PATCH 677/704] Drop test-tools as a nuget feed source We don't need it now that we're using stable Microsoft.CodeCoverage package versions. --- nuget.config | 9 --------- 1 file changed, 9 deletions(-) diff --git a/nuget.config b/nuget.config index 6ce7cfd0..22f7b809 100644 --- a/nuget.config +++ b/nuget.config @@ -7,18 +7,9 @@ - - - - - - - - - From b9d3738c44be1103609c77d4a5f53b865c8412da Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 7 Mar 2023 12:46:51 -0700 Subject: [PATCH 678/704] Fix compiler warning --- src/NerdBank.GitVersioning/VersionFile.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/NerdBank.GitVersioning/VersionFile.cs b/src/NerdBank.GitVersioning/VersionFile.cs index c2ba6e05..02f78a94 100644 --- a/src/NerdBank.GitVersioning/VersionFile.cs +++ b/src/NerdBank.GitVersioning/VersionFile.cs @@ -44,7 +44,7 @@ protected VersionFile(GitContext context) public bool IsVersionDefined() => this.GetVersion() is object; /// - public VersionOptions? GetWorkingCopyVersion() => this.GetWorkingCopyVersion(out string _); + public VersionOptions? GetWorkingCopyVersion() => this.GetWorkingCopyVersion(out _); /// /// Reads the version file from the working tree and returns the deserialized from it. @@ -213,7 +213,7 @@ protected static VersionOptions TryReadVersionFile(TextReader versionTextContent { if (parentDirectory is object) { - result = this.GetWorkingCopyVersion(parentDirectory, out string _); + result = this.GetWorkingCopyVersion(parentDirectory, out _); if (result is object) { JsonConvert.PopulateObject( From 5132c2206f248cc3ff0e65c0a087a74b6d734d77 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 11 Mar 2023 16:30:55 -0700 Subject: [PATCH 679/704] Add ASP.NET Core runtime installation support --- tools/Install-DotNetSdk.ps1 | 59 ++++++++++++++++++++++++++++++++++--- 1 file changed, 55 insertions(+), 4 deletions(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 39e47eb6..6bff5c27 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -19,13 +19,16 @@ Skips installing the runtime. .PARAMETER IncludeX86 Installs a x86 SDK and runtimes in addition to the x64 ones. Only supported on Windows. Ignored on others. +.PARAMETER IncludeAspNetCore + Installs the ASP.NET Core runtime along with the .NET runtime. #> [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')] Param ( [ValidateSet('repo','user','machine')] [string]$InstallLocality='user', [switch]$SdkOnly, - [switch]$IncludeX86 + [switch]$IncludeX86, + [switch]$IncludeAspNetCore ) $DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools" @@ -49,6 +52,7 @@ if (!$arch) { # Windows Powershell leaves this blank # Search for all .NET runtime versions referenced from MSBuild projects and arrange to install them. $runtimeVersions = @() $windowsDesktopRuntimeVersions = @() +$aspnetRuntimeVersions = @() if (!$SdkOnly) { Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% { $projXml = [xml](Get-Content -Path $_) @@ -65,6 +69,7 @@ if (!$SdkOnly) { $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% { $v = $Matches[1] $runtimeVersions += $v + $aspnetRuntimeVersions += $v if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) { $windowsDesktopRuntimeVersions += $v } @@ -74,6 +79,7 @@ if (!$SdkOnly) { $targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% { $v = $Matches[1] $runtimeVersions += $v + $aspnetRuntimeVersions += $v if (-not ($IsMacOS -or $IsLinux)) { $windowsDesktopRuntimeVersions += $v } @@ -81,6 +87,10 @@ if (!$SdkOnly) { } } +if (!$IncludeAspNetCore) { + $aspnetRuntimeVersions = @() +} + Function Get-FileFromWeb([Uri]$Uri, $OutDir) { $OutFile = Join-Path $OutDir $Uri.Segments[-1] if (!(Test-Path $OutFile)) { @@ -149,7 +159,7 @@ Function Get-InstallerExe( } } -Function Install-DotNet($Version, $Architecture, [ValidateSet('Sdk','Runtime','WindowsDesktop')][string]$sku = 'Sdk') { +Function Install-DotNet($Version, $Architecture, [ValidateSet('Sdk','Runtime','WindowsDesktop','AspNetCore')][string]$sku = 'Sdk') { Write-Host "Downloading .NET $sku $Version..." $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -sku $sku Write-Host "Installing .NET $sku $Version..." @@ -206,6 +216,17 @@ if ($InstallLocality -eq 'machine') { } } + $aspnetRuntimeVersions | Sort-Object | Get-Unique |% { + if ($PSCmdlet.ShouldProcess("ASP.NET Core $_", "Install")) { + Install-DotNet -Version $_ -sku AspNetCore -Architecture $arch + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + + if ($IncludeX86) { + Install-DotNet -Version $_ -sku AspNetCore -Architecture x86 + $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010) + } + } + } if ($restartRequired) { Write-Host -ForegroundColor Yellow "System restart required" Exit 3010 @@ -244,10 +265,10 @@ if ($IncludeX86) { } if ($IsMacOS -or $IsLinux) { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/88bd34f089b8a023e3523f22c92abd0ab88e4409/src/dotnet-install.sh" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/0b09de9bc136cacb5f849a6957ebd4062173c148/src/dotnet-install.sh" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh" } else { - $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/88bd34f089b8a023e3523f22c92abd0ab88e4409/src/dotnet-install.ps1" + $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/0b09de9bc136cacb5f849a6957ebd4062173c148/src/dotnet-install.ps1" $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1" } @@ -352,6 +373,36 @@ $windowsDesktopRuntimeVersions | Sort-Object -Unique |% { } } +$aspnetRuntimeSwitches = $switches + '-Runtime','aspnetcore' + +$aspnetRuntimeVersions | Sort-Object -Unique |% { + if ($PSCmdlet.ShouldProcess(".NET ASP.NET Core $arch runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $aspnetRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $aspnetRuntimeSwitches -DryRun" + } + + if ($IncludeX86) { + if ($PSCmdlet.ShouldProcess(".NET ASP.NET Core x86 runtime $_", "Install")) { + $anythingInstalled = $true + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $aspnetRuntimeSwitches" + + if ($LASTEXITCODE -ne 0) { + Write-Error ".NET SDK installation failure: $LASTEXITCODE" + exit $LASTEXITCODE + } + } else { + Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $aspnetRuntimeSwitches -DryRun" + } + } +} + if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) { & "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null } From a921f8dcaf0ba4f93dfec660f503d17ce19d58ea Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 11 Mar 2023 16:40:50 -0700 Subject: [PATCH 680/704] Drop Microsoft.CodeCoverage reference It's brought in via Microsoft.NET.Test.Sdk anyway. --- Directory.Packages.props | 1 - test/Library.Tests/Library.Tests.csproj | 1 - 2 files changed, 2 deletions(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index b792f3f6..b523e5c6 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -5,7 +5,6 @@ true - diff --git a/test/Library.Tests/Library.Tests.csproj b/test/Library.Tests/Library.Tests.csproj index d557e4c7..3a6cc044 100644 --- a/test/Library.Tests/Library.Tests.csproj +++ b/test/Library.Tests/Library.Tests.csproj @@ -10,7 +10,6 @@ - From ea48c8eaa182f224ca3ed1a38f2a8034d15dacce Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 13 Mar 2023 15:27:56 -0600 Subject: [PATCH 681/704] Updated SDK installer script to be able to find 7.0.200 --- tools/Install-DotNetSdk.ps1 | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 6bff5c27..10af5041 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -137,6 +137,14 @@ Function Get-InstallerExe( if ($release.$sku.version -eq $Version) { $filesElement = $release.$sku.files } + if (!$filesElement -and ($sku -eq 'sdk') -and $release.sdks) { + foreach ($sdk in $release.sdks) { + if ($sdk.version -eq $Version) { + $filesElement = $sdk.files + break + } + } + } if ($filesElement) { foreach ($file in $filesElement) { @@ -155,7 +163,7 @@ Function Get-InstallerExe( if ($url) { Get-FileFromWeb -Uri $url -OutDir $DotNetInstallScriptRoot } else { - Write-Error "Unable to find release of $sku v$Version" + throw "Unable to find release of $sku v$Version" } } From 2987b4457b0242e91913e9d9f4b43b5db079fd50 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Mon, 13 Mar 2023 15:31:46 -0600 Subject: [PATCH 682/704] Bump SDK version to 7.0.201 --- global.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/global.json b/global.json index cc08211e..cf9eefa6 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.101", + "version": "7.0.201", "rollForward": "patch", "allowPrerelease": false } From 73916c222d9ca965ee442790874029e944520b34 Mon Sep 17 00:00:00 2001 From: David Gardiner Date: Tue, 14 Mar 2023 15:38:48 +1030 Subject: [PATCH 683/704] Fix a couple of minor typos --- doc/cloudbuild.md | 2 +- doc/nbgv-cli.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/cloudbuild.md b/doc/cloudbuild.md index ae8fbb2b..3db9e4b9 100644 --- a/doc/cloudbuild.md +++ b/doc/cloudbuild.md @@ -45,7 +45,7 @@ See this [example change](https://github.com/AArnott/Library.Template/commit/5d1 By specifying certain `cloudBuild` options in your `version.json` file, you can activate features for some cloud build systems, as follows: -### Automatically match cloud build numbers to to your git version +### Automatically match cloud build numbers to your git version Cloud builds tend to associate some calendar date or monotonically increasing build number to each build. These build numbers are not very informative, if at all. diff --git a/doc/nbgv-cli.md b/doc/nbgv-cli.md index 46ae2d10..b7e58610 100644 --- a/doc/nbgv-cli.md +++ b/doc/nbgv-cli.md @@ -128,7 +128,7 @@ By default, the `prepare-release` command writes information about created and u Alternatively the information can be written to the output as `json`. The output format to use can be set using the `--format` command line parameter. -For example, running the follwoing command on `master` +For example, running the following command on `master` ``` nbgv prepare-release --format json From b09b391cc0b00d0c3541593d68614c19e5668ea6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alex=20R=C3=B8nne=20Petersen?= Date: Mon, 20 Mar 2023 12:50:50 +0100 Subject: [PATCH 684/704] Add support for NBGV_ThisAssemblyNamespace property. --- .../AssemblyVersionInfo.cs | 77 ++++++-- .../build/Nerdbank.GitVersioning.targets | 1 + .../AssemblyInfoTest.cs | 180 ++++++++++++++++++ 3 files changed, 241 insertions(+), 17 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs index d5d05d5a..6ff17c7b 100644 --- a/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs +++ b/src/Nerdbank.GitVersioning.Tasks/AssemblyVersionInfo.cs @@ -67,6 +67,8 @@ the code is regenerated. public string RootNamespace { get; set; } + public string ThisAssemblyNamespace { get; set; } + public string AssemblyOriginatorKeyFile { get; set; } public string AssemblyKeyContainerName { get; set; } @@ -112,14 +114,15 @@ the code is regenerated. public string BuildCode() { - this.generator = this.CreateGenerator(); + this.generator = this.CreateGenerator(this.ThisAssemblyNamespace, this.RootNamespace); + if (this.generator is object) { this.generator.AddComment(FileHeaderComment); this.generator.AddBlankLine(); this.generator.AddAnalysisSuppressions(); this.generator.AddBlankLine(); - this.generator.EmitNamespaceIfRequired(this.RootNamespace ?? "AssemblyInfo"); + this.GenerateAssemblyAttributes(); if (this.EmitThisAssemblyClass) @@ -368,6 +371,7 @@ private IEnumerable CreateAssemblyAttributes() private void GenerateAssemblyAttributes() { + this.generator.StartAssemblyAttributes(); this.generator.DeclareAttribute(typeof(AssemblyVersionAttribute), this.AssemblyVersion); this.generator.DeclareAttribute(typeof(AssemblyFileVersionAttribute), this.AssemblyFileVersion); this.generator.DeclareAttribute(typeof(AssemblyInformationalVersionAttribute), this.AssemblyInformationalVersion); @@ -560,18 +564,23 @@ private void GenerateThisAssemblyClass() this.generator.EndThisAssemblyClass(); } - private CodeGenerator CreateGenerator() + private CodeGenerator CreateGenerator(string thisAssemblyNamespace, string rootNamespace) { + // The C#/VB generators did not emit namespaces in past versions of NB.GV, so for compatibility, only check the + // new ThisAssemblyNamespace property for these. + var userNs = !string.IsNullOrEmpty(thisAssemblyNamespace) ? thisAssemblyNamespace : null; + switch (this.CodeLanguage.ToLowerInvariant()) { case "c#": - return new CSharpCodeGenerator(); + return new CSharpCodeGenerator(userNs); case "visual basic": case "visualbasic": case "vb": - return new VisualBasicCodeGenerator(); + return new VisualBasicCodeGenerator(userNs); case "f#": - return new FSharpCodeGenerator(); + // The F# generator must emit a namespace, so it respects both ThisAssemblyNamespace and RootNamespace. + return new FSharpCodeGenerator(userNs ?? (!string.IsNullOrEmpty(rootNamespace) ? rootNamespace : "AssemblyInfo")); default: return null; } @@ -626,13 +635,16 @@ private bool TryReadKeyInfo(out string publicKey, out string publicKeyToken) private abstract class CodeGenerator { - internal CodeGenerator() + internal CodeGenerator(string ns) { this.CodeBuilder = new StringBuilder(); + this.Namespace = ns; } protected StringBuilder CodeBuilder { get; } + protected string Namespace { get; } + protected virtual IEnumerable WarningCodesToSuppress { get; } = new string[] { "CA2243", // Attribute string literals should parse correctly @@ -642,6 +654,10 @@ internal CodeGenerator() internal abstract void AddComment(string comment); + internal virtual void StartAssemblyAttributes() + { + } + internal abstract void DeclareAttribute(Type type, string arg); internal abstract void StartThisAssemblyClass(); @@ -654,14 +670,6 @@ internal CodeGenerator() internal abstract void EndThisAssemblyClass(); - /// - /// Gives languages that *require* a namespace a chance to emit such. - /// - /// The RootNamespace of the project. - internal virtual void EmitNamespaceIfRequired(string ns) - { - } - internal string GetCode() => this.CodeBuilder.ToString(); internal void AddBlankLine() @@ -683,6 +691,11 @@ protected void AddCodeComment(string comment, string token) private class FSharpCodeGenerator : CodeGenerator { + public FSharpCodeGenerator(string ns) + : base(ns) + { + } + internal override void AddAnalysisSuppressions() { this.CodeBuilder.AppendLine($"#nowarn {string.Join(" ", this.WarningCodesToSuppress.Select(c => $"\"{c}\""))}"); @@ -708,9 +721,9 @@ internal override void AddThisAssemblyMember(string name, DateTime value) this.CodeBuilder.AppendLine($" static member internal {name} = new System.DateTime({value.Ticks}L, System.DateTimeKind.Utc)"); } - internal override void EmitNamespaceIfRequired(string ns) + internal override void StartAssemblyAttributes() { - this.CodeBuilder.AppendLine($"namespace {ns}"); + this.CodeBuilder.AppendLine($"namespace {this.Namespace}"); } internal override void DeclareAttribute(Type type, string arg) @@ -738,6 +751,11 @@ internal override void StartThisAssemblyClass() private class CSharpCodeGenerator : CodeGenerator { + public CSharpCodeGenerator(string ns) + : base(ns) + { + } + internal override void AddAnalysisSuppressions() { this.CodeBuilder.AppendLine($"#pragma warning disable {string.Join(", ", this.WarningCodesToSuppress)}"); @@ -755,6 +773,11 @@ internal override void DeclareAttribute(Type type, string arg) internal override void StartThisAssemblyClass() { + if (this.Namespace is { } ns) + { + this.CodeBuilder.AppendLine($"namespace {ns} {{"); + } + this.CodeBuilder.AppendLine($"#if {CompilerDefinesAroundGeneratedCodeAttribute}"); this.CodeBuilder.AppendLine($"[System.CodeDom.Compiler.GeneratedCode(\"{GeneratorName}\",\"{GeneratorVersion}\")]"); this.CodeBuilder.AppendLine("#endif"); @@ -782,11 +805,21 @@ internal override void AddThisAssemblyMember(string name, DateTime value) internal override void EndThisAssemblyClass() { this.CodeBuilder.AppendLine("}"); + + if (this.Namespace is not null) + { + this.CodeBuilder.AppendLine("}"); + } } } private class VisualBasicCodeGenerator : CodeGenerator { + public VisualBasicCodeGenerator(string ns) + : base(ns) + { + } + internal override void AddAnalysisSuppressions() { this.CodeBuilder.AppendLine($"#Disable Warning {string.Join(", ", this.WarningCodesToSuppress)}"); @@ -804,6 +837,11 @@ internal override void DeclareAttribute(Type type, string arg) internal override void StartThisAssemblyClass() { + if (this.Namespace is { } ns) + { + this.CodeBuilder.AppendLine($"Namespace {ns}"); + } + this.CodeBuilder.AppendLine($"#If {CompilerDefinesAroundExcludeFromCodeCoverageAttribute.Replace("||", " Or ")} Then"); this.CodeBuilder.AppendLine($""); this.CodeBuilder.AppendLine(""); @@ -834,6 +872,11 @@ internal override void AddThisAssemblyMember(string name, DateTime value) internal override void EndThisAssemblyClass() { this.CodeBuilder.AppendLine("End Class"); + + if (this.Namespace is not null) + { + this.CodeBuilder.AppendLine("End Namespace"); + } } } } diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index 1a65d0fe..ff19cab7 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -126,6 +126,7 @@ AssemblyInformationalVersion="$(AssemblyInformationalVersion)" AssemblyName="$(AssemblyName)" RootNamespace="$(RootNamespace)" + ThisAssemblyNamespace="$(NBGV_ThisAssemblyNamespace)" AssemblyOriginatorKeyFile="$(AssemblyOriginatorKeyFile)" AssemblyTitle="$(AssemblyTitle)" AssemblyProduct="$(AssemblyProduct)" diff --git a/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs b/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs index 7acc991b..43641569 100644 --- a/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs +++ b/test/Nerdbank.GitVersioning.Tests/AssemblyInfoTest.cs @@ -90,6 +90,67 @@ type internal ThisAssembly() = Assert.Equal(expected, built); } + [SkippableTheory(typeof(PlatformNotSupportedException))] + [InlineData(null, "MyRootNamespace")] + [InlineData("", "MyRootNamespace")] + [InlineData("MyCustomNamespace", null)] + [InlineData("MyCustomNamespace", "")] + [InlineData("MyCustomNamespace", "MyRootNamespace")] + public void FSharpGeneratorWithNamespace(string thisAssemblyNamespace, string rootNamespace) + { + var info = new AssemblyVersionInfo + { + AssemblyCompany = "company", + AssemblyFileVersion = "1.3.1.0", + AssemblyVersion = "1.3.0.0", + CodeLanguage = "f#", + RootNamespace = rootNamespace, + ThisAssemblyNamespace = thisAssemblyNamespace, + }; + + string built = info.BuildCode(); + + string expected = $@"//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#nowarn ""CA2243"" + +namespace {( + !string.IsNullOrWhiteSpace(thisAssemblyNamespace) + ? thisAssemblyNamespace + : !string.IsNullOrWhiteSpace(rootNamespace) + ? rootNamespace + : "AssemblyInfo")} +[] +[] +[] +do() +#if NETSTANDARD || NETFRAMEWORK || NETCOREAPP +[] +#endif +#if NET40_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER +[] +#endif +type internal ThisAssembly() = + static member internal AssemblyCompany = ""company"" + static member internal AssemblyFileVersion = ""1.3.1.0"" + static member internal AssemblyVersion = ""1.3.0.0"" + static member internal IsPrerelease = false + static member internal IsPublicRelease = false + static member internal RootNamespace = ""{rootNamespace}"" +do() +"; + + Assert.Equal(expected, built); + } + [SkippableTheory(typeof(PlatformNotSupportedException))] [InlineData(false)] [InlineData(true)] @@ -166,6 +227,64 @@ internal static partial class ThisAssembly {{ Assert.Equal(expected, built); } + [SkippableTheory(typeof(PlatformNotSupportedException))] + [InlineData(null, "MyRootNamespace")] + [InlineData("", "MyRootNamespace")] + [InlineData("MyCustomNamespace", null)] + [InlineData("MyCustomNamespace", "")] + [InlineData("MyCustomNamespace", "MyRootNamespace")] + public void CSharpGeneratorWithNamespace(string thisAssemblyNamespace, string rootNamespace) + { + var info = new AssemblyVersionInfo + { + AssemblyCompany = "company", + AssemblyFileVersion = "1.3.1.0", + AssemblyVersion = "1.3.0.0", + CodeLanguage = "c#", + RootNamespace = rootNamespace, + ThisAssemblyNamespace = thisAssemblyNamespace, + }; + + string built = info.BuildCode(); + + (string nsStart, string nsEnd) = !string.IsNullOrWhiteSpace(thisAssemblyNamespace) + ? ($"{Environment.NewLine}namespace {thisAssemblyNamespace} {{", $"{Environment.NewLine}}}") + : (string.Empty, string.Empty); + + string expected = $@"//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +#pragma warning disable CA2243 + +[assembly: System.Reflection.AssemblyVersionAttribute(""1.3.0.0"")] +[assembly: System.Reflection.AssemblyFileVersionAttribute(""1.3.1.0"")] +[assembly: System.Reflection.AssemblyInformationalVersionAttribute("""")]{nsStart} +#if NETSTANDARD || NETFRAMEWORK || NETCOREAPP +[System.CodeDom.Compiler.GeneratedCode(""{AssemblyVersionInfo.GeneratorName}"",""{AssemblyVersionInfo.GeneratorVersion}"")] +#endif +#if NET40_OR_GREATER || NETCOREAPP2_0_OR_GREATER || NETSTANDARD2_0_OR_GREATER +[System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] +#endif +internal static partial class ThisAssembly {{ + internal const string AssemblyCompany = ""company""; + internal const string AssemblyFileVersion = ""1.3.1.0""; + internal const string AssemblyVersion = ""1.3.0.0""; + internal const bool IsPrerelease = false; + internal const bool IsPublicRelease = false; + internal const string RootNamespace = ""{rootNamespace}""; +}}{nsEnd} +"; + + Assert.Equal(expected, built); + } + [SkippableTheory(typeof(PlatformNotSupportedException))] [InlineData(false)] [InlineData(true)] @@ -221,4 +340,65 @@ End Class Assert.Equal(expected, built); } + + [SkippableTheory(typeof(PlatformNotSupportedException))] + [InlineData(null, "MyRootNamespace")] + [InlineData("", "MyRootNamespace")] + [InlineData("MyCustomNamespace", null)] + [InlineData("MyCustomNamespace", "")] + [InlineData("MyCustomNamespace", "MyRootNamespace")] + public void VisualBasicGeneratorWithNamespace(string thisAssemblyNamespace, string rootNamespace) + { + var info = new AssemblyVersionInfo + { + AssemblyCompany = "company", + AssemblyFileVersion = "1.3.1.0", + AssemblyVersion = "1.3.0.0", + CodeLanguage = "vb", + RootNamespace = rootNamespace, + ThisAssemblyNamespace = thisAssemblyNamespace, + }; + + string built = info.BuildCode(); + + (string nsStart, string nsEnd) = !string.IsNullOrWhiteSpace(thisAssemblyNamespace) + ? ($"{Environment.NewLine}Namespace {thisAssemblyNamespace}", $"{Environment.NewLine}End Namespace") + : (string.Empty, string.Empty); + + string expected = $@"'------------------------------------------------------------------------------ +' +' This code was generated by a tool. +' Runtime Version:4.0.30319.42000 +' +' Changes to this file may cause incorrect behavior and will be lost if +' the code is regenerated. +' +'------------------------------------------------------------------------------ + +#Disable Warning CA2243 + + + +{nsStart} +#If NET40_OR_GREATER Or NETCOREAPP2_0_OR_GREATER Or NETSTANDARD2_0_OR_GREATER Then + + +Partial Friend NotInheritable Class ThisAssembly +#ElseIf NETSTANDARD Or NETFRAMEWORK Or NETCOREAPP Then + +Partial Friend NotInheritable Class ThisAssembly +#Else +Partial Friend NotInheritable Class ThisAssembly +#End If + Friend Const AssemblyCompany As String = ""company"" + Friend Const AssemblyFileVersion As String = ""1.3.1.0"" + Friend Const AssemblyVersion As String = ""1.3.0.0"" + Friend Const IsPrerelease As Boolean = False + Friend Const IsPublicRelease As Boolean = False + Friend Const RootNamespace As String = ""{rootNamespace}"" +End Class{nsEnd} +"; + + Assert.Equal(expected, built); + } } From 56b1dacf898765b3c701ded513e1a6c72a332c81 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 27 Mar 2023 12:43:46 -0600 Subject: [PATCH 685/704] Bump Cake.Core from 2.3.0 to 3.0.0 (#867) Bumps [Cake.Core](https://github.com/cake-build/cake) from 2.3.0 to 3.0.0. - [Release notes](https://github.com/cake-build/cake/releases) - [Changelog](https://github.com/cake-build/cake/blob/develop/ReleaseNotes.md) - [Commits](https://github.com/cake-build/cake/compare/v2.3.0...v3.0.0) --- updated-dependencies: - dependency-name: Cake.Core dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/Cake.GitVersioning/Cake.GitVersioning.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj index 117a2753..d5759726 100644 --- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj +++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj @@ -28,7 +28,7 @@ - + From 99df8185b1a6aa6abb1cc98aa7f4c0245f8d9012 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 28 Mar 2023 15:53:46 -0600 Subject: [PATCH 686/704] Move `dotnet-coverage` to repo-level tool --- .config/dotnet-tools.json | 8 ++++- azure-pipelines/Merge-CodeCoverage.ps1 | 46 +++++++++++++------------- 2 files changed, 30 insertions(+), 24 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 2599e26a..610b59c9 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -13,6 +13,12 @@ "commands": [ "dotnet-format" ] + }, + "dotnet-coverage": { + "version": "17.6.11", + "commands": [ + "dotnet-coverage" + ] } } -} \ No newline at end of file +} diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1 index 02ff12b0..5ecabbc9 100644 --- a/azure-pipelines/Merge-CodeCoverage.ps1 +++ b/azure-pipelines/Merge-CodeCoverage.ps1 @@ -20,32 +20,32 @@ Param( ) $RepoRoot = [string](Resolve-Path $PSScriptRoot/..) - -if (!(Test-Path $RepoRoot/obj/dotnet-coverage*)) { - dotnet tool install --tool-path $RepoRoot/obj dotnet-coverage --version 17.4.3 --configfile $PSScriptRoot/justnugetorg.nuget.config -} - -Write-Verbose "Searching $Path for *.cobertura.xml files" -$reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml - -if ($reports) { - $reports |% { $_.FullName } |% { - # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. - $xml = [xml](Get-Content -Path $_) - $xml.coverage.packages.package.classes.class |? { $_.filename} |% { - $_.filename = $_.filename.Replace('{reporoot}', $RepoRoot).Replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) +Push-Location $RepoRoot +try { + Write-Verbose "Searching $Path for *.cobertura.xml files" + $reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml + + if ($reports) { + $reports |% { $_.FullName } |% { + # In addition to replacing {reporoot}, we also normalize on one kind of slash so that the report aggregates data for a file whether data was collected on Windows or not. + $xml = [xml](Get-Content -Path $_) + $xml.coverage.packages.package.classes.class |? { $_.filename} |% { + $_.filename = $_.filename.Replace('{reporoot}', $RepoRoot).Replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) + } + + $xml.Save($_) } - $xml.Save($_) - } + $Inputs = $reports |% { Resolve-Path -relative $_.FullName } - $Inputs = $reports |% { Resolve-Path -relative $_.FullName } + if ((Split-Path $OutputFile) -and -not (Test-Path (Split-Path $OutputFile))) { + New-Item -Type Directory -Path (Split-Path $OutputFile) | Out-Null + } - if ((Split-Path $OutputFile) -and -not (Test-Path (Split-Path $OutputFile))) { - New-Item -Type Directory -Path (Split-Path $OutputFile) | Out-Null + & dotnet tool run dotnet-coverage merge $Inputs -o $OutputFile -f cobertura + } else { + Write-Error "No reports found to merge." } - - & "$RepoRoot/obj/dotnet-coverage" merge $Inputs -o $OutputFile -f cobertura -} else { - Write-Error "No reports found to merge." +} finally { + Pop-Location } From 14699417fbde409397e7efec56c1b33268ed3634 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 28 Mar 2023 15:58:33 -0600 Subject: [PATCH 687/704] Move `nbgv` into dotnet-tools.json --- .config/dotnet-tools.json | 6 ++++++ azure-pipelines/Get-nbgv.ps1 | 24 ------------------------ azure-pipelines/build.yml | 2 +- 3 files changed, 7 insertions(+), 25 deletions(-) delete mode 100644 azure-pipelines/Get-nbgv.ps1 diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 610b59c9..5d3dae87 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -19,6 +19,12 @@ "commands": [ "dotnet-coverage" ] + }, + "nbgv": { + "version": "3.5.119", + "commands": [ + "nbgv" + ] } } } diff --git a/azure-pipelines/Get-nbgv.ps1 b/azure-pipelines/Get-nbgv.ps1 deleted file mode 100644 index a5be2cf7..00000000 --- a/azure-pipelines/Get-nbgv.ps1 +++ /dev/null @@ -1,24 +0,0 @@ -<# -.SYNOPSIS - Gets the path to the nbgv CLI tool, installing it if necessary. -#> -Param( -) - -$existingTool = Get-Command "nbgv" -ErrorAction SilentlyContinue -if ($existingTool) { - return $existingTool.Path -} - -$toolInstallDir = & "$PSScriptRoot/Get-TempToolsPath.ps1" - -$toolPath = "$toolInstallDir/nbgv" -if (!(Test-Path $toolInstallDir)) { New-Item -Path $toolInstallDir -ItemType Directory | Out-Null } - -if (!(Get-Command $toolPath -ErrorAction SilentlyContinue)) { - Write-Host "Installing nbgv to $toolInstallDir" - dotnet tool install --tool-path "$toolInstallDir" nbgv --configfile "$PSScriptRoot/justnugetorg.nuget.config" | Out-Null -} - -# Normalize the path on the way out. -return (Get-Command $toolPath).Path diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index c8687859..2e2f426e 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -17,7 +17,7 @@ jobs: clean: true - template: install-dependencies.yml - - powershell: '& (./azure-pipelines/Get-nbgv.ps1) cloud -c' + - script: dotnet tool run nbgv cloud -c displayName: ⚙ Set build number - template: dotnet.yml From 3f1e85823fac9136c058aaf48f4b8febed1d0843 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Tue, 28 Mar 2023 16:34:38 -0600 Subject: [PATCH 688/704] Install tools except when `-NoToolRestore` is specified --- init.ps1 | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/init.ps1 b/init.ps1 index 5bace1e6..6211304f 100755 --- a/init.ps1 +++ b/init.ps1 @@ -28,6 +28,8 @@ No effect if -NoPrerequisites is specified. .PARAMETER NoRestore Skips the package restore step. +.PARAMETER NoToolRestore + Skips the dotnet tool restore step. .PARAMETER AccessToken An optional access token for authenticating to Azure Artifacts authenticated feeds. .PARAMETER Interactive @@ -46,6 +48,8 @@ Param ( [Parameter()] [switch]$NoRestore, [Parameter()] + [switch]$NoToolRestore, + [Parameter()] [string]$AccessToken, [Parameter()] [switch]$Interactive @@ -91,11 +95,13 @@ try { if ($lastexitcode -ne 0) { throw "Failure while restoring packages." } + } - dotnet tool restore @RestoreArguments - if ($lastexitcode -ne 0) { - throw "Failure while restoring dotnet CLI tools." - } + if (!$NoToolRestore -and $PSCmdlet.ShouldProcess("dotnet tool", "restore")) { + dotnet tool restore @RestoreArguments + if ($lastexitcode -ne 0) { + throw "Failure while restoring dotnet CLI tools." + } } & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars -PrependPath $PrependPath | Out-Null From d9fb70bacf15cd97fc0442dfdf80c7d84c64753c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 2 Apr 2023 08:26:27 -0600 Subject: [PATCH 689/704] Bump Moq from 4.18.2 to 4.18.4 (#917) Bumps [Moq](https://github.com/moq/moq4) from 4.18.2 to 4.18.4. - [Release notes](https://github.com/moq/moq4/releases) - [Changelog](https://github.com/moq/moq4/blob/main/CHANGELOG.md) - [Commits](https://github.com/moq/moq4/compare/v4.18.2...v4.18.4) --- updated-dependencies: - dependency-name: Moq dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .../Nerdbank.GitVersioning.Tests.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj index 80cffc79..84bf12f8 100644 --- a/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj +++ b/test/Nerdbank.GitVersioning.Tests/Nerdbank.GitVersioning.Tests.csproj @@ -1,4 +1,4 @@ - + net6.0;net462 true @@ -39,7 +39,7 @@ - + From 37cbd96e5b583bf09159db755b44bad40a9b30bd Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 10:04:43 -0600 Subject: [PATCH 690/704] Bump System.Text.Json from 4.7.2 to 7.0.2 (#902) Bumps [System.Text.Json](https://github.com/dotnet/runtime) from 4.7.2 to 7.0.2. - [Release notes](https://github.com/dotnet/runtime/releases) - [Commits](https://github.com/dotnet/runtime/commits/v7.0.2) --- updated-dependencies: - dependency-name: System.Text.Json dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj b/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj index 645345d5..33336934 100644 --- a/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj @@ -16,7 +16,7 @@ - + From 6f51530c1feb764dcec5ef76c8744489e362467a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 6 Apr 2023 10:05:09 -0600 Subject: [PATCH 691/704] Bump minimatch from 3.0.4 to 3.1.2 in /src/nerdbank-gitversioning.npm (#863) Bumps [minimatch](https://github.com/isaacs/minimatch) from 3.0.4 to 3.1.2. - [Release notes](https://github.com/isaacs/minimatch/releases) - [Commits](https://github.com/isaacs/minimatch/compare/v3.0.4...v3.1.2) --- updated-dependencies: - dependency-name: minimatch dependency-type: indirect ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- src/nerdbank-gitversioning.npm/yarn.lock | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index f7bab7dd..da6bdc50 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -247,9 +247,9 @@ bach@^1.0.0: now-and-later "^2.0.0" balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== base@^0.11.1: version "0.11.2" @@ -483,7 +483,7 @@ component-emitter@^1.2.1: concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== concat-stream@^1.6.0: version "1.6.2" @@ -1794,9 +1794,9 @@ micromatch@^4.0.4: picomatch "^2.3.1" minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== dependencies: brace-expansion "^1.1.7" From 98c4e844cf20a39751384dc6fc7fa85468fdcb8d Mon Sep 17 00:00:00 2001 From: maniglia Date: Fri, 7 Apr 2023 08:43:24 +0200 Subject: [PATCH 692/704] Compatibility improvement for WiX Toolset V4 projects. In WiX Toolset projects the language is set to "wix", in these cases the "GenerateAssemblyVersionInfo" is set to false. --- .../build/Nerdbank.GitVersioning.targets | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets index ff19cab7..f617e51a 100644 --- a/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets +++ b/src/Nerdbank.GitVersioning.Tasks/build/Nerdbank.GitVersioning.targets @@ -40,6 +40,9 @@ false false + + false + GenerateNativeNBGVVersionInfo; From 2381c7276720eb8084c1006baf16e6ac6aae2c9a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Fri, 14 Apr 2023 20:54:34 -0600 Subject: [PATCH 693/704] Fix ARM64 detection on Windows Powershell --- tools/Install-DotNetSdk.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1 index 10af5041..e190fcfb 100644 --- a/tools/Install-DotNetSdk.ps1 +++ b/tools/Install-DotNetSdk.ps1 @@ -47,6 +47,7 @@ $arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture if (!$arch) { # Windows Powershell leaves this blank $arch = 'x64' if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' } + if (${env:ProgramFiles(Arm)}) { $arch = 'ARM64' } } # Search for all .NET runtime versions referenced from MSBuild projects and arrange to install them. From 6f0d42eafda745bc7ed22e8932edc7e16d0c81de Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 15 Apr 2023 11:16:08 -0600 Subject: [PATCH 694/704] Move whitespace-sensitive targets out of the project file --- .../Nerdbank.GitVersioning.Tasks.csproj | 27 ++------------ .../Nerdbank.GitVersioning.Tasks.targets | 35 +++++++++++++++++++ 2 files changed, 37 insertions(+), 25 deletions(-) create mode 100644 src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.targets diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj index c8154c95..d4e8d7c8 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.csproj @@ -16,31 +16,6 @@ true - - - $(NuGetPackageRoot)libgit2sharp.nativebinaries\$(LibGit2SharpNativeVersion)\ - $(NuspecProperties);Version=$(Version);commit=$(GitCommitId);BaseOutputPath=$(OutputPath);LibGit2SharpNativeBinaries=$(LibGit2SharpNativeBinaries) - $(NuspecProperties);LKGSuffix=.LKG - - - - - - MSBuildCore\ - MSBuildFull\ - - - - - build\$(BuildSubDir) - - - - build\$(BuildSubDir)%(ContentWithTargetPath.TargetPath) - - - - true @@ -81,4 +56,6 @@ + + diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.targets b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.targets new file mode 100644 index 00000000..f61154df --- /dev/null +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.Tasks.targets @@ -0,0 +1,35 @@ + + + + $(NuGetPackageRoot)libgit2sharp.nativebinaries\$(LibGit2SharpNativeVersion)\ + $(NuspecProperties);Version=$(Version);commit=$(GitCommitId);BaseOutputPath=$(OutputPath);LibGit2SharpNativeBinaries=$(LibGit2SharpNativeBinaries) + $(NuspecProperties);LKGSuffix=.LKG + + + + + + MSBuildCore\ + MSBuildFull\ + + + + + build\$(BuildSubDir) + + + + build\$(BuildSubDir)%(ContentWithTargetPath.TargetPath) + + + + From 57cd23ff5ad72d8d7a538979de7a0059307bae3a Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 15 Apr 2023 11:20:12 -0600 Subject: [PATCH 695/704] Drop libgit2 copies that only supported ps1 scripts that no longer exist --- .../Nerdbank.GitVersioning.nuspec | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec index 19c0efea..7cbd1117 100644 --- a/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec +++ b/src/Nerdbank.GitVersioning.Tasks/Nerdbank.GitVersioning.nuspec @@ -36,10 +36,6 @@ IMPORTANT: The 3.x release may produce a different version height than prior maj - - - - From 50b72066a715bf1b4bc733f09de10d736e1f8378 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 15 Apr 2023 15:08:19 -0600 Subject: [PATCH 696/704] Bump CsWin32 to 0.2.206-beta --- src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs | 8 ++++---- src/NerdBank.GitVersioning/NativeMethods.txt | 1 + src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs index 7ddafd62..2d33693e 100644 --- a/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs +++ b/src/NerdBank.GitVersioning/ManagedGit/FileHelpers.cs @@ -8,8 +8,8 @@ using System.Runtime.Versioning; using Microsoft.Win32.SafeHandles; using Windows.Win32; +using Windows.Win32.Foundation; using Windows.Win32.Storage.FileSystem; -using Windows.Win32.System.SystemServices; namespace Nerdbank.GitVersioning.ManagedGit; @@ -31,7 +31,7 @@ internal static bool TryOpen(string path, out FileStream? stream) if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) #endif { - SafeFileHandle? handle = PInvoke.CreateFile(path, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); + SafeFileHandle? handle = PInvoke.CreateFile(path, (uint)FILE_ACCESS_RIGHTS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, lpSecurityAttributes: null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, null); if (!handle.IsInvalid) { @@ -76,10 +76,10 @@ internal static unsafe bool TryOpen(ReadOnlySpan path, [NotNullWhen(true)] HANDLE handle; fixed (char* pPath = &path[0]) { - handle = PInvoke.CreateFile(pPath, FILE_ACCESS_FLAGS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default); + handle = PInvoke.CreateFile(pPath, (uint)FILE_ACCESS_RIGHTS.FILE_GENERIC_READ, FILE_SHARE_MODE.FILE_SHARE_READ, null, FILE_CREATION_DISPOSITION.OPEN_EXISTING, FILE_FLAGS_AND_ATTRIBUTES.FILE_ATTRIBUTE_NORMAL, default); } - if (!handle.Equals(Constants.INVALID_HANDLE_VALUE)) + if (!handle.Equals(HANDLE.INVALID_HANDLE_VALUE)) { var fileHandle = new SafeFileHandle(handle, ownsHandle: true); stream = new FileStream(fileHandle, System.IO.FileAccess.Read); diff --git a/src/NerdBank.GitVersioning/NativeMethods.txt b/src/NerdBank.GitVersioning/NativeMethods.txt index 885be08e..286f297a 100644 --- a/src/NerdBank.GitVersioning/NativeMethods.txt +++ b/src/NerdBank.GitVersioning/NativeMethods.txt @@ -1,2 +1,3 @@ CreateFile +FILE_ACCESS_RIGHTS INVALID_HANDLE_VALUE diff --git a/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj b/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj index 33336934..d163c2c0 100644 --- a/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj +++ b/src/NerdBank.GitVersioning/Nerdbank.GitVersioning.csproj @@ -12,7 +12,7 @@ - + From 8b28a71fdaac53e8a7bdce2e51d2059b1d14a7cf Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sat, 15 Apr 2023 15:15:15 -0600 Subject: [PATCH 697/704] Fix loading of libgit2 native binary on .NET Framework and .NET Tested on Windows. Fixes #919 --- .../LibGit2/LibGit2GitExtensions.cs | 54 +++++++++++++++---- src/NerdBank.GitVersioning/NativeMethods.txt | 1 + .../ContextAwareTask.cs | 21 +++----- .../GitLoaderContext.cs | 50 ++++++++++++++++- src/nbgv/Program.cs | 3 +- 5 files changed, 100 insertions(+), 29 deletions(-) diff --git a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs index 5a5e67d4..e4221cd9 100644 --- a/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs +++ b/src/NerdBank.GitVersioning/LibGit2/LibGit2GitExtensions.cs @@ -6,6 +6,7 @@ using System.Text; using LibGit2Sharp; using Validation; +using Windows.Win32; using Version = System.Version; #nullable enable @@ -41,6 +42,10 @@ public static class LibGit2GitExtensions ContextLines = 0, }; +#if !NETCOREAPP + private static FreeLibrarySafeHandle? nativeLibrary; +#endif + /// /// Gets the number of commits in the longest single path between /// the specified commit and the most distant ancestor (inclusive). @@ -111,24 +116,51 @@ public static IEnumerable GetCommitsFromVersion(LibGit2Context context, /// /// Finds the directory that contains the appropriate native libgit2 module. /// - /// The path to the directory that contains the lib folder. + /// The path to the directory that contains the runtimes folder. /// Receives the directory that native binaries are expected. public static string? FindLibGit2NativeBinaries(string basePath) { - if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) - { - return Path.Combine(basePath, "lib", "win32", IntPtr.Size == 4 ? "x86" : "x64"); - } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) + string arch = RuntimeInformation.ProcessArchitecture.ToString().ToLowerInvariant(); + + // TODO: learn how to detect when to use "linux-musl". + string? os = + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? "win" : + RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? "linux" : + RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? "osx" : + null; + + if (os is null) { - return Path.Combine(basePath, "lib", "linux", IntPtr.Size == 4 ? "x86" : "x86_64"); + return null; } - else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX)) + + string candidatePath = Path.Combine(basePath, "runtimes", $"{os}-{arch}", "native"); + return Directory.Exists(candidatePath) ? candidatePath : null; + } + + /// + /// Loads the git2 native library from the expected path so that it's available later when needed. + /// + /// + /// + /// This method should only be called on .NET Framework, and only loads the module when on Windows. + /// + public static void LoadNativeBinary(string basePath) + { +#if NETCOREAPP + throw new PlatformNotSupportedException(); +#else + if (nativeLibrary is null && RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { - return Path.Combine(basePath, "lib", "osx", RuntimeInformation.OSArchitecture == Architecture.Arm64 ? "arm_64" : "x86_64"); + if (FindLibGit2NativeBinaries(basePath) is string directoryPath) + { + if (Directory.EnumerateFiles(directoryPath).FirstOrDefault() is string filePath) + { + nativeLibrary = PInvoke.LoadLibrary(filePath); + } + } } - - return null; +#endif } /// diff --git a/src/NerdBank.GitVersioning/NativeMethods.txt b/src/NerdBank.GitVersioning/NativeMethods.txt index 286f297a..669c0efc 100644 --- a/src/NerdBank.GitVersioning/NativeMethods.txt +++ b/src/NerdBank.GitVersioning/NativeMethods.txt @@ -1,3 +1,4 @@ CreateFile FILE_ACCESS_RIGHTS INVALID_HANDLE_VALUE +LoadLibrary diff --git a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs index b20499a0..c49bc387 100644 --- a/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs +++ b/src/Nerdbank.GitVersioning.Tasks/ContextAwareTask.cs @@ -11,6 +11,7 @@ #endif using Microsoft.Build.Framework; using Microsoft.Build.Utilities; +using Nerdbank.GitVersioning.LibGit2; namespace MSBuildExtensionTask { @@ -23,10 +24,11 @@ public abstract class ContextAwareTask : Microsoft.Build.Utilities.Task /// public override bool Execute() { -#if NETCOREAPP string taskAssemblyPath = this.GetType().GetTypeInfo().Assembly.Location; - - Assembly inContextAssembly = GitLoaderContext.Instance.LoadFromAssemblyPath(taskAssemblyPath); + string unmanagedBaseDirectory = Path.GetDirectoryName(Path.GetDirectoryName(taskAssemblyPath)); +#if NETCOREAPP + GitLoaderContext loaderContext = new(unmanagedBaseDirectory); + Assembly inContextAssembly = loaderContext.LoadFromAssemblyPath(taskAssemblyPath); Type innerTaskType = inContextAssembly.GetType(this.GetType().FullName); object innerTask = Activator.CreateInstance(innerTaskType); @@ -55,18 +57,7 @@ where outerProperty.SetMethod is not null && outerProperty.GetMethod is not null return result; #else - // On .NET Framework (on Windows), we find native binaries by adding them to our PATH. - if (this.UnmanagedDllDirectory is not null) - { - string pathEnvVar = Environment.GetEnvironmentVariable("PATH") ?? string.Empty; - string[] searchPaths = pathEnvVar.Split(Path.PathSeparator); - if (!searchPaths.Contains(this.UnmanagedDllDirectory, StringComparer.OrdinalIgnoreCase)) - { - pathEnvVar += Path.PathSeparator + this.UnmanagedDllDirectory; - Environment.SetEnvironmentVariable("PATH", pathEnvVar); - } - } - + LibGit2GitExtensions.LoadNativeBinary(unmanagedBaseDirectory); return this.ExecuteInner(); #endif } diff --git a/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs b/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs index c0ec84e1..9ce0c39b 100644 --- a/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs +++ b/src/Nerdbank.GitVersioning.Tasks/GitLoaderContext.cs @@ -3,6 +3,8 @@ // This code originally copied from https://github.com/dotnet/sourcelink/tree/c092238370e0437eb95722f28c79273244dc7f1a/src/Microsoft.Build.Tasks.Git // Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See license information at https://github.com/dotnet/sourcelink/blob/c092238370e0437eb95722f28c79273244dc7f1a/License.txt. +#nullable enable + #if NETCOREAPP using System; @@ -10,6 +12,7 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Loader; +using Nerdbank.GitVersioning.LibGit2; using RuntimeEnvironment = Microsoft.DotNet.PlatformAbstractions.RuntimeEnvironment; namespace Nerdbank.GitVersioning @@ -17,17 +20,60 @@ namespace Nerdbank.GitVersioning public class GitLoaderContext : AssemblyLoadContext { public const string RuntimePath = "./runtimes"; + private readonly string nativeDependencyBasePath; + + private (string?, IntPtr) lastLoadedLibrary; - public static readonly GitLoaderContext Instance = new GitLoaderContext(); + /// + /// Initializes a new instance of the class. + /// + /// The path to the directory that contains the "runtimes" folder. + public GitLoaderContext(string nativeDependencyBasePath) + { + this.nativeDependencyBasePath = nativeDependencyBasePath; + } /// protected override Assembly Load(AssemblyName assemblyName) { - string path = Path.Combine(Path.GetDirectoryName(typeof(GitLoaderContext).Assembly.Location), assemblyName.Name + ".dll"); + string path = Path.Combine(Path.GetDirectoryName(typeof(GitLoaderContext).Assembly.Location)!, assemblyName.Name + ".dll"); return File.Exists(path) ? this.LoadFromAssemblyPath(path) : Default.LoadFromAssemblyName(assemblyName); } + + protected override IntPtr LoadUnmanagedDll(string unmanagedDllName) + { + IntPtr p = base.LoadUnmanagedDll(unmanagedDllName); + + if (p == IntPtr.Zero) + { + if (unmanagedDllName == this.lastLoadedLibrary.Item1) + { + return this.lastLoadedLibrary.Item2; + } + + string prefix = + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? string.Empty : + "lib"; + + string? extension = + RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ".dll" : + RuntimeInformation.IsOSPlatform(OSPlatform.Linux) ? ".so" : + RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ? ".dylib" : + null; + + string fileName = $"{prefix}{unmanagedDllName}{extension}"; + string? directoryPath = LibGit2GitExtensions.FindLibGit2NativeBinaries(this.nativeDependencyBasePath); + if (directoryPath is not null && NativeLibrary.TryLoad(Path.Combine(directoryPath, fileName), out p)) + { + // Cache this to make us a little faster next time. + this.lastLoadedLibrary = (unmanagedDllName, p); + } + } + + return p; + } } } #endif diff --git a/src/nbgv/Program.cs b/src/nbgv/Program.cs index 19457436..d1380d71 100644 --- a/src/nbgv/Program.cs +++ b/src/nbgv/Program.cs @@ -79,7 +79,8 @@ public static int Main(string[] args) { string thisAssemblyPath = typeof(Program).GetTypeInfo().Assembly.Location; - Assembly inContextAssembly = GitLoaderContext.Instance.LoadFromAssemblyPath(thisAssemblyPath); + GitLoaderContext loaderContext = new(Path.GetDirectoryName(thisAssemblyPath)); + Assembly inContextAssembly = loaderContext.LoadFromAssemblyPath(thisAssemblyPath); Type innerProgramType = inContextAssembly.GetType(typeof(Program).FullName); object innerProgram = Activator.CreateInstance(innerProgramType); From b3e9f4ee3722b395ea4e3cdae74e812b9884d8aa Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 16 Apr 2023 07:29:40 -0600 Subject: [PATCH 698/704] Bump up SDK and tools versions --- .config/dotnet-tools.json | 4 ++-- global.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 5d3dae87..151689b6 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -3,7 +3,7 @@ "isRoot": true, "tools": { "powershell": { - "version": "7.3.3", + "version": "7.3.4", "commands": [ "pwsh" ] @@ -15,7 +15,7 @@ ] }, "dotnet-coverage": { - "version": "17.6.11", + "version": "17.7.0", "commands": [ "dotnet-coverage" ] diff --git a/global.json b/global.json index cf9eefa6..c7d7e468 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "7.0.201", + "version": "7.0.203", "rollForward": "patch", "allowPrerelease": false } From f2d80e4d7e4e64ffc413b297602c45578f544b9f Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 16 Apr 2023 10:38:56 -0600 Subject: [PATCH 699/704] Fix 32-bit msbuild version reference --- test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs b/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs index 6cb214b9..d77f7ba5 100644 --- a/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs +++ b/test/Nerdbank.GitVersioning.Tests/MSBuildExtensions.cs @@ -25,7 +25,7 @@ internal static void LoadMSBuild() if (IntPtr.Size == 4) { // 32-bit .NET runtime requires special code to find the x86 SDK (where MSBuild is). - MSBuildLocator.RegisterMSBuildPath(@"C:\Program Files (x86)\dotnet\sdk\7.0.101"); + MSBuildLocator.RegisterMSBuildPath(@"C:\Program Files (x86)\dotnet\sdk\7.0.203"); } else { From 39553c3fbcfc3a58f40fc394d829502cdd77d4c6 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 16 Apr 2023 10:42:07 -0600 Subject: [PATCH 700/704] Update .NET SDK more consistently --- .devcontainer/Dockerfile | 2 +- azure-pipelines.yml | 4 ++-- azure-pipelines/build.yml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index 7ffd07ef..01c94a90 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:7.0.101-jammy +FROM mcr.microsoft.com/dotnet/sdk:7.0.203-jammy # 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/azure-pipelines.yml b/azure-pipelines.yml index fff3e430..8ab8348e 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -106,10 +106,10 @@ stages: clean: true submodules: true # keep the warnings quiet about the wiki not being enlisted - task: UseDotNet@2 - displayName: Install .NET 7.0.101 SDK + displayName: Install .NET 7.0.203 SDK inputs: packageType: sdk - version: 7.0.101 + version: 7.0.203 - script: dotnet --info displayName: Show dotnet SDK info - bash: | diff --git a/azure-pipelines/build.yml b/azure-pipelines/build.yml index 73f22820..021256ae 100644 --- a/azure-pipelines/build.yml +++ b/azure-pipelines/build.yml @@ -23,7 +23,7 @@ jobs: - template: install-dependencies.yml - pwsh: | Invoke-WebRequest -Uri "https://dot.net/v1/dotnet-install.ps1" -OutFile dotnet-install.ps1 - & .\dotnet-install.ps1 -Architecture x86 -Version 7.0.101 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose + & .\dotnet-install.ps1 -Architecture x86 -Version 7.0.203 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose displayName: ⚙ Install 32-bit .NET SDK and runtimes - template: dotnet.yml From bf85fe8975d7b8b18ccd765e06d39e78de119c8b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Apr 2023 17:11:59 +0000 Subject: [PATCH 701/704] Bump typescript from 4.8.2 to 5.0.4 in /src/nerdbank-gitversioning.npm Bumps [typescript](https://github.com/Microsoft/TypeScript) from 4.8.2 to 5.0.4. - [Release notes](https://github.com/Microsoft/TypeScript/releases) - [Commits](https://github.com/Microsoft/TypeScript/compare/v4.8.2...v5.0.4) --- updated-dependencies: - dependency-name: typescript dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- src/nerdbank-gitversioning.npm/package.json | 2 +- src/nerdbank-gitversioning.npm/yarn.lock | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/package.json b/src/nerdbank-gitversioning.npm/package.json index fc834dee..b56dcd96 100644 --- a/src/nerdbank-gitversioning.npm/package.json +++ b/src/nerdbank-gitversioning.npm/package.json @@ -34,7 +34,7 @@ "gulp-util": "^3.0.8", "merge2": "^1.4.1", "path": "^0.12.7", - "typescript": "^4.6.4" + "typescript": "^5.0.4" }, "dependencies": { "camel-case": "^4.1.2" diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index da6bdc50..6ee197d9 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -2742,10 +2742,10 @@ typedarray@^0.0.6: resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= -typescript@^4.6.4: - version "4.8.2" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.8.2.tgz#e3b33d5ccfb5914e4eeab6699cf208adee3fd790" - integrity sha512-C0I1UsrrDHo2fYI5oaCGbSejwX4ch+9Y5jTQELvovfmFkK3HHSZJB8MSJcWLmCUBzQBchCrZ9rMRV6GuNrvGtw== +typescript@^5.0.4: + version "5.0.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" + integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== unc-path-regex@^0.1.2: version "0.1.2" From 6f2cad52c659b036b6c86da9ddc5a5fdfb96dd9f Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Apr 2023 17:12:15 +0000 Subject: [PATCH 702/704] Bump @types/node in /src/nerdbank-gitversioning.npm Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 18.7.14 to 18.15.11. - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases) - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node) --- updated-dependencies: - dependency-name: "@types/node" dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- src/nerdbank-gitversioning.npm/yarn.lock | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nerdbank-gitversioning.npm/yarn.lock b/src/nerdbank-gitversioning.npm/yarn.lock index da6bdc50..d2ce73b4 100644 --- a/src/nerdbank-gitversioning.npm/yarn.lock +++ b/src/nerdbank-gitversioning.npm/yarn.lock @@ -50,9 +50,9 @@ camel-case "*" "@types/node@^18.7.14": - version "18.7.14" - resolved "https://registry.yarnpkg.com/@types/node/-/node-18.7.14.tgz#0fe081752a3333392d00586d815485a17c2cf3c9" - integrity sha512-6bbDaETVi8oyIARulOE9qF1/Qdi/23z6emrUh0fNJRUmjznqrixD4MpGDdgOFk5Xb0m2H6Xu42JGdvAxaJR/wA== + version "18.15.11" + resolved "https://registry.yarnpkg.com/@types/node/-/node-18.15.11.tgz#b3b790f09cb1696cffcec605de025b088fa4225f" + integrity sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q== acorn@^6.4.1: version "6.4.2" From 849734ecf162dc2b96dfe71b634059f5937dad9d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Sun, 16 Apr 2023 11:46:39 -0600 Subject: [PATCH 703/704] Bump BenchmarkDotNetVersion from 0.13.2 to 0.13.5 (#922) Bumps `BenchmarkDotNetVersion` from 0.13.2 to 0.13.5. Updates `BenchmarkDotNet` from 0.13.2 to 0.13.5 - [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases) - [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.2...v0.13.5) Updates `BenchmarkDotNet.Diagnostics.Windows` from 0.13.2 to 0.13.5 - [Release notes](https://github.com/dotnet/BenchmarkDotNet/releases) - [Commits](https://github.com/dotnet/BenchmarkDotNet/compare/v0.13.2...v0.13.5) --- updated-dependencies: - dependency-name: BenchmarkDotNet dependency-type: direct:production update-type: version-update:semver-patch - dependency-name: BenchmarkDotNet.Diagnostics.Windows dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Directory.Packages.props | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Directory.Packages.props b/Directory.Packages.props index cd1aace6..c27742d9 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -3,7 +3,7 @@ true true - 0.13.2 + 0.13.5 16.9.0 15.9.20 From 3671f1349adc838e0d69d2ce76712d7df6844ea8 Mon Sep 17 00:00:00 2001 From: Andrew Arnott Date: Sun, 16 Apr 2023 16:45:23 -0600 Subject: [PATCH 704/704] Fix build break --- src/nerdbank-gitversioning.npm/gulpfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nerdbank-gitversioning.npm/gulpfile.js b/src/nerdbank-gitversioning.npm/gulpfile.js index ff05ca9f..8850d780 100644 --- a/src/nerdbank-gitversioning.npm/gulpfile.js +++ b/src/nerdbank-gitversioning.npm/gulpfile.js @@ -15,7 +15,7 @@ var tsProject = ts.createProject('tsconfig.json', { }); gulp.task('tsc', function () { - var tsResult = gulp.src(['*.ts', 'ts/**/*.ts', 'node_modules/@types/**/index.d.ts']) + var tsResult = gulp.src(['*.ts', 'ts/**/*.ts']) // .pipe(tslint()) .pipe(sourcemaps.init()) .pipe(tsProject());