diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 00000000..151689b6
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,30 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "powershell": {
+ "version": "7.3.4",
+ "commands": [
+ "pwsh"
+ ]
+ },
+ "dotnet-format": {
+ "version": "5.1.250801",
+ "commands": [
+ "dotnet-format"
+ ]
+ },
+ "dotnet-coverage": {
+ "version": "17.7.0",
+ "commands": [
+ "dotnet-coverage"
+ ]
+ },
+ "nbgv": {
+ "version": "3.5.119",
+ "commands": [
+ "nbgv"
+ ]
+ }
+ }
+}
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 00000000..01c94a90
--- /dev/null
+++ b/.devcontainer/Dockerfile
@@ -0,0 +1,14 @@
+# Refer to https://hub.docker.com/_/microsoft-dotnet-sdk for available versions
+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.
+#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..e0b8f033 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}]
+# 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}]
+[*.{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,24 @@ 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
+
+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/.gitattributes b/.gitattributes
index e9ae1b43..1f35e683 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -2,7 +2,13 @@
# 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
+
+# The macOS codesign tool is extremely picky, and requires LF line endings.
+*.plist eol=lf
###############################################################################
# Set default behavior for command prompt diff.
diff --git a/.gitignore b/.gitignore
index 41470811..69599b87 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,19 @@ _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
+/coveragereport/
+
# NCrunch
_NCrunch_*
.*crunch*.local.xml
+nCrunchTemp_*
# MightyMoose
*.mm.*
@@ -125,49 +173,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 +249,106 @@ _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/
+
+# mac-created file to track user view preferences for a directory
+.DS_Store
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 9335c88f..c4ddc1a7 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -1,6 +1,20 @@
{
+ // 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",
+ "tintoy.msbuild-project-tools"
+ ],
+ // 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..9fccf55b 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/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/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 00000000..22caf1d1
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,81 @@
+
+
+ Debug
+ $(MSBuildThisFileDirectory)
+ $(RepoRootPath)obj\$([MSBuild]::MakeRelative($(RepoRootPath), $(MSBuildProjectDirectory)))\
+ $(RepoRootPath)bin\$(MSBuildProjectName)\
+ $(RepoRootPath)bin\Packages\$(Configuration)\
+ $(MSBuildThisFileDirectory)..\wiki\api
+ latest
+
+ enable
+ latest
+ true
+ true
+ true
+
+
+ true
+
+
+
+ false
+
+
+ $(MSBuildThisFileDirectory)
+
+ embedded
+
+ true
+ $(MSBuildThisFileDirectory)strongname.snk
+
+ https://github.com/dotnet/Nerdbank.GitVersioning
+ Andrew Arnott
+ git commit versioning version assemblyinfo
+ Copyright (c) .NET Foundation and Contributors
+ MIT
+ true
+ true
+
+
+
+
+ 2.0.315-alpha.0.9
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(PackageProjectUrl)/releases/tag/v$(Version)
+
+
+
+
+ false
+ true
+
+
+
+
+ false
+ false
+ false
+ false
+
+
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 00000000..ea7b6e6f
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,11 @@
+
+
+
+ false
+
+
+
+
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 00000000..c27742d9
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,51 @@
+
+
+
+ true
+ true
+ 0.13.5
+ 16.9.0
+ 15.9.20
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Nerdbank.GitVersioning.sln b/Nerdbank.GitVersioning.sln
similarity index 54%
rename from src/Nerdbank.GitVersioning.sln
rename to Nerdbank.GitVersioning.sln
index 9077863c..09148d66 100644
--- a/src/Nerdbank.GitVersioning.sln
+++ b/Nerdbank.GitVersioning.sln
@@ -5,34 +5,50 @@ 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
+ Directory.Packages.props = Directory.Packages.props
+ 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", "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("{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
@@ -74,6 +90,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
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.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 914908dd..8ab8348e 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -2,301 +2,67 @@ trigger:
batch: true
branches:
include:
- - master
- - 'v*.*'
- - 'validate/*'
+ - main
+ - 'v*.*'
+ - 'validate/*'
paths:
exclude:
- - doc
+ - doc/
- '*.md'
+ - .vscode/
+ - .github/
- azure-pipelines/release.yml
+parameters:
+- name: RunTests
+ displayName: Run tests
+ type: boolean
+ default: true
+
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
+ MSBuildTreatWarningsAsErrors: 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
+ ci_npm_feed: https://pkgs.dev.azure.com/andrewarnott/OSS/_packaging/PublicCI/npm/registry/
+ NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/
stages:
- stage: Build
jobs:
- - job: Build
- strategy:
- matrix:
- linux:
- imageName: 'ubuntu-20.04'
- testModifier: -f net5.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 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
-
-
- - 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
- 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
+ parameters:
+ RunTests: ${{ parameters.RunTests }}
- stage: Test
displayName: Functional testing
+ condition: and(succeeded(), ${{ parameters.RunTests }})
jobs:
- 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)
@@ -305,8 +71,14 @@ stages:
- template: azure-pipelines/xplattest-pipeline.yml
- job: macOS
+ strategy:
+ matrix:
+ macOS_Catalina:
+ vmImage: macOS-12
+ macOS_Monterey:
+ vmImage: macOS-12
pool:
- vmImage: macOS-10.15
+ vmImage: $[ variables['vmImage'] ]
steps:
- template: azure-pipelines/xplattest-pipeline.yml
@@ -318,32 +90,26 @@ stages:
strategy:
matrix:
ubuntu:
- imageName: ubuntu-18.04
+ imageName: ubuntu-22.04
repoDir: '~/git'
windows:
- imageName: windows-2019
+ imageName: windows-2022
repoDir: '${USERPROFILE}/source/repos'
macOS:
- imageName: macOS-10.15
+ imageName: macOS-12
repoDir: '~/git'
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 Core 3.1 runtime
- 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
+ displayName: Install .NET 7.0.203 SDK
inputs:
packageType: sdk
- version: 6.0.100
+ version: 7.0.203
- script: dotnet --info
displayName: Show dotnet SDK info
- bash: |
@@ -351,15 +117,14 @@ 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
- 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
+ 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: |
cd $(repoDir)/xunit
@@ -371,12 +136,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
+ 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
inputs:
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-CodeCovTool.ps1 b/azure-pipelines/Get-CodeCovTool.ps1
new file mode 100644
index 00000000..ca580b4d
--- /dev/null
+++ b/azure-pipelines/Get-CodeCovTool.ps1
@@ -0,0 +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
+)
+
+if ($IsMacOS) {
+ $codeCovUrl = "https://uploader.codecov.io/latest/macos/codecov"
+ $toolName = 'codecov'
+}
+elseif ($IsLinux) {
+ $codeCovUrl = "https://uploader.codecov.io/latest/linux/codecov"
+ $toolName = 'codecov'
+}
+else {
+ $codeCovUrl = "https://uploader.codecov.io/latest/windows/codecov.exe"
+ $toolName = 'codecov.exe'
+}
+
+$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
+}
+
+$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 $finalToolPath
diff --git a/azure-pipelines/Get-NuGetTool.ps1 b/azure-pipelines/Get-NuGetTool.ps1
new file mode 100644
index 00000000..3097c873
--- /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='6.4.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..0ce229fc
--- /dev/null
+++ b/azure-pipelines/Get-SymbolFiles.ps1
@@ -0,0 +1,61 @@
+<#
+.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|\.test\."
+
+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
+ } else {
+ Write-Warning "`"$_`" found with no matching binary file."
+ $BinaryImagePath = $null
+ }
+
+ if ($BinaryImagePath) {
+ 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/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1
new file mode 100644
index 00000000..5ecabbc9
--- /dev/null
+++ b/azure-pipelines/Merge-CodeCoverage.ps1
@@ -0,0 +1,51 @@
+#!/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]$OutputFile=("$PSScriptRoot/../coveragereport/merged.cobertura.xml")
+)
+
+$RepoRoot = [string](Resolve-Path $PSScriptRoot/..)
+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($_)
+ }
+
+ $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
+ }
+
+ & dotnet tool run dotnet-coverage merge $Inputs -o $OutputFile -f cobertura
+ } else {
+ Write-Error "No reports found to merge."
+ }
+} finally {
+ Pop-Location
+}
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..9a22a1d0
--- /dev/null
+++ b/azure-pipelines/artifacts/_all.ps1
@@ -0,0 +1,72 @@
+#!/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 staged.
+#>
+
+[CmdletBinding(SupportsShouldProcess = $true)]
+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-ArtifactStaged($artifactName) {
+ $varName = "ARTIFACTSTAGED_$($artifactName.ToUpper())"
+ Test-Path "env:$varName"
+}
+
+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() | % {
+ $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 staged." -ForegroundColor DarkGray
+ }
+}
diff --git a/azure-pipelines/artifacts/_pipelines.ps1 b/azure-pipelines/artifacts/_pipelines.ps1
new file mode 100644
index 00000000..2d3338b2
--- /dev/null
+++ b/azure-pipelines/artifacts/_pipelines.ps1
@@ -0,0 +1,44 @@
+<#
+.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
+)
+
+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.
+ 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
new file mode 100644
index 00000000..d81d16d4
--- /dev/null
+++ b/azure-pipelines/artifacts/_stage_all.ps1
@@ -0,0 +1,60 @@
+<#
+.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
+)
+
+$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
+ }
+}
+
+$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 $_)
+ 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..280ff9ae
--- /dev/null
+++ b/azure-pipelines/artifacts/coverageResults.ps1
@@ -0,0 +1,23 @@
+$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
+
+$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) {
+ Write-Host "Substituting $env:SYSTEM_DEFAULTWORKINGDIRECTORY with `"{reporoot}`""
+ $coverageFiles |% {
+ $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 = (
+ $coverageFiles +
+ (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..8d47a2a6
--- /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 *.LKG.*.nupkg)
+}
diff --git a/azure-pipelines/artifacts/deployables.ps1 b/azure-pipelines/artifacts/deployables.ps1
new file mode 100644
index 00000000..315a2532
--- /dev/null
+++ b/azure-pipelines/artifacts/deployables.ps1
@@ -0,0 +1,15 @@
+$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
+$BuildConfiguration = $env:BUILDCONFIGURATION
+if (!$BuildConfiguration) {
+ $BuildConfiguration = 'Debug'
+}
+
+$PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration"
+$JsRoot = "$RepoRoot/bin/js"
+
+if (!(Test-Path $PackagesRoot)) { return }
+
+@{
+ "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse -Exclude *.LKG.*.nupkg);
+ "$JsRoot" = (Get-ChildItem $JsRoot *.tgz);
+}
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..301a4376
--- /dev/null
+++ b/azure-pipelines/artifacts/testResults.ps1
@@ -0,0 +1,15 @@
+[CmdletBinding()]
+Param(
+)
+
+$result = @{}
+
+$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..021256ae
--- /dev/null
+++ b/azure-pipelines/build.yml
@@ -0,0 +1,63 @@
+parameters:
+- name: windowsPool
+ type: object
+ default:
+ vmImage: windows-2022
+- name: RunTests
+ type: boolean
+ default: true
+
+jobs:
+- job: Windows
+ pool: ${{ parameters.windowsPool }}
+ variables:
+ - name: testModifier
+ value:
+ - ${{ if eq(variables['System.TeamFoundationCollectionUri'], 'https://dev.azure.com/andrewarnott/') }}:
+ - group: dotnetfoundation code signing
+ 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
+ - 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.203 -InstallDir "C:\Program Files (x86)\dotnet\" -NoPath -Verbose
+ displayName: ⚙ Install 32-bit .NET SDK and runtimes
+
+ - template: dotnet.yml
+ parameters:
+ RunTests: ${{ parameters.RunTests }}
+
+- job: Linux
+ pool:
+ vmImage: Ubuntu 20.04
+ 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
+ - template: install-dependencies.yml
+ - powershell: dotnet tool run nbgv cloud -c
+ displayName: ⚙ Set build number
+ - template: dotnet.yml
+ parameters:
+ RunTests: ${{ parameters.RunTests }}
+
+- 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
+ fetchDepth: 0 # avoid shallow clone so nbgv can do its work.
+ clean: true
+ - template: install-dependencies.yml
+ parameters:
+ initArgs: -NoRestore
+ - ${{ if parameters.RunTests }}:
+ - template: publish-codecoverage.yml
+ - 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..24bf812a
--- /dev/null
+++ b/azure-pipelines/dotnet-test-cloud.ps1
@@ -0,0 +1,83 @@
+#!/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]$x86,
+ [string]$dotnet32
+)
+
+$RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path
+$ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1"
+
+$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" `
+ --collect "Code Coverage;Format=cobertura" `
+ --settings "$PSScriptRoot/test.runsettings" `
+ --blame-hang-timeout 60s `
+ --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 $_)
+ $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)$x86RunTitleSuffix, $Agent)"
+ }
+ }
+ }
+ if (!$runTitle) {
+ $unknownCounter += 1;
+ $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
new file mode 100644
index 00000000..92ffd970
--- /dev/null
+++ b/azure-pipelines/dotnet.yml
@@ -0,0 +1,84 @@
+parameters:
+ RunTests:
+
+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/net6.0/any /bl:"$(Build.ArtifactStagingDirectory)/build_logs/nbgv_publish.binlog"
+ displayName: 📢 Publish nbgv tool
+ workingDirectory: src/nbgv
+
+- script: yarn build
+ displayName: 🛠️ Build nerdbank-gitversioning NPM package
+ workingDirectory: src/nerdbank-gitversioning.npm
+
+- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults
+ displayName: 🧪 dotnet test
+ condition: and(succeeded(), ${{ parameters.RunTests }})
+
+- powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults -X86
+ 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-Windows'
+ --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-Windows'
+ --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)" -Verbose
+ failOnStderr: true
+ displayName: 📢 Publish artifacts
+ condition: succeededOrFailed()
+
+- ${{ 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
diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml
new file mode 100644
index 00000000..761d1800
--- /dev/null
+++ b/azure-pipelines/install-dependencies.yml
@@ -0,0 +1,30 @@
+parameters:
+ initArgs:
+
+steps:
+
+- task: NodeTool@0
+ inputs:
+ versionSpec: 16.x
+ displayName: ⚙️ Install Node.js
+
+- task: NuGetAuthenticate@1
+ 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-CodeCov.ps1 b/azure-pipelines/publish-CodeCov.ps1
new file mode 100644
index 00000000..9926f018
--- /dev/null
+++ b/azure-pipelines/publish-CodeCov.ps1
@@ -0,0 +1,30 @@
+<#
+.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
+ Name to upload with codecoverge
+.PARAMETER Flags
+ Flags to upload with codecoverge
+#>
+[CmdletBinding()]
+Param (
+ [Parameter(Mandatory=$true)]
+ [string]$CodeCovToken,
+ [Parameter(Mandatory=$true)]
+ [string]$PathToCodeCoverage,
+ [string]$Name,
+ [string]$Flags
+)
+
+$RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path
+
+Get-ChildItem -Recurse -Path $PathToCodeCoverage -Filter "*.cobertura.xml" | % {
+ $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
+}
diff --git a/azure-pipelines/publish-codecoverage.yml b/azure-pipelines/publish-codecoverage.yml
new file mode 100644
index 00000000..403b769f
--- /dev/null
+++ b/azure-pipelines/publish-codecoverage.yml
@@ -0,0 +1,17 @@
+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
+- 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/merged.cobertura.xml
+ failIfCoverageEmpty: true
diff --git a/azure-pipelines/publish-deployables.yml b/azure-pipelines/publish-deployables.yml
new file mode 100644
index 00000000..6e5e3803
--- /dev/null
+++ b/azure-pipelines/publish-deployables.yml
@@ -0,0 +1,25 @@
+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: 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"
+ npm publish $tgz
+ workingDirectory: $(Agent.TempDirectory)
+ displayName: 📦 npm publish to PublicCI feed
+ continueOnError: true
+ condition: and(succeeded(), ne(variables['ci_npm_feed'], ''), ne(variables['Build.Reason'], 'PullRequest'))
diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml
index 613b925c..e89ac645 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 change", "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/test.runsettings b/azure-pipelines/test.runsettings
new file mode 100644
index 00000000..4e24a0a6
--- /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
+
+ False
+
+ False
+
+ True
+
+
+
+
+
+
diff --git a/azure-pipelines/variables/_all.ps1 b/azure-pipelines/variables/_all.ps1
new file mode 100644
index 00000000..cc6e8810
--- /dev/null
+++ b/azure-pipelines/variables/_all.ps1
@@ -0,0 +1,20 @@
+#!/usr/bin/env pwsh
+
+<#
+.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 = @{}
+
+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..11748b81
--- /dev/null
+++ b/azure-pipelines/variables/_pipelines.ps1
@@ -0,0 +1,31 @@
+<#
+.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.
+#>
+
+[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.
+ $keyCaps = $_.Key.ToUpper()
+ 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
+ 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/azure-pipelines/xplattest-pipeline.yml b/azure-pipelines/xplattest-pipeline.yml
index 0841124a..0b2e29f9 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 &&
@@ -43,19 +43,7 @@ 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/Cake.GitVersioning.*nupkg)
+ PkgFileName=$(ls deployables-Windows/Cake.GitVersioning.*nupkg)
NBGV_NuGetPackageVersion=$([[ $PkgFileName =~ Cake.GitVersioning\.(.*)\.nupkg ]] && echo "${BASH_REMATCH[1]}")
@@ -80,11 +68,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
diff --git a/build.ps1 b/build.ps1
index f49055e5..269bdaa2 100644
--- a/build.ps1
+++ b/build.ps1
@@ -15,7 +15,7 @@ Param(
[string]$MsBuildVerbosity = 'minimal'
)
-$msbuildCommandLine = "dotnet build `"$PSScriptRoot\src\Nerdbank.GitVersioning.sln`" /m /verbosity:$MsBuildVerbosity /nologo /p:Platform=`"Any CPU`" /t:build,pack"
+$msbuildCommandLine = "dotnet build `"$PSScriptRoot\Nerdbank.GitVersioning.sln`" /m /verbosity:$MsBuildVerbosity /nologo /p:Platform=`"Any CPU`" /t:build,pack"
if (Test-Path "C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll") {
$msbuildCommandLine += " /logger:`"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll`""
@@ -27,7 +27,7 @@ if ($Configuration) {
Push-Location .
try {
- if ($PSCmdlet.ShouldProcess("$PSScriptRoot\src\Nerdbank.GitVersioning.sln", "msbuild")) {
+ if ($PSCmdlet.ShouldProcess("$PSScriptRoot\Nerdbank.GitVersioning.sln", "msbuild")) {
Invoke-Expression $msbuildCommandLine
if ($LASTEXITCODE -ne 0) {
throw "dotnet build failed"
diff --git a/doc/cloudbuild.md b/doc/cloudbuild.md
index 9230c4c0..3db9e4b9 100644
--- a/doc/cloudbuild.md
+++ b/doc/cloudbuild.md
@@ -22,12 +22,30 @@ 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
+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).
+
+[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,
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.
@@ -177,3 +195,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
diff --git a/doc/nbgv-cli.md b/doc/nbgv-cli.md
index 3c9f46af..b7e58610 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
@@ -127,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
@@ -164,6 +165,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 910a03e3..a56adb55 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"
}
```
@@ -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"
diff --git a/global.json b/global.json
index e2af429b..c7d7e468 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "6.0.100",
+ "version": "7.0.203",
"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..062c8c85 100755
--- a/init.ps1
+++ b/init.ps1
@@ -2,68 +2,123 @@
<#
.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 NoToolRestore
+ Skips the dotnet tool 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(
- [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()]
+ [switch]$NoToolRestore,
+ [Parameter()]
+ [string]$AccessToken,
+ [Parameter()]
+ [switch]$Interactive
)
+$EnvVars = @{}
+$PrependPath = @()
+
if (!$NoPrerequisites) {
- & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality
+ if (!$NoNuGetCredProvider) {
+ & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites
+ }
+
+ & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality -IncludeX86
+ 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 {
$HeaderColor = 'Green'
if (!$NoRestore -and $PSCmdlet.ShouldProcess("NuGet packages", "Restore")) {
+ $RestoreArguments = @()
+ if ($Interactive)
+ {
+ $RestoreArguments += '--interactive'
+ }
+
Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor
- dotnet restore "$PSScriptRoot\src"
+ dotnet restore @RestoreArguments
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 (!$NoToolRestore -and $PSCmdlet.ShouldProcess("dotnet tool", "restore")) {
+ dotnet tool restore @RestoreArguments
+ if ($lastexitcode -ne 0) {
+ throw "Failure while restoring dotnet CLI tools."
+ }
+ }
+
+ 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
if ($PSCmdlet.ShouldProcess("$PSScriptRoot\src\nerdbank-gitversioning.npm", "yarn install")) {
- yarn install --loglevel error
+ yarn install --cwd src/nerdbank-gitversioning.npm --loglevel error
}
- } 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/nuget.config b/nuget.config
new file mode 100644
index 00000000..b60f26be
--- /dev/null
+++ b/nuget.config
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/.editorconfig b/src/.editorconfig
new file mode 100644
index 00000000..b12e588d
--- /dev/null
+++ 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/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.Tests/Cake.GitVersioning.Tests.csproj b/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj
deleted file mode 100644
index cbf2dcd2..00000000
--- a/src/Cake.GitVersioning.Tests/Cake.GitVersioning.Tests.csproj
+++ /dev/null
@@ -1,28 +0,0 @@
-
-
-
- net5.0;net461
- false
- true
- false
- true
- true
- full
-
-
-
-
-
-
-
-
-
-
-
- runtime; build; native; contentfiles; analyzers; buildtransitive
- all
-
-
-
-
-
diff --git a/src/Cake.GitVersioning/Cake.GitVersioning.csproj b/src/Cake.GitVersioning/Cake.GitVersioning.csproj
index ed37946b..7c978f07 100644
--- a/src/Cake.GitVersioning/Cake.GitVersioning.csproj
+++ b/src/Cake.GitVersioning/Cake.GitVersioning.csproj
@@ -1,12 +1,11 @@
- netstandard2.0
+ net6.0
true
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
@@ -29,45 +28,32 @@
-
-
-
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
+
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..0e9ad07d 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.
@@ -49,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/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/Directory.Build.props b/src/Directory.Build.props
index 105676df..052fe3ef 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..c1d929a5
--- /dev/null
+++ b/src/Directory.Build.targets
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/src/NerdBank.GitVersioning.Benchmarks/Program.cs b/src/NerdBank.GitVersioning.Benchmarks/Program.cs
deleted file mode 100644
index 90149bd6..00000000
--- a/src/NerdBank.GitVersioning.Benchmarks/Program.cs
+++ /dev/null
@@ -1,11 +0,0 @@
-using System;
-using BenchmarkDotNet.Running;
-
-namespace Nerdbank.GitVersioning.Benchmarks
-{
- class Program
- {
- static void Main(string[] args) =>
- BenchmarkSwitcher.FromAssembly(typeof(Program).Assembly).Run(args);
- }
-}
diff --git a/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs b/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs
deleted file mode 100644
index 253fdeb6..00000000
--- a/src/NerdBank.GitVersioning.Tests/AssemblyInfoTest.cs
+++ /dev/null
@@ -1,221 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using Microsoft.Build.Utilities;
-using Nerdbank.GitVersioning.Tasks;
-using Xunit;
-
-public class AssemblyInfoTest : IClassFixture
-{
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- [InlineData(null)]
- public void FSharpGenerator(bool? thisAssemblyClass)
- {
- var info = new AssemblyVersionInfo();
- info.AssemblyCompany = "company";
- info.AssemblyFileVersion = "1.3.1.0";
- info.AssemblyVersion = "1.3.0.0";
- info.AdditionalThisAssemblyFields =
- new TaskItem[]
- {
- new TaskItem(
- "CustomString1",
- new Dictionary() { { "String", "abc" } } ),
- new TaskItem(
- "CustomString2",
- new Dictionary() { { "String", "" } } ),
- new TaskItem(
- "CustomString3",
- new Dictionary() { { "String", "" }, { "EmitIfEmpty", "true" } } ),
- new TaskItem(
- "CustomBool",
- new Dictionary() { { "Boolean", "true" } } ),
- new TaskItem(
- "CustomTicks",
- new Dictionary() { { "Ticks", "637509805729817056" } } ),
- };
- info.CodeLanguage = "f#";
-
- if (thisAssemblyClass.HasValue)
- {
- info.EmitThisAssemblyClass = thisAssemblyClass.GetValueOrDefault();
- }
-
- var built = info.BuildCode();
-
- var 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 AssemblyInfo
-[]
-[]
-[]
-{(thisAssemblyClass.GetValueOrDefault(true) ? $@"do()
-#if NETSTANDARD || NETFRAMEWORK || NETCOREAPP
-[]
-#endif
-#if NETFRAMEWORK || NETCOREAPP || NETSTANDARD2_0 || NETSTANDARD2_1
-[]
-#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 CustomBool = true
- static member internal CustomString1 = ""abc""
- static member internal CustomString3 = """"
- static member internal CustomTicks = new System.DateTime(637509805729817056L, System.DateTimeKind.Utc)
- static member internal IsPrerelease = false
- static member internal IsPublicRelease = false
- static member internal RootNamespace = """"
-do()
-" : "")}";
-
- Assert.Equal(expected, built);
- }
-
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- [InlineData(null)]
- public void CSharpGenerator(bool? thisAssemblyClass)
- {
- var info = new AssemblyVersionInfo();
- info.AssemblyCompany = "company";
- info.AssemblyFileVersion = "1.3.1.0";
- info.AssemblyVersion = "1.3.0.0";
- info.CodeLanguage = "c#";
- info.AdditionalThisAssemblyFields =
- new TaskItem[]
- {
- new TaskItem(
- "CustomString1",
- new Dictionary() { { "String", "abc" } } ),
- new TaskItem(
- "CustomString2",
- new Dictionary() { { "String", "" } } ),
- new TaskItem(
- "CustomString3",
- new Dictionary() { { "String", "" }, { "EmitIfEmpty", "true" } } ),
- new TaskItem(
- "CustomBool",
- new Dictionary() { { "Boolean", "true" } } ),
- new TaskItem(
- "CustomTicks",
- new Dictionary() { { "Ticks", "637509805729817056" } } ),
- };
-
- if (thisAssemblyClass.HasValue)
- {
- info.EmitThisAssemblyClass = thisAssemblyClass.GetValueOrDefault();
- }
-
- var built = info.BuildCode();
-
- var 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("""")]
-{(thisAssemblyClass.GetValueOrDefault(true) ? $@"#if NETSTANDARD || NETFRAMEWORK || NETCOREAPP
-[System.CodeDom.Compiler.GeneratedCode(""{AssemblyVersionInfo.GeneratorName}"",""{AssemblyVersionInfo.GeneratorVersion}"")]
-#endif
-#if NETFRAMEWORK || NETCOREAPP || NETSTANDARD2_0 || NETSTANDARD2_1
-[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 CustomBool = true;
- internal const string CustomString1 = ""abc"";
- internal const string CustomString3 = """";
- internal static readonly System.DateTime CustomTicks = new System.DateTime(637509805729817056L, System.DateTimeKind.Utc);
- internal const bool IsPrerelease = false;
- internal const bool IsPublicRelease = false;
- internal const string RootNamespace = """";
-}}
-" : "")}";
-
- Assert.Equal(expected, built);
- }
-
- [Theory]
- [InlineData(false)]
- [InlineData(true)]
- [InlineData(null)]
- public void VisualBasicGenerator(bool? thisAssemblyClass)
- {
- var info = new AssemblyVersionInfo();
- info.AssemblyCompany = "company";
- info.AssemblyFileVersion = "1.3.1.0";
- info.AssemblyVersion = "1.3.0.0";
- info.CodeLanguage = "vb";
-
- if (thisAssemblyClass.HasValue)
- {
- info.EmitThisAssemblyClass = thisAssemblyClass.GetValueOrDefault();
- }
-
- var built = info.BuildCode();
-
- var 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
-
-
-
-
-{(thisAssemblyClass.GetValueOrDefault(true) ? $@"#If NETFRAMEWORK Or NETCOREAPP Or NETSTANDARD2_0 Or NETSTANDARD2_1 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 = """"
-End Class
-" : "")}";
-
- Assert.Equal(expected, built);
- }
-}
diff --git a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs b/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs
deleted file mode 100644
index 159ee377..00000000
--- a/src/NerdBank.GitVersioning.Tests/BuildIntegrationTests.cs
+++ /dev/null
@@ -1,1367 +0,0 @@
-using System;
-using System.Collections.Generic;
-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;
-using Microsoft.Build.Evaluation;
-using Microsoft.Build.Execution;
-using Microsoft.Build.Framework;
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using Nerdbank.GitVersioning;
-using Validation;
-using Xunit;
-using Xunit.Abstractions;
-using Version = System.Version;
-
-[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
-{
- public BuildIntegrationManagedTests(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";
-}
-
-[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
-{
- public BuildIntegrationLibGit2Tests(ITestOutputHelper logger)
- : base(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";
-}
-
-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[]
- {
- "APPVEYOR",
- "SYSTEM_",
- "BUILD_",
- "NBGV_GitEngine",
- };
- private BuildManager buildManager;
- private ProjectCollection projectCollection;
- private string projectDirectory;
- private ProjectRootElement testProject;
- private Dictionary globalProperties = new Dictionary(StringComparer.OrdinalIgnoreCase)
- {
- // Set global properties to neutralize environment variables
- // that might actually be defined by a CI that is building and running these tests.
- { "PublicRelease", string.Empty },
- };
- private Random random;
-
- public BuildIntegrationTests(ITestOutputHelper logger)
- : base(logger)
- {
- // MSBuildExtensions.LoadMSBuild will be called as part of the base constructor, because this class
- // implements the IClassFixture interface. LoadMSBuild will load the MSBuild assemblies.
- // This must happen _before_ any method that directly references types in the Microsoft.Build namespace has been called.
- // Net, don't init MSBuild-related fields in the constructor, but in a method that is called by the constructor.
- this.Init();
- }
-
- 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 string CommitIdShort => this.Context.GitCommitId?.Substring(0, VersionOptions.DefaultGitCommitIdShortFixedLength);
-
- protected abstract void ApplyGlobalProperties(IDictionary globalProperties);
-
- protected override void Dispose(bool disposing)
- {
- Environment.SetEnvironmentVariable("_NBGV_UnitTest", string.Empty);
- base.Dispose(disposing);
- }
-
- [Fact]
- public async Task GetBuildVersion_Returns_BuildVersion_Property()
- {
- this.WriteVersionFile();
- this.InitializeSourceControl();
- var buildResult = await this.BuildAsync();
- Assert.Equal(
- buildResult.BuildVersion,
- buildResult.BuildResult.ResultsByTarget[Targets.GetBuildVersion].Items.Single().ItemSpec);
- }
-
- [Fact]
- public async Task GetBuildVersion_Without_Git()
- {
- this.WriteVersionFile("3.4");
- var buildResult = await this.BuildAsync();
- Assert.Equal("3.4", buildResult.BuildVersion);
- Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion);
- }
-
- [Fact]
- public async Task GetBuildVersion_WithThreeVersionIntegers()
- {
- VersionOptions workingCopyVersion = new VersionOptions
- {
- Version = SemanticVersion.Parse("7.8.9-beta.3"),
- SemVer1NumericIdentifierPadding = 1,
- };
- this.WriteVersionFile(workingCopyVersion);
- this.InitializeSourceControl();
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(workingCopyVersion, buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_Without_Git_HighPrecisionAssemblyVersion()
- {
- this.WriteVersionFile(new VersionOptions
- {
- Version = SemanticVersion.Parse("3.4"),
- AssemblyVersion = new VersionOptions.AssemblyVersionOptions
- {
- Precision = VersionOptions.VersionPrecision.Revision,
- },
- });
- var buildResult = await this.BuildAsync();
- Assert.Equal("3.4", buildResult.BuildVersion);
- Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion);
- }
-
- [Fact]
- public async Task GetBuildVersion_OutsideGit_PointingToGit()
- {
- // Write a version file to the 'virtualized' repo.
- string version = "3.4";
- this.WriteVersionFile(version);
-
- string repoRelativeProjectPath = this.testProject.FullPath.Substring(this.RepoPath.Length + 1);
-
- // Update the repo path so we create the 'normal' one elsewhere
- this.RepoPath = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName());
- this.InitializeSourceControl();
-
- // Write the same version file to the 'real' repo
- this.WriteVersionFile(version);
-
- // Point the project to the 'real' repo
- this.testProject.AddProperty("GitRepoRoot", this.RepoPath);
- this.testProject.AddProperty("ProjectPathRelativeToGitRepoRoot", repoRelativeProjectPath);
-
- var buildResult = await this.BuildAsync();
-
- var workingCopyVersion = VersionOptions.FromVersion(new Version(version));
-
- this.AssertStandardProperties(workingCopyVersion, buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_In_Git_But_Without_Commits()
- {
- Repository.Init(this.RepoPath);
- 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();
- Assert.Equal("3.4.0.0", buildResult.BuildVersion);
- Assert.Equal("3.4.0", buildResult.AssemblyInformationalVersion);
- }
-
- [Fact]
- public async Task GetBuildVersion_In_Git_But_Head_Lacks_VersionFile()
- {
- 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 });
- this.WriteVersionFile("3.4");
- 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);
- }
-
- [Fact]
- public async Task GetBuildVersion_In_Git_But_WorkingCopy_Has_Changes()
- {
- const string majorMinorVersion = "5.8";
- const string prerelease = "";
-
- this.WriteVersionFile(majorMinorVersion, prerelease);
- this.InitializeSourceControl();
- var workingCopyVersion = VersionOptions.FromVersion(new Version("6.0"));
- this.Context.VersionFile.SetVersion(this.RepoPath, workingCopyVersion);
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(workingCopyVersion, buildResult);
- }
-
- [Fact]
- 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();
- 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);
- }
-
- [Fact]
- public async Task GetBuildVersion_In_Git_With_Version_File_In_Subdirectory_Works()
- {
- const string majorMinorVersion = "5.8";
- const string prerelease = "";
- const string subdirectory = "projdir";
-
- this.WriteVersionFile(majorMinorVersion, prerelease, subdirectory);
- this.InitializeSourceControl();
- this.AddCommits(this.random.Next(15));
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult, subdirectory);
- }
-
- [Fact]
- public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Subdirectory_Works()
- {
- var rootVersionSpec = new VersionOptions
- {
- Version = SemanticVersion.Parse("14.1"),
- AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)),
- };
- var subdirVersionSpec = new VersionOptions { Version = SemanticVersion.Parse("11.0") };
- const string subdirectory = "projdir";
-
- this.WriteVersionFile(rootVersionSpec);
- this.WriteVersionFile(subdirVersionSpec, subdirectory);
- this.InitializeSourceControl();
- this.AddCommits(this.random.Next(15));
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(subdirVersionSpec, buildResult, subdirectory);
- }
-
- [Fact]
- public async Task GetBuildVersion_In_Git_With_Version_File_In_Root_And_Project_In_Root_Works()
- {
- var rootVersionSpec = new VersionOptions
- {
- Version = SemanticVersion.Parse("14.1"),
- AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)),
- };
-
- this.WriteVersionFile(rootVersionSpec);
- this.InitializeSourceControl();
- this.AddCommits(this.random.Next(15));
- this.testProject = this.CreateProjectRootElement(this.RepoPath, "root.proj");
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(rootVersionSpec, buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_StablePreRelease()
- {
- const string majorMinorVersion = "5.8";
- const string prerelease = "";
-
- this.WriteVersionFile(majorMinorVersion, prerelease);
- this.InitializeSourceControl();
- this.AddCommits(this.random.Next(15));
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_StableRelease()
- {
- const string majorMinorVersion = "5.8";
- const string prerelease = "";
-
- this.WriteVersionFile(majorMinorVersion, prerelease);
- this.InitializeSourceControl();
- this.AddCommits(this.random.Next(15));
- this.globalProperties["PublicRelease"] = "true";
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion)), buildResult);
-
- Version version = this.GetVersion();
- Assert.Equal($"{version.Major}.{version.Minor}.{buildResult.GitVersionHeight}", buildResult.NuGetPackageVersion);
- }
-
- [Fact]
- public async Task GetBuildVersion_UnstablePreRelease()
- {
- const string majorMinorVersion = "5.8";
- const string prerelease = "-beta";
-
- this.WriteVersionFile(majorMinorVersion, prerelease);
- this.InitializeSourceControl();
- this.AddCommits(this.random.Next(15));
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_UnstableRelease()
- {
- const string majorMinorVersion = "5.8";
- const string prerelease = "-beta";
-
- this.WriteVersionFile(majorMinorVersion, prerelease);
- this.InitializeSourceControl();
- this.AddCommits(this.random.Next(15));
- this.globalProperties["PublicRelease"] = "true";
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(VersionOptions.FromVersion(new Version(majorMinorVersion), prerelease), buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_CustomAssemblyVersion()
- {
- this.WriteVersionFile("14.0");
- this.InitializeSourceControl();
- var versionOptions = new VersionOptions
- {
- Version = new SemanticVersion(new Version(14, 1)),
- AssemblyVersion = new VersionOptions.AssemblyVersionOptions(new Version(14, 0)),
- };
- this.WriteVersionFile(versionOptions);
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(versionOptions, buildResult);
- }
-
- [Theory]
- [InlineData(VersionOptions.VersionPrecision.Major)]
- [InlineData(VersionOptions.VersionPrecision.Build)]
- [InlineData(VersionOptions.VersionPrecision.Revision)]
- public async Task GetBuildVersion_CustomAssemblyVersionWithPrecision(VersionOptions.VersionPrecision precision)
- {
- var versionOptions = new VersionOptions
- {
- Version = new SemanticVersion("14.1"),
- AssemblyVersion = new VersionOptions.AssemblyVersionOptions
- {
- Version = new Version("15.2"),
- Precision = precision,
- },
- };
- this.WriteVersionFile(versionOptions);
- this.InitializeSourceControl();
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(versionOptions, buildResult);
- }
-
- [Theory]
- [InlineData(VersionOptions.VersionPrecision.Major)]
- [InlineData(VersionOptions.VersionPrecision.Build)]
- [InlineData(VersionOptions.VersionPrecision.Revision)]
- public async Task GetBuildVersion_CustomAssemblyVersionPrecision(VersionOptions.VersionPrecision precision)
- {
- var versionOptions = new VersionOptions
- {
- Version = new SemanticVersion("14.1"),
- AssemblyVersion = new VersionOptions.AssemblyVersionOptions
- {
- Precision = precision,
- },
- };
- this.WriteVersionFile(versionOptions);
- this.InitializeSourceControl();
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(versionOptions, buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_CustomBuildNumberOffset()
- {
- this.WriteVersionFile("14.0");
- this.InitializeSourceControl();
- var versionOptions = new VersionOptions
- {
- Version = new SemanticVersion(new Version(14, 1)),
- VersionHeightOffset = 5,
- };
- this.WriteVersionFile(versionOptions);
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(versionOptions, buildResult);
- }
-
- [Fact]
- public async Task GetBuildVersion_OverrideBuildNumberOffset()
- {
- this.WriteVersionFile("14.0");
- this.InitializeSourceControl();
- var versionOptions = new VersionOptions
- {
- Version = new SemanticVersion(new Version(14, 1))
- };
- this.WriteVersionFile(versionOptions);
- this.testProject.AddProperty("OverrideBuildNumberOffset", "10");
- var buildResult = await this.BuildAsync();
- Assert.StartsWith("14.1.11.", buildResult.AssemblyFileVersion);
- }
-
- [Fact]
- public async Task GetBuildVersion_Minus1BuildOffset_NotYetCommitted()
- {
- this.WriteVersionFile("14.0");
- this.InitializeSourceControl();
- var versionOptions = new VersionOptions
- {
- Version = new SemanticVersion(new Version(14, 1)),
- VersionHeightOffset = -1,
- };
- this.Context.VersionFile.SetVersion(this.RepoPath, versionOptions);
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(versionOptions, buildResult);
- }
-
- [Theory]
- [InlineData(0)]
- [InlineData(21)]
- public async Task GetBuildVersion_BuildNumberSpecifiedInVersionJson(int buildNumber)
- {
- var versionOptions = new VersionOptions
- {
- Version = SemanticVersion.Parse("14.0." + buildNumber),
- };
- this.WriteVersionFile(versionOptions);
- this.InitializeSourceControl();
- var buildResult = await this.BuildAsync();
- this.AssertStandardProperties(versionOptions, buildResult);
- }
-
- [Fact]
- public async Task PublicRelease_RegEx_Unsatisfied()
- {
- var versionOptions = new VersionOptions
- {
- Version = SemanticVersion.Parse("1.0"),
- PublicReleaseRefSpec = new string[] { "^refs/heads/release$" },
- };
- this.WriteVersionFile(versionOptions);
- this.InitializeSourceControl();
-
- // Just build "master", which doesn't conform to the regex.
- var buildResult = await this.BuildAsync();
- Assert.False(buildResult.PublicRelease);
- this.AssertStandardProperties(versionOptions, buildResult);
- }
-
- public static IEnumerable