diff --git a/.azuredevops/dependabot.yml b/.azuredevops/dependabot.yml
new file mode 100644
index 00000000..4d848fb5
--- /dev/null
+++ b/.azuredevops/dependabot.yml
@@ -0,0 +1,9 @@
+# Please see the documentation for all configuration options:
+# https://eng.ms/docs/products/dependabot/configuration/version_updates
+
+version: 2
+updates:
+- package-ecosystem: nuget
+ directory: /
+ schedule:
+ interval: monthly
diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json
new file mode 100644
index 00000000..a333e70b
--- /dev/null
+++ b/.config/dotnet-tools.json
@@ -0,0 +1,34 @@
+{
+ "version": 1,
+ "isRoot": true,
+ "tools": {
+ "powershell": {
+ "version": "7.4.6",
+ "commands": [
+ "pwsh"
+ ],
+ "rollForward": false
+ },
+ "dotnet-coverage": {
+ "version": "17.12.6",
+ "commands": [
+ "dotnet-coverage"
+ ],
+ "rollForward": false
+ },
+ "nbgv": {
+ "version": "3.6.146",
+ "commands": [
+ "nbgv"
+ ],
+ "rollForward": false
+ },
+ "docfx": {
+ "version": "2.77.0",
+ "commands": [
+ "docfx"
+ ],
+ "rollForward": false
+ }
+ }
+}
\ No newline at end of file
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
new file mode 100644
index 00000000..9626b31b
--- /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:8.0.402-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
new file mode 100644
index 00000000..b268b5ee
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,192 @@
+# EditorConfig is awesome:http://EditorConfig.org
+
+# top-most EditorConfig file
+root = true
+
+# Don't use tabs for indentation.
+[*]
+indent_style = space
+
+# (Please don't specify an indent_size here; that has too many unintended consequences.)
+
+[*.yml]
+indent_size = 2
+indent_style = space
+
+# Code files
+[*.{cs,csx,vb,vbx,h,cpp,idl}]
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+# MSBuild project files
+[*.{csproj,vbproj,vcxproj,vcxproj.filters,proj,projitems,shproj,msbuildproj,props,targets}]
+indent_size = 2
+
+# Xml config files
+[*.{ruleset,config,nuspec,resx,vsixmanifest,vsct,runsettings}]
+indent_size = 2
+indent_style = space
+
+# JSON files
+[*.json]
+indent_size = 2
+indent_style = space
+
+[*.ps1]
+indent_style = space
+indent_size = 4
+
+# Dotnet code style settings:
+[*.{cs,vb}]
+# Sort using and Import directives with System.* appearing first
+dotnet_sort_system_directives_first = true
+dotnet_separate_import_directive_groups = false
+dotnet_style_qualification_for_field = true:warning
+dotnet_style_qualification_for_property = true:warning
+dotnet_style_qualification_for_method = true:warning
+dotnet_style_qualification_for_event = true:warning
+
+# Use language keywords instead of framework type names for type references
+dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
+dotnet_style_predefined_type_for_member_access = true:suggestion
+
+# Suggest more modern language features when available
+dotnet_style_object_initializer = true:suggestion
+dotnet_style_collection_initializer = true:suggestion
+dotnet_style_coalesce_expression = true:suggestion
+dotnet_style_null_propagation = true:suggestion
+dotnet_style_explicit_tuple_names = true:suggestion
+
+# Non-private static fields are PascalCase
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.symbols = non_private_static_fields
+dotnet_naming_rule.non_private_static_fields_should_be_pascal_case.style = non_private_static_field_style
+
+dotnet_naming_symbols.non_private_static_fields.applicable_kinds = field
+dotnet_naming_symbols.non_private_static_fields.applicable_accessibilities = public, protected, internal, protected internal, private protected
+dotnet_naming_symbols.non_private_static_fields.required_modifiers = static
+
+dotnet_naming_style.non_private_static_field_style.capitalization = pascal_case
+
+# Constants are PascalCase
+dotnet_naming_rule.constants_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.constants_should_be_pascal_case.symbols = constants
+dotnet_naming_rule.constants_should_be_pascal_case.style = constant_style
+
+dotnet_naming_symbols.constants.applicable_kinds = field, local
+dotnet_naming_symbols.constants.required_modifiers = const
+
+dotnet_naming_style.constant_style.capitalization = pascal_case
+
+# Static fields are camelCase
+dotnet_naming_rule.static_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.static_fields_should_be_camel_case.symbols = static_fields
+dotnet_naming_rule.static_fields_should_be_camel_case.style = static_field_style
+
+dotnet_naming_symbols.static_fields.applicable_kinds = field
+dotnet_naming_symbols.static_fields.required_modifiers = static
+
+dotnet_naming_style.static_field_style.capitalization = camel_case
+
+# Instance fields are camelCase
+dotnet_naming_rule.instance_fields_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.instance_fields_should_be_camel_case.symbols = instance_fields
+dotnet_naming_rule.instance_fields_should_be_camel_case.style = instance_field_style
+
+dotnet_naming_symbols.instance_fields.applicable_kinds = field
+
+dotnet_naming_style.instance_field_style.capitalization = camel_case
+
+# Locals and parameters are camelCase
+dotnet_naming_rule.locals_should_be_camel_case.severity = suggestion
+dotnet_naming_rule.locals_should_be_camel_case.symbols = locals_and_parameters
+dotnet_naming_rule.locals_should_be_camel_case.style = camel_case_style
+
+dotnet_naming_symbols.locals_and_parameters.applicable_kinds = parameter, local
+
+dotnet_naming_style.camel_case_style.capitalization = camel_case
+
+# Local functions are PascalCase
+dotnet_naming_rule.local_functions_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.local_functions_should_be_pascal_case.symbols = local_functions
+dotnet_naming_rule.local_functions_should_be_pascal_case.style = local_function_style
+
+dotnet_naming_symbols.local_functions.applicable_kinds = local_function
+
+dotnet_naming_style.local_function_style.capitalization = pascal_case
+
+# By default, name items with PascalCase
+dotnet_naming_rule.members_should_be_pascal_case.severity = suggestion
+dotnet_naming_rule.members_should_be_pascal_case.symbols = all_members
+dotnet_naming_rule.members_should_be_pascal_case.style = pascal_case_style
+
+dotnet_naming_symbols.all_members.applicable_kinds = *
+
+dotnet_naming_style.pascal_case_style.capitalization = pascal_case
+
+# CSharp code style settings:
+[*.cs]
+# Indentation preferences
+csharp_indent_block_contents = true
+csharp_indent_braces = false
+csharp_indent_case_contents = true
+csharp_indent_switch_labels = true
+csharp_indent_labels = flush_left
+
+# Prefer "var" everywhere
+csharp_style_var_for_built_in_types = 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 = false:none
+csharp_style_expression_bodied_constructors = false:none
+csharp_style_expression_bodied_operators = false:none
+
+# Prefer property-like constructs to have an expression-body
+csharp_style_expression_bodied_properties = true:none
+csharp_style_expression_bodied_indexers = true:none
+csharp_style_expression_bodied_accessors = true:none
+
+# Suggest more modern language features when available
+csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
+csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
+csharp_style_inlined_variable_declaration = true:suggestion
+csharp_style_throw_expression = true:suggestion
+csharp_style_conditional_delegate_call = true:suggestion
+
+# Newline settings
+csharp_new_line_before_open_brace = all
+csharp_new_line_before_else = true
+csharp_new_line_before_catch = true
+csharp_new_line_before_finally = true
+csharp_new_line_before_members_in_object_initializers = true
+csharp_new_line_before_members_in_anonymous_types = true
+
+# Blocks are allowed
+csharp_prefer_braces = true:silent
+
+# 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
+
+# CA1062: Validate arguments of public methods
+dotnet_diagnostic.CA1062.severity = warning
+
+# CA2016: Forward the CancellationToken parameter
+dotnet_diagnostic.CA2016.severity = warning
+
+[*.sln]
+indent_style = tab
diff --git a/.gitattributes b/.gitattributes
index 1ff0c423..1f35e683 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -3,6 +3,13 @@
###############################################################################
* text=auto
+# 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.
#
@@ -17,7 +24,7 @@
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
-# the diff markers are never inserted). Diff markers may cause the following
+# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
@@ -46,9 +53,9 @@
###############################################################################
# diff behavior for common document formats
-#
+#
# Convert binary document formats to text before diffing them. This feature
-# is only available from the command line. Turn it on by uncommenting the
+# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 00000000..63e3e890
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,9 @@
+# Please see the documentation for all configuration options:
+# https://docs.github.com/en/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
+
+version: 2
+updates:
+- package-ecosystem: nuget
+ directory: /
+ schedule:
+ interval: weekly
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
new file mode 100644
index 00000000..4ccf1187
--- /dev/null
+++ b/.github/workflows/build.yml
@@ -0,0 +1,118 @@
+name: CI
+
+on:
+ push:
+ branches:
+ - main
+ - microbuild
+ - validate/*
+ pull_request:
+
+env:
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ BUILDCONFIGURATION: Release
+ # codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/
+ NUGET_PACKAGES: ${{ github.workspace }}/.nuget/packages/
+
+jobs:
+ build:
+
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - windows-2022
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
+ - name: โ Install prerequisites
+ run: |
+ ./init.ps1 -UpgradePrerequisites
+ dotnet --info
+
+ # Print mono version if it is present.
+ if (Get-Command mono -ErrorAction SilentlyContinue) {
+ mono --version
+ }
+ shell: pwsh
+ - name: โ๏ธ Set pipeline variables based on source
+ run: azure-pipelines/variables/_pipelines.ps1
+ shell: pwsh
+ - name: ๐ build
+ run: dotnet build src -t:build,pack --no-restore -c ${{ env.BUILDCONFIGURATION }} /bl:"${{ runner.temp }}/_artifacts/build_logs/build.binlog"
+ - name: ๐งช test
+ run: azure-pipelines/dotnet-test-cloud.ps1 -Configuration ${{ env.BUILDCONFIGURATION }} -Agent ${{ runner.os }}
+ shell: pwsh
+ - name: ๐
๐ป Verify formatted code
+ run: dotnet format --verify-no-changes --no-restore
+ shell: pwsh
+ if: runner.os == 'Linux'
+ - name: โ Update pipeline variables based on build outputs
+ run: azure-pipelines/variables/_pipelines.ps1
+ shell: pwsh
+ - name: ๐ฅ Collect artifacts
+ run: azure-pipelines/artifacts/_stage_all.ps1
+ shell: pwsh
+ if: always()
+ - name: ๐ข Upload project.assets.json files
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: projectAssetsJson-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/projectAssetsJson
+ continue-on-error: true
+ - name: ๐ข Upload variables
+ uses: actions/upload-artifact@v4
+ with:
+ name: variables-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/Variables
+ continue-on-error: true
+ - name: ๐ข Upload build_logs
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: build_logs-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/build_logs
+ continue-on-error: true
+ - name: ๐ข Upload test_logs
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: test_logs-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/test_logs
+ continue-on-error: true
+ - name: ๐ข Upload testResults
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: testResults-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/testResults
+ continue-on-error: true
+ - name: ๐ข Upload coverageResults
+ if: always()
+ uses: actions/upload-artifact@v4
+ with:
+ name: coverageResults-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/coverageResults
+ continue-on-error: true
+ - name: ๐ข Upload symbols
+ uses: actions/upload-artifact@v4
+ with:
+ name: symbols-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/symbols
+ continue-on-error: true
+ - name: ๐ข Upload deployables
+ uses: actions/upload-artifact@v4
+ with:
+ name: deployables-${{ runner.os }}
+ path: ${{ runner.temp }}/_artifacts/deployables
+ if: always()
+ - name: ๐ข Publish code coverage results to codecov.io
+ run: ./azure-pipelines/publish-CodeCov.ps1 -CodeCovToken "${{ env.codecov_token }}" -PathToCodeCoverage "${{ runner.temp }}/_artifacts/coverageResults" -Name "${{ runner.os }} Coverage Results" -Flags "${{ runner.os }}"
+ shell: pwsh
+ timeout-minutes: 3
+ continue-on-error: true
+ if: env.codecov_token != ''
diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000..6e6e64a0
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,41 @@
+name: ๐ Docs
+
+on:
+ push:
+ branches:
+ - main
+
+# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
+permissions:
+ actions: read
+ pages: write
+ id-token: write
+
+# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
+# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
+concurrency:
+ group: pages
+ cancel-in-progress: false
+
+jobs:
+ publish-docs:
+ environment:
+ name: github-pages
+ url: ${{ steps.deployment.outputs.page_url }}
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v4
+ - name: โ Install prerequisites
+ run: ./init.ps1 -UpgradePrerequisites
+
+ - run: dotnet docfx docfx/docfx.json
+ name: ๐ Generate documentation
+
+ - name: Upload artifact
+ uses: actions/upload-pages-artifact@v3
+ with:
+ path: docfx/_site
+
+ - name: Deploy to GitHub Pages
+ id: deployment
+ uses: actions/deploy-pages@v4
diff --git a/.github/workflows/libtemplate-update.yml b/.github/workflows/libtemplate-update.yml
new file mode 100644
index 00000000..0831ced6
--- /dev/null
+++ b/.github/workflows/libtemplate-update.yml
@@ -0,0 +1,98 @@
+name: Library.Template update
+
+# PREREQUISITE: This workflow requires the repo to be configured to allow workflows to create pull requests.
+# Visit https://github.com/USER/REPO/settings/actions
+# Under "Workflow permissions" check "Allow GitHub Actions to create ...pull requests"
+# Click Save.
+
+on:
+ schedule:
+ - cron: "0 3 * * Mon" # Sun @ 8 or 9 PM Mountain Time (depending on DST)
+ workflow_dispatch:
+
+jobs:
+ merge:
+ runs-on: ubuntu-latest
+ permissions:
+ contents: write
+ pull-requests: write
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ fetch-depth: 0 # avoid shallow clone so nbgv can do its work.
+
+ - name: merge
+ id: merge
+ shell: pwsh
+ run: |
+ $LibTemplateBranch = & ./azure-pipelines/Get-LibTemplateBasis.ps1 -ErrorIfNotRelated
+ if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+ }
+
+ git fetch https://github.com/aarnott/Library.Template $LibTemplateBranch
+ if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+ }
+ $LibTemplateCommit = git rev-parse FETCH_HEAD
+ git diff --stat ...FETCH_HEAD
+
+ if ((git rev-list FETCH_HEAD ^HEAD --count) -eq 0) {
+ Write-Host "There are no Library.Template updates to merge."
+ echo "uptodate=true" >> $env:GITHUB_OUTPUT
+ exit 0
+ }
+
+ # Pushing commits that add or change files under .github/workflows will cause our workflow to fail.
+ # But it usually isn't necessary because the target branch already has (or doesn't have) these changes.
+ # So if the merged doesn't bring in any changes to these files, try the merge locally and push that
+ # to keep github happy.
+ if ((git rev-list FETCH_HEAD ^HEAD --count -- .github/workflows) -eq 0) {
+ # Indeed there are no changes in that area. So merge locally to try to appease GitHub.
+ git checkout -b auto/libtemplateUpdate
+ git config user.name "Andrew Arnott"
+ git config user.email "andrewarnott@live.com"
+ git merge FETCH_HEAD
+ if ($LASTEXITCODE -ne 0) {
+ Write-Host "Merge conflicts prevent creating the pull request. Please run tools/MergeFrom-Template.ps1 locally and push the result as a pull request."
+ exit 2
+ }
+
+ git -c http.extraheader="AUTHORIZATION: bearer $env:GH_TOKEN" push origin -u HEAD
+ } else {
+ Write-Host "Changes to github workflows are included in this update. Please run tools/MergeFrom-Template.ps1 locally and push the result as a pull request."
+ exit 1
+ }
+ - name: pull request
+ shell: pwsh
+ if: success() && steps.merge.outputs.uptodate != 'true'
+ run: |
+ # If there is already an active pull request, don't create a new one.
+ $existingPR = gh pr list -H auto/libtemplateUpdate --json url | ConvertFrom-Json
+ if ($existingPR) {
+ Write-Host "::warning::Skipping pull request creation because one already exists at $($existingPR[0].url)"
+ exit 0
+ }
+
+ $prTitle = "Merge latest Library.Template"
+ $prBody = "This merges the latest features and fixes from [Library.Template's branch](https://github.com/AArnott/Library.Template/tree/).
+
+ โ ๏ธ Do **not** squash this pull request when completing it. You must *merge* it."
+
+
+ Merge conflicts?
+ Resolve merge conflicts locally by carrying out these steps:
+
+ ```
+ git fetch
+ git checkout auto/libtemplateUpdate
+ git merge origin/main
+ # resolve conflicts
+ git commit
+ git push
+ ```
+
+
+ gh pr create -H auto/libtemplateUpdate -b $prBody -t $prTitle
+ env:
+ GH_TOKEN: ${{ github.token }}
diff --git a/.gitignore b/.gitignore
index f1e3d20e..cc2b1247 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,15 +1,23 @@
## 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
+*.lutconfig
+launchSettings.json
# User-specific files (MonoDevelop/Xamarin Studio)
*.userprefs
+# Mono auto generated files
+mono_crash.*
+
# Build results
[Dd]ebug/
[Dd]ebugPublic/
@@ -17,50 +25,66 @@
[Rr]eleases/
x64/
x86/
+[Aa][Rr][Mm]/
+[Aa][Rr][Mm]64/
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
-# Visual Studio 2015 cache/options directory
+# Visual Studio 2015/2017 cache/options directory
.vs/
# Uncomment if you have tasks that create the project's static files in wwwroot
#wwwroot/
+# Jetbrains Rider cache directory
+.idea/
+
+# 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
-# DNX
-project.lock.json
-artifacts/
+# 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
*.vspscc
*.vssscc
@@ -89,6 +113,9 @@ ipch/
*.vspx
*.sap
+# Visual Studio Trace Files
+*.e2e
+
# TFS 2012 Local Workspace
$tf/
@@ -109,6 +136,15 @@ _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
@@ -140,7 +176,7 @@ publish/
# Publish Web Output
*.[Pp]ublish.xml
*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings
+# 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
@@ -152,13 +188,15 @@ PublishScripts/
# NuGet Packages
*.nupkg
+# NuGet Symbol Packages
+*.snupkg
# The packages folder can be ignored because of Package Restore
-**/packages/*
+**/[Pp]ackages/*
# except build/, which is used as an MSBuild target.
-!**/packages/build/
+!**/[Pp]ackages/build/
# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-# NuGet v3's project.json files produces more ignoreable files
+#!**/[Pp]ackages/repositories.config
+# NuGet v3's project.json files produces more ignorable files
*.nuget.props
*.nuget.targets
@@ -175,12 +213,15 @@ 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/
+!?*.[Cc]ache/
# Others
ClientBin/
@@ -188,11 +229,15 @@ ClientBin/
*~
*.dbmdl
*.dbproj.schemaview
+*.jfm
*.pfx
*.publishsettings
-node_modules/
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/
@@ -207,15 +252,22 @@ _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/
@@ -225,6 +277,7 @@ FakesAssemblies/
# Node.js Tools for Visual Studio
.ntvs_analysis.dat
+node_modules/
# Visual Studio 6 build log
*.plg
@@ -232,6 +285,9 @@ FakesAssemblies/
# 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
@@ -247,6 +303,58 @@ paket-files/
# FAKE - F# Make
.fake/
-# JetBrains Rider
-.idea/
-*.sln.iml
+# 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
+
+# Analysis results
+*.sarif
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
new file mode 100644
index 00000000..acaf0213
--- /dev/null
+++ b/.vscode/extensions.json
@@ -0,0 +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": [
+ "ms-azure-devops.azure-pipelines",
+ "ms-dotnettools.csharp",
+ "k--kato.docomment",
+ "editorconfig.editorconfig",
+ "esbenp.prettier-vscode",
+ "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/launch.json b/.vscode/launch.json
new file mode 100644
index 00000000..a6e4859c
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,14 @@
+{
+ // Use IntelliSense to find out which attributes exist for C# debugging
+ // Use hover for the description of the existing attributes
+ // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
+ "version": "0.2.0",
+ "configurations": [
+ {
+ "name": ".NET Core Attach",
+ "type": "coreclr",
+ "request": "attach",
+ "processId": "${command:pickProcess}"
+ }
+ ]
+}
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 00000000..aa4ef023
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,24 @@
+{
+ "files.trimTrailingWhitespace": true,
+ "files.insertFinalNewline": true,
+ "files.trimFinalNewlines": true,
+ "azure-pipelines.1ESPipelineTemplatesSchemaFile": true,
+ "omnisharp.enableEditorConfigSupport": true,
+ "omnisharp.enableRoslynAnalyzers": true,
+ "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true,
+ "editor.formatOnSave": true,
+ "[xml]": {
+ "editor.wordWrap": "off"
+ },
+ // Treat these files as Azure Pipelines files
+ "files.associations": {
+ "**/azure-pipelines/**/*.yml": "azure-pipelines",
+ "azure-pipelines.yml": "azure-pipelines"
+ },
+ // Use Prettier as the default formatter for Azure Pipelines files.
+ // Needs to be explicitly configured: https://github.com/Microsoft/azure-pipelines-vscode#document-formatting
+ "[azure-pipelines]": {
+ "editor.defaultFormatter": "esbenp.prettier-vscode",
+ "editor.formatOnSave": false // enable this when they conform
+ },
+}
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
new file mode 100644
index 00000000..67b06180
--- /dev/null
+++ b/.vscode/tasks.json
@@ -0,0 +1,17 @@
+{
+ "version": "2.0.0",
+ "tasks": [
+ {
+ "label": "build",
+ "command": "dotnet",
+ "type": "process",
+ "args": [
+ "build",
+ "${workspaceFolder}",
+ "/property:GenerateFullPaths=true",
+ "/consoleloggerparameters:NoSummary"
+ ],
+ "problemMatcher": "$msCompile"
+ }
+ ]
+}
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 00000000..f9ba8cf6
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,9 @@
+# Microsoft Open Source Code of Conduct
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
+
+Resources:
+
+- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
+- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
+- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 00000000..a094cfdf
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,59 @@
+
+
+
+ Debug
+ $(MSBuildThisFileDirectory)
+ $(RepoRootPath)obj\$([MSBuild]::MakeRelative($(RepoRootPath), $(MSBuildProjectDirectory)))\
+ $(RepoRootPath)bin\$(MSBuildProjectName)\
+ $(RepoRootPath)bin\Packages\$(Configuration)\NuGet\
+ $(RepoRootPath)bin\Packages\$(Configuration)\Vsix\$(Platform)\
+ enable
+ enable
+ latest
+ true
+ true
+ true
+
+
+ true
+
+
+
+ false
+
+
+ $(MSBuildThisFileDirectory)
+
+
+ embedded
+
+ https://github.com/microsoft/json-document-transforms
+ Microsoft
+ Microsoft
+ ยฉ Microsoft Corporation. All rights reserved.
+ MIT
+ true
+ true
+ true
+ snupkg
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(RepositoryUrl)/releases/tag/v$(Version)
+
+
+
diff --git a/Directory.Build.rsp b/Directory.Build.rsp
new file mode 100644
index 00000000..9a833a03
--- /dev/null
+++ b/Directory.Build.rsp
@@ -0,0 +1,16 @@
+#------------------------------------------------------------------------------
+# This file contains command-line options that MSBuild will process as part of
+# every build, unless the "/noautoresponse" switch is specified.
+#
+# MSBuild processes the options in this file first, before processing the
+# options on the command line. As a result, options on the command line can
+# override the options in this file. However, depending on the options being
+# set, the overriding can also result in conflicts.
+#
+# NOTE: The "/noautoresponse" switch cannot be specified in this file, nor in
+# any response file that is referenced by this file.
+#------------------------------------------------------------------------------
+/nr:false
+/m
+/verbosity:minimal
+/clp:Summary;ForceNoAlign
diff --git a/Directory.Build.targets b/Directory.Build.targets
new file mode 100644
index 00000000..27b0fad1
--- /dev/null
+++ b/Directory.Build.targets
@@ -0,0 +1,13 @@
+
+
+
+ 13
+ 16.9
+
+
+
+
+
+
+
+
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 00000000..62383d30
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,26 @@
+
+
+
+
+ true
+ true
+ 2.0.171
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LICENSE b/LICENSE
index fdf12460..85c615ef 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,5 +1,5 @@
JSON Document Transforms
-
+
MIT License
Copyright (c) Microsoft Corporation. All rights reserved.
diff --git a/SECURITY.md b/SECURITY.md
index 869fdfe2..0dc4b6a7 100644
--- a/SECURITY.md
+++ b/SECURITY.md
@@ -1,20 +1,20 @@
-
+
## Security
Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin), and [our GitHub organizations](https://opensource.microsoft.com/).
-If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/opensource/security/definition), please report it to us as described below.
+If you believe you have found a security vulnerability in any Microsoft-owned 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.
## Reporting Security Issues
**Please do not report security vulnerabilities through public GitHub issues.**
-Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/opensource/security/create-report).
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report).
-If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/opensource/security/pgpkey).
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://www.microsoft.com/msrc/pgp-key-msrc).
-You should 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. Additional information can be found at [microsoft.com/msrc](https://aka.ms/opensource/security/msrc).
+You should 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. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
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:
@@ -28,7 +28,7 @@ Please include the requested information listed below (as much as you can provid
This information will help us triage your report more quickly.
-If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/opensource/security/bounty) page for more details about our active programs.
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://microsoft.com/msrc/bounty) page for more details about our active programs.
## Preferred Languages
@@ -36,6 +36,6 @@ We prefer all communications to be in English.
## Policy
-Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/opensource/security/cvd).
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/msrc/cvd).
diff --git a/SUPPORT.md b/SUPPORT.md
new file mode 100644
index 00000000..9bf7fd97
--- /dev/null
+++ b/SUPPORT.md
@@ -0,0 +1,13 @@
+# Support
+
+## How to file issues and get help
+
+This project uses GitHub Issues to track bugs and feature requests. Please search the existing
+issues before filing new issues to avoid duplicates. For new issues, file your bug or
+feature request as a new Issue.
+
+For help and questions about using this project, please create an issue.
+
+## Microsoft Support Policy
+
+Support for this **json-document-transforms** is limited to the resources listed above.
diff --git a/azure-pipelines.yml b/azure-pipelines.yml
index 549bf520..79f69c22 100644
--- a/azure-pipelines.yml
+++ b/azure-pipelines.yml
@@ -1,252 +1,34 @@
trigger:
+ batch: true
branches:
include:
- main
+ - microbuild
+ - 'validate/*'
paths:
exclude:
- - .github
- - doc
+ - doc/
- '*.md'
-schedules:
-- cron: "0 10 * * Sun"
- displayName: Weekly api-scan
- always: true
- branches:
- include:
- - main
+ - .vscode/
+ - .github/
+ - azure-pipelines/release.yml
+
parameters:
-- name: RunApiScanTools
- displayName: Run API Scan?
+- name: EnableMacOSBuild
+ displayName: Build on macOS
type: boolean
- default: false
-variables:
- NugetSecurityAnalysisWarningLevel: none
- ${{ if or(eq(parameters.RunApiScanTools, 'true'), eq(variables['Build.CronSchedule.DisplayName'], 'Weekly api-scan')) }}:
- RunAPIScan: true
- ${{ else }}:
- RunAPIScan: false
- Codeql.Enabled: true
- Codeql.TSAEnabled: true
- Codeql.TSAOptionsPath: $(Build.SourcesDirectory)\azure-pipelines\TSAOptions.json
+ default: false # macOS is often bogged down in Azure Pipelines
+- name: RunTests
+ displayName: Run tests
+ type: boolean
+ default: true
-resources:
- repositories:
- - repository: MicroBuildTemplate
- type: git
- name: 1ESPipelineTemplates/MicroBuildTemplate
- ref: refs/tags/release
+variables:
+- template: /azure-pipelines/BuildStageVariables.yml@self
-extends:
- template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
+jobs:
+- template: azure-pipelines/build.yml
parameters:
- sdl:
- sourceAnalysisPool:
- name: VSEngSS-MicroBuild2022-1ES
- image: server2022-microbuildVS2022-1es
-
- pool:
- name: VSEngSS-MicroBuild2022-1ES
- image: server2022-microbuildVS2022-1es
- os: windows
- customBuildTags:
- - ES365AIMigrationTooling
- stages:
- - stage: stage
- jobs:
- - job: job
- templateContext:
- mb:
- signing:
- enabled: true
- signType: $(SignType)
- zipSources: false
- feedSource: 'https://pkgs.dev.azure.com/devdiv/_packaging/MicroBuildToolset/nuget/v3/index.json' # Optional parameter: Artifact feed for outside DevDiv.
- azureSubscription: 'MicroBuild Signing Task (DevDiv)' # Optional parameter: Microbuild Service Connection.
- outputs:
- # - output: pipelineArtifact
- # displayName: 'Publish Artifact: ESRP signing logs'
- # condition: eq(variables['SignType'], 'real')
- # targetPath: $(Build.ArtifactStagingDirectory)/MicroBuild/ESRPClient
- # artifactName: esrpclient_logs
- # artifactType: Container
- - output: pipelineArtifact
- displayName: 'Publish Artifact: build logs'
- condition: succeededOrFailed()
- targetPath: $(Build.ArtifactStagingDirectory)/build_logs
- artifactName: build_logs
- artifactType: Container
- - output: pipelineArtifact
- displayName: 'Publish Artifact: symbols'
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- targetPath: '$(Build.ArtifactStagingDirectory)/symbols'
- artifactName: symbols
- publishLocation: Container
- - output: pipelineArtifact
- displayName: 'Publish packages'
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- targetPath: $(Build.ArtifactStagingDirectory)/packages
- artifactName: packages
- artifactType: Container
- - output: nuget
- displayName: 'Publish Sdk NuGet packages to VSTS feeds'
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- packageParentPath: '$(Build.ArtifactStagingDirectory)'
- searchPatternPush: 'bin/$(BuildConfiguration)/packages/*.nupkg'
- publishVstsFeed: $(feedGuid)
- allowPackageConflicts: true
- steps:
- - checkout: self
- fetchDepth: 0
- - task: ComponentGovernanceComponentDetection@0
- inputs:
- scanType: 'Register'
- verbosity: 'Verbose'
- alertWarningLevel: 'High'
- - task: PowerShell@2
- displayName: Set VSTS variables
- inputs:
- targetType: inline
- script: |
- if ($env:SignType -eq 'Real') {
- $feedGuid = '09d8d03c-1ac8-456e-9274-4d2364527d99' ## VSIDE-RealSigned-Release
- } else {
- $feedGuid = 'da484c78-f942-44ef-b197-99e2a1bef53c' ## VSIDE-TestSigned-Release
- }
- Write-Host "##vso[task.setvariable variable=feedGuid]$feedGuid"
- $SkipPublishingNetworkArtifacts = 'true' ## Network artifacts not allowed on Scale Set Pool
- Write-Host "##vso[task.setvariable variable=SkipPublishingNetworkArtifacts]$SkipPublishingNetworkArtifacts"
- if ($env:ComputerName.StartsWith('factoryvm', [StringComparison]::OrdinalIgnoreCase)) {
- Write-Host "Running on hosted queue"
- Write-Host "##vso[task.setvariable variable=Hosted]true"
- }
- - task: CmdLine@2
- inputs:
- script: |
- del /s /q "bin"
- displayName: Purge bin
- - task: NuGetToolInstaller@0
- displayName: Pin nuget.exe version
- inputs:
- versionSpec: 6.4.0
- - task: NuGetAuthenticate@1
- displayName: 'NuGet Authenticate'
- inputs:
- forceReinstallCredentialProvider: true
- - task: VSBuild@1
- inputs:
- vsVersion: 15.0
- solution: 'src\jdt.sln'
- msbuildArgs: /t:Restore
- platform: $(BuildPlatform)
- configuration: $(BuildConfiguration)
- displayName: Restore jdt solution
- - task: VSBuild@1
- inputs:
- vsVersion: 15.0
- solution: 'src\jdt.sln'
- msbuildArgs: '/bl:"$(Build.ArtifactStagingDirectory)/build_logs/jdt.binlog"'
- platform: $(BuildPlatform)
- configuration: $(BuildConfiguration)
- displayName: Build jdt solution
- - task: MicroBuildCodesignVerify@3
- inputs:
- TargetFolders: |
- $(Build.SourcesDirectory)\bin\$(BuildConfiguration)\packages
- ApprovalListPathForCerts: $(Build.SourcesDirectory)\src\build\no_authenticode.txt
- ApprovalListPathForSigs: $(Build.SourcesDirectory)\src\build\no_strongname.txt
- displayName: Verify code signing
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- - task: VSTest@2
- inputs:
- testFiltercriteria: TestCategory!=FailsInCloudTest
- searchFolder: $(System.DefaultWorkingDirectory)\bin\
- testAssemblyVer2: |
- $(BuildConfiguration)\**\net472\*test*.dll
- !**\obj\**
- platform: $(BuildPlatform)
- configuration: $(BuildConfiguration)
- diagnosticsEnabled: true
- displayName: Run Tests
- condition: and(succeeded(), ne(variables['SignType'], 'real'))
- - task: AntiMalware@4
- displayName: 'Run MpCmdRun.exe'
- inputs:
- InputType: Basic
- ScanType: CustomScan
- FileDirPath: '$(Build.StagingDirectory)'
- DisableRemediation: false
- - task: PoliCheck@2
- displayName: 'Run PoliCheck'
- inputs:
- targetType: F
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
- - task: ManifestGeneratorTask@0
- inputs:
- BuildDropPath: $(Build.ArtifactStagingDirectory)/build_logs
- - task: BinSkim@4
- displayName: Run BinSkim
- inputs:
- InputType: 'Basic'
- Function: 'analyze'
- TargetPattern: 'guardianGlob'
- AnalyzeTargetGlob: 'bin/$(BuildConfiguration)/net472/Microsoft.VisualStudio.Jdt*.dll;'
- - task: CopyFiles@2
- displayName: 'Copy Files for APIScan'
- inputs:
- SourceFolder: 'bin/$(BuildConfiguration)/net472/'
- Contents: |
- **/Microsoft.VisualStudio.Jdt*.dll
- **/Microsoft.VisualStudio.Jdt*.pdb
- TargetFolder: $(Agent.TempDirectory)\APIScanFiles
- condition: and(succeeded(), eq(variables['RunApiScan'], 'true'))
- - task: APIScan@2
- displayName: Run APIScan
- inputs:
- softwareFolder: $(Agent.TempDirectory)\APIScanFiles
- softwareName: 'json-document-transform'
- softwareVersionNum: '$(Build.BuildId)'
- isLargeApp: false
- toolVersion: 'Latest'
- condition: and(succeeded(), eq(variables['RunApiScan'], 'true'))
- env:
- AzureServicesAuthConnectionString: RunAs=App;AppId=$(ApiScanClientId)
- - task: PublishSecurityAnalysisLogs@3
- displayName: 'Publish Guardian Artifacts'
- inputs:
- ArtifactName: CodeAnalysisLogs
- ArtifactType: Container
- PublishProcessedResults: false
- AllTools: true
- - task: TSAUpload@2
- displayName: 'Create bugs for APIScan'
- inputs:
- GdnPublishTsaOnboard: true
- GdnPublishTsaConfigFile: '$(Build.SourcesDirectory)\azure-pipelines\TSAOptions.json'
- condition: eq(variables['RunApiScan'], 'true')
- - task: CopyFiles@1
- displayName: Collecting symbols artifacts
- inputs:
- SourceFolder: bin/$(BuildConfiguration)/net472
- Contents: |
- **/Microsoft.VisualStudio.Jdt?(*.dll|*.pdb|*.xml)
- !**/*Test*
- TargetFolder: $(Build.ArtifactStagingDirectory)/symbols
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
-
- - task: MicroBuildArchiveSymbols@5
- displayName: ๐ฃ Archive symbols to Symweb
- inputs:
- SymbolsFeatureName: $(SymbolsFeatureName)
- SymbolsProject: VS
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'), eq(variables['SignType'], 'real'))
-
-
- - task: CopyFiles@1
- displayName: Collecting packages
- inputs:
- SourceFolder: bin/$(BuildConfiguration)/packages
- Contents: |
- *.nupkg
- TargetFolder: $(Build.ArtifactStagingDirectory)/packages
- flattenFolders: false
- condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
\ No newline at end of file
+ Is1ESPT: false
+ EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }}
+ RunTests: ${{ parameters.RunTests }}
diff --git a/azure-pipelines/Archive-SourceCode.ps1 b/azure-pipelines/Archive-SourceCode.ps1
new file mode 100644
index 00000000..0360a14f
--- /dev/null
+++ b/azure-pipelines/Archive-SourceCode.ps1
@@ -0,0 +1,234 @@
+#Requires -PSEdition Core -Version 7
+<#
+.SYNOPSIS
+ Submits a source archival request for this repo.
+.PARAMETER Requester
+ The alias for the user requesting this backup.
+.PARAMETER ManagerAlias
+ The alias of the manager that owns the repo.
+.PARAMETER TeamAlias
+ The alias of the team that owns the repo.
+.PARAMETER BusinessGroupName
+ A human-readable title for your team or business group.
+.PARAMETER ProductionType
+.PARAMETER ReleaseType
+ The type of release being backed up.
+.PARAMETER ReleaseDate
+ The date of the release of your software. Defaults to today.
+.PARAMETER OwnerAlias
+ The alias of the owner.
+.PARAMETER OS
+.PARAMETER ProductLanguage
+ One or more languages.
+.PARAMETER Notes
+ Any notes to record with the backup.
+.PARAMETER FileCollection
+ One or more collections to archive.
+.PARAMETER ProductName
+ The name of the product. This will default to the repository name.
+.PARAMETER RepoUrl
+ The URL to the repository. This will default to the repository containing this script.
+.PARAMETER BackupType
+ The kind of backup to be performed.
+.PARAMETER ServerPath
+ The UNC path to the server to be backed up (if applicable).
+.PARAMETER SourceCodeArchivalUri
+ The URI to POST the source code archival request to.
+ This value will typically come automatically by a variable group associated with your pipeline.
+ You can also look it up at https://dpsopsrequestforms.azurewebsites.net/#/help -> SCA Request Help -> SCA API Help -> Description
+#>
+[CmdletBinding(SupportsShouldProcess = $true, PositionalBinding = $false)]
+param (
+ [Parameter()]
+ [string]$Requester,
+ [Parameter(Mandatory = $true)]
+ [string]$ManagerAlias,
+ [Parameter(Mandatory = $true)]
+ [string]$TeamAlias,
+ [Parameter(Mandatory = $true)]
+ [string]$BusinessGroupName,
+ [Parameter()]
+ [string]$ProductionType = 'Visual Studio',
+ [Parameter()]
+ [string]$ReleaseType = 'RTW',
+ [Parameter()]
+ [DateTime]$ReleaseDate = [DateTime]::Today,
+ [Parameter()]
+ [string]$OwnerAlias,
+ [Parameter()]
+ [ValidateSet('64-Bit Win', '32-Bit Win', 'Linux', 'Mac', '64-Bit ARM', '32-Bit ARM')]
+ [string[]]$OS = @('64-Bit Win'),
+ [Parameter(Mandatory = $true)]
+ [ValidateSet('English', 'Chinese Simplified', 'Chinese Traditional', 'Czech', 'French', 'German', 'Italian', 'Japanese', 'Korean', 'Polish', 'Portuguese', 'Russian', 'Spanish', 'Turkish')]
+ [string[]]$ProductLanguage,
+ [Parameter()]
+ [string]$Notes = '',
+ [Parameter()]
+ [ValidateSet('Binaries', 'Localization', 'Source Code')]
+ [string[]]$FileCollection = @('Source Code'),
+ [Parameter()]
+ [string]$ProductName,
+ [Parameter()]
+ [Uri]$RepoUrl,
+ [Parameter()]
+ [ValidateSet('Server Path', 'Code Repo(Git URL/AzureDevOps)', 'Git', 'Azure Storage Account')]
+ [string]$BackupType = 'Code Repo(Git URL/AzureDevOps)',
+ [Parameter()]
+ [string]$ServerPath = '',
+ [Parameter()]
+ [Uri]$SourceCodeArchivalUri = $env:SOURCECODEARCHIVALURI,
+ [Parameter(Mandatory = $true)]
+ [string]$AccessToken
+)
+
+function Invoke-Git() {
+ # Make sure we invoke git from within the repo.
+ Push-Location $PSScriptRoot
+ try {
+ return (git $args)
+ }
+ finally {
+ Pop-Location
+ }
+}
+
+if (!$ProductName) {
+ if ($env:BUILD_REPOSITORY_NAME) {
+ Write-Verbose 'Using $env:BUILD_REPOSITORY_NAME for ProductName.' # single quotes are intentional so user sees the name of env var.
+ $ProductName = $env:BUILD_REPOSITORY_NAME
+ }
+ else {
+ $originUrl = [Uri](Invoke-Git remote get-url origin)
+ if ($originUrl) {
+ $lastPathSegment = $originUrl.Segments[$originUrl.Segments.Length - 1]
+ if ($lastPathSegment.EndsWith('.git')) {
+ $lastPathSegment = $lastPathSegment.Substring(0, $lastPathSegment.Length - '.git'.Length)
+ }
+ Write-Verbose 'Using origin remote URL to derive ProductName.'
+ $ProductName = $lastPathSegment
+ }
+ }
+
+ if (!$ProductName) {
+ Write-Error "Unable to determine default value for -ProductName."
+ }
+}
+
+if (!$OwnerAlias) {
+ if ($env:BUILD_REQUESTEDFOREMAIL) {
+ Write-Verbose 'Using $env:BUILD_REQUESTEDFOREMAIL and slicing to just the alias for OwnerAlias.'
+ $OwnerAlias = ($env:BUILD_REQUESTEDFOREMAIL -split '@')[0]
+ } else {
+ $OwnerAlias = $TeamAlias
+ }
+
+ if (!$OwnerAlias) {
+ Write-Error "Unable to determine default value for -OwnerAlias."
+ }
+}
+
+if (!$Requester) {
+ if ($env:BUILD_REQUESTEDFOREMAIL) {
+ Write-Verbose 'Using $env:BUILD_REQUESTEDFOREMAIL and slicing to just the alias for Requester.'
+ $Requester = ($env:BUILD_REQUESTEDFOREMAIL -split '@')[0]
+ }
+ else {
+ Write-Verbose 'Using $env:USERNAME for Requester.'
+ $Requester = $env:USERNAME
+ }
+ if (!$Requester) {
+ $Requester = $OwnerAlias
+ }
+}
+
+if (!$RepoUrl) {
+ $RepoUrl = $env:BUILD_REPOSITORY_URI
+ if (!$RepoUrl) {
+ $originUrl = [Uri](Invoke-Git remote get-url origin)
+ if ($originUrl) {
+ Write-Verbose 'Using git origin remote url for GitURL.'
+ $RepoUrl = $originUrl
+ }
+
+ if (!$RepoUrl) {
+ Write-Error "Unable to determine default value for -RepoUrl."
+ }
+ }
+}
+
+Push-Location $PSScriptRoot
+$versionsObj = dotnet nbgv get-version -f json | ConvertFrom-Json
+Pop-Location
+
+$ReleaseDateString = $ReleaseDate.ToShortDateString()
+$Version = $versionsObj.Version
+
+$BackupSize = Get-ChildItem $PSScriptRoot\..\.git -Recurse -File | Measure-Object -Property Length -Sum
+$DataSizeMB = [int]($BackupSize.Sum / 1mb)
+$FileCount = $BackupSize.Count
+
+$Request = @{
+ "Requester" = $Requester
+ "Manager" = $ManagerAlias
+ "TeamAlias" = $TeamAlias
+ "AdditionalContacts" = $AdditionalContacts
+ "BusinessGroupName" = $BusinessGroupName
+ "ProductName" = $ProductName
+ "Version" = $Version
+ "ProductionType" = $ProductionType
+ "ReleaseType" = $ReleaseType
+ "ReleaseDateString" = $ReleaseDateString
+ "OS" = [string]::Join(',', $OS)
+ "ProductLanguage" = [string]::Join(',', $ProductLanguage)
+ "FileCollection" = [string]::Join(',', $FileCollection)
+ "OwnerAlias" = $OwnerAlias
+ "Notes" = $Notes.Trim()
+ "CustomerProvidedDataSizeMB" = $DataSizeMB
+ "CustomerProvidedFileCount" = $FileCount
+ "BackupType" = $BackupType
+ "ServerPath" = $ServerPath
+ "AzureStorageAccount" = $AzureStorageAccount
+ "AzureStorageContainer" = $AzureStorageContainer
+ "GitURL" = $RepoUrl
+}
+
+$RequestJson = ConvertTo-Json $Request
+Write-Host "SCA request:`n$RequestJson"
+
+if ($PSCmdlet.ShouldProcess('source archival request', 'post')) {
+ if (!$SourceCodeArchivalUri) {
+ Write-Error "Unable to post request without -SourceCodeArchivalUri parameter."
+ exit 1
+ }
+
+ $headers = @{
+ 'Authorization' = "Bearer $AccessToken"
+ }
+
+ [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
+
+ $Response = Invoke-WebRequest -Uri $SourceCodeArchivalUri -Method POST -Headers $headers -Body $RequestJson -ContentType "application/json" -UseBasicParsing -SkipHttpErrorCheck
+ Write-Host "Status Code : " -NoNewline
+ if ($Response.StatusCode -eq 200) {
+ Write-Host $Response.StatusCode -ForegroundColor Green
+ Write-Host "Ticket ID : " -NoNewline
+ $responseContent = ConvertFrom-Json ($Response.Content)
+ Write-Host $responseContent
+ }
+ else {
+ Write-Host $Response.StatusCode -ForegroundColor Red
+ try {
+ $responseContent = ConvertFrom-Json $Response.Content
+ Write-Host "Message : $($responseContent.message)"
+ }
+ catch {
+ Write-Host "JSON Parse Error: $($_.Exception.Message)"
+ Write-Host "Raw response content:"
+ Write-Host $Response.Content
+ }
+
+ exit 2
+ }
+} elseif ($SourceCodeArchivalUri) {
+ Write-Host "Would have posted to $SourceCodeArchivalUri"
+}
diff --git a/azure-pipelines/BuildStageVariables.yml b/azure-pipelines/BuildStageVariables.yml
new file mode 100644
index 00000000..2a683569
--- /dev/null
+++ b/azure-pipelines/BuildStageVariables.yml
@@ -0,0 +1,5 @@
+variables:
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ BuildConfiguration: Release
+ NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/
+ # codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/
diff --git a/azure-pipelines/Convert-PDB.ps1 b/azure-pipelines/Convert-PDB.ps1
new file mode 100644
index 00000000..f119a164
--- /dev/null
+++ b/azure-pipelines/Convert-PDB.ps1
@@ -0,0 +1,42 @@
+<#
+.SYNOPSIS
+ Converts between Windows PDB and Portable PDB formats.
+.PARAMETER DllPath
+ The path to the DLL whose PDB is to be converted.
+.PARAMETER PdbPath
+ The path to the PDB to convert. May be omitted if the DLL was compiled on this machine and the PDB is still at its original path.
+.PARAMETER OutputPath
+ The path of the output PDB to write.
+#>
+[CmdletBinding()]
+Param(
+ [Parameter(Mandatory=$true,Position=0)]
+ [string]$DllPath,
+ [Parameter()]
+ [string]$PdbPath,
+ [Parameter(Mandatory=$true,Position=1)]
+ [string]$OutputPath
+)
+
+if ($IsMacOS -or $IsLinux) {
+ Write-Error "This script only works on Windows"
+ return
+}
+
+$version = '1.1.0-beta2-21101-01'
+$baseDir = "$PSScriptRoot/../obj/tools"
+$pdb2pdbpath = "$baseDir/Microsoft.DiaSymReader.Pdb2Pdb.$version/tools/Pdb2Pdb.exe"
+if (-not (Test-Path $pdb2pdbpath)) {
+ if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null }
+ $baseDir = (Resolve-Path $baseDir).Path # Normalize it
+ Write-Verbose "& (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null"
+ & (& $PSScriptRoot/Get-NuGetTool.ps1) install Microsoft.DiaSymReader.Pdb2Pdb -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-tools/nuget/v3/index.json | Out-Null
+}
+
+$args = $DllPath,'/out',$OutputPath,'/nowarn','0021'
+if ($PdbPath) {
+ $args += '/pdb',$PdbPath
+}
+
+Write-Verbose "$pdb2pdbpath $args"
+& $pdb2pdbpath $args
diff --git a/azure-pipelines/Get-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-InsertionPRId.ps1 b/azure-pipelines/Get-InsertionPRId.ps1
new file mode 100644
index 00000000..62cb30cd
--- /dev/null
+++ b/azure-pipelines/Get-InsertionPRId.ps1
@@ -0,0 +1,26 @@
+<#
+.SYNOPSIS
+ Look up the pull request URL of the insertion PR.
+#>
+$stagingFolder = $env:BUILD_STAGINGDIRECTORY
+if (!$stagingFolder) {
+ $stagingFolder = $env:SYSTEM_DEFAULTWORKINGDIRECTORY
+ if (!$stagingFolder) {
+ Write-Error "This script must be run in an Azure Pipeline."
+ exit 1
+ }
+}
+$markdownFolder = Join-Path $stagingFolder (Join-Path 'MicroBuild' 'Output')
+$markdownFile = Join-Path $markdownFolder 'PullRequestUrl.md'
+if (!(Test-Path $markdownFile)) {
+ Write-Error "This script should be run after the MicroBuildInsertVsPayload task."
+ exit 2
+}
+
+$insertionPRUrl = Get-Content $markdownFile
+if (!($insertionPRUrl -match 'https:.+?/pullrequest/(\d+)')) {
+ Write-Error "Failed to parse pull request URL: $insertionPRUrl"
+ exit 3
+}
+
+$Matches[1]
diff --git a/azure-pipelines/Get-LibTemplateBasis.ps1 b/azure-pipelines/Get-LibTemplateBasis.ps1
new file mode 100644
index 00000000..2181c77b
--- /dev/null
+++ b/azure-pipelines/Get-LibTemplateBasis.ps1
@@ -0,0 +1,25 @@
+<#
+.SYNOPSIS
+ Returns the name of the well-known branch in the Library.Template repository upon which HEAD is based.
+#>
+[CmdletBinding(SupportsShouldProcess = $true)]
+Param(
+ [switch]$ErrorIfNotRelated
+)
+
+# This list should be sorted in order of decreasing specificity.
+$branchMarkers = @(
+ @{ commit = 'fd0a7b25ccf030bbd16880cca6efe009d5b1fffc'; branch = 'microbuild' };
+ @{ commit = '05f49ce799c1f9cc696d53eea89699d80f59f833'; branch = 'main' };
+)
+
+foreach ($entry in $branchMarkers) {
+ if (git rev-list HEAD | Select-String -Pattern $entry.commit) {
+ return $entry.branch
+ }
+}
+
+if ($ErrorIfNotRelated) {
+ Write-Error "Library.Template has not been previously merged with this repo. Please review https://github.com/AArnott/Library.Template/tree/main?tab=readme-ov-file#readme for instructions."
+ exit 1
+}
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..b5063cec
--- /dev/null
+++ b/azure-pipelines/Get-SymbolFiles.ps1
@@ -0,0 +1,66 @@
+<#
+.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.
+ $rootName = "$($_.Directory)/$($_.BaseName)"
+ if ($rootName.EndsWith('.ni')) {
+ $rootName = $rootName.Substring(0, $rootName.Length - 3)
+ }
+
+ $dllPath = "$rootName.dll"
+ $exePath = "$rootName.exe"
+ if (Test-Path $dllPath) {
+ $BinaryImagePath = $dllPath
+ } elseif (Test-Path $exePath) {
+ $BinaryImagePath = $exePath
+ } else {
+ Write-Warning "`"$_`" found with no matching binary file."
+ $BinaryImagePath = $null
+ }
+
+ if ($BinaryImagePath) {
+ Write-Output $BinaryImagePath
+ Write-Output $_.FullName
+ }
+}
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/GlobalVariables.yml b/azure-pipelines/GlobalVariables.yml
new file mode 100644
index 00000000..cee858b1
--- /dev/null
+++ b/azure-pipelines/GlobalVariables.yml
@@ -0,0 +1,6 @@
+variables:
+ # These variables are required for MicroBuild tasks
+ TeamName: VS IDE
+ TeamEmail: vsidemicrobuild@microsoft.com
+ # These variables influence insertion pipelines
+ ContainsVsix: false # This should be true when the repo builds a VSIX that should be inserted to VS.
diff --git a/azure-pipelines/Install-NuGetPackage.ps1 b/azure-pipelines/Install-NuGetPackage.ps1
new file mode 100644
index 00000000..9afde055
--- /dev/null
+++ b/azure-pipelines/Install-NuGetPackage.ps1
@@ -0,0 +1,55 @@
+<#
+.SYNOPSIS
+ Installs a NuGet package.
+.PARAMETER PackageID
+ The Package ID to install.
+.PARAMETER Version
+ The version of the package to install. If unspecified, the latest stable release is installed.
+.PARAMETER Source
+ The package source feed to find the package to install from.
+.PARAMETER PackagesDir
+ The directory to install the package to. By default, it uses the Packages folder at the root of the repo.
+.PARAMETER ConfigFile
+ The nuget.config file to use. By default, it uses :/nuget.config.
+.OUTPUTS
+ System.String. The path to the installed package.
+#>
+[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Low')]
+Param(
+ [Parameter(Position=1,Mandatory=$true)]
+ [string]$PackageId,
+ [Parameter()]
+ [string]$Version,
+ [Parameter()]
+ [string]$Source,
+ [Parameter()]
+ [switch]$Prerelease,
+ [Parameter()]
+ [string]$PackagesDir="$PSScriptRoot\..\packages",
+ [Parameter()]
+ [string]$ConfigFile="$PSScriptRoot\..\nuget.config",
+ [Parameter()]
+ [ValidateSet('Quiet','Normal','Detailed')]
+ [string]$Verbosity='normal'
+)
+
+$nugetPath = & "$PSScriptRoot\Get-NuGetTool.ps1"
+
+try {
+ Write-Verbose "Installing $PackageId..."
+ $nugetArgs = "Install",$PackageId,"-OutputDirectory",$PackagesDir,'-ConfigFile',$ConfigFile
+ if ($Version) { $nugetArgs += "-Version",$Version }
+ if ($Source) { $nugetArgs += "-FallbackSource",$Source }
+ if ($Prerelease) { $nugetArgs += "-Prerelease" }
+ $nugetArgs += '-Verbosity',$Verbosity
+
+ if ($PSCmdlet.ShouldProcess($PackageId, 'nuget install')) {
+ $p = Start-Process $nugetPath $nugetArgs -NoNewWindow -Wait -PassThru
+ if ($null -ne $p.ExitCode -and $p.ExitCode -ne 0) { throw }
+ }
+
+ # Provide the path to the installed package directory to our caller.
+ Write-Output (Get-ChildItem "$PackagesDir\$PackageId.*")[0].FullName
+} finally {
+ Pop-Location
+}
diff --git a/azure-pipelines/Merge-CodeCoverage.ps1 b/azure-pipelines/Merge-CodeCoverage.ps1
new file mode 100644
index 00000000..b126268c
--- /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 dotnet-coverage merge $Inputs -o $OutputFile -f cobertura
+ } else {
+ Write-Error "No reports found to merge."
+ }
+} finally {
+ Pop-Location
+}
diff --git a/azure-pipelines/NuGetSbom.targets b/azure-pipelines/NuGetSbom.targets
new file mode 100644
index 00000000..a2599e88
--- /dev/null
+++ b/azure-pipelines/NuGetSbom.targets
@@ -0,0 +1,12 @@
+
+
+ true
+ $(TargetsForTfmSpecificBuildOutput);IncludeSbomInNupkg
+
+
+
+
+
+
+
+
diff --git a/azure-pipelines/OptProf.yml b/azure-pipelines/OptProf.yml
new file mode 100644
index 00000000..4e309418
--- /dev/null
+++ b/azure-pipelines/OptProf.yml
@@ -0,0 +1,121 @@
+trigger: none
+pr: none
+schedules:
+- cron: "0 3 * * Fri" # Thu @ 8 or 9 PM Mountain Time (depending on DST)
+ displayName: Weekly OptProf run
+ branches:
+ include:
+ - 'v*.*'
+ - main
+ always: true # we must keep data fresh since optimizationdata drops are purged after 30 days
+
+# Avoid errant CI builds: https://developercommunity.visualstudio.com/content/problem/1154409/azure-pipeline-is-triggering-due-to-events-that-ne.html
+#resources:
+# repositories:
+# - repository: scripts
+# type: git
+# name: DeploymentScripts
+# ref: refs/heads/test
+
+parameters:
+ - name: ShouldSkipOptimize
+ displayName: Skip OptProf optimization
+ type: boolean
+ default: false # Should usually be false so that optprof LKG can apply when tests fail, but may need to be set to true in a manually queued pipeline run if all drops have expired.
+
+variables:
+- template: GlobalVariables.yml
+- name: PublicRelease
+ value: false # avoid using nice version since we're building a preliminary/unoptimized package
+- name: IsOptProf
+ value: true
+- name: MicroBuild_NuPkgSigningEnabled
+ value: false # test-signed nuget packages fail to restore in the VS insertion PR validations. Just don't sign them *at all*.
+
+stages:
+- stage: Library
+ variables:
+ - name: OptProf
+ value: true
+ - template: BuildStageVariables.yml
+ jobs:
+ - template: build.yml
+ parameters:
+ Is1ESPT: false
+ RealSign: false
+ windowsPool: VSEngSS-MicroBuild2022-1ES
+ EnableMacOSBuild: false
+ ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+ IsOptProf: true
+ RunTests: false
+ SkipCodesignVerify: true
+- stage: QueueVSBuild
+ jobs:
+ - job: QueueOptProf
+ pool: VSEngSS-MicroBuild2022-1ES
+ variables:
+ InsertPayloadName: LibraryName
+ InsertTopicBranch: team/VS-IDE/LibraryName-OptProf-run-$(Build.BuildId)
+ steps:
+ - checkout: none # We don't need source from our own repo
+ clean: true
+
+ # Pipeline YAML does not yet support checking out other repos. So we'll do it by hand.
+# - checkout: scripts # We DO need source from the DeploymentScripts repo
+# clean: true
+# path: $(Agent.TempDirectory)/DeploymentScripts
+# fetchDepth: 1
+ - script: 'git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" clone https://devdiv.visualstudio.com/DevDiv/_git/DeploymentScripts --depth 1 --branch test "$(Agent.TempDirectory)/DeploymentScripts"'
+ displayName: Download DeploymentScripts repo
+
+ - task: DownloadBuildArtifacts@0
+ displayName: Download insertion artifacts
+ inputs:
+ artifactName: VSInsertion-Windows
+ downloadPath: $(Agent.TempDirectory)
+ - task: DownloadBuildArtifacts@0
+ displayName: Download variables artifacts
+ inputs:
+ artifactName: Variables-Windows
+ downloadPath: $(Agent.TempDirectory)
+ - task: PowerShell@2
+ displayName: Set pipeline variables based on artifacts
+ inputs:
+ targetType: filePath
+ filePath: $(Agent.TempDirectory)/Variables-Windows/_pipelines.ps1
+ - task: NuGetCommand@2
+ displayName: Push VS-repo packages to VS feed
+ inputs:
+ command: push
+ packagesToPush: $(Agent.TempDirectory)/VSInsertion-Windows/*.nupkg
+ publishVstsFeed: 97a41293-2972-4f48-8c0e-05493ae82010 # VS feed
+ allowPackageConflicts: true
+ - task: MicroBuildInsertVsPayload@4
+ displayName: Insert VS Payload
+ inputs:
+ TeamName: $(TeamName)
+ TeamEmail: $(TeamEmail)
+ SkipCreatePR: true
+ CustomScriptExecutionCommand: src\VSSDK\NuGet\AllowUnstablePackages.ps1
+ - task: benjhuser.tfs-extensions-build-tasks.trigger-build-task.TriggerBuild@3
+ displayName: Trigger a new build of DD-CB-TestSignVS-devCI
+ inputs:
+ buildDefinition: DD-CB-TestSignVS-devCI
+ useSameBranch: false
+ branchToUse: $(InsertTopicBranch)
+ storeInEnvironmentVariable: true
+ queueBuildForUserThatTriggeredBuild: false
+ authenticationMethod: OAuth Token
+ password: $(System.AccessToken)
+ - task: PowerShell@2
+ displayName: Associate InsertionOutputs artifacts with CloudBuild
+ inputs:
+ targetType: filePath
+ filePath: $(Agent.TempDirectory)/DeploymentScripts/Scripts/Insertion/WriteArtifact.ps1
+ arguments: '-oldBuildID $(Build.BuildId) -newBuildID $(TriggeredBuildIds) -artifactName "InsertionOutputs" -accessToken $(System.AccessToken)'
+ - task: PowerShell@2
+ displayName: Tag the build with LibraryName-insertion
+ inputs:
+ targetType: filePath
+ filePath: $(Agent.TempDirectory)/DeploymentScripts/Scripts/Insertion/TagBuild.ps1
+ arguments: '-buildID $(TriggeredBuildIds) -tagName "LibraryName-insertion" -accessToken $(System.AccessToken)'
diff --git a/azure-pipelines/OptProf_part2.yml b/azure-pipelines/OptProf_part2.yml
new file mode 100644
index 00000000..c59d6999
--- /dev/null
+++ b/azure-pipelines/OptProf_part2.yml
@@ -0,0 +1,91 @@
+trigger: none
+pr: none
+
+resources:
+ pipelines:
+ - pipeline: VisualStudioBuildUnderTest
+ source: DD-CB-TestSignVS-devCI
+ trigger:
+ tags:
+ - LibraryName-insertion
+ - pipeline: DartLab
+ source: DartLab
+ branch: main
+ - pipeline: DartLab.OptProf
+ source: DartLab.OptProf
+ branch: main
+ tags:
+ - production
+ repositories:
+ - repository: DartLabTemplates
+ type: git
+ name: DartLab.Templates
+ ref: refs/heads/main
+ - repository: DartLabOptProfTemplates
+ type: git
+ name: DartLab.OptProf
+ ref: refs/tags/Production
+
+parameters:
+
+# The prefix naming of the OptimizationInputs drop
+- name: optimizationDropPrefix
+ type: string
+ default: OptimizationInputs/$(System.TeamProject)/$(Build.Repository.Name)
+
+stages:
+- template: \templates\stages\visual-studio\single-runsettings.yml@DartLabOptProfTemplates
+ parameters:
+ ##### Required #####
+ runSettingsURI: $(Pipeline.Workspace)\VisualStudioBuildUnderTest\BuildArtifacts\runsettings\LibraryName.OptProf.runsettings
+ visualStudioBootstrapperURI: https://vsdrop.corp.microsoft.com/file/v1/$(VisualStudio.BuildUnderTest.ProductsDropName);bootstrappers/Enterprise/vs_enterprise.exe
+ ##### Optional #####
+ name: OptProfProfilingWorkflow
+ displayName: OptProf Profiling Workflow
+ optOptimizationInputsDropName: $(OptimizationInputsDropName)
+ previousOptimizationInputsDropName: $(PreviousOptimizationInputsDropName)
+ testLabPoolName: VS-Platform
+ ##### Step Hooks #####
+ preTestMachineConfigurationStepList:
+ - download: VisualStudioBuildUnderTest
+ - task: PowerShell@2
+ name: SetProductsDropName
+ displayName: Set 'VisualStudio.BuildUnderTest.ProductsDropName'
+ inputs:
+ filePath: $(DartLab.Path)\Scripts\VisualStudio\Build\Get-VisualStudioDropName.ps1
+ arguments: -DropNamePrefix 'Products' -VstsDropUrlsJson '$(Pipeline.Workspace)\VisualStudioBuildUnderTest\BuildArtifacts\VstsDropUrls.json' -OutVariableName 'VisualStudio.BuildUnderTest.ProductsDropName'
+ preDeployAndRunTestsStepList:
+ - download: VisualStudioBuildUnderTest
+ prePublishOptimizationInputsDropStepList:
+ # Set parameter for PreviousOptimizationInputsDropName, MicroBuildCommitID, and OptimizationInputsDropName
+ - powershell: |
+ try {
+ $artifactName = 'InsertionOutputs'
+ $BuildID = $(resources.pipeline.VisualStudioBuildUnderTest.runID)
+ $artifact = Get-BuildArtifact -InstanceURL 'https://dev.azure.com/devdiv' -ProjectName 'DevDiv' -BuildID $BuildID -ArtifactName $artifactName -OAuthAccessToken (ConvertTo-SecureString '$(System.AccessToken)' -AsPlainText -Force)
+ $containerName = $artifact.Resource.Data -Split '/' | Select-Object -Last 1
+ $fileName = Join-Path $containerName 'Metadata.json'
+ $jsonString = Read-BuildArtifactFile -InstanceURL 'https://dev.azure.com/devdiv' -ProjectName 'DevDiv' -BuildID $BuildID -ArtifactName $artifactName -FileName $fileName -OAuthAccessToken (ConvertTo-SecureString '$(System.AccessToken)' -AsPlainText -Force)
+ $json = $jsonString | ConvertFrom-Json
+
+ Write-Host "The content of the metadata.json file was $json"
+
+ $dropname = $json.OptimizationData
+ $commitID = $json.CommitID
+ $OptimizationInputsDropName = "${{parameters.optimizationDropPrefix}}/$($commitID)/$(Build.BuildId)/$(System.StageId)/$(System.StageAttempt)"
+
+ Write-Host "PreviousOptimizationInputsDropName: $dropname"
+ Set-AzurePipelinesVariable 'PreviousOptimizationInputsDropName' $dropname
+
+ Write-Host "MicroBuildCommitID: $commitID"
+ Set-AzurePipelinesVariable 'MicroBuildCommitID' $commitID
+
+ Write-Host "OptimizationInputsDropName: $OptimizationInputsDropName"
+ Set-AzurePipelinesVariable 'OptimizationInputsDropName' $OptimizationInputsDropName
+ }
+ catch {
+ Write-Host $_
+ Write-Error "Failed to set OptimizationInputsDropName pipeline variable"
+ throw
+ }
+ displayName: Set MicroBuildCommitID, PreviousOptimizationInputsDropName, and OptimizationInputsDropName
diff --git a/azure-pipelines/PoliCheckExclusions.xml b/azure-pipelines/PoliCheckExclusions.xml
new file mode 100644
index 00000000..5ae16710
--- /dev/null
+++ b/azure-pipelines/PoliCheckExclusions.xml
@@ -0,0 +1,10 @@
+
+
+ NODE_MODULES|.STORE
+
+
+
+
+
+
+
diff --git a/azure-pipelines/PostPRMessage.ps1 b/azure-pipelines/PostPRMessage.ps1
new file mode 100644
index 00000000..4a2b7886
--- /dev/null
+++ b/azure-pipelines/PostPRMessage.ps1
@@ -0,0 +1,57 @@
+[CmdletBinding(SupportsShouldProcess = $true)]
+param(
+ [Parameter(Mandatory=$true)]
+ $AccessToken,
+ [Parameter(Mandatory=$true)]
+ $Markdown,
+ [ValidateSet('Active','ByDesign','Closed','Fixed','Pending','Unknown','WontFix')]
+ $CommentState='Active'
+)
+
+# See https://docs.microsoft.com/en-us/dotnet/api/microsoft.teamfoundation.sourcecontrol.webapi.commentthreadstatus?view=azure-devops-dotnet
+if ($CommentState -eq 'Active') {
+ $StatusCode = 1
+} elseif ($CommentState -eq 'ByDesign') {
+ $StatusCode = 5
+} elseif ($CommentState -eq 'Closed') {
+ $StatusCode = 4
+} elseif ($CommentState -eq 'Fixed') {
+ $StatusCode = 2
+} elseif ($CommentState -eq 'Pending') {
+ $StatusCode = 6
+} elseif ($CommentState -eq 'Unknown') {
+ $StatusCode = 0
+} elseif ($CommentState -eq 'WontFix') {
+ $StatusCode = 3
+}
+
+# Build the JSON body up
+$body = ConvertTo-Json @{
+ comments = @(@{
+ parentCommentId = 0
+ content = $Markdown
+ commentType = 1
+ })
+ status = $StatusCode
+}
+
+Write-Verbose "Posting JSON payload: `n$Body"
+
+# Post the message to the Pull Request
+# https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20threads?view=azure-devops-rest-5.1
+$url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/git/repositories/$($env:BUILD_REPOSITORY_NAME)/pullRequests/$($env:SYSTEM_PULLREQUEST_PULLREQUESTID)/threads?api-version=5.1"
+if ($PSCmdlet.ShouldProcess($url, 'Post comment via REST call')) {
+ try {
+ if (!$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI) {
+ Write-Error "Posting to the pull request requires that the script is running in an Azure Pipelines context."
+ exit 1
+ }
+ Write-Host "Posting PR comment to: $url"
+ Invoke-RestMethod -Uri $url -Method POST -Headers @{Authorization = "Bearer $AccessToken"} -Body $Body -ContentType application/json
+ }
+ catch {
+ Write-Error $_
+ Write-Error $_.Exception.Message
+ exit 2
+ }
+}
diff --git a/azure-pipelines/Prepare-Legacy-Symbols.ps1 b/azure-pipelines/Prepare-Legacy-Symbols.ps1
new file mode 100644
index 00000000..ae0bc40c
--- /dev/null
+++ b/azure-pipelines/Prepare-Legacy-Symbols.ps1
@@ -0,0 +1,35 @@
+Param(
+ [string]$Path
+)
+
+$ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1"
+$ArtifactStagingFolder += '/symbols-legacy'
+robocopy $Path $ArtifactStagingFolder /mir /njh /njs /ndl /nfl
+$WindowsPdbSubDirName = 'symstore'
+
+Get-ChildItem "$ArtifactStagingFolder\*.pdb" -Recurse |% {
+ $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) {
+ # Convert the PDB to legacy Windows PDBs
+ Write-Host "Converting PDB for $_" -ForegroundColor DarkGray
+ $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName"
+ if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null }
+ $legacyPdbPath = "$WindowsPdbDir\$($_.BaseName).pdb"
+ & "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath $legacyPdbPath
+ if ($LASTEXITCODE -ne 0) {
+ Write-Warning "PDB conversion of `"$_`" failed."
+ }
+
+ Move-Item $legacyPdbPath $_ -Force
+ }
+}
diff --git a/azure-pipelines/TSAOptions.json b/azure-pipelines/TSAOptions.json
index 854ce6c9..5e67a50d 100644
--- a/azure-pipelines/TSAOptions.json
+++ b/azure-pipelines/TSAOptions.json
@@ -16,4 +16,4 @@
"CodeQL"
],
"repositoryName": "json-document-transforms"
-}
\ No newline at end of file
+}
diff --git a/azure-pipelines/WIFtoPATauth.yml b/azure-pipelines/WIFtoPATauth.yml
new file mode 100644
index 00000000..cb78f61f
--- /dev/null
+++ b/azure-pipelines/WIFtoPATauth.yml
@@ -0,0 +1,22 @@
+parameters:
+- name: deadPATServiceConnectionId # The GUID of the PAT-based service connection whose access token must be replaced.
+ type: string
+- name: wifServiceConnectionName # The name of the WIF service connection to use to get the access token.
+ type: string
+- name: resource # The scope for which the access token is requested.
+ type: string
+ default: 499b84ac-1321-427f-aa17-267ca6975798 # Azure Artifact feeds (any of them)
+
+steps:
+- task: AzureCLI@2
+ displayName: ๐ Authenticate with WIF service connection
+ inputs:
+ azureSubscription: ${{ parameters.wifServiceConnectionName }}
+ scriptType: pscore
+ scriptLocation: inlineScript
+ inlineScript: |
+ $accessToken = az account get-access-token --query accessToken --resource '${{ parameters.resource }}' -o tsv
+ # Set the access token as a secret, so it doesn't get leaked in the logs
+ Write-Host "##vso[task.setsecret]$accessToken"
+ # Override the apitoken of the nuget service connection, for the duration of this stage
+ Write-Host "##vso[task.setendpoint id=${{ parameters.deadPATServiceConnectionId }};field=authParameter;key=apitoken]$accessToken"
diff --git a/azure-pipelines/apiscan.yml b/azure-pipelines/apiscan.yml
new file mode 100644
index 00000000..af78f15c
--- /dev/null
+++ b/azure-pipelines/apiscan.yml
@@ -0,0 +1,53 @@
+parameters:
+- name: windowsPool
+ type: object
+
+jobs:
+- job: apiscan
+ displayName: APIScan
+ dependsOn: Windows
+ pool: ${{ parameters.windowsPool }}
+ timeoutInMinutes: 120
+ templateContext:
+ outputs:
+ - output: pipelineArtifact
+ displayName: ๐ข collect apiscan artifact
+ targetPath: $(Pipeline.Workspace)/.gdn/.r/apiscan/001/Logs
+ artifactName: apiscan-logs
+ condition: succeededOrFailed()
+ variables:
+ - name: SymbolsFeatureName
+ value: $[ dependencies.Windows.outputs['SetPipelineVariables.SymbolsFeatureName'] ]
+ - name: NBGV_MajorMinorVersion
+ value: $[ dependencies.Windows.outputs['nbgv.NBGV_MajorMinorVersion'] ]
+ - ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
+ # https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/25351/APIScan-step-by-step-guide-to-setting-up-a-Pipeline
+ - group: VSEng sponsored APIScan # Expected to provide ApiScanClientId
+ steps:
+ # We need TSAOptions.json
+ - checkout: self
+ fetchDepth: 1
+
+ - download: current
+ artifact: APIScanInputs
+ displayName: ๐ป Download APIScanInputs artifact
+
+ - task: APIScan@2
+ displayName: ๐ Run APIScan
+ inputs:
+ softwareFolder: $(Pipeline.Workspace)/APIScanInputs
+ softwareName: $(SymbolsFeatureName)
+ softwareVersionNum: $(NBGV_MajorMinorVersion)
+ isLargeApp: false
+ toolVersion: Latest
+ preserveLogsFolder: true
+ env:
+ AzureServicesAuthConnectionString: runAs=App;AppId=$(ApiScanClientId)
+
+ # File bugs when APIScan finds issues
+ - task: TSAUpload@2
+ displayName: ๐ชณ TSA upload
+ inputs:
+ GdnPublishTsaOnboard: True
+ GdnPublishTsaConfigFile: $(Build.SourcesDirectory)\azure-pipelines\TSAOptions.json
+ condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main'))
diff --git a/azure-pipelines/archive-sourcecode.yml b/azure-pipelines/archive-sourcecode.yml
new file mode 100644
index 00000000..f5b4781e
--- /dev/null
+++ b/azure-pipelines/archive-sourcecode.yml
@@ -0,0 +1,88 @@
+trigger: none # We only want to trigger manually or based on resources
+pr: none
+
+# Source archival requirements come from a compliance tenet. Review a sample task here: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1550985
+# Source code should be archived within 30 days of the release date, and at least every quarter if your product is releasing more than once every 6 months.
+# If your sources on GitHub are public open source project, then using GitHub Public Archive is sufficient.
+schedules:
+- cron: "13 13 13 */3 *" # Every three months
+ displayName: Periodic source archival
+ branches:
+ include:
+ - main
+
+resources:
+ repositories:
+ - repository: MicroBuildTemplate
+ type: git
+ name: 1ESPipelineTemplates/MicroBuildTemplate
+ ref: refs/tags/release
+
+parameters:
+- name: notes
+ displayName: Notes to include in the SCA request
+ type: string
+ default: ' ' # optional parameters require a non-empty default.
+- name: whatif
+ displayName: Only simulate the request
+ type: boolean
+ default: false
+
+variables:
+- group: VS Core team # Expected to provide ManagerAlias, SourceCodeArchivalUri
+- template: GlobalVariables.yml
+
+extends:
+ template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
+ parameters:
+ sdl:
+ sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES
+
+ stages:
+ - stage: archive
+ jobs:
+ - job: archive
+ pool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+ os: Linux
+
+ steps:
+ - checkout: self
+ clean: true
+ fetchDepth: 0
+ - powershell: tools/Install-DotNetSdk.ps1
+ displayName: โ Install .NET SDK
+ - task: NuGetAuthenticate@1
+ displayName: ๐ Authenticate NuGet feeds
+ inputs:
+ forceReinstallCredentialProvider: true
+ - script: dotnet tool restore
+ displayName: โ๏ธ Restore CLI tools
+ - powershell: azure-pipelines/variables/_pipelines.ps1
+ failOnStderr: true
+ displayName: โ Set pipeline variables based on source
+ - task: AzureCLI@2
+ displayName: ๐ Authenticate with WIF service connection
+ inputs:
+ azureSubscription: VS Core Source Code Archival
+ scriptType: pscore
+ scriptLocation: inlineScript
+ inlineScript: |
+ $accessToken = az account get-access-token --query accessToken --resource api://177cf50a-4bf5-4481-8b7e-f32900dfc8e6 -o tsv
+ Write-Host "##vso[task.setvariable variable=scaToken;issecret=true]$accessToken"
+ - pwsh: >
+ $TeamAlias = '$(TeamEmail)'.Substring(0, '$(TeamEmail)'.IndexOf('@'))
+
+ azure-pipelines/Archive-SourceCode.ps1
+ -ManagerAlias '$(ManagerAlias)'
+ -TeamAlias $TeamAlias
+ -BusinessGroupName '$(BusinessGroupName)'
+ -ProductName '$(SymbolsFeatureName)'
+ -ProductLanguage English
+ -Notes '${{ parameters.notes }}'
+ -AccessToken '$(scaToken)'
+ -Verbose
+ -WhatIf:$${{ parameters.whatif }}
+ displayName: ๐๏ธ Submit archival request
diff --git a/azure-pipelines/artifacts/APIScanInputs.ps1 b/azure-pipelines/artifacts/APIScanInputs.ps1
new file mode 100644
index 00000000..b1550bfa
--- /dev/null
+++ b/azure-pipelines/artifacts/APIScanInputs.ps1
@@ -0,0 +1,22 @@
+$inputs = & "$PSScriptRoot/symbols.ps1"
+
+if (!$inputs) { return }
+
+# Filter out specific files that target OS's that are not subject to APIScan.
+# Files that are subject but are not supported must be scanned and an SEL exception filed.
+$outputs = @{}
+$forbiddenSubPaths = @(
+ , 'linux-*'
+ , 'osx*'
+)
+
+$inputs.GetEnumerator() | % {
+ $list = $_.Value | ? {
+ $path = $_.Replace('\', '/')
+ return !($forbiddenSubPaths | ? { $path -like "*/$_/*" })
+ }
+ $outputs[$_.Key] = $list
+}
+
+
+$outputs
diff --git a/azure-pipelines/artifacts/LocBin.ps1 b/azure-pipelines/artifacts/LocBin.ps1
new file mode 100644
index 00000000..3b6945f7
--- /dev/null
+++ b/azure-pipelines/artifacts/LocBin.ps1
@@ -0,0 +1,17 @@
+# Identify LCE files and the binary files they describe
+$BinRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin")
+if (!(Test-Path $BinRoot)) { return }
+
+$FilesToCopy = @()
+$FilesToCopy += Get-ChildItem -Recurse -File -Path $BinRoot |? { $_.FullName -match '\\Localize\\' }
+
+Get-ChildItem -rec "$BinRoot\*.lce" -File | % {
+ $FilesToCopy += $_
+ $FilesToCopy += $_.FullName.SubString(0, $_.FullName.Length - 4)
+}
+
+$FilesToCopy += Get-ChildItem -rec "$BinRoot\*.lcg" -File | % { [xml](Get-Content $_) } | % { $_.lcx.name }
+
+@{
+ "$BinRoot" = $FilesToCopy;
+}
diff --git a/azure-pipelines/artifacts/VSInsertion.ps1 b/azure-pipelines/artifacts/VSInsertion.ps1
new file mode 100644
index 00000000..ffc7e29a
--- /dev/null
+++ b/azure-pipelines/artifacts/VSInsertion.ps1
@@ -0,0 +1,41 @@
+# This artifact captures everything needed to insert into VS (NuGet packages, insertion metadata, etc.)
+
+[CmdletBinding()]
+Param (
+)
+
+if ($IsMacOS -or $IsLinux) {
+ # We only package up for insertions on Windows agents since they are where optprof can happen.
+ Write-Verbose "Skipping VSInsertion artifact since we're not on Windows."
+ return @{}
+}
+
+$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
+$BuildConfiguration = $env:BUILDCONFIGURATION
+if (!$BuildConfiguration) {
+ $BuildConfiguration = 'Debug'
+}
+
+$PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration"
+$NuGetPackages = "$PackagesRoot/NuGet"
+$VsixPackages = "$PackagesRoot/Vsix"
+
+if (!(Test-Path $NuGetPackages)) {
+ Write-Warning "Skipping because NuGet packages haven't been built yet."
+ return @{}
+}
+
+$result = @{
+ "$NuGetPackages" = (Get-ChildItem $NuGetPackages -Recurse)
+}
+
+if (Test-Path $VsixPackages) {
+ $result["$PackagesRoot"] += Get-ChildItem $VsixPackages -Recurse
+}
+
+if ($env:IsOptProf) {
+ $VSRepoPackages = "$PackagesRoot/VSRepo"
+ $result["$VSRepoPackages"] = (Get-ChildItem "$VSRepoPackages\*.VSInsertionMetadata.*.nupkg");
+}
+
+$result
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..47321ed5
--- /dev/null
+++ b/azure-pipelines/artifacts/_pipelines.ps1
@@ -0,0 +1,45 @@
+<#
+.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,
+ [switch]$AvoidSymbolicLinks
+)
+
+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 -AvoidSymbolicLinks:$AvoidSymbolicLinks |% {
+ # 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..74d7a38d
--- /dev/null
+++ b/azure-pipelines/artifacts/_stage_all.ps1
@@ -0,0 +1,72 @@
+<#
+.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,
+ [switch]$AvoidSymbolicLinks
+)
+
+$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
+ }
+
+ if ($LASTEXITCODE -ne 0) {
+ # Windows requires admin privileges to create symbolic links
+ # unless Developer Mode has been enabled.
+ throw "Failed to create symbolic link at $Link that points to $Target"
+ }
+}
+
+# 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
+ $TargetPath = Join-Path $DestinationFolder $Name
+ if ($AvoidSymbolicLinks) {
+ Copy-Item -Path $_.Source -Destination $TargetPath
+ } else {
+ Create-SymbolicLink -Link $TargetPath -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.ps1 b/azure-pipelines/artifacts/deployables.ps1
new file mode 100644
index 00000000..94c48cdd
--- /dev/null
+++ b/azure-pipelines/artifacts/deployables.ps1
@@ -0,0 +1,13 @@
+$RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..")
+$BuildConfiguration = $env:BUILDCONFIGURATION
+if (!$BuildConfiguration) {
+ $BuildConfiguration = 'Debug'
+}
+
+$PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration"
+
+if (!(Test-Path $PackagesRoot)) { return }
+
+@{
+ "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse)
+}
diff --git a/azure-pipelines/artifacts/projectAssetsJson.ps1 b/azure-pipelines/artifacts/projectAssetsJson.ps1
new file mode 100644
index 00000000..d2e85ffb
--- /dev/null
+++ b/azure-pipelines/artifacts/projectAssetsJson.ps1
@@ -0,0 +1,9 @@
+$ObjRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\obj")
+
+if (!(Test-Path $ObjRoot)) { return }
+
+@{
+ "$ObjRoot" = (
+ (Get-ChildItem "$ObjRoot\project.assets.json" -Recurse)
+ );
+}
diff --git a/azure-pipelines/artifacts/symbols.ps1 b/azure-pipelines/artifacts/symbols.ps1
new file mode 100644
index 00000000..9e2c7bd5
--- /dev/null
+++ b/azure-pipelines/artifacts/symbols.ps1
@@ -0,0 +1,7 @@
+$BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin")
+if (!(Test-Path $BinPath)) { return }
+$symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique
+
+@{
+ "$BinPath" = $SymbolFiles;
+}
diff --git a/azure-pipelines/artifacts/testResults.ps1 b/azure-pipelines/artifacts/testResults.ps1
new file mode 100644
index 00000000..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..375c422e
--- /dev/null
+++ b/azure-pipelines/build.yml
@@ -0,0 +1,307 @@
+parameters:
+##### The following parameters are not set by other YAML files that import this one,
+##### but we use parameters because they support rich types and defaults.
+##### Feel free to adjust their default value as needed.
+
+# Whether this repo uses OptProf to optimize the built binaries.
+# When enabling this, be sure to update these files:
+# - OptProf.targets: InstallationPath and match TestCase selection with what's in the VS repo.
+# - The project file(s) for the libraries to optimize must import OptProf.targets (for multi-targeted projects, only import it for ONE target).
+# - OptProf.yml: Search for LibraryName (or your library's name) and verify that those names are appropriate.
+# - OptProf_part2.yml: Search for LibraryName (or your library's name) and verify that those names are appropriate.
+# and create pipelines for OptProf.yml, OptProf_part2.yml
+- name: EnableOptProf
+ type: boolean
+ default: false
+# Whether this repo is localized.
+- name: EnableLocalization
+ type: boolean
+ default: false
+# Whether to run `dotnet format` as part of the build to ensure code style consistency.
+# This is just one of a a few mechanisms to enforce code style consistency.
+- name: EnableDotNetFormatCheck
+ type: boolean
+ default: false
+# This lists the names of the artifacts that will be published *from every OS build agent*.
+# Any new azure-pipelines/artifacts/*.ps1 script needs to be added to this list.
+# If an artifact is only generated or collected on one OS, it should NOT be listed here,
+# but should be manually added to the `outputs:` field in the appropriate OS job.
+- name: artifact_names
+ type: object
+ default:
+ - build_logs
+ - coverageResults
+ - deployables
+ - projectAssetsJson
+ - symbols
+ - testResults
+ - test_symbols
+ - Variables
+# The Enable*Build parameters turn non-Windows agents on or off.
+# Their default value should be based on whether the build and tests are expected/required to pass on that platform.
+# Callers (e.g. Official.yml) *may* expose these parameters at queue-time in order to turn OFF optional agents.
+- name: EnableLinuxBuild
+ type: boolean
+ default: false
+- name: EnableMacOSBuild
+ type: boolean
+ default: false
+
+##### ๐๐ผ You MAY change the defaults above.
+##### ๐๐ผ You should NOT change the defaults below.
+
+##### The following parameters are expected to be set by other YAML files that import this one.
+##### Those without defaults require explicit values to be provided by our importers.
+
+# Indicates whether the entrypoint file is 1ESPT compliant. Use this parameter to switch between publish tasks to fit 1ES or non-1ES needs.
+- name: Is1ESPT
+ type: boolean
+
+- name: RealSign
+ type: boolean
+ default: false
+
+# Whether this particular run is an OptProf profiling run.
+# This is used to skip unit tests and other non-essential work to improve reliability of the OptProf pipeline.
+- name: IsOptProf
+ type: boolean
+ default: false
+
+- name: RunTests
+ type: boolean
+ default: true
+
+# Whether this is a special one-off build for inserting into VS for a validation insertion PR (that will never be merged).
+- name: SkipCodesignVerify
+ type: boolean
+ default: false
+
+- name: EnableAPIScan
+ type: boolean
+ default: false
+
+# This parameter exists to provide a workaround to get a build out even when no OptProf profiling outputs can be found.
+# Entrypoint yaml files like official.yml should expose this as a queue-time setting when EnableOptProf is true in this file.
+# The OptProf.yml entrypoint sets this parameter to true so that collecting profile data isn't blocked by a prior lack of profile data.
+- name: ShouldSkipOptimize
+ type: boolean
+ default: false
+
+# The pool parameters are set to defaults that work in the azure-public AzDO account.
+# They are overridden by callers for the devdiv AzDO account to use 1ES compliant pools.
+- name: windowsPool
+ type: object
+ default:
+ vmImage: windows-2022
+- name: linuxPool
+ type: object
+ default:
+ vmImage: ubuntu-22.04
+- name: macOSPool
+ type: object
+ default:
+ vmImage: macOS-14
+
+jobs:
+- job: Windows
+ pool: ${{ parameters.windowsPool }}
+ timeoutInMinutes: 180 # Give plenty of time due to real signing
+ ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
+ templateContext:
+ mb:
+ signing:
+ enabled: true
+ zipSources: false
+ ${{ if parameters.RealSign }}:
+ signType: real
+ ${{ else }}:
+ signType: test
+ sbom:
+ enabled: true
+ localization:
+ enabled: ${{ parameters.EnableLocalization }}
+ ${{ if eq(variables['Build.Reason'], 'pullRequest') }}:
+ languages: ENU,JPN
+ optprof:
+ enabled: ${{ parameters.EnableOptProf }}
+ ProfilingInputsDropName: $(ProfilingInputsDropName)
+ OptimizationInputsLookupMethod: DropPrefix
+ DropNamePrefix: OptimizationInputs/$(System.TeamProject)/$(Build.Repository.Name)
+ ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+ AccessToken: $(System.AccessToken)
+ mbpresteps:
+ - checkout: self
+ fetchDepth: 0 # avoid shallow clone so nbgv can do its work.
+ clean: true
+ - ${{ if parameters.EnableOptProf }}:
+ - powershell: Write-Host "##vso[task.setvariable variable=PROFILINGINPUTSDROPNAME]$(azure-pipelines/variables/ProfilingInputsDropName.ps1)"
+ displayName: โ Set ProfilingInputsDropName for optprof
+
+ outputParentDirectory: $(Build.ArtifactStagingDirectory)
+ outputs:
+ - ${{ each artifact_name in parameters.artifact_names }}:
+ - ${{ if or(ne(artifact_name, 'testResults'), parameters.RunTests) }}:
+ - output: pipelineArtifact
+ displayName: ๐ข Publish ${{ artifact_name }}-Windows
+ targetPath: $(Build.ArtifactStagingDirectory)/${{ artifact_name }}-Windows
+ artifactName: ${{ artifact_name }}-Windows
+ condition: succeededOrFailed()
+ - output: pipelineArtifact
+ displayName: ๐ข Publish VSInsertion-Windows
+ targetPath: $(Build.ArtifactStagingDirectory)/VSInsertion-Windows
+ artifactName: VSInsertion-Windows
+ - ${{ if parameters.EnableLocalization }}:
+ - output: pipelineArtifact
+ displayName: ๐ข Publish LocBin-Windows
+ targetPath: $(Build.ArtifactStagingDirectory)/LocBin-Windows
+ artifactName: LocBin-Windows
+ - ${{ if parameters.EnableAPIScan }}:
+ - output: pipelineArtifact
+ displayName: ๐ข Publish APIScanInputs
+ targetPath: $(Build.ArtifactStagingDirectory)/APIScanInputs-Windows
+ artifactName: APIScanInputs
+ steps:
+ - ${{ if not(parameters.Is1ESPT) }}:
+ - checkout: self
+ fetchDepth: 0 # avoid shallow clone so nbgv can do its work.
+ clean: true
+ - ${{ if parameters.EnableOptProf }}:
+ - powershell: Write-Host "##vso[task.setvariable variable=PROFILINGINPUTSDROPNAME]$(azure-pipelines/variables/ProfilingInputsDropName.ps1)"
+ displayName: โ Set ProfilingInputsDropName for optprof
+
+ - ${{ if eq(variables['Build.Reason'], 'Schedule') }}:
+ - template: schedule-only-steps.yml
+
+ - template: install-dependencies.yml
+
+ - script: dotnet nbgv cloud -ca
+ displayName: โ Set build number
+ name: nbgv
+
+ - ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
+ - template: microbuild.before.yml
+ parameters:
+ EnableLocalization: ${{ parameters.EnableLocalization }}
+ EnableOptProf: ${{ parameters.EnableOptProf }}
+ IsOptProf: ${{ parameters.IsOptProf }}
+ ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+ RealSign: ${{ parameters.RealSign }}
+
+ - template: dotnet.yml
+ parameters:
+ Is1ESPT: ${{ parameters.Is1ESPT }}
+ RunTests: ${{ parameters.RunTests }}
+ IsOptProf: ${{ parameters.IsOptProf }}
+
+ - ${{ if and(parameters.EnableDotNetFormatCheck, not(parameters.EnableLinuxBuild)) }}:
+ - script: dotnet format --verify-no-changes --no-restore src
+ displayName: ๐
Verify formatted code
+
+ - ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
+ - template: microbuild.after.yml
+ parameters:
+ EnableOptProf: ${{ parameters.EnableOptProf }}
+ IsOptProf: ${{ parameters.IsOptProf }}
+ SkipCodesignVerify: ${{ parameters.SkipCodesignVerify }}
+
+- ${{ if not(parameters.IsOptProf) }}:
+ - ${{ if parameters.EnableLinuxBuild }}:
+ - job: Linux
+ pool: ${{ parameters.linuxPool }}
+ ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
+ templateContext:
+ mb:
+ ${{ if parameters.RealSign }}:
+ signing:
+ enabled: false # enable when building unique artifacts on this agent that must be signed
+ signType: real
+ outputParentDirectory: $(Build.ArtifactStagingDirectory)
+ outputs:
+ - ${{ each artifact_name in parameters.artifact_names }}:
+ - ${{ if or(ne(artifact_name, 'testResults'), parameters.RunTests) }}:
+ - output: pipelineArtifact
+ displayName: ๐ข Publish ${{ artifact_name }}-Linux
+ targetPath: $(Build.ArtifactStagingDirectory)/${{ artifact_name }}-Linux
+ artifactName: ${{ artifact_name }}-Linux
+ condition: succeededOrFailed()
+ steps:
+ - checkout: self
+ fetchDepth: 0 # avoid shallow clone so nbgv can do its work.
+ clean: true
+ - template: install-dependencies.yml
+ - template: dotnet.yml
+ parameters:
+ Is1ESPT: ${{ parameters.Is1ESPT }}
+ RunTests: ${{ parameters.RunTests }}
+ - ${{ if parameters.EnableDotNetFormatCheck }}:
+ - script: dotnet format --verify-no-changes --no-restore src
+ displayName: ๐
Verify formatted code
+
+ - ${{ if parameters.EnableMacOSBuild }}:
+ - job: macOS
+ pool: ${{ parameters.macOSPool }}
+ ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
+ templateContext:
+ mb:
+ ${{ if parameters.RealSign }}:
+ signing:
+ enabled: false # enable when building unique artifacts on this agent that must be signed
+ signType: real
+ outputParentDirectory: $(Build.ArtifactStagingDirectory)
+ outputs:
+ - ${{ each artifact_name in parameters.artifact_names }}:
+ - ${{ if or(ne(artifact_name, 'testResults'), parameters.RunTests) }}:
+ - output: pipelineArtifact
+ displayName: ๐ข Publish ${{ artifact_name }}-macOS
+ targetPath: $(Build.ArtifactStagingDirectory)/${{ artifact_name }}-macOS
+ artifactName: ${{ artifact_name }}-macOS
+ condition: succeededOrFailed()
+ steps:
+ - checkout: self
+ fetchDepth: 0 # avoid shallow clone so nbgv can do its work.
+ clean: true
+ - template: install-dependencies.yml
+ - template: dotnet.yml
+ parameters:
+ Is1ESPT: ${{ parameters.Is1ESPT }}
+ RunTests: ${{ parameters.RunTests }}
+
+ - job: WrapUp
+ dependsOn:
+ - Windows
+ - ${{ if parameters.EnableLinuxBuild }}:
+ - Linux
+ - ${{ if parameters.EnableMacOSBuild }}:
+ - macOS
+ pool: ${{ parameters.windowsPool }} # Use Windows agent because PublishSymbols task requires it (https://github.com/microsoft/azure-pipelines-tasks/issues/13821).
+ condition: succeededOrFailed()
+ ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}:
+ templateContext:
+ outputParentDirectory: $(Build.ArtifactStagingDirectory)
+ outputs:
+ - output: pipelineArtifact
+ displayName: ๐ข Publish symbols-legacy
+ targetPath: $(Build.ArtifactStagingDirectory)/symbols-legacy
+ artifactName: symbols-legacy
+ 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
+ - template: publish-symbols.yml
+ parameters:
+ EnableLinuxBuild: ${{ parameters.EnableLinuxBuild }}
+ EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }}
+ - ${{ if parameters.RunTests }}:
+ - template: publish-codecoverage.yml
+ parameters:
+ EnableLinuxBuild: ${{ parameters.EnableLinuxBuild }}
+ EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }}
+
+ - ${{ if parameters.EnableAPIScan }}:
+ - template: apiscan.yml
+ parameters:
+ windowsPool: ${{ parameters.windowsPool }}
diff --git a/azure-pipelines/dotnet-test-cloud.ps1 b/azure-pipelines/dotnet-test-cloud.ps1
new file mode 100644
index 00000000..56b019e9
--- /dev/null
+++ b/azure-pipelines/dotnet-test-cloud.ps1
@@ -0,0 +1,86 @@
+#!/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\test\Microsoft.VisualStudio.Jdt.Tests"`
+ --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..638170d1
--- /dev/null
+++ b/azure-pipelines/dotnet.yml
@@ -0,0 +1,46 @@
+parameters:
+- name: RunTests
+- name: IsOptProf
+ type: boolean
+ default: false
+- name: Is1ESPT
+ type: boolean
+
+steps:
+
+- script: dotnet build src -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog"
+ displayName: ๐ dotnet build
+
+- ${{ if not(parameters.IsOptProf) }}:
+ - powershell: azure-pipelines/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults
+ displayName: ๐งช dotnet test
+ condition: and(succeeded(), ${{ parameters.RunTests }})
+
+- ${{ if parameters.IsOptProf }}:
+ - script: dotnet pack src\VSInsertionMetadata -c $(BuildConfiguration) -warnaserror /bl:"$(Build.ArtifactStagingDirectory)/build_logs/VSInsertion-Pack.binlog"
+ displayName: ๐ง dotnet pack VSInsertionMetadata
+
+- powershell: azure-pipelines/variables/_pipelines.ps1
+ failOnStderr: true
+ displayName: โ Update pipeline variables based on build outputs
+ condition: succeededOrFailed()
+
+- ${{ if parameters.Is1ESPT }}:
+ - powershell: azure-pipelines/artifacts/_pipelines.ps1 -StageOnly -AvoidSymbolicLinks -ArtifactNameSuffix "-$(Agent.JobName)" -Verbose
+ failOnStderr: true
+ displayName: ๐ข Stage artifacts
+ condition: succeededOrFailed()
+- ${{ else }}:
+ - 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)"
+ displayName: ๐ข Publish code coverage results to codecov.io
+ timeoutInMinutes: 3
+ continueOnError: true
diff --git a/azure-pipelines/falsepositives.gdnsuppress b/azure-pipelines/falsepositives.gdnsuppress
new file mode 100644
index 00000000..1248172b
--- /dev/null
+++ b/azure-pipelines/falsepositives.gdnsuppress
@@ -0,0 +1,12 @@
+{
+ "version": "latest",
+ "suppressionSets": {
+ "falsepositives": {
+ "name": "falsepositives",
+ "createdDate": "2021-12-03 00:23:08Z",
+ "lastUpdatedDate": "2021-12-03 00:23:08Z"
+ }
+ },
+ "results": {
+ }
+}
diff --git a/azure-pipelines/install-dependencies.yml b/azure-pipelines/install-dependencies.yml
new file mode 100644
index 00000000..e5d58f41
--- /dev/null
+++ b/azure-pipelines/install-dependencies.yml
@@ -0,0 +1,36 @@
+parameters:
+- name: initArgs
+ type: string
+ default: ''
+- name: needsAzurePublicFeeds
+ type: boolean
+ default: true # If nuget.config pulls from the azure-public account, we need to authenticate when building on the devdiv account.
+
+steps:
+- ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}:
+ - template: WIFtoPATauth.yml
+ parameters:
+ wifServiceConnectionName: azure-public/vside package pull
+ deadPATServiceConnectionId: 0ae39abc-4d06-4436-a7b5-865833df49db # azure-public/msft_consumption
+
+- task: NuGetAuthenticate@1
+ displayName: ๐ Authenticate NuGet feeds
+ inputs:
+ ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}:
+ nuGetServiceConnections: azure-public/msft_consumption
+
+- 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/libtemplate-update.yml b/azure-pipelines/libtemplate-update.yml
new file mode 100644
index 00000000..a67a4ece
--- /dev/null
+++ b/azure-pipelines/libtemplate-update.yml
@@ -0,0 +1,168 @@
+# This pipeline schedules regular merges of Library.Template into a repo that is based on it.
+# Only Azure Repos are supported. GitHub support comes via a GitHub Actions workflow.
+
+trigger: none
+pr: none
+schedules:
+- cron: "0 3 * * Mon" # Sun @ 8 or 9 PM Mountain Time (depending on DST)
+ displayName: Weekly trigger
+ branches:
+ include:
+ - main
+ always: true
+
+resources:
+ repositories:
+ - repository: MicroBuildTemplate
+ type: git
+ name: 1ESPipelineTemplates/MicroBuildTemplate
+ ref: refs/tags/release
+
+parameters:
+- name: AutoComplete
+ displayName: Auto-complete pull request
+ type: boolean
+ default: false
+
+variables:
+- template: GlobalVariables.yml
+
+extends:
+ template: azure-pipelines/MicroBuild.1ES.Unofficial.yml@MicroBuildTemplate
+ parameters:
+ sdl:
+ sourceAnalysisPool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Windows2022
+
+ stages:
+ - stage: Merge
+ jobs:
+ - job: merge
+ pool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+ os: Linux
+ steps:
+ - checkout: self
+ fetchDepth: 0
+ clean: true
+ - pwsh: |
+ $LibTemplateBranch = & ./azure-pipelines/Get-LibTemplateBasis.ps1 -ErrorIfNotRelated
+ if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+ }
+
+ git fetch https://github.com/aarnott/Library.Template $LibTemplateBranch
+ if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+ }
+ $LibTemplateCommit = git rev-parse FETCH_HEAD
+
+ if ((git rev-list FETCH_HEAD ^HEAD --count) -eq 0) {
+ Write-Host "There are no Library.Template updates to merge."
+ exit 0
+ }
+
+ $UpdateBranchName = 'auto/libtemplateUpdate'
+ git -c http.extraheader="AUTHORIZATION: bearer $(System.AccessToken)" push origin -f FETCH_HEAD:refs/heads/$UpdateBranchName
+
+ Write-Host "Creating pull request"
+ $contentType = 'application/json';
+ $headers = @{ Authorization = 'Bearer $(System.AccessToken)' };
+ $rawRequest = @{
+ sourceRefName = "refs/heads/$UpdateBranchName";
+ targetRefName = "refs/heads/main";
+ title = 'Merge latest Library.Template';
+ description = "This merges the latest features and fixes from [Library.Template's $LibTemplateBranch branch](https://github.com/AArnott/Library.Template/tree/$LibTemplateBranch).";
+ }
+ $request = ConvertTo-Json $rawRequest
+
+ $prApiBaseUri = '$(System.TeamFoundationCollectionUri)/$(System.TeamProject)/_apis/git/repositories/$(Build.Repository.ID)/pullrequests'
+ $prCreationUri = $prApiBaseUri + "?api-version=6.0"
+ Write-Host "POST $prCreationUri"
+ Write-Host $request
+
+ $prCreationResult = Invoke-RestMethod -uri $prCreationUri -method POST -Headers $headers -ContentType $contentType -Body $request
+ $prUrl = "$($prCreationResult.repository.webUrl)/pullrequest/$($prCreationResult.pullRequestId)"
+ Write-Host "Pull request: $prUrl"
+ $prApiBaseUri += "/$($prCreationResult.pullRequestId)"
+
+ $SummaryPath = Join-Path '$(Agent.TempDirectory)' 'summary.md'
+ Set-Content -Path $SummaryPath -Value "[Insertion pull request]($prUrl)"
+ Write-Host "##vso[task.uploadsummary]$SummaryPath"
+
+ # Tag the PR
+ $tagUri = "$prApiBaseUri/labels?api-version=7.0"
+ $rawRequest = @{
+ name = 'auto-template-merge';
+ }
+ $request = ConvertTo-Json $rawRequest
+ Invoke-RestMethod -uri $tagUri -method POST -Headers $headers -ContentType $contentType -Body $request | Out-Null
+
+ # Add properties to the PR that we can programatically parse later.
+ Function Set-PRProperties($properties) {
+ $rawRequest = $properties.GetEnumerator() |% {
+ @{
+ op = 'add'
+ path = "/$($_.key)"
+ from = $null
+ value = $_.value
+ }
+ }
+ $request = ConvertTo-Json $rawRequest
+ $setPrPropertyUri = "$prApiBaseUri/properties?api-version=7.0"
+ Write-Debug "$request"
+ $setPrPropertyResult = Invoke-RestMethod -uri $setPrPropertyUri -method PATCH -Headers $headers -ContentType 'application/json-patch+json' -Body $request -StatusCodeVariable setPrPropertyStatus -SkipHttpErrorCheck
+ if ($setPrPropertyStatus -ne 200) {
+ Write-Host "##vso[task.logissue type=warning]Failed to set pull request properties. Result: $setPrPropertyStatus. $($setPrPropertyResult.message)"
+ }
+ }
+ Write-Host "Setting pull request properties"
+ Set-PRProperties @{
+ 'AutomatedMerge.SourceBranch' = $LibTemplateBranch
+ 'AutomatedMerge.SourceCommit' = $LibTemplateCommit
+ }
+
+ # Add an *active* PR comment to warn users to *merge* the pull request instead of squash it.
+ $request = ConvertTo-Json @{
+ comments = @(
+ @{
+ parentCommentId = 0
+ content = "Do **not** squash this pull request when completing it. You must *merge* it."
+ commentType = 'system'
+ }
+ )
+ status = 'active'
+ }
+ $result = Invoke-RestMethod -uri "$prApiBaseUri/threads?api-version=7.1" -method POST -Headers $headers -ContentType $contentType -Body $request -StatusCodeVariable addCommentStatus -SkipHttpErrorCheck
+ if ($addCommentStatus -ne 200) {
+ Write-Host "##vso[task.logissue type=warning]Failed to post comment on pull request. Result: $addCommentStatus. $($result.message)"
+ }
+
+ # Set auto-complete on the PR
+ if ('${{ parameters.AutoComplete }}' -eq 'True') {
+ Write-Host "Setting auto-complete"
+ $mergeMessage = "Merged PR $($prCreationResult.pullRequestId): " + $commitMessage
+ $rawRequest = @{
+ autoCompleteSetBy = @{
+ id = $prCreationResult.createdBy.id
+ };
+ completionOptions = @{
+ deleteSourceBranch = $true;
+ mergeCommitMessage = $mergeMessage;
+ mergeStrategy = 'noFastForward';
+ };
+ }
+ $request = ConvertTo-Json $rawRequest
+ Write-Host $request
+ $uri = "$($prApiBaseUri)?api-version=6.0"
+ $result = Invoke-RestMethod -uri $uri -method PATCH -Headers $headers -ContentType $contentType -Body $request -StatusCodeVariable autoCompleteStatus -SkipHttpErrorCheck
+ if ($autoCompleteStatus -ne 200) {
+ Write-Host "##vso[task.logissue type=warning]Failed to set auto-complete on pull request. Result: $autoCompleteStatus. $($result.message)"
+ }
+ }
+
+ displayName: Create pull request
diff --git a/azure-pipelines/microbuild.after.yml b/azure-pipelines/microbuild.after.yml
new file mode 100644
index 00000000..e2107433
--- /dev/null
+++ b/azure-pipelines/microbuild.after.yml
@@ -0,0 +1,38 @@
+parameters:
+- name: EnableOptProf
+ type: boolean
+ default: false
+- name: IsOptProf
+ type: boolean
+ default: false
+- name: SkipCodesignVerify
+ type: boolean
+
+steps:
+- ${{ if not(parameters.SkipCodesignVerify) }}: # skip CodesignVerify on validation builds because we don't even test-sign nupkg's.
+ - task: MicroBuildCodesignVerify@3
+ displayName: ๐ Verify Signed Files
+ inputs:
+ ApprovalListPathForSigs: $(Build.SourcesDirectory)\azure-pipelines\no_strongname.txt
+ ApprovalListPathForCerts: $(Build.SourcesDirectory)\azure-pipelines\no_authenticode.txt
+ TargetFolders: |
+ $(Build.SourcesDirectory)/bin/Packages/$(BuildConfiguration)
+ condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT'))
+
+- ${{ if parameters.IsOptProf }}:
+ - task: ms-vscs-artifact.build-tasks.artifactDropTask-1.artifactDropTask@0
+ inputs:
+ dropServiceURI: https://devdiv.artifacts.visualstudio.com
+ buildNumber: $(ProfilingInputsDropName)
+ sourcePath: $(Build.ArtifactStagingDirectory)\OptProf\ProfilingInputs
+ toLowerCase: false
+ usePat: true
+ displayName: ๐ข Publish to Artifact Services - ProfilingInputs
+ condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest'))
+
+ - task: PublishBuildArtifacts@1
+ inputs:
+ PathtoPublish: $(Build.ArtifactStagingDirectory)/InsertionOutputs
+ ArtifactName: InsertionOutputs
+ ArtifactType: Container
+ displayName: ๐ข Publish InsertionOutputs as Azure DevOps artifacts
diff --git a/azure-pipelines/microbuild.before.yml b/azure-pipelines/microbuild.before.yml
new file mode 100644
index 00000000..05acd319
--- /dev/null
+++ b/azure-pipelines/microbuild.before.yml
@@ -0,0 +1,53 @@
+parameters:
+- name: EnableLocalization
+ type: boolean
+ default: false
+- name: EnableOptProf
+ type: boolean
+ default: false
+- name: IsOptProf
+ type: boolean
+ default: false
+- name: ShouldSkipOptimize
+ type: boolean
+ default: false
+- name: RealSign
+ type: boolean
+
+steps:
+- ${{ if and(not(parameters.IsOptProf), ne(variables['Build.Reason'], 'PullRequest')) }}:
+ # notice@0 requires CG detection to run first, and non-default branches don't inject it automatically.
+ - ${{ if ne(variables['Build.SourceBranch'], 'refs/heads/main') }}:
+ - task: ComponentGovernanceComponentDetection@0
+ displayName: ๐ Component Detection
+
+ - task: notice@0
+ displayName: ๐ ๏ธ Generate NOTICE file
+ inputs:
+ outputfile: $(System.DefaultWorkingDirectory)/obj/NOTICE
+ outputformat: text
+ retryCountOnTaskFailure: 3 # fails when the cloud service is overloaded
+ continueOnError: ${{ not(parameters.RealSign) }} # Tolerate failures when we're not building something that may ship.
+
+- ${{ if parameters.IsOptProf }}:
+ # We have to install these plugins ourselves for Optprof runs because those pipelines haven't migrated to 1ES PT yet.
+ - task: MicroBuildOptProfPlugin@6
+ inputs:
+ ProfilingInputsDropName: $(ProfilingInputsDropName)
+ OptimizationInputsLookupMethod: DropPrefix
+ DropNamePrefix: OptimizationInputs/$(System.TeamProject)/$(Build.Repository.Name)
+ ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+ AccessToken: $(System.AccessToken)
+ displayName: ๐ง Install OptProf Plugin
+
+ - task: MicroBuildSigningPlugin@4
+ inputs:
+ signType: Real
+ zipSources: false
+ displayName: ๐ง Install MicroBuild Signing Plugin
+
+ - ${{ if parameters.EnableLocalization }}:
+ - task: MicroBuildLocalizationPlugin@4
+ inputs:
+ languages: $(LocLanguages)
+ displayName: ๐ง Install MicroBuild Localization Plugin
diff --git a/azure-pipelines/no_authenticode.txt b/azure-pipelines/no_authenticode.txt
new file mode 100644
index 00000000..262625ac
--- /dev/null
+++ b/azure-pipelines/no_authenticode.txt
@@ -0,0 +1,2 @@
+bin\packages\release\vsix\_manifest\manifest.cat,sbom signed
+bin\packages\release\vsix\_manifest\spdx_2.2\manifest.cat,sbom signed
diff --git a/azure-pipelines/no_strongname.txt b/azure-pipelines/no_strongname.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/azure-pipelines/official.yml b/azure-pipelines/official.yml
new file mode 100644
index 00000000..e01575fa
--- /dev/null
+++ b/azure-pipelines/official.yml
@@ -0,0 +1,129 @@
+trigger:
+ batch: true
+ branches:
+ include:
+ - main
+ - microbuild
+ - 'validate/*'
+ paths:
+ exclude:
+ - doc/
+ - '*.md'
+ - .vscode/
+ - azure-pipelines/release.yml
+ - azure-pipelines/vs-insertion.yml
+#schedules:
+#- cron: "0 3 * * *" # Daily @ 8 PM PST
+# displayName: Daily vs-insertion
+# branches:
+# include:
+# - microbuild
+
+parameters:
+# As an entrypoint pipeline yml file, all parameters here show up in the Queue Run dialog.
+# If any paramaters should NOT be queue-time options, they should be removed from here
+# and references to them in this file replaced with hard-coded values.
+- name: ForceOfficialBuild
+ displayName: Official build (sign, compliance, etc.)
+ type: boolean
+ default: false # this should remain false so PR builds using this pipeline are unofficial
+# - name: ShouldSkipOptimize # Uncomment this and references to it below when setting EnableOptProf to true in build.yml.
+# displayName: Skip OptProf optimization
+# type: boolean
+# default: false
+- name: EnableMacOSBuild
+ displayName: Build on macOS
+ type: boolean
+ default: false # macOS is often bogged down in Azure Pipelines
+- name: RunTests
+ displayName: Run tests
+ type: boolean
+ default: true
+- name: EnableAPIScan
+ displayName: Include APIScan with compliance tools
+ type: boolean
+ default: false # enable in individual repos only AFTER updating TSAOptions.json with your own values
+
+resources:
+ repositories:
+ - repository: MicroBuildTemplate
+ type: git
+ name: 1ESPipelineTemplates/MicroBuildTemplate
+ ref: refs/tags/release
+
+variables:
+- template: GlobalVariables.yml
+
+extends:
+ ${{ if or(parameters.ForceOfficialBuild, eq(variables['Build.Reason'],'Schedule')) }}:
+ template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
+ parameters:
+ sdl:
+ sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES
+ codeSignValidation:
+ enabled: true
+ break: true
+ additionalTargetsGlobPattern: -|Variables-*\*.ps1;-|APIScanInputs-*\**;-|test_symbols-*\**;-|MicroBuild\**
+ policheck:
+ enabled: true
+ exclusionsFile: $(System.DefaultWorkingDirectory)\azure-pipelines\PoliCheckExclusions.xml
+ suppression:
+ suppressionFile: $(System.DefaultWorkingDirectory)\azure-pipelines\falsepositives.gdnsuppress
+ sbom:
+ enabled: true
+ stages:
+ - stage: Build
+ variables:
+ - template: /azure-pipelines/BuildStageVariables.yml@self
+ jobs:
+ - template: /azure-pipelines/build.yml@self
+ parameters:
+ Is1ESPT: true
+ RealSign: true
+ # ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+ EnableAPIScan: ${{ and(parameters.EnableAPIScan, ne(variables['Build.Reason'], 'pullRequest')) }}
+ windowsPool: VSEngSS-MicroBuild2022-1ES
+ linuxPool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+ os: Linux
+ macOSPool:
+ name: Azure Pipelines
+ vmImage: macOS-12
+ os: macOS
+ EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }}
+ RunTests: ${{ parameters.RunTests }}
+ - template: /azure-pipelines/prepare-insertion-stages.yml@self
+ parameters:
+ RealSign: true
+ ${{ else }}:
+ template: azure-pipelines/MicroBuild.1ES.Unofficial.yml@MicroBuildTemplate
+ parameters:
+ sdl:
+ sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES
+ suppression:
+ suppressionFile: $(System.DefaultWorkingDirectory)\azure-pipelines\falsepositives.gdnsuppress
+ stages:
+ - stage: Build
+ variables:
+ - template: /azure-pipelines/BuildStageVariables.yml@self
+ jobs:
+ - template: /azure-pipelines/build.yml@self
+ parameters:
+ Is1ESPT: true
+ RealSign: false
+ # ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }}
+ EnableAPIScan: false
+ windowsPool: VSEngSS-MicroBuild2022-1ES
+ linuxPool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+ os: Linux
+ macOSPool:
+ name: Azure Pipelines
+ vmImage: macOS-12
+ os: macOS
+ EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }}
+ RunTests: ${{ parameters.RunTests }}
diff --git a/azure-pipelines/prepare-insertion-stages.yml b/azure-pipelines/prepare-insertion-stages.yml
new file mode 100644
index 00000000..e838b424
--- /dev/null
+++ b/azure-pipelines/prepare-insertion-stages.yml
@@ -0,0 +1,78 @@
+parameters:
+- name: ArchiveSymbols
+ type: boolean
+ default: true
+- name: RealSign
+ displayName: Real sign?
+ type: boolean
+- name: PackagePush
+ type: boolean
+ default: false # Switch to true to enable the push job below
+
+stages:
+- ${{ if or(parameters.ArchiveSymbols, parameters.PackagePush) }}:
+ - stage: release
+ displayName: Publish
+ jobs:
+ - ${{ if parameters.ArchiveSymbols }}:
+ - job: symbol_archive
+ displayName: Archive symbols
+ pool: VSEngSS-MicroBuild2022-1ES
+ steps:
+ - checkout: none
+ - download: current
+ artifact: Variables-Windows
+ displayName: ๐ป Download Variables-Windows artifact
+ - powershell: $(Pipeline.Workspace)/Variables-Windows/_pipelines.ps1
+ displayName: โ๏ธ Set pipeline variables based on artifacts
+ - download: current
+ artifact: symbols-legacy
+ displayName: ๐ป Download symbols-legacy artifact
+ - task: MicroBuildArchiveSymbols@5
+ displayName: ๐ฃ Archive symbols to Symweb
+ inputs:
+ SymbolsFeatureName: $(SymbolsFeatureName)
+ SymbolsProject: VS
+ SymbolsAgentPath: $(Pipeline.Workspace)/symbols-legacy
+
+ - ${{ if parameters.PackagePush }}:
+ - job: push
+ ${{ if parameters.RealSign }}:
+ displayName: azure-public/vs-impl feed
+ ${{ else }}:
+ displayName: devdiv/vs-impl feed # Leave this as-is, since non-signed builds must not be pushed to public feeds.
+ ${{ if parameters.ArchiveSymbols }}:
+ dependsOn: symbol_archive
+ pool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+ os: Linux
+ templateContext:
+ outputs:
+ - output: nuget
+ displayName: ๐ฆ Push nuget packages
+ packagesToPush: '$(Pipeline.Workspace)/deployables-Windows/NuGet/*.nupkg'
+ packageParentPath: $(Pipeline.Workspace)/deployables-Windows/NuGet
+ allowPackageConflicts: true
+ ${{ if parameters.RealSign }}:
+ nuGetFeedType: external
+ publishFeedCredentials: azure-public/vs-impl
+ ${{ else }}:
+ nuGetFeedType: internal
+ publishVstsFeed: vs-impl # Leave this as-is, since non-signed builds must not be pushed to public feeds.
+ steps:
+ - checkout: none
+ - download: current
+ artifact: Variables-Windows
+ displayName: ๐ป Download Variables-Windows artifact
+ - powershell: $(Pipeline.Workspace)/Variables-Windows/_pipelines.ps1
+ displayName: โ๏ธ Set pipeline variables based on artifacts
+ - download: current
+ artifact: deployables-Windows
+ displayName: ๐ป Download deployables-Windows artifact
+ - ${{ if parameters.RealSign }}:
+ - template: WIFtoPATauth.yml
+ parameters:
+ wifServiceConnectionName: azure-public/vside package push
+ deadPATServiceConnectionId: 207efd62-fd0f-43e7-aeae-17c4febcc660 # azure-public/vs-impl
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..987b2fe2
--- /dev/null
+++ b/azure-pipelines/publish-codecoverage.yml
@@ -0,0 +1,28 @@
+parameters:
+- name: EnableMacOSBuild
+ type: boolean
+- name: EnableLinuxBuild
+ type: boolean
+
+steps:
+- download: current
+ artifact: coverageResults-Windows
+ displayName: ๐ป Download Windows code coverage results
+ continueOnError: true
+- ${{ if parameters.EnableLinuxBuild }}:
+ - download: current
+ artifact: coverageResults-Linux
+ displayName: ๐ป Download Linux code coverage results
+ continueOnError: true
+- ${{ if parameters.EnableMacOSBuild }}:
+ - download: current
+ artifact: coverageResults-macOS
+ displayName: ๐ป Download macOS 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@2
+ displayName: ๐ข Publish code coverage results to Azure DevOps
+ inputs:
+ summaryFileLocation: coveragereport/merged.cobertura.xml
+ failIfCoverageEmpty: true
diff --git a/azure-pipelines/publish-symbols.yml b/azure-pipelines/publish-symbols.yml
new file mode 100644
index 00000000..9078ea25
--- /dev/null
+++ b/azure-pipelines/publish-symbols.yml
@@ -0,0 +1,67 @@
+parameters:
+- name: EnableMacOSBuild
+ type: boolean
+- name: EnableLinuxBuild
+ type: boolean
+
+steps:
+- task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: symbols-Windows
+ path: $(Pipeline.Workspace)/symbols/Windows
+ displayName: ๐ป Download Windows symbols
+ continueOnError: true
+- ${{ if parameters.EnableLinuxBuild }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: symbols-Linux
+ path: $(Pipeline.Workspace)/symbols/Linux
+ displayName: ๐ป Download Linux symbols
+ continueOnError: true
+- ${{ if parameters.EnableMacOSBuild }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: symbols-macOS
+ path: $(Pipeline.Workspace)/symbols/macOS
+ displayName: ๐ป Download macOS symbols
+ continueOnError: true
+
+- task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: test_symbols-Windows
+ path: $(Pipeline.Workspace)/test_symbols/Windows
+ displayName: ๐ป Download Windows test symbols
+ continueOnError: true
+- ${{ if parameters.EnableLinuxBuild }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: test_symbols-Linux
+ path: $(Pipeline.Workspace)/test_symbols/Linux
+ displayName: ๐ป Download Linux test symbols
+ continueOnError: true
+- ${{ if parameters.EnableMacOSBuild }}:
+ - task: DownloadPipelineArtifact@2
+ inputs:
+ artifact: test_symbols-macOS
+ path: $(Pipeline.Workspace)/test_symbols/macOS
+ displayName: ๐ป Download macOS test symbols
+ continueOnError: true
+
+- task: PublishSymbols@2
+ inputs:
+ SymbolsFolder: $(Pipeline.Workspace)/symbols
+ SearchPattern: '**/*.pdb'
+ IndexSources: false
+ SymbolServerType: TeamServices
+ displayName: ๐ข Publish symbols
+
+- task: PublishSymbols@2
+ inputs:
+ SymbolsFolder: $(Pipeline.Workspace)/test_symbols
+ SearchPattern: '**/*.pdb'
+ IndexSources: false
+ SymbolServerType: TeamServices
+ displayName: ๐ข Publish test symbols
+
+- powershell: azure-pipelines/Prepare-Legacy-Symbols.ps1 -Path $(Pipeline.Workspace)/symbols/Windows
+ displayName: โ Prepare symbols for symbol archival
diff --git a/azure-pipelines/release-deployment-prep.yml b/azure-pipelines/release-deployment-prep.yml
new file mode 100644
index 00000000..d9a9ffd3
--- /dev/null
+++ b/azure-pipelines/release-deployment-prep.yml
@@ -0,0 +1,6 @@
+steps:
+- download: CI
+ artifact: Variables-Windows
+ displayName: ๐ป Download Variables-Windows artifact
+- powershell: $(Pipeline.Workspace)/CI/Variables-Windows/_pipelines.ps1
+ displayName: โ๏ธ Set pipeline variables based on artifacts
diff --git a/azure-pipelines/release.yml b/azure-pipelines/release.yml
new file mode 100644
index 00000000..673934c8
--- /dev/null
+++ b/azure-pipelines/release.yml
@@ -0,0 +1,77 @@
+trigger: none # We only want to trigger manually or based on resources
+pr: none
+
+resources:
+ repositories:
+ - repository: MicroBuildTemplate
+ type: git
+ name: 1ESPipelineTemplates/MicroBuildTemplate
+ ref: refs/tags/release
+ pipelines:
+ - pipeline: CI
+ source: json-document-transforms-ci # TODO: This should match the name of your CI pipeline
+ trigger:
+ tags:
+ - auto-release
+
+variables:
+- template: GlobalVariables.yml
+
+extends:
+ template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
+ parameters:
+ sdl:
+ sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES
+
+ stages:
+ - stage: release
+ jobs:
+ - job: release
+ pool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+ os: Linux
+ templateContext:
+ outputs:
+ - output: nuget
+ displayName: ๐ฆ Push packages to nuget.org
+ packagesToPush: '$(Pipeline.Workspace)/CI/deployables-Windows/NuGet/*.nupkg'
+ packageParentPath: $(Pipeline.Workspace)/CI/deployables-Windows/NuGet
+ allowPackageConflicts: true
+ nuGetFeedType: external
+ publishFeedCredentials: VisualStudioExtensibility (nuget.org)
+ 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
+ - download: CI
+ artifact: deployables-Windows
+ displayName: ๐ป Download deployables-Windows artifact
+ patterns: 'NuGet/*'
+ - task: GitHubRelease@1
+ displayName: ๐ข GitHub release (create)
+ inputs:
+ gitHubConnection: ttstanley # TODO: fill in service connection here
+ repositoryName: $(Build.Repository.Name)
+ target: $(resources.pipeline.CI.sourceCommit)
+ tagSource: userSpecifiedTag
+ tag: v$(resources.pipeline.CI.runName)
+ title: v$(resources.pipeline.CI.runName)
+ isDraft: true # After running this step, visit the new draft release, edit, and publish.
+ isPreRelease: $(IsPrerelease)
+ assets: $(Pipeline.Workspace)/CI/deployables-Windows/NuGet/*.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" }
+ ]
diff --git a/azure-pipelines/schedule-only-steps.yml b/azure-pipelines/schedule-only-steps.yml
new file mode 100644
index 00000000..ad07a341
--- /dev/null
+++ b/azure-pipelines/schedule-only-steps.yml
@@ -0,0 +1,3 @@
+steps:
+- powershell: echo "##vso[build.addbuildtag]auto-insertion"
+ displayName: Tag for auto-insertion
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/BusinessGroupName.ps1 b/azure-pipelines/variables/BusinessGroupName.ps1
new file mode 100644
index 00000000..00824266
--- /dev/null
+++ b/azure-pipelines/variables/BusinessGroupName.ps1
@@ -0,0 +1 @@
+'Visual Studio - VS Core'
diff --git a/azure-pipelines/variables/DotNetSdkVersion.ps1 b/azure-pipelines/variables/DotNetSdkVersion.ps1
new file mode 100644
index 00000000..b213fbc2
--- /dev/null
+++ b/azure-pipelines/variables/DotNetSdkVersion.ps1
@@ -0,0 +1,2 @@
+$globalJson = Get-Content -Path "$PSScriptRoot\..\..\global.json" | ConvertFrom-Json
+$globalJson.sdk.version
diff --git a/azure-pipelines/variables/InsertJsonValues.ps1 b/azure-pipelines/variables/InsertJsonValues.ps1
new file mode 100644
index 00000000..807ca1cb
--- /dev/null
+++ b/azure-pipelines/variables/InsertJsonValues.ps1
@@ -0,0 +1,18 @@
+$vstsDropNames = & "$PSScriptRoot\VstsDropNames.ps1"
+$BuildConfiguration = $env:BUILDCONFIGURATION
+if (!$BuildConfiguration) {
+ $BuildConfiguration = 'Debug'
+}
+
+$BasePath = "$PSScriptRoot\..\..\bin\Packages\$BuildConfiguration\Vsix"
+
+if (Test-Path $BasePath) {
+ $vsmanFiles = @()
+ Get-ChildItem $BasePath *.vsman -Recurse -File |% {
+ $version = (Get-Content $_.FullName | ConvertFrom-Json).info.buildVersion
+ $fn = $_.Name
+ $vsmanFiles += "LibraryName.vsman{$version}=https://vsdrop.corp.microsoft.com/file/v1/$vstsDropNames;$fn"
+ }
+
+ [string]::join(',',$vsmanFiles)
+}
diff --git a/azure-pipelines/variables/InsertPropsValues.ps1 b/azure-pipelines/variables/InsertPropsValues.ps1
new file mode 100644
index 00000000..3ae11de9
--- /dev/null
+++ b/azure-pipelines/variables/InsertPropsValues.ps1
@@ -0,0 +1,14 @@
+$InsertedPkgs = (& "$PSScriptRoot\..\artifacts\VSInsertion.ps1")
+
+$icv=@()
+foreach ($kvp in $InsertedPkgs.GetEnumerator()) {
+ $kvp.Value |% {
+ if ($_.Name -match "^(.*?)\.(\d+\.\d+\.\d+(?:\.\d+)?(?:-.*?)?)(?:\.symbols)?\.nupkg$") {
+ $id = $Matches[1]
+ $version = $Matches[2]
+ $icv += "$id=$version"
+ }
+ }
+}
+
+Write-Output ([string]::join(',',$icv))
diff --git a/azure-pipelines/variables/InsertTargetBranch.ps1 b/azure-pipelines/variables/InsertTargetBranch.ps1
new file mode 100644
index 00000000..cdcc9194
--- /dev/null
+++ b/azure-pipelines/variables/InsertTargetBranch.ps1
@@ -0,0 +1,2 @@
+# This is the default branch of the VS repo that we will use to insert into VS.
+'main'
diff --git a/azure-pipelines/variables/InsertVersionsValues.ps1 b/azure-pipelines/variables/InsertVersionsValues.ps1
new file mode 100644
index 00000000..7475f6be
--- /dev/null
+++ b/azure-pipelines/variables/InsertVersionsValues.ps1
@@ -0,0 +1,11 @@
+# When you need binding redirects in the VS repo updated to match
+# assemblies that you build here, remove the "return" statement
+# and update the hashtable below with the T4 macro you'll use for
+# your libraries as defined in the src\ProductData\AssemblyVersions.tt file.
+return
+
+$MacroName = 'LibraryNoDotsVersion'
+$SampleProject = "$PSScriptRoot\..\..\src\LibraryName"
+[string]::join(',',(@{
+ ($MacroName) = & { (dotnet nbgv get-version --project $SampleProject --format json | ConvertFrom-Json).AssemblyVersion };
+}.GetEnumerator() |% { "$($_.key)=$($_.value)" }))
diff --git a/azure-pipelines/variables/LocLanguages.ps1 b/azure-pipelines/variables/LocLanguages.ps1
new file mode 100644
index 00000000..f38e72e2
--- /dev/null
+++ b/azure-pipelines/variables/LocLanguages.ps1
@@ -0,0 +1,6 @@
+## For faster PR/CI builds localize only for 2 languages, ENU and JPN provide good enough coverage
+if ($env:BUILD_REASON -eq 'PullRequest') {
+ 'ENU,JPN'
+} else {
+ 'VS'
+}
diff --git a/azure-pipelines/variables/ProfilingInputsDropName.ps1 b/azure-pipelines/variables/ProfilingInputsDropName.ps1
new file mode 100644
index 00000000..88d21f69
--- /dev/null
+++ b/azure-pipelines/variables/ProfilingInputsDropName.ps1
@@ -0,0 +1,5 @@
+if ($env:SYSTEM_TEAMPROJECT) {
+ "ProfilingInputs/$env:SYSTEM_TEAMPROJECT/$env:BUILD_REPOSITORY_NAME/$env:BUILD_SOURCEBRANCHNAME/$env:BUILD_BUILDID"
+} else {
+ Write-Warning "No Azure Pipelines build detected. No Azure Pipelines drop name will be computed."
+}
diff --git a/azure-pipelines/variables/SymbolsFeatureName.ps1 b/azure-pipelines/variables/SymbolsFeatureName.ps1
new file mode 100644
index 00000000..a6d08bb4
--- /dev/null
+++ b/azure-pipelines/variables/SymbolsFeatureName.ps1
@@ -0,0 +1 @@
+'json-document-transforms'
diff --git a/azure-pipelines/variables/VstsDropNames.ps1 b/azure-pipelines/variables/VstsDropNames.ps1
new file mode 100644
index 00000000..4ff36b2c
--- /dev/null
+++ b/azure-pipelines/variables/VstsDropNames.ps1
@@ -0,0 +1 @@
+"Products/$env:SYSTEM_TEAMPROJECT/$env:BUILD_REPOSITORY_NAME/$env:BUILD_SOURCEBRANCHNAME/$env:BUILD_BUILDID"
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/vs-insertion.yml b/azure-pipelines/vs-insertion.yml
new file mode 100644
index 00000000..add241f0
--- /dev/null
+++ b/azure-pipelines/vs-insertion.yml
@@ -0,0 +1,76 @@
+trigger: none # We only want to trigger manually or based on resources
+pr: none
+
+resources:
+ repositories:
+ - repository: MicroBuildTemplate
+ type: git
+ name: 1ESPipelineTemplates/MicroBuildTemplate
+ ref: refs/tags/release
+ pipelines:
+ - pipeline: CI
+ source: Library # TODO: This should match the name of your CI pipeline
+ tags:
+ - Real signed
+ trigger:
+ tags:
+ - Real signed
+ - auto-insertion
+
+variables:
+- template: GlobalVariables.yml
+
+extends:
+ template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate
+ parameters:
+ sdl:
+ sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES
+
+ stages:
+ - stage: insertion
+ jobs:
+ - job: insertion
+ displayName: VS insertion
+ pool: VSEngSS-MicroBuild2022-1ES
+ steps:
+ - checkout: none
+ - powershell: Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)"
+ displayName: โ๏ธ Set pipeline name
+ - template: azure-pipelines/release-deployment-prep.yml@self
+ - download: CI
+ artifact: VSInsertion-Windows
+ displayName: ๐ป Download VSInsertion-Windows artifact
+ - ${{ if eq(variables['ContainsVsix'], 'true') }}:
+ - task: 1ES.MicroBuildVstsDrop@1
+ displayName: ๐บ Upload VSTS Drop
+ inputs:
+ dropFolder: $(Pipeline.Workspace)/CI/VSInsertion-windows/Vsix
+ dropName: $(VstsDropNames)
+ accessToken: $(System.AccessToken)
+ - task: 1ES.PublishNuget@1
+ displayName: ๐ฆ Push VS-repo packages to VS feed
+ inputs:
+ packagesToPush: '$(Pipeline.Workspace)/CI/VSInsertion-Windows/*.nupkg'
+ packageParentPath: $(Pipeline.Workspace)/CI/VSInsertion-Windows
+ allowPackageConflicts: true
+ publishVstsFeed: VS
+ - task: MicroBuildInsertVsPayload@4
+ displayName: ๐ญ Insert VS Payload
+ inputs:
+ TeamName: $(TeamName)
+ TeamEmail: $(TeamEmail)
+ InsertionPayloadName: $(Build.Repository.Name) $(Build.BuildNumber)
+ InsertionBuildPolicy: Request Perf DDRITs
+ InsertionReviewers: $(Build.RequestedFor) # Append `,Your team name` (without quotes)
+ AutoCompletePR: true
+ AutoCompleteMergeStrategy: Squash
+ ShallowClone: true
+ - powershell: |
+ $contentType = 'application/json';
+ $headers = @{ Authorization = 'Bearer $(System.AccessToken)' };
+ $rawRequest = @{ daysValid = 365 * 2; definitionId = $(resources.pipeline.CI.pipelineID); ownerId = 'User:$(Build.RequestedForId)'; protectPipeline = $false; runId = $(resources.pipeline.CI.runId) };
+ $request = ConvertTo-Json @($rawRequest);
+ Write-Host $request
+ $uri = "$(System.CollectionUri)$(System.TeamProject)/_apis/build/retention/leases?api-version=6.0-preview.1";
+ Invoke-RestMethod -uri $uri -method POST -Headers $headers -ContentType $contentType -Body $request;
+ displayName: ๐ป Retain inserted builds
diff --git a/azure-pipelines/vs-validation.yml b/azure-pipelines/vs-validation.yml
new file mode 100644
index 00000000..1bb9f22e
--- /dev/null
+++ b/azure-pipelines/vs-validation.yml
@@ -0,0 +1,113 @@
+# This is a top-level pipeline file, which is designed to be added as an optional PR build policy
+# so that a VS insertion and all the validation that entails can be done before ever merging the PR
+# in its original repo.
+
+trigger: none # We only want to trigger manually or based on resources
+pr: none
+
+resources:
+ repositories:
+ - repository: MicroBuildTemplate
+ type: git
+ name: 1ESPipelineTemplates/MicroBuildTemplate
+ ref: refs/tags/release
+
+variables:
+- template: GlobalVariables.yml
+- name: MicroBuild_NuPkgSigningEnabled
+ value: false # test-signed nuget packages fail to restore in the VS insertion PR validations. Just don't sign them *at all*.
+
+extends:
+ template: azure-pipelines/MicroBuild.1ES.Unofficial.yml@MicroBuildTemplate
+ parameters:
+ sdl:
+ sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES
+
+ stages:
+ - stage: Build
+ variables:
+ DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true
+ NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/
+ BuildConfiguration: Release
+ SkipCodesignVerify: true
+
+ jobs:
+ - template: /azure-pipelines/build.yml@self
+ parameters:
+ Is1ESPT: true
+ RealSign: false
+ windowsPool: VSEngSS-MicroBuild2022-1ES
+ linuxPool:
+ name: AzurePipelines-EO
+ demands:
+ - ImageOverride -equals 1ESPT-Ubuntu22.04
+ os: Linux
+ macOSPool:
+ name: Azure Pipelines
+ vmImage: macOS-12
+ os: macOS
+ EnableMacOSBuild: false
+ RunTests: false
+ SkipCodesignVerify: true
+
+ - template: /azure-pipelines/prepare-insertion-stages.yml@self
+ parameters:
+ ArchiveSymbols: false
+ RealSign: false
+
+ - stage: insertion
+ displayName: VS insertion
+ jobs:
+ - job: insertion
+ displayName: VS insertion
+ pool: VSEngSS-MicroBuild2022-1ES
+ steps:
+ - checkout: self
+ clean: true
+ fetchDepth: 1
+ - download: current
+ artifact: Variables-Windows
+ displayName: ๐ป Download Variables-Windows artifact
+ - powershell: $(Pipeline.Workspace)/Variables-Windows/_pipelines.ps1
+ displayName: โ๏ธ Set pipeline variables based on artifacts
+ - download: current
+ artifact: VSInsertion-Windows
+ displayName: ๐ป Download VSInsertion-Windows artifact
+ - ${{ if eq(variables['ContainsVsix'], 'true') }}:
+ - task: 1ES.MicroBuildVstsDrop@1
+ displayName: ๐บ Upload VSTS Drop
+ inputs:
+ dropFolder: $(Pipeline.Workspace)/VSInsertion-windows/Vsix
+ dropName: $(VstsDropNames)
+ accessToken: $(System.AccessToken)
+ - task: 1ES.PublishNuget@1
+ displayName: ๐ฆ Push VS-repo packages to VS feed
+ inputs:
+ packagesToPush: '$(Pipeline.Workspace)/VSInsertion-Windows/*.nupkg'
+ packageParentPath: $(Pipeline.Workspace)/VSInsertion-Windows
+ allowPackageConflicts: true
+ publishVstsFeed: VS
+ - task: MicroBuildInsertVsPayload@4
+ displayName: ๐ญ Insert VS Payload
+ inputs:
+ TeamName: $(TeamName)
+ TeamEmail: $(TeamEmail)
+ InsertionPayloadName: $(Build.Repository.Name) VALIDATION BUILD $(Build.BuildNumber) ($(Build.SourceBranch)) [Skip-SymbolCheck] [Skip-HashCheck] [Skip-SignCheck]
+ InsertionDescription: |
+ This PR is for **validation purposes only** for !$(System.PullRequest.PullRequestId). **Do not complete**.
+ CustomScriptExecutionCommand: src/VSSDK/NuGet/AllowUnstablePackages.ps1
+ InsertionBuildPolicy: Request Perf DDRITs
+ InsertionReviewers: $(Build.RequestedFor)
+ DraftPR: false # set to true and update InsertionBuildPolicy when we can specify all the validations we want to run (https://dev.azure.com/devdiv/DevDiv/_workitems/edit/2224288)
+ AutoCompletePR: false
+ ShallowClone: true
+ - powershell: |
+ $insertionPRId = azure-pipelines/Get-InsertionPRId.ps1
+ $Markdown = @"
+ Validation insertion pull request created: !$insertionPRId
+ Please check status there before proceeding to merge this PR.
+ Remember to Abandon and (if allowed) to Delete Source Branch on that insertion PR when validation is complete.
+ "@
+ azure-pipelines/PostPRMessage.ps1 -AccessToken '$(System.AccessToken)' -Markdown $Markdown -Verbose
+ displayName: โ๏ธ Comment on pull request
+ condition: and(succeeded(), eq(variables['Build.Reason'], 'PullRequest'))
diff --git a/global.json b/global.json
new file mode 100644
index 00000000..9b900542
--- /dev/null
+++ b/global.json
@@ -0,0 +1,10 @@
+{
+ "sdk": {
+ "version": "9.0.100",
+ "rollForward": "patch",
+ "allowPrerelease": false
+ },
+ "msbuild-sdks": {
+ "Microsoft.Build.NoTargets": "3.7.56"
+ }
+}
diff --git a/init.cmd b/init.cmd
new file mode 100644
index 00000000..667efabb
--- /dev/null
+++ b/init.cmd
@@ -0,0 +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
new file mode 100644
index 00000000..5a31bea7
--- /dev/null
+++ b/init.ps1
@@ -0,0 +1,175 @@
+#!/usr/bin/env pwsh
+
+<#
+.SYNOPSIS
+ Installs dependencies required to build and test the projects in this repository.
+.DESCRIPTION
+ This MAY not require elevation, as the SDK and runtimes are installed 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.
+.PARAMETER NoPrerequisites
+ Skips the installation of prerequisite software (e.g. SDKs, tools).
+.PARAMETER NoNuGetCredProvider
+ Skips the installation of the NuGet credential provider. Useful in pipelines with the `NuGetAuthenticate` task, as a workaround for https://github.com/microsoft/artifacts-credprovider/issues/244.
+ This switch is ignored and installation is skipped when -NoPrerequisites is specified.
+.PARAMETER UpgradePrerequisites
+ Takes time to install prerequisites even if they are already present in case they need to be upgraded.
+ No effect if -NoPrerequisites is specified.
+.PARAMETER NoRestore
+ Skips the package restore step.
+.PARAMETER NoToolRestore
+ Skips the dotnet tool restore step.
+.PARAMETER Signing
+ Install the MicroBuild signing plugin for building test-signed builds on desktop machines.
+.PARAMETER Localization
+ Install the MicroBuild localization plugin for building loc builds on desktop machines.
+ The environment is configured to build pseudo-loc for JPN only, but may be used to build
+ all languages with shipping-style loc by using the `/p:loctype=full,loclanguages=vs`
+ when building.
+.PARAMETER Setup
+ Install the MicroBuild setup plugin for building VSIXv3 packages.
+.PARAMETER OptProf
+ Install the MicroBuild OptProf plugin for building optimized assemblies on desktop machines.
+.PARAMETER Sbom
+ Install the MicroBuild SBOM plugin.
+.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',
+ [Parameter()]
+ [switch]$NoPrerequisites,
+ [Parameter()]
+ [switch]$NoNuGetCredProvider,
+ [Parameter()]
+ [switch]$UpgradePrerequisites,
+ [Parameter()]
+ [switch]$NoRestore,
+ [Parameter()]
+ [switch]$NoToolRestore,
+ [Parameter()]
+ [switch]$Signing,
+ [Parameter()]
+ [switch]$Localization,
+ [Parameter()]
+ [switch]$Setup,
+ [Parameter()]
+ [switch]$OptProf,
+ [Parameter()]
+ [switch]$SBOM,
+ [Parameter()]
+ [string]$AccessToken,
+ [Parameter()]
+ [switch]$Interactive
+)
+
+$EnvVars = @{}
+$PrependPath = @()
+
+if (!$NoPrerequisites) {
+ if (!$NoNuGetCredProvider) {
+ & "$PSScriptRoot\tools\Install-NuGetCredProvider.ps1" -AccessToken $AccessToken -Force:$UpgradePrerequisites
+ }
+
+ & "$PSScriptRoot\tools\Install-DotNetSdk.ps1" -InstallLocality $InstallLocality
+ if ($LASTEXITCODE -eq 3010) {
+ Exit 3010
+ }
+
+ # The procdump tool and env var is required for dotnet test to collect hang/crash dumps of tests.
+ # But it only works on Windows.
+ if ($env:OS -eq 'Windows_NT') {
+ $EnvVars['PROCDUMP_PATH'] = & "$PSScriptRoot\azure-pipelines\Get-ProcDump.ps1"
+ }
+}
+
+# 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'
+
+ $RestoreArguments = @()
+ if ($Interactive) {
+ $RestoreArguments += '--interactive'
+ }
+
+ if (!$NoRestore -and $PSCmdlet.ShouldProcess("NuGet packages", "Restore")) {
+ Write-Host "Restoring NuGet packages" -ForegroundColor $HeaderColor
+ dotnet restore @RestoreArguments src
+ if ($lastexitcode -ne 0) {
+ throw "Failure while restoring packages."
+ }
+ }
+
+ if (!$NoToolRestore -and $PSCmdlet.ShouldProcess("dotnet tool", "restore")) {
+ dotnet tool restore @RestoreArguments
+ if ($lastexitcode -ne 0) {
+ throw "Failure while restoring dotnet CLI tools."
+ }
+ }
+
+ $InstallNuGetPkgScriptPath = "$PSScriptRoot\azure-pipelines\Install-NuGetPackage.ps1"
+ $nugetVerbosity = 'quiet'
+ if ($Verbose) { $nugetVerbosity = 'normal' }
+ $MicroBuildPackageSource = 'https://pkgs.dev.azure.com/devdiv/_packaging/MicroBuildToolset%40Local/nuget/v3/index.json'
+ if ($Signing) {
+ Write-Host "Installing MicroBuild signing plugin" -ForegroundColor $HeaderColor
+ & $InstallNuGetPkgScriptPath MicroBuild.Plugins.Signing -source $MicroBuildPackageSource -Verbosity $nugetVerbosity
+ $EnvVars['SignType'] = "Test"
+ }
+
+ if ($Setup) {
+ Write-Host "Installing MicroBuild SwixBuild plugin..." -ForegroundColor $HeaderColor
+ & $InstallNuGetPkgScriptPath Microsoft.VisualStudioEng.MicroBuild.Plugins.SwixBuild -source $MicroBuildPackageSource -Verbosity $nugetVerbosity
+ }
+
+ if ($OptProf) {
+ Write-Host "Installing MicroBuild OptProf plugin" -ForegroundColor $HeaderColor
+ & $InstallNuGetPkgScriptPath MicroBuild.Plugins.OptProf -source $MicroBuildPackageSource -Verbosity $nugetVerbosity
+ $EnvVars['OptProfEnabled'] = '1'
+ }
+
+ if ($Localization) {
+ Write-Host "Installing MicroBuild localization plugin" -ForegroundColor $HeaderColor
+ & $InstallNuGetPkgScriptPath MicroBuild.Plugins.Localization -source $MicroBuildPackageSource -Verbosity $nugetVerbosity
+ $EnvVars['LocType'] = "Pseudo"
+ $EnvVars['LocLanguages'] = "JPN"
+ }
+
+ if ($SBOM) {
+ Write-Host "Installing MicroBuild SBOM plugin" -ForegroundColor $HeaderColor
+ & $InstallNuGetPkgScriptPath MicroBuild.Plugins.Sbom -source $MicroBuildPackageSource -Verbosity $nugetVerbosity
+ # The feed with the latest versions of the tool is at 'https://1essharedassets.pkgs.visualstudio.com/1esPkgs/_packaging/SBOMTool/nuget/v3/index.json',
+ # but we'll use the feed that the SBOM task itself uses to install the tool for consistency.
+ $PkgMicrosoft_ManifestTool_CrossPlatform = & $InstallNuGetPkgScriptPath Microsoft.ManifestTool.CrossPlatform -source $MicroBuildPackageSource -Verbosity $nugetVerbosity
+ $EnvVars['GenerateSBOM'] = "true"
+ $EnvVars['PkgMicrosoft_ManifestTool_CrossPlatform'] = $PkgMicrosoft_ManifestTool_CrossPlatform
+ }
+
+ & "$PSScriptRoot/tools/Set-EnvVars.ps1" -Variables $EnvVars -PrependPath $PrependPath | Out-Null
+}
+catch {
+ Write-Error $error[0]
+ exit $lastexitcode
+}
+finally {
+ Pop-Location
+}
diff --git a/nuget.config b/nuget.config
index 9eddc6be..efd1a949 100644
--- a/nuget.config
+++ b/nuget.config
@@ -1,4 +1,4 @@
-
+๏ปฟ
diff --git a/src/.editorconfig b/src/.editorconfig
new file mode 100644
index 00000000..e69de29b
diff --git a/src/AssemblyInfo.cs b/src/AssemblyInfo.cs
new file mode 100644
index 00000000..9731a830
--- /dev/null
+++ b/src/AssemblyInfo.cs
@@ -0,0 +1,6 @@
+// Copyright (c) Microsoft Corporation. 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/AssemblyInfo.vb b/src/AssemblyInfo.vb
new file mode 100644
index 00000000..75fe6ea4
--- /dev/null
+++ b/src/AssemblyInfo.vb
@@ -0,0 +1,6 @@
+' Copyright (c) Microsoft Corporation. All rights reserved.
+' Licensed under the MIT license. See LICENSE file in the project root for full license information.
+
+Imports System.Runtime.InteropServices
+
+
diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index ca3652d2..9ba7818d 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,23 +1,12 @@
-
-
+
+
+
- Debug
- AnyCPU
- $(MSBuildThisFileDirectory)..\bin\
- $(MSBuildThisFileDirectory)..\obj\$(MSBuildProjectName)\
- $(BaseIntermediateOutputPath)$(Configuration)\
- $(BaseOutputPath)$(Configuration)\
- $(OutputPath)packages\
- true
+ README.md
-
-
-
-
-
-
-
+
+
diff --git a/src/Directory.Build.targets b/src/Directory.Build.targets
new file mode 100644
index 00000000..654f5c6d
--- /dev/null
+++ b/src/Directory.Build.targets
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj b/src/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj
deleted file mode 100644
index 666def7b..00000000
--- a/src/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj
+++ /dev/null
@@ -1,33 +0,0 @@
-๏ปฟ
-
-
- net472;net5.0
- false
- $(NoWarn);CS1591
-
-
-
-
-
-
-
-
- all
- runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/Microsoft.VisualStudio.Jdt/IJsonTransformationLogger.cs b/src/Microsoft.VisualStudio.Jdt/IJsonTransformationLogger.cs
index 2d91942c..09a82c3a 100644
--- a/src/Microsoft.VisualStudio.Jdt/IJsonTransformationLogger.cs
+++ b/src/Microsoft.VisualStudio.Jdt/IJsonTransformationLogger.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/JdtException.cs b/src/Microsoft.VisualStudio.Jdt/JdtException.cs
index 756c3807..658179c2 100644
--- a/src/Microsoft.VisualStudio.Jdt/JdtException.cs
+++ b/src/Microsoft.VisualStudio.Jdt/JdtException.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -12,17 +12,17 @@ namespace Microsoft.VisualStudio.Jdt
public enum ErrorLocation
{
///
- /// Represents no location set
+ /// Represents no location set.
///
None,
///
- /// Represents the source file
+ /// Represents the source file.
///
Source,
///
- /// Represents the transform file
+ /// Represents the transform file.
///
Transform,
}
diff --git a/src/Microsoft.VisualStudio.Jdt/JdtExtensions.cs b/src/Microsoft.VisualStudio.Jdt/JdtExtensions.cs
index dd07bc41..7984e907 100644
--- a/src/Microsoft.VisualStudio.Jdt/JdtExtensions.cs
+++ b/src/Microsoft.VisualStudio.Jdt/JdtExtensions.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -58,7 +58,7 @@ internal static JObject CloneWithLineInfo(this JObject objectToClone)
LineInfoHandling = JdtUtilities.GetLineInfoHandling(),
};
- using (var objectReader = objectToClone.CreateReader())
+ using (Newtonsoft.Json.JsonReader objectReader = objectToClone.CreateReader())
{
return JObject.Load(objectReader, loadSettings);
}
diff --git a/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs b/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs
index f0a45ade..b9f2e3d9 100644
--- a/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs
+++ b/src/Microsoft.VisualStudio.Jdt/JdtUtilities.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/JsonTransformation.cs b/src/Microsoft.VisualStudio.Jdt/JsonTransformation.cs
index f661cb44..3339a34c 100644
--- a/src/Microsoft.VisualStudio.Jdt/JsonTransformation.cs
+++ b/src/Microsoft.VisualStudio.Jdt/JsonTransformation.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/JsonTransformationContextLogger.cs b/src/Microsoft.VisualStudio.Jdt/JsonTransformationContextLogger.cs
index bc3841a8..ed46d45c 100644
--- a/src/Microsoft.VisualStudio.Jdt/JsonTransformationContextLogger.cs
+++ b/src/Microsoft.VisualStudio.Jdt/JsonTransformationContextLogger.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/Microsoft.VisualStudio.Jdt.csproj b/src/Microsoft.VisualStudio.Jdt/Microsoft.VisualStudio.Jdt.csproj
index 64775cc7..3e4c39ba 100644
--- a/src/Microsoft.VisualStudio.Jdt/Microsoft.VisualStudio.Jdt.csproj
+++ b/src/Microsoft.VisualStudio.Jdt/Microsoft.VisualStudio.Jdt.csproj
@@ -2,7 +2,7 @@
library
- netstandard1.5;net472
+ netstandard2.0;net472
@@ -13,20 +13,24 @@
json transformation transforms file-transform jdt
https://aka.ms/VsExtensibilityIcon
true
- https://raw.githubusercontent.com/Microsoft/json-document-transforms/master/LICENSE
https://github.com/Microsoft/json-document-transforms
https://github.com/Microsoft/json-document-transforms
True
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
@@ -44,9 +48,4 @@
-
-
-
-
-
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeExtensions.cs b/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeExtensions.cs
index 91508afa..7d32c875 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeExtensions.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeExtensions.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeValidator.cs b/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeValidator.cs
index 0e8f6e06..bcb43a68 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeValidator.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeValidator.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -14,17 +14,17 @@ namespace Microsoft.VisualStudio.Jdt
internal enum JdtAttributes
{
///
- /// Represents an non existant attribute
+ /// Represents an non existant attribute.
///
None = 0,
///
- /// The JDT path attribute
+ /// The JDT path attribute.
///
Path,
///
- /// The JDT path attribute
+ /// The JDT path attribute.
///
Value,
}
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs
index 7561be80..e2e0a59b 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs
index 4da52d4a..e7c37876 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs
index 3a9d1d2d..f83ee2d6 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtMerge.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -52,7 +52,7 @@ protected override bool ProcessCore(JObject source, JToken transformValue, JsonT
private void MergeWithObject(JObject source, JObject mergeObject, JsonTransformationContextLogger logger)
{
- var attributes = this.attributeValidator.ValidateAndReturnAttributes(mergeObject);
+ Dictionary attributes = this.attributeValidator.ValidateAndReturnAttributes(mergeObject);
// If there are attributes, handle them accordingly
if (attributes.Any())
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs
index 556d9c5a..e98e2e37 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -37,9 +37,9 @@ public JdtProcessorChain()
// The successor of each transform processor should be the next one on the list
// The last processor defaults to the end of chain processor
- var processorsEnumerator = this.processors.GetEnumerator();
+ List.Enumerator processorsEnumerator = this.processors.GetEnumerator();
processorsEnumerator.MoveNext();
- foreach (var successor in this.processors.Skip(1))
+ foreach (JdtProcessor? successor in this.processors.Skip(1))
{
if (!string.IsNullOrEmpty(successor.Verb))
{
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs
index 96984e14..22c131db 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs
index 44e5dae7..7e48263c 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs
index fb5e8751..31c9cba2 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRemove.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -64,7 +64,7 @@ protected override bool ProcessCore(JObject source, JToken transformValue, JsonT
private bool RemoveWithAttributes(JObject source, JObject removeObject, JsonTransformationContextLogger logger)
{
- var attributes = this.attributeValidator.ValidateAndReturnAttributes(removeObject);
+ Dictionary attributes = this.attributeValidator.ValidateAndReturnAttributes(removeObject);
// The remove attribute only accepts objects if they have only the path attribute
JToken pathToken;
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs
index 24476f72..d8ec2e89 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtRename.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -37,7 +37,7 @@ protected override bool ProcessCore(JObject source, JToken transformValue, JsonT
{
// Try and get attributes from the object
var renameObject = (JObject)transformValue;
- var attributes = this.attributeValidator.ValidateAndReturnAttributes(renameObject);
+ Dictionary attributes = this.attributeValidator.ValidateAndReturnAttributes(renameObject);
// If there are attributes, handle them accordingly
if (attributes.Any())
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs
index 56025753..1a56613c 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtReplace.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
@@ -50,7 +50,7 @@ protected override bool ProcessCore(JObject source, JToken transformValue, JsonT
private bool ReplaceWithProperties(JObject source, JObject replaceObject, JsonTransformationContextLogger logger)
{
- var attributes = this.attributeValidator.ValidateAndReturnAttributes(replaceObject);
+ Dictionary attributes = this.attributeValidator.ValidateAndReturnAttributes(replaceObject);
// If there are attributes, handle them accordingly
if (attributes.Any())
diff --git a/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs b/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs
index 3141a3b7..cb1971f1 100644
--- a/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs
+++ b/src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt
{
diff --git a/src/OptProf.targets b/src/OptProf.targets
new file mode 100644
index 00000000..d0167d7c
--- /dev/null
+++ b/src/OptProf.targets
@@ -0,0 +1,17 @@
+
+
+
+ IBC
+ Common7\IDE\PrivateAssemblies\$(TargetFileName)
+ /ExeConfig:"%VisualStudio.InstallationUnderTest.Path%\Common7\IDE\vsn.exe"
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/VSInsertionMetadata/Library.VSInsertionMetadata.proj b/src/VSInsertionMetadata/Library.VSInsertionMetadata.proj
new file mode 100644
index 00000000..0caaedb9
--- /dev/null
+++ b/src/VSInsertionMetadata/Library.VSInsertionMetadata.proj
@@ -0,0 +1,11 @@
+
+
+ netstandard2.0
+ true
+ $(RepoRootPath)bin\Packages\$(Configuration)\VSRepo\
+ false
+ false
+ Contains metadata for insertion into VS.
+
+
+
diff --git a/src/VSInsertionMetadata/ProfilingInputs.props b/src/VSInsertionMetadata/ProfilingInputs.props
new file mode 100644
index 00000000..fb19d604
--- /dev/null
+++ b/src/VSInsertionMetadata/ProfilingInputs.props
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/src/VSInsertionMetadata/VSInsertionMetadata.targets b/src/VSInsertionMetadata/VSInsertionMetadata.targets
new file mode 100644
index 00000000..84ebb5a8
--- /dev/null
+++ b/src/VSInsertionMetadata/VSInsertionMetadata.targets
@@ -0,0 +1,71 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(TargetsForTfmSpecificContentInPackage);
+ SubstituteProfilingInputsMacro;
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(PackageVersion).$(Build_BuildId)
+
+
+
+
+
+
diff --git a/src/jdt.sln b/src/jdt.sln
index 1043516d..69d4c554 100644
--- a/src/jdt.sln
+++ b/src/jdt.sln
@@ -1,18 +1,21 @@
๏ปฟ
Microsoft Visual Studio Solution File, Format Version 12.00
-# Visual Studio 15
-VisualStudioVersion = 15.0.26403.7
+# Visual Studio Version 17
+VisualStudioVersion = 17.13.35505.181
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.Jdt", "Microsoft.VisualStudio.Jdt\Microsoft.VisualStudio.Jdt.csproj", "{E4517B62-6E49-47A9-93A3-889B2E0A92B5}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.Jdt.Tests", "Microsoft.VisualStudio.Jdt.Tests\Microsoft.VisualStudio.Jdt.Tests.csproj", "{A17BD5AD-EB38-4D71-90CE-25DAE7BFAAC0}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{386BAD62-57B8-4AEB-AEE5-D122A8330656}"
ProjectSection(SolutionItems) = preProject
+ Directory.Build.props = Directory.Build.props
+ Directory.Build.targets = Directory.Build.targets
+ ..\Directory.Packages.props = ..\Directory.Packages.props
stylecop.json = stylecop.json
version.json = version.json
EndProjectSection
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.Jdt.Tests", "..\test\Microsoft.VisualStudio.Jdt.Tests\Microsoft.VisualStudio.Jdt.Tests.csproj", "{DC4029BB-86FD-AC0B-8024-03ECD0301F86}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -23,12 +26,15 @@ Global
{E4517B62-6E49-47A9-93A3-889B2E0A92B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E4517B62-6E49-47A9-93A3-889B2E0A92B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E4517B62-6E49-47A9-93A3-889B2E0A92B5}.Release|Any CPU.Build.0 = Release|Any CPU
- {A17BD5AD-EB38-4D71-90CE-25DAE7BFAAC0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {A17BD5AD-EB38-4D71-90CE-25DAE7BFAAC0}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {A17BD5AD-EB38-4D71-90CE-25DAE7BFAAC0}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {A17BD5AD-EB38-4D71-90CE-25DAE7BFAAC0}.Release|Any CPU.Build.0 = Release|Any CPU
+ {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {F194D4D1-A28A-4C19-941E-BF828EA6DD8C}
+ EndGlobalSection
EndGlobal
diff --git a/src/stylecop.json b/src/stylecop.json
index 5743660d..c125c72f 100644
--- a/src/stylecop.json
+++ b/src/stylecop.json
@@ -1,17 +1,15 @@
{
// https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md
-
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"documentationRules": {
"companyName": "Microsoft Corporation",
- "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName}. See {licenseFile} file in the project root for full license information.",
+ "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.",
"variables": {
- "licenseName": "MIT License",
+ "licenseName": "MIT",
"licenseFile": "LICENSE"
},
"xmlHeader": false
}
}
-
-}
\ No newline at end of file
+}
diff --git a/src/version.json b/src/version.json
index 71368d09..8170c45d 100644
--- a/src/version.json
+++ b/src/version.json
@@ -2,7 +2,7 @@
"$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json",
"version": "0.9",
"publicReleaseRefSpec": [
- "^refs/heads/master$", // we release out of master
+ "^refs/heads/main$" // we release out of main
],
"cloudBuild": {
"buildNumber": {
diff --git a/test/.editorconfig b/test/.editorconfig
new file mode 100644
index 00000000..74dd4a1f
--- /dev/null
+++ b/test/.editorconfig
@@ -0,0 +1,55 @@
+[*.cs]
+
+# SA1600: Elements should be documented
+dotnet_diagnostic.SA1600.severity = silent
+
+# SA1601: Partial elements should be documented
+dotnet_diagnostic.SA1601.severity = silent
+
+# SA1602: Enumeration items should be documented
+dotnet_diagnostic.SA1602.severity = silent
+
+# SA1615: Element return value should be documented
+dotnet_diagnostic.SA1615.severity = silent
+
+# VSTHRD103: Call async methods when in an async method
+dotnet_diagnostic.VSTHRD103.severity = silent
+
+# VSTHRD111: Use .ConfigureAwait(bool)
+dotnet_diagnostic.VSTHRD111.severity = none
+
+# VSTHRD200: Use Async suffix for async methods
+dotnet_diagnostic.VSTHRD200.severity = silent
+
+# CA1014: Mark assemblies with CLSCompliant
+dotnet_diagnostic.CA1014.severity = none
+
+# CA1050: Declare types in namespaces
+dotnet_diagnostic.CA1050.severity = none
+
+# CA1303: Do not pass literals as localized parameters
+dotnet_diagnostic.CA1303.severity = none
+
+# CS1591: Missing XML comment for publicly visible type or member
+dotnet_diagnostic.CS1591.severity = silent
+
+# CA1707: Identifiers should not contain underscores
+dotnet_diagnostic.CA1707.severity = silent
+
+# CA1062: Validate arguments of public methods
+dotnet_diagnostic.CA1062.severity = suggestion
+
+# CA1063: Implement IDisposable Correctly
+dotnet_diagnostic.CA1063.severity = silent
+
+# CA1816: Dispose methods should call SuppressFinalize
+dotnet_diagnostic.CA1816.severity = silent
+
+# CA2007: Consider calling ConfigureAwait on the awaited task
+dotnet_diagnostic.CA2007.severity = none
+
+# SA1401: Fields should be private
+dotnet_diagnostic.SA1401.severity = silent
+
+# SA1133: Do not combine attributes
+dotnet_diagnostic.SA1133.severity = silent
diff --git a/test/Directory.Build.props b/test/Directory.Build.props
new file mode 100644
index 00000000..395359dd
--- /dev/null
+++ b/test/Directory.Build.props
@@ -0,0 +1,13 @@
+
+
+
+
+
+ false
+ true
+
+
+
+
+
+
diff --git a/test/Directory.Build.targets b/test/Directory.Build.targets
new file mode 100644
index 00000000..a6e0f4ac
--- /dev/null
+++ b/test/Directory.Build.targets
@@ -0,0 +1,4 @@
+
+
+
+
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/App.config b/test/Microsoft.VisualStudio.Jdt.Tests/App.config
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/App.config
rename to test/Microsoft.VisualStudio.Jdt.Tests/App.config
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.Source.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.Source.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.Source.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.Source.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Expected.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Expected.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Expected.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Expected.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Transform.json b/test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Transform.json
similarity index 100%
rename from src/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Transform.json
rename to test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Transform.json
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/JdtUtilitiesTest.cs b/test/Microsoft.VisualStudio.Jdt.Tests/JdtUtilitiesTest.cs
similarity index 97%
rename from src/Microsoft.VisualStudio.Jdt.Tests/JdtUtilitiesTest.cs
rename to test/Microsoft.VisualStudio.Jdt.Tests/JdtUtilitiesTest.cs
index 22d83e86..15e77086 100644
--- a/src/Microsoft.VisualStudio.Jdt.Tests/JdtUtilitiesTest.cs
+++ b/test/Microsoft.VisualStudio.Jdt.Tests/JdtUtilitiesTest.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt.Tests
{
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTest.cs b/test/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTest.cs
similarity index 95%
rename from src/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTest.cs
rename to test/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTest.cs
index 253366dc..5386d12c 100644
--- a/src/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTest.cs
+++ b/test/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTest.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt.Tests
{
@@ -261,11 +261,11 @@ public void ThrowAndLogException()
string transformString = @"{
'@jdt.invalid': false
}";
- using (var transformStream = this.GetStreamFromString(transformString))
- using (var sourceStream = this.GetStreamFromString(SimpleSourceString))
+ using (Stream transformStream = this.GetStreamFromString(transformString))
+ using (Stream sourceStream = this.GetStreamFromString(SimpleSourceString))
{
JsonTransformation transform = new JsonTransformation(transformStream, this.logger);
- var exception = Record.Exception(() => transform.Apply(sourceStream));
+ Exception exception = Record.Exception(() => transform.Apply(sourceStream));
Assert.NotNull(exception);
Assert.IsType(exception);
var jdtException = exception as JdtException;
@@ -302,7 +302,7 @@ public void ReadOnly()
private static void LogHasSingleEntry(List log, string fileName, int lineNumber, int linePosition, bool fromException)
{
Assert.Single(log);
- var errorEntry = log.Single();
+ JsonTransformationTestLogger.TestLogEntry errorEntry = log.Single();
Assert.Equal(fileName, errorEntry.FileName);
Assert.Equal(lineNumber, errorEntry.LineNumber);
Assert.Equal(linePosition, errorEntry.LinePosition);
@@ -311,8 +311,8 @@ private static void LogHasSingleEntry(List applyTransformMethod, bool sho
{
Stream result = null;
- var exception = Record.Exception(() => result = applyTransformMethod());
+ Exception exception = Record.Exception(() => result = applyTransformMethod());
if (shouldTransformSucceed)
{
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTestLogger.cs b/test/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTestLogger.cs
similarity index 98%
rename from src/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTestLogger.cs
rename to test/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTestLogger.cs
index 40843c70..e87f15e7 100644
--- a/src/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTestLogger.cs
+++ b/test/Microsoft.VisualStudio.Jdt.Tests/JsonTransformationTestLogger.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt.Tests
{
diff --git a/test/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj b/test/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj
new file mode 100644
index 00000000..b511263d
--- /dev/null
+++ b/test/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj
@@ -0,0 +1,33 @@
+๏ปฟ
+
+
+ net472;net5.0
+ false
+ $(NoWarn);CS1591
+
+
+
+
+
+
+
+
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/ReadOnlyTempFile.cs b/test/Microsoft.VisualStudio.Jdt.Tests/ReadOnlyTempFile.cs
similarity index 96%
rename from src/Microsoft.VisualStudio.Jdt.Tests/ReadOnlyTempFile.cs
rename to test/Microsoft.VisualStudio.Jdt.Tests/ReadOnlyTempFile.cs
index 3a75a0f3..3802b32b 100644
--- a/src/Microsoft.VisualStudio.Jdt.Tests/ReadOnlyTempFile.cs
+++ b/test/Microsoft.VisualStudio.Jdt.Tests/ReadOnlyTempFile.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt.Tests
{
diff --git a/src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs b/test/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs
similarity index 97%
rename from src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs
rename to test/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs
index 317e7439..15b35848 100644
--- a/src/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs
+++ b/test/Microsoft.VisualStudio.Jdt.Tests/TransformTest.cs
@@ -1,5 +1,5 @@
๏ปฟ// Copyright (c) Microsoft Corporation. All rights reserved.
-// Licensed under the MIT License. See LICENSE file in the project root for full license information.
+// Licensed under the MIT license. See LICENSE file in the project root for full license information.
namespace Microsoft.VisualStudio.Jdt.Tests
{
@@ -16,7 +16,7 @@ namespace Microsoft.VisualStudio.Jdt.Tests
public class TransformTest
{
// Directory for test inputs, that are JSON files
- private static readonly string TestInputDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.FullName + "\\src\\Microsoft.VisualStudio.Jdt.Tests\\Inputs\\";
+ private static readonly string TestInputDirectory = Directory.GetParent(Directory.GetCurrentDirectory()).Parent.Parent.Parent.FullName + "\\test\\Microsoft.VisualStudio.Jdt.Tests\\Inputs\\";
// Directory for Default transformation tests
private static readonly string DefaultTestDirectory = TestInputDirectory + "Default\\";
diff --git a/tools/Check-DotNetRuntime.ps1 b/tools/Check-DotNetRuntime.ps1
new file mode 100644
index 00000000..9d012109
--- /dev/null
+++ b/tools/Check-DotNetRuntime.ps1
@@ -0,0 +1,41 @@
+<#
+.SYNOPSIS
+ Checks whether a given .NET Core runtime is installed.
+#>
+[CmdletBinding()]
+Param (
+ [Parameter()]
+ [ValidateSet('Microsoft.AspNetCore.App','Microsoft.NETCore.App')]
+ [string]$Runtime='Microsoft.NETCore.App',
+ [Parameter(Mandatory=$true)]
+ [Version]$Version
+)
+
+$dotnet = Get-Command dotnet -ErrorAction SilentlyContinue
+if (!$dotnet) {
+ # Nothing is installed.
+ Write-Output $false
+ exit 1
+}
+
+Function IsVersionMatch {
+ Param(
+ [Parameter()]
+ $actualVersion
+ )
+ return $actualVersion -and
+ $Version.Major -eq $actualVersion.Major -and
+ $Version.Minor -eq $actualVersion.Minor -and
+ (($Version.Build -eq -1) -or ($Version.Build -eq $actualVersion.Build)) -and
+ (($Version.Revision -eq -1) -or ($Version.Revision -eq $actualVersion.Revision))
+}
+
+$installedRuntimes = dotnet --list-runtimes |? { $_.Split()[0] -ieq $Runtime } |% { $v = $null; [Version]::tryparse($_.Split()[1], [ref] $v); $v }
+$matchingRuntimes = $installedRuntimes |? { IsVersionMatch -actualVersion $_ }
+if (!$matchingRuntimes) {
+ Write-Output $false
+ exit 1
+}
+
+Write-Output $true
+exit 0
diff --git a/tools/Check-DotNetSdk.ps1 b/tools/Check-DotNetSdk.ps1
new file mode 100644
index 00000000..6c9fa772
--- /dev/null
+++ b/tools/Check-DotNetSdk.ps1
@@ -0,0 +1,37 @@
+<#
+.SYNOPSIS
+ Checks whether the .NET Core SDK required by this repo is installed.
+#>
+[CmdletBinding()]
+Param (
+)
+
+$dotnet = Get-Command dotnet -ErrorAction SilentlyContinue
+if (!$dotnet) {
+ # Nothing is installed.
+ Write-Output $false
+ exit 1
+}
+
+# We need to set the current directory so dotnet considers the SDK required by our global.json file.
+Push-Location "$PSScriptRoot\.."
+try {
+ dotnet -h 2>&1 | Out-Null
+ if (($LASTEXITCODE -eq 129) -or # On Linux
+ ($LASTEXITCODE -eq -2147450751) # On Windows
+ ) {
+ # These exit codes indicate no matching SDK exists.
+ Write-Output $false
+ exit 2
+ }
+
+ # The required SDK is already installed!
+ Write-Output $true
+ exit 0
+} catch {
+ # I don't know why, but on some build agents (e.g. MicroBuild), an exception is thrown from the `dotnet` invocation when a match is not found.
+ Write-Output $false
+ exit 3
+} finally {
+ Pop-Location
+}
diff --git a/tools/Install-DotNetSdk.ps1 b/tools/Install-DotNetSdk.ps1
new file mode 100644
index 00000000..e190fcfb
--- /dev/null
+++ b/tools/Install-DotNetSdk.ps1
@@ -0,0 +1,421 @@
+#!/usr/bin/env pwsh
+
+<#
+.SYNOPSIS
+ Installs the .NET SDK specified in the global.json file at the root of this repository,
+ along with supporting .NET runtimes used for testing.
+.DESCRIPTION
+ This MAY not require elevation, as the SDK and runtimes are installed locally to this repo location,
+ unless `-InstallLocality machine` is specified.
+.PARAMETER InstallLocality
+ A value indicating whether dependencies should be installed locally to the repo or at a per-user location.
+ Per-user allows sharing the installed dependencies across repositories and allows use of a shared expanded package cache.
+ Visual Studio will only notice and use these SDKs/runtimes if VS is launched from the environment that runs this script.
+ Per-repo allows for high isolation, allowing for a more precise recreation of the environment within an Azure Pipelines build.
+ When using 'repo', environment variables are set to cause the locally installed dotnet SDK to be used.
+ Per-repo can lead to file locking issues when dotnet.exe is left running as a build server and can be mitigated by running `dotnet build-server shutdown`.
+ Per-machine requires elevation and will download and install all SDKs and runtimes to machine-wide locations so all applications can find it.
+.PARAMETER SdkOnly
+ Skips installing the runtime.
+.PARAMETER IncludeX86
+ Installs a x86 SDK and runtimes in addition to the x64 ones. Only supported on Windows. Ignored on others.
+.PARAMETER IncludeAspNetCore
+ Installs the ASP.NET Core runtime along with the .NET runtime.
+#>
+[CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Medium')]
+Param (
+ [ValidateSet('repo','user','machine')]
+ [string]$InstallLocality='user',
+ [switch]$SdkOnly,
+ [switch]$IncludeX86,
+ [switch]$IncludeAspNetCore
+)
+
+$DotNetInstallScriptRoot = "$PSScriptRoot/../obj/tools"
+if (!(Test-Path $DotNetInstallScriptRoot)) { New-Item -ItemType Directory -Path $DotNetInstallScriptRoot -WhatIf:$false | Out-Null }
+$DotNetInstallScriptRoot = Resolve-Path $DotNetInstallScriptRoot
+
+# Look up actual required .NET SDK version from global.json
+$sdkVersion = & "$PSScriptRoot/../azure-pipelines/variables/DotNetSdkVersion.ps1"
+
+If ($IncludeX86 -and ($IsMacOS -or $IsLinux)) {
+ Write-Verbose "Ignoring -IncludeX86 switch because 32-bit runtimes are only supported on Windows."
+ $IncludeX86 = $false
+}
+
+$arch = [System.Runtime.InteropServices.RuntimeInformation]::ProcessArchitecture
+if (!$arch) { # Windows Powershell leaves this blank
+ $arch = 'x64'
+ if ($env:PROCESSOR_ARCHITECTURE -eq 'ARM64') { $arch = 'ARM64' }
+ if (${env:ProgramFiles(Arm)}) { $arch = 'ARM64' }
+}
+
+# Search for all .NET runtime versions referenced from MSBuild projects and arrange to install them.
+$runtimeVersions = @()
+$windowsDesktopRuntimeVersions = @()
+$aspnetRuntimeVersions = @()
+if (!$SdkOnly) {
+ Get-ChildItem "$PSScriptRoot\..\src\*.*proj","$PSScriptRoot\..\test\*.*proj","$PSScriptRoot\..\Directory.Build.props" -Recurse |% {
+ $projXml = [xml](Get-Content -Path $_)
+ $pg = $projXml.Project.PropertyGroup
+ if ($pg) {
+ $targetFrameworks = @()
+ $tf = $pg.TargetFramework
+ $targetFrameworks += $tf
+ $tfs = $pg.TargetFrameworks
+ if ($tfs) {
+ $targetFrameworks = $tfs -Split ';'
+ }
+ }
+ $targetFrameworks |? { $_ -match 'net(?:coreapp)?(\d+\.\d+)' } |% {
+ $v = $Matches[1]
+ $runtimeVersions += $v
+ $aspnetRuntimeVersions += $v
+ if ($v -ge '3.0' -and -not ($IsMacOS -or $IsLinux)) {
+ $windowsDesktopRuntimeVersions += $v
+ }
+ }
+
+ # Add target frameworks of the form: netXX
+ $targetFrameworks |? { $_ -match 'net(\d+\.\d+)' } |% {
+ $v = $Matches[1]
+ $runtimeVersions += $v
+ $aspnetRuntimeVersions += $v
+ if (-not ($IsMacOS -or $IsLinux)) {
+ $windowsDesktopRuntimeVersions += $v
+ }
+ }
+ }
+}
+
+if (!$IncludeAspNetCore) {
+ $aspnetRuntimeVersions = @()
+}
+
+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
+}
+
+Function Get-InstallerExe(
+ $Version,
+ $Architecture,
+ [ValidateSet('Sdk','Runtime','WindowsDesktop')]
+ [string]$sku
+) {
+ # Get the latest/actual version for the specified one
+ $TypedVersion = $null
+ if (![Version]::TryParse($Version, [ref] $TypedVersion)) {
+ Write-Error "Unable to parse $Version into an a.b.c.d version. This version cannot be installed machine-wide."
+ exit 1
+ }
+
+ if ($TypedVersion.Build -eq -1) {
+ $versionInfo = -Split (Invoke-WebRequest -Uri "https://dotnetcli.blob.core.windows.net/dotnet/$sku/$Version/latest.version" -UseBasicParsing)
+ $Version = $versionInfo[-1]
+ }
+
+ $majorMinor = "$($TypedVersion.Major).$($TypedVersion.Minor)"
+ $ReleasesFile = Join-Path $DotNetInstallScriptRoot "$majorMinor\releases.json"
+ if (!(Test-Path $ReleasesFile)) {
+ Get-FileFromWeb -Uri "https://dotnetcli.blob.core.windows.net/dotnet/release-metadata/$majorMinor/releases.json" -OutDir (Split-Path $ReleasesFile) | Out-Null
+ }
+
+ $releases = Get-Content $ReleasesFile | ConvertFrom-Json
+ $url = $null
+ foreach ($release in $releases.releases) {
+ $filesElement = $null
+ if ($release.$sku.version -eq $Version) {
+ $filesElement = $release.$sku.files
+ }
+ if (!$filesElement -and ($sku -eq 'sdk') -and $release.sdks) {
+ foreach ($sdk in $release.sdks) {
+ if ($sdk.version -eq $Version) {
+ $filesElement = $sdk.files
+ break
+ }
+ }
+ }
+
+ if ($filesElement) {
+ foreach ($file in $filesElement) {
+ if ($file.rid -eq "win-$Architecture") {
+ $url = $file.url
+ Break
+ }
+ }
+
+ if ($url) {
+ Break
+ }
+ }
+ }
+
+ if ($url) {
+ Get-FileFromWeb -Uri $url -OutDir $DotNetInstallScriptRoot
+ } else {
+ throw "Unable to find release of $sku v$Version"
+ }
+}
+
+Function Install-DotNet($Version, $Architecture, [ValidateSet('Sdk','Runtime','WindowsDesktop','AspNetCore')][string]$sku = 'Sdk') {
+ Write-Host "Downloading .NET $sku $Version..."
+ $Installer = Get-InstallerExe -Version $Version -Architecture $Architecture -sku $sku
+ Write-Host "Installing .NET $sku $Version..."
+ cmd /c start /wait $Installer /install /passive /norestart
+ if ($LASTEXITCODE -eq 3010) {
+ Write-Verbose "Restart required"
+ } elseif ($LASTEXITCODE -ne 0) {
+ throw "Failure to install .NET SDK"
+ }
+}
+
+$switches = @()
+$envVars = @{
+ # For locally installed dotnet, skip first time experience which takes a long time
+ 'DOTNET_SKIP_FIRST_TIME_EXPERIENCE' = 'true';
+}
+
+if ($InstallLocality -eq 'machine') {
+ if ($IsMacOS -or $IsLinux) {
+ $DotNetInstallDir = '/usr/share/dotnet'
+ } else {
+ $restartRequired = $false
+ if ($PSCmdlet.ShouldProcess(".NET SDK $sdkVersion", "Install")) {
+ Install-DotNet -Version $sdkVersion -Architecture $arch
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+
+ if ($IncludeX86) {
+ Install-DotNet -Version $sdkVersion -Architecture x86
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+ }
+ }
+
+ $runtimeVersions | Sort-Object | Get-Unique |% {
+ if ($PSCmdlet.ShouldProcess(".NET runtime $_", "Install")) {
+ Install-DotNet -Version $_ -sku Runtime -Architecture $arch
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+
+ if ($IncludeX86) {
+ Install-DotNet -Version $_ -sku Runtime -Architecture x86
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+ }
+ }
+ }
+
+ $windowsDesktopRuntimeVersions | Sort-Object | Get-Unique |% {
+ if ($PSCmdlet.ShouldProcess(".NET Windows Desktop $_", "Install")) {
+ Install-DotNet -Version $_ -sku WindowsDesktop -Architecture $arch
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+
+ if ($IncludeX86) {
+ Install-DotNet -Version $_ -sku WindowsDesktop -Architecture x86
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+ }
+ }
+ }
+
+ $aspnetRuntimeVersions | Sort-Object | Get-Unique |% {
+ if ($PSCmdlet.ShouldProcess("ASP.NET Core $_", "Install")) {
+ Install-DotNet -Version $_ -sku AspNetCore -Architecture $arch
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+
+ if ($IncludeX86) {
+ Install-DotNet -Version $_ -sku AspNetCore -Architecture x86
+ $restartRequired = $restartRequired -or ($LASTEXITCODE -eq 3010)
+ }
+ }
+ }
+ if ($restartRequired) {
+ Write-Host -ForegroundColor Yellow "System restart required"
+ Exit 3010
+ }
+
+ return
+ }
+} elseif ($InstallLocality -eq 'repo') {
+ $DotNetInstallDir = "$DotNetInstallScriptRoot/.dotnet"
+ $DotNetX86InstallDir = "$DotNetInstallScriptRoot/x86/.dotnet"
+} elseif ($env:AGENT_TOOLSDIRECTORY) {
+ $DotNetInstallDir = "$env:AGENT_TOOLSDIRECTORY/dotnet"
+ $DotNetX86InstallDir = "$env:AGENT_TOOLSDIRECTORY/x86/dotnet"
+} else {
+ $DotNetInstallDir = Join-Path $HOME .dotnet
+}
+
+if ($DotNetInstallDir) {
+ if (!(Test-Path $DotNetInstallDir)) { New-Item -ItemType Directory -Path $DotNetInstallDir }
+ $DotNetInstallDir = Resolve-Path $DotNetInstallDir
+ Write-Host "Installing .NET SDK and runtimes to $DotNetInstallDir" -ForegroundColor Blue
+ $envVars['DOTNET_MULTILEVEL_LOOKUP'] = '0'
+ $envVars['DOTNET_ROOT'] = $DotNetInstallDir
+}
+
+if ($IncludeX86) {
+ if ($DotNetX86InstallDir) {
+ if (!(Test-Path $DotNetX86InstallDir)) { New-Item -ItemType Directory -Path $DotNetX86InstallDir }
+ $DotNetX86InstallDir = Resolve-Path $DotNetX86InstallDir
+ Write-Host "Installing x86 .NET SDK and runtimes to $DotNetX86InstallDir" -ForegroundColor Blue
+ } else {
+ # Only machine-wide or repo-wide installations can handle two unique dotnet.exe architectures.
+ Write-Error "The installation location or OS isn't supported for x86 installation. Try a different -InstallLocality value."
+ return 1
+ }
+}
+
+if ($IsMacOS -or $IsLinux) {
+ $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/0b09de9bc136cacb5f849a6957ebd4062173c148/src/dotnet-install.sh"
+ $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.sh"
+} else {
+ $DownloadUri = "https://raw.githubusercontent.com/dotnet/install-scripts/0b09de9bc136cacb5f849a6957ebd4062173c148/src/dotnet-install.ps1"
+ $DotNetInstallScriptPath = "$DotNetInstallScriptRoot/dotnet-install.ps1"
+}
+
+if (-not (Test-Path $DotNetInstallScriptPath)) {
+ Invoke-WebRequest -Uri $DownloadUri -OutFile $DotNetInstallScriptPath -UseBasicParsing
+ if ($IsMacOS -or $IsLinux) {
+ chmod +x $DotNetInstallScriptPath
+ }
+}
+
+# In case the script we invoke is in a directory with spaces, wrap it with single quotes.
+# In case the path includes single quotes, escape them.
+$DotNetInstallScriptPathExpression = $DotNetInstallScriptPath.Replace("'", "''")
+$DotNetInstallScriptPathExpression = "& '$DotNetInstallScriptPathExpression'"
+
+$anythingInstalled = $false
+$global:LASTEXITCODE = 0
+
+if ($PSCmdlet.ShouldProcess(".NET SDK $sdkVersion", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+} else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture $arch -InstallDir $DotNetInstallDir $switches -DryRun"
+}
+
+if ($IncludeX86) {
+ if ($PSCmdlet.ShouldProcess(".NET x86 SDK $sdkVersion", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET x86 SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ } else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Version $sdkVersion -Architecture x86 -InstallDir $DotNetX86InstallDir $switches -DryRun"
+ }
+}
+
+$dotnetRuntimeSwitches = $switches + '-Runtime','dotnet'
+
+$runtimeVersions | Sort-Object -Unique |% {
+ if ($PSCmdlet.ShouldProcess(".NET $Arch runtime $_", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $dotnetRuntimeSwitches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ } else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $dotnetRuntimeSwitches -DryRun"
+ }
+
+ if ($IncludeX86) {
+ if ($PSCmdlet.ShouldProcess(".NET x86 runtime $_", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $dotnetRuntimeSwitches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ } else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $dotnetRuntimeSwitches -DryRun"
+ }
+ }
+}
+
+$windowsDesktopRuntimeSwitches = $switches + '-Runtime','windowsdesktop'
+
+$windowsDesktopRuntimeVersions | Sort-Object -Unique |% {
+ if ($PSCmdlet.ShouldProcess(".NET WindowsDesktop $arch runtime $_", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $windowsDesktopRuntimeSwitches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ } else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $windowsDesktopRuntimeSwitches -DryRun"
+ }
+
+ if ($IncludeX86) {
+ if ($PSCmdlet.ShouldProcess(".NET WindowsDesktop x86 runtime $_", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $windowsDesktopRuntimeSwitches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ } else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $windowsDesktopRuntimeSwitches -DryRun"
+ }
+ }
+}
+
+$aspnetRuntimeSwitches = $switches + '-Runtime','aspnetcore'
+
+$aspnetRuntimeVersions | Sort-Object -Unique |% {
+ if ($PSCmdlet.ShouldProcess(".NET ASP.NET Core $arch runtime $_", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $aspnetRuntimeSwitches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ } else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture $arch -InstallDir $DotNetInstallDir $aspnetRuntimeSwitches -DryRun"
+ }
+
+ if ($IncludeX86) {
+ if ($PSCmdlet.ShouldProcess(".NET ASP.NET Core x86 runtime $_", "Install")) {
+ $anythingInstalled = $true
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $aspnetRuntimeSwitches"
+
+ if ($LASTEXITCODE -ne 0) {
+ Write-Error ".NET SDK installation failure: $LASTEXITCODE"
+ exit $LASTEXITCODE
+ }
+ } else {
+ Invoke-Expression -Command "$DotNetInstallScriptPathExpression -Channel $_ -Architecture x86 -InstallDir $DotNetX86InstallDir $aspnetRuntimeSwitches -DryRun"
+ }
+ }
+}
+
+if ($PSCmdlet.ShouldProcess("Set DOTNET environment variables to discover these installed runtimes?")) {
+ & "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars -PrependPath $DotNetInstallDir | Out-Null
+}
+
+if ($anythingInstalled -and ($InstallLocality -ne 'machine') -and !$env:TF_BUILD -and !$env:GITHUB_ACTIONS) {
+ Write-Warning ".NET runtimes or SDKs were installed to a non-machine location. Perform your builds or open Visual Studio from this same environment in order for tools to discover the location of these dependencies."
+}
diff --git a/tools/Install-NuGetCredProvider.ps1 b/tools/Install-NuGetCredProvider.ps1
new file mode 100644
index 00000000..857324b6
--- /dev/null
+++ b/tools/Install-NuGetCredProvider.ps1
@@ -0,0 +1,76 @@
+#!/usr/bin/env pwsh
+
+<#
+.SYNOPSIS
+ Downloads and installs the Microsoft Artifacts Credential Provider
+ from https://github.com/microsoft/artifacts-credprovider
+ to assist in authenticating to Azure Artifact feeds in interactive development
+ or unattended build agents.
+.PARAMETER Force
+ Forces install of the CredProvider plugin even if one already exists. This is useful to upgrade an older version.
+.PARAMETER AccessToken
+ An optional access token for authenticating to Azure Artifacts authenticated feeds.
+#>
+[CmdletBinding()]
+Param (
+ [Parameter()]
+ [switch]$Force,
+ [Parameter()]
+ [string]$AccessToken
+)
+
+$envVars = @{}
+
+$toolsPath = & "$PSScriptRoot\..\azure-pipelines\Get-TempToolsPath.ps1"
+
+if ($IsMacOS -or $IsLinux) {
+ $installerScript = "installcredprovider.sh"
+ $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh"
+} else {
+ $installerScript = "installcredprovider.ps1"
+ $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1"
+}
+
+$installerScript = Join-Path $toolsPath $installerScript
+
+if (!(Test-Path $installerScript) -or $Force) {
+ Invoke-WebRequest $sourceUrl -OutFile $installerScript
+}
+
+$installerScript = (Resolve-Path $installerScript).Path
+
+if ($IsMacOS -or $IsLinux) {
+ chmod u+x $installerScript
+}
+
+& $installerScript -Force:$Force -AddNetfx -InstallNet8
+
+if ($AccessToken) {
+ $endpoints = @()
+
+ $endpointURIs = @()
+ Get-ChildItem "$PSScriptRoot\..\nuget.config" -Recurse |% {
+ $nugetConfig = [xml](Get-Content -Path $_)
+
+ $nugetConfig.configuration.packageSources.add |? { ($_.value -match '^https://pkgs\.dev\.azure\.com/') -or ($_.value -match '^https://[\w\-]+\.pkgs\.visualstudio\.com/') } |% {
+ if ($endpointURIs -notcontains $_.Value) {
+ $endpointURIs += $_.Value
+ $endpoint = New-Object -TypeName PSObject
+ Add-Member -InputObject $endpoint -MemberType NoteProperty -Name endpoint -Value $_.value
+ Add-Member -InputObject $endpoint -MemberType NoteProperty -Name username -Value ado
+ Add-Member -InputObject $endpoint -MemberType NoteProperty -Name password -Value $AccessToken
+ $endpoints += $endpoint
+ }
+ }
+ }
+
+ $auth = New-Object -TypeName PSObject
+ Add-Member -InputObject $auth -MemberType NoteProperty -Name endpointCredentials -Value $endpoints
+
+ $authJson = ConvertTo-Json -InputObject $auth
+ $envVars += @{
+ 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'=$authJson;
+ }
+}
+
+& "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars | Out-Null
diff --git a/tools/MergeFrom-Template.ps1 b/tools/MergeFrom-Template.ps1
new file mode 100644
index 00000000..3f721c6a
--- /dev/null
+++ b/tools/MergeFrom-Template.ps1
@@ -0,0 +1,79 @@
+
+<#
+.SYNOPSIS
+ Merges the latest changes from Library.Template into HEAD of this repo.
+.PARAMETER LocalBranch
+ The name of the local branch to create at HEAD and use to merge into from Library.Template.
+#>
+[CmdletBinding(SupportsShouldProcess = $true)]
+Param(
+ [string]$LocalBranch = "dev/$($env:USERNAME)/libtemplateUpdate"
+)
+
+Function Spawn-Tool($command, $commandArgs, $workingDirectory, $allowFailures) {
+ if ($workingDirectory) {
+ Push-Location $workingDirectory
+ }
+ try {
+ if ($env:TF_BUILD) {
+ Write-Host "$pwd >"
+ Write-Host "##[command]$command $commandArgs"
+ }
+ else {
+ Write-Host "$command $commandArgs" -ForegroundColor Yellow
+ }
+ if ($commandArgs) {
+ & $command @commandArgs
+ } else {
+ Invoke-Expression $command
+ }
+ if ((!$allowFailures) -and ($LASTEXITCODE -ne 0)) { exit $LASTEXITCODE }
+ }
+ finally {
+ if ($workingDirectory) {
+ Pop-Location
+ }
+ }
+}
+
+$remoteBranch = & $PSScriptRoot\..\azure-pipelines\Get-LibTemplateBasis.ps1 -ErrorIfNotRelated
+if ($LASTEXITCODE -ne 0) {
+ exit $LASTEXITCODE
+}
+
+$LibTemplateUrl = 'https://github.com/aarnott/Library.Template'
+Spawn-Tool 'git' ('fetch', $LibTemplateUrl, $remoteBranch)
+$SourceCommit = Spawn-Tool 'git' ('rev-parse', 'FETCH_HEAD')
+$BaseBranch = Spawn-Tool 'git' ('branch', '--show-current')
+$SourceCommitUrl = "$LibTemplateUrl/commit/$SourceCommit"
+
+# To reduce the odds of merge conflicts at this stage, we always move HEAD to the last successful merge.
+$basis = Spawn-Tool 'git' ('rev-parse', 'HEAD') # TODO: consider improving this later
+
+Write-Host "Merging the $remoteBranch branch of Library.Template ($SourceCommit) into local repo $basis" -ForegroundColor Green
+
+Spawn-Tool 'git' ('checkout', '-b', $LocalBranch, $basis) $null $true
+if ($LASTEXITCODE -eq 128) {
+ Spawn-Tool 'git' ('checkout', $LocalBranch)
+ Spawn-Tool 'git' ('merge', $basis)
+}
+
+Spawn-Tool 'git' ('merge', 'FETCH_HEAD', '--no-ff', '-m', "Merge the $remoteBranch branch from $LibTemplateUrl`n`nSpecifically, this merges [$SourceCommit from that repo]($SourceCommitUrl).")
+if ($LASTEXITCODE -eq 1) {
+ Write-Error "Merge conflict detected. Manual resolution required."
+ exit 1
+}
+elseif ($LASTEXITCODE -ne 0) {
+ Write-Error "Merge failed with exit code $LASTEXITCODE."
+ exit $LASTEXITCODE
+}
+
+$result = New-Object PSObject -Property @{
+ BaseBranch = $BaseBranch # The original branch that was checked out when the script ran.
+ LocalBranch = $LocalBranch # The name of the local branch that was created before the merge.
+ SourceCommit = $SourceCommit # The commit from Library.Template that was merged in.
+ SourceBranch = $remoteBranch # The branch from Library.Template that was merged in.
+}
+
+Write-Host $result
+Write-Output $result
diff --git a/tools/Set-EnvVars.ps1 b/tools/Set-EnvVars.ps1
new file mode 100644
index 00000000..3f6f86ba
--- /dev/null
+++ b/tools/Set-EnvVars.ps1
@@ -0,0 +1,97 @@
+<#
+.SYNOPSIS
+ Set environment variables in the environment.
+ Azure Pipeline and CMD environments are considered.
+.PARAMETER Variables
+ A hashtable of variables to be set.
+.PARAMETER PrependPath
+ A set of paths to prepend to the PATH environment variable.
+.OUTPUTS
+ A boolean indicating whether the environment variables can be expected to propagate to the caller's environment.
+.DESCRIPTION
+ The CmdEnvScriptPath environment variable may be optionally set to a path to a cmd shell script to be created (or appended to if it already exists) that will set the environment variables in cmd.exe that are set within the PowerShell environment.
+ This is used by init.cmd in order to reapply any new environment variables to the parent cmd.exe process that were set in the powershell child process.
+#>
+[CmdletBinding(SupportsShouldProcess=$true)]
+Param(
+ [Parameter(Mandatory=$true, Position=1)]
+ $Variables,
+ [string[]]$PrependPath
+)
+
+if ($Variables.Count -eq 0) {
+ return $true
+}
+
+$cmdInstructions = !$env:TF_BUILD -and !$env:GITHUB_ACTIONS -and !$env:CmdEnvScriptPath -and ($env:PS1UnderCmd -eq '1')
+if ($cmdInstructions) {
+ Write-Warning "Environment variables have been set that will be lost because you're running under cmd.exe"
+ Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue
+} else {
+ Write-Host "Environment variables set:" -ForegroundColor Blue
+ Write-Host ($Variables | Out-String)
+ if ($PrependPath) {
+ Write-Host "Paths prepended to PATH: $PrependPath"
+ }
+}
+
+if ($env:TF_BUILD) {
+ Write-Host "Azure Pipelines detected. Logging commands will be used to propagate environment variables and prepend path."
+}
+
+if ($env:GITHUB_ACTIONS) {
+ Write-Host "GitHub Actions detected. Logging commands will be used to propagate environment variables and prepend path."
+}
+
+$CmdEnvScript = ''
+$Variables.GetEnumerator() |% {
+ Set-Item -Path env:$($_.Key) -Value $_.Value
+
+ # If we're running in a cloud CI, set these environment variables so they propagate.
+ if ($env:TF_BUILD) {
+ Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)"
+ }
+ if ($env:GITHUB_ACTIONS) {
+ Add-Content -Path $env:GITHUB_ENV -Value "$($_.Key)=$($_.Value)"
+ }
+
+ if ($cmdInstructions) {
+ Write-Host "SET $($_.Key)=$($_.Value)"
+ }
+
+ $CmdEnvScript += "SET $($_.Key)=$($_.Value)`r`n"
+}
+
+$pathDelimiter = ';'
+if ($IsMacOS -or $IsLinux) {
+ $pathDelimiter = ':'
+}
+
+if ($PrependPath) {
+ $PrependPath |% {
+ $newPathValue = "$_$pathDelimiter$env:PATH"
+ Set-Item -Path env:PATH -Value $newPathValue
+ if ($cmdInstructions) {
+ Write-Host "SET PATH=$newPathValue"
+ }
+
+ if ($env:TF_BUILD) {
+ Write-Host "##vso[task.prependpath]$_"
+ }
+ if ($env:GITHUB_ACTIONS) {
+ Add-Content -Path $env:GITHUB_PATH -Value $_
+ }
+
+ $CmdEnvScript += "SET PATH=$_$pathDelimiter%PATH%"
+ }
+}
+
+if ($env:CmdEnvScriptPath) {
+ if (Test-Path $env:CmdEnvScriptPath) {
+ $CmdEnvScript = (Get-Content -Path $env:CmdEnvScriptPath) + $CmdEnvScript
+ }
+
+ Set-Content -Path $env:CmdEnvScriptPath -Value $CmdEnvScript
+}
+
+return !$cmdInstructions