├── .azuredevops └── dependabot.yml ├── .config └── dotnet-tools.json ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .editorconfig ├── .gitattributes ├── .github ├── .editorconfig ├── actions │ └── publish-artifacts │ │ └── action.yaml ├── renovate.json └── workflows │ ├── build.yml │ ├── docs.yml │ ├── docs_validate.yml │ └── libtemplate-update.yml ├── .gitignore ├── .vscode ├── extensions.json ├── launch.json ├── settings.json └── tasks.json ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Directory.Build.props ├── Directory.Build.rsp ├── Directory.Build.targets ├── Directory.Packages.props ├── LICENSE ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── azure-pipelines.yml ├── azure-pipelines ├── Archive-SourceCode.ps1 ├── BuildStageVariables.yml ├── Get-InsertionPRId.ps1 ├── GlobalVariables.yml ├── Install-NuGetPackage.ps1 ├── Merge-CodeCoverage.ps1 ├── NuGetSbom.targets ├── OptProf.yml ├── OptProf_part2.yml ├── PoliCheckExclusions.xml ├── PostPRMessage.ps1 ├── TSAOptions.json ├── WIFtoPATauth.yml ├── apiscan.yml ├── archive-sourcecode.yml ├── build.yml ├── dotnet.yml ├── falsepositives.gdnsuppress ├── install-dependencies.yml ├── libtemplate-update.yml ├── microbuild.after.yml ├── microbuild.before.yml ├── no_authenticode.txt ├── no_strongname.txt ├── official.yml ├── prepare-insertion-stages.yml ├── publish-codecoverage.yml ├── publish-symbols.yml ├── publish_artifacts.ps1 ├── release-deployment-prep.yml ├── release.yml ├── schedule-only-steps.yml ├── unofficial.yml ├── vs-insertion.yml └── vs-validation.yml ├── docfx ├── .gitignore ├── docfx.json ├── docs │ ├── features.md │ ├── getting-started.md │ └── toc.yml ├── index.md └── toc.yml ├── global.json ├── init.cmd ├── init.ps1 ├── nuget.config ├── src ├── .editorconfig ├── AssemblyInfo.cs ├── AssemblyInfo.vb ├── Directory.Build.props ├── Directory.Build.targets ├── Microsoft.VisualStudio.Jdt │ ├── IJsonTransformationLogger.cs │ ├── JdtException.cs │ ├── JdtExtensions.cs │ ├── JdtUtilities.cs │ ├── JsonTransformation.cs │ ├── JsonTransformationContextLogger.cs │ ├── Microsoft.VisualStudio.Jdt.csproj │ ├── Processors │ │ ├── Attributes │ │ │ ├── JdtAttributeExtensions.cs │ │ │ └── JdtAttributeValidator.cs │ │ ├── JdtArrayProcessor.cs │ │ ├── JdtDefault.cs │ │ ├── JdtMerge.cs │ │ ├── JdtProcessor.ProcessorChain.cs │ │ ├── JdtProcessor.cs │ │ ├── JdtRecurse.cs │ │ ├── JdtRemove.cs │ │ ├── JdtRename.cs │ │ ├── JdtReplace.cs │ │ └── JdtValidator.cs │ ├── Resources.Designer.cs │ └── Resources.resx ├── OptProf.targets ├── VSInsertionMetadata │ ├── Library.VSInsertionMetadata.proj │ ├── ProfilingInputs.props │ └── VSInsertionMetadata.targets ├── jdt.sln ├── stylecop.json └── version.json ├── test ├── .editorconfig ├── Directory.Build.props ├── Directory.Build.targets └── Microsoft.VisualStudio.Jdt.Tests │ ├── App.config │ ├── Inputs │ ├── Default │ │ ├── Array.Merge.Expected.json │ │ ├── Array.Merge.Transform.json │ │ ├── Array.Replace.Expected.json │ │ ├── Array.Replace.Transform.json │ │ ├── Array.Source.json │ │ ├── Object.Merge.Expected.json │ │ ├── Object.Merge.Transform.json │ │ ├── Object.Replace.Expected.json │ │ ├── Object.Replace.Transform.json │ │ ├── Object.Source.json │ │ ├── Primitive.AddArray.Expected.json │ │ ├── Primitive.AddArray.Transform.json │ │ ├── Primitive.AddObject.Expected.json │ │ ├── Primitive.AddObject.Transform.json │ │ ├── Primitive.AddPrimitive.Expected.json │ │ ├── Primitive.AddPrimitive.Transform.json │ │ ├── Primitive.Replace.Expected.json │ │ ├── Primitive.Replace.Transform.json │ │ └── Primitive.Source.json │ ├── Merge │ │ ├── Object.MergeObjects.Expected.json │ │ ├── Object.MergeObjects.Transform.json │ │ ├── Object.Source.json │ │ ├── Object.UsingDirectPath.Expected.json │ │ ├── Object.UsingDirectPath.Transform.json │ │ ├── Primitive.MergeObjects.Expected.json │ │ ├── Primitive.MergeObjects.Transform.json │ │ ├── Primitive.MergePrimitives.Expected.json │ │ ├── Primitive.MergePrimitives.Transform.json │ │ ├── Primitive.Source.json │ │ ├── Primitive.UsingSimplePath.Expected.json │ │ └── Primitive.UsingSimplePath.Transform.json │ ├── Remove │ │ ├── Array.DirectPath.Expected.json │ │ ├── Array.DirectPath.Transform.json │ │ ├── Array.ScriptPath.Expected.json │ │ ├── Array.ScriptPath.Transform.json │ │ ├── Array.Source.json │ │ ├── Object.DirectPath.Expected.json │ │ ├── Object.DirectPath.Transform.json │ │ ├── Object.InObject.Expected.json │ │ ├── Object.InObject.Transform.json │ │ ├── Object.PathToItself.Expected.json │ │ ├── Object.PathToItself.Transform.json │ │ ├── Object.Source.json │ │ ├── Object.WithBool.Expected.json │ │ ├── Object.WithBool.Transform.json │ │ ├── Primitive.FromRoot.Expected.json │ │ ├── Primitive.FromRoot.Transform.json │ │ ├── Primitive.Source.json │ │ ├── Primitive.UsingPathArray.Expected.json │ │ ├── Primitive.UsingPathArray.Transform.json │ │ ├── Primitive.UsingSimpleArray.Expected.json │ │ ├── Primitive.UsingSimpleArray.Transform.json │ │ ├── Primitive.UsingSimplePath.Expected.json │ │ ├── Primitive.UsingSimplePath.Transform.json │ │ └── Skipped │ │ │ ├── Object.ScriptPath.Expected.json │ │ │ └── Object.ScriptPath.Transform.json │ ├── Rename │ │ ├── Array.DirectPath.Expected.json │ │ ├── Array.DirectPath.Transform.json │ │ ├── Array.ScriptPath.Expected.json │ │ ├── Array.ScriptPath.Transform .json │ │ ├── Array.Source.json │ │ ├── Object.InObject.Expected.json │ │ ├── Object.InObject.Transform.json │ │ ├── Object.Source.json │ │ ├── Object.UsingSimplePath.Expected.json │ │ ├── Object.UsingSimplePath.Transform.json │ │ ├── Object.WithChangingNames.Expected.json │ │ ├── Object.WithChangingNames.Transform.json │ │ ├── Primitive.FromRoot.Expected.json │ │ ├── Primitive.FromRoot.Transform.json │ │ ├── Primitive.Source.json │ │ ├── Primitive.UsingSimpleArray.Expected.json │ │ ├── Primitive.UsingSimpleArray.Transform.json │ │ ├── Primitive.UsingSimplePath.Expected.json │ │ └── Primitive.UsingSimplePath.Transform.json │ └── Replace │ │ ├── Array.DirectPath.Expected.json │ │ ├── Array.DirectPath.Transform.json │ │ ├── Array.ScriptPath.Expected.json │ │ ├── Array.ScriptPath.Transform.json │ │ ├── Array.Source.json │ │ ├── Object.Source.json │ │ ├── Object.WithArray.Expected.json │ │ ├── Object.WithArray.Transform.json │ │ ├── Object.WithObject.Expected.json │ │ ├── Object.WithObject.Transform.json │ │ ├── Object.WithPrimitive.Expected.json │ │ └── Object.WithPrimitive.Transform.json │ ├── JdtUtilitiesTest.cs │ ├── JsonTransformationTest.cs │ ├── JsonTransformationTestLogger.cs │ ├── Microsoft.VisualStudio.Jdt.Tests.csproj │ ├── ReadOnlyTempFile.cs │ ├── TransformTest.cs │ └── xunit.runner.json └── tools ├── Check-DotNetRuntime.ps1 ├── Check-DotNetSdk.ps1 ├── Convert-PDB.ps1 ├── Get-ArtifactsStagingDirectory.ps1 ├── Get-CodeCovTool.ps1 ├── Get-LibTemplateBasis.ps1 ├── Get-NuGetTool.ps1 ├── Get-ProcDump.ps1 ├── Get-SymbolFiles.ps1 ├── Get-TempToolsPath.ps1 ├── Install-DotNetSdk.ps1 ├── Install-NuGetCredProvider.ps1 ├── MergeFrom-Template.ps1 ├── Prepare-Legacy-Symbols.ps1 ├── Set-EnvVars.ps1 ├── artifacts ├── APIScanInputs.ps1 ├── LocBin.ps1 ├── VSInsertion.ps1 ├── Variables.ps1 ├── _all.ps1 ├── _stage_all.ps1 ├── build_logs.ps1 ├── coverageResults.ps1 ├── deployables.ps1 ├── projectAssetsJson.ps1 ├── symbols.ps1 ├── testResults.ps1 └── test_symbols.ps1 ├── dotnet-test-cloud.ps1 ├── publish-CodeCov.ps1 ├── test.runsettings └── variables ├── BusinessGroupName.ps1 ├── DotNetSdkVersion.ps1 ├── InsertJsonValues.ps1 ├── InsertPropsValues.ps1 ├── InsertTargetBranch.ps1 ├── InsertVersionsValues.ps1 ├── LocLanguages.ps1 ├── ProfilingInputsDropName.ps1 ├── SymbolsFeatureName.ps1 ├── VstsDropNames.ps1 ├── _all.ps1 └── _define.ps1 /.azuredevops/dependabot.yml: -------------------------------------------------------------------------------- 1 | # Please see the documentation for all configuration options: 2 | # https://eng.ms/docs/products/dependabot/configuration/version_updates 3 | 4 | version: 2 5 | updates: 6 | - package-ecosystem: nuget 7 | directory: / 8 | schedule: 9 | interval: monthly 10 | -------------------------------------------------------------------------------- /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "powershell": { 6 | "version": "7.5.0", 7 | "commands": [ 8 | "pwsh" 9 | ], 10 | "rollForward": false 11 | }, 12 | "dotnet-coverage": { 13 | "version": "17.14.2", 14 | "commands": [ 15 | "dotnet-coverage" 16 | ], 17 | "rollForward": false 18 | }, 19 | "nbgv": { 20 | "version": "3.7.115", 21 | "commands": [ 22 | "nbgv" 23 | ], 24 | "rollForward": false 25 | }, 26 | "docfx": { 27 | "version": "2.78.3", 28 | "commands": [ 29 | "docfx" 30 | ], 31 | "rollForward": false 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /.devcontainer/Dockerfile: -------------------------------------------------------------------------------- 1 | # Refer to https://hub.docker.com/_/microsoft-dotnet-sdk for available versions 2 | FROM mcr.microsoft.com/dotnet/sdk:9.0.202-noble@sha256:332e0362dd210a10348d436a5fb7f87aeec28c2c53ac2c3c2659e57c22294d0e 3 | 4 | # Installing mono makes `dotnet test` work without errors even for net472. 5 | # But installing it takes a long time, so it's excluded by default. 6 | #RUN apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 3FA7E0328081BFF6A14DA29AA6A19B38D3D831EF 7 | #RUN echo "deb https://download.mono-project.com/repo/ubuntu stable-bionic main" | tee /etc/apt/sources.list.d/mono-official-stable.list 8 | #RUN apt-get update 9 | #RUN DEBIAN_FRONTEND=noninteractive apt-get install -y mono-devel 10 | 11 | # Clear the NUGET_XMLDOC_MODE env var so xml api doc files get unpacked, allowing a rich experience in Intellisense. 12 | # See https://github.com/dotnet/dotnet-docker/issues/2790 for a discussion on this, where the prioritized use case 13 | # was *not* devcontainers, sadly. 14 | ENV NUGET_XMLDOC_MODE= 15 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Dev space", 3 | "dockerFile": "Dockerfile", 4 | "customizations": { 5 | "vscode": { 6 | "settings": { 7 | "terminal.integrated.shell.linux": "/usr/bin/pwsh" 8 | }, 9 | "extensions": [ 10 | "ms-azure-devops.azure-pipelines", 11 | "ms-dotnettools.csharp", 12 | "k--kato.docomment", 13 | "editorconfig.editorconfig", 14 | "esbenp.prettier-vscode", 15 | "pflannery.vscode-versionlens", 16 | "davidanson.vscode-markdownlint", 17 | "dotjoshjohnson.xml", 18 | "ms-vscode-remote.remote-containers", 19 | "ms-azuretools.vscode-docker", 20 | "tintoy.msbuild-project-tools" 21 | ] 22 | } 23 | }, 24 | "postCreateCommand": "./init.ps1 -InstallLocality machine" 25 | } 26 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | # Ensure shell scripts use LF line endings (linux only accepts LF) 7 | *.sh eol=lf 8 | *.ps1 eol=lf 9 | 10 | # The macOS codesign tool is extremely picky, and requires LF line endings. 11 | *.plist eol=lf 12 | 13 | ############################################################################### 14 | # Set default behavior for command prompt diff. 15 | # 16 | # This is need for earlier builds of msysgit that does not have it on by 17 | # default for csharp files. 18 | # Note: This is only used by command line 19 | ############################################################################### 20 | #*.cs diff=csharp 21 | 22 | ############################################################################### 23 | # Set the merge driver for project and solution files 24 | # 25 | # Merging from the command prompt will add diff markers to the files if there 26 | # are conflicts (Merging from VS is not affected by the settings below, in VS 27 | # the diff markers are never inserted). Diff markers may cause the following 28 | # file extensions to fail to load in VS. An alternative would be to treat 29 | # these files as binary and thus will always conflict and require user 30 | # intervention with every merge. To do so, just uncomment the entries below 31 | ############################################################################### 32 | #*.sln merge=binary 33 | #*.csproj merge=binary 34 | #*.vbproj merge=binary 35 | #*.vcxproj merge=binary 36 | #*.vcproj merge=binary 37 | #*.dbproj merge=binary 38 | #*.fsproj merge=binary 39 | #*.lsproj merge=binary 40 | #*.wixproj merge=binary 41 | #*.modelproj merge=binary 42 | #*.sqlproj merge=binary 43 | #*.wwaproj merge=binary 44 | 45 | ############################################################################### 46 | # behavior for image files 47 | # 48 | # image files are treated as binary by default. 49 | ############################################################################### 50 | #*.jpg binary 51 | #*.png binary 52 | #*.gif binary 53 | 54 | ############################################################################### 55 | # diff behavior for common document formats 56 | # 57 | # Convert binary document formats to text before diffing them. This feature 58 | # is only available from the command line. Turn it on by uncommenting the 59 | # entries below. 60 | ############################################################################### 61 | #*.doc diff=astextplain 62 | #*.DOC diff=astextplain 63 | #*.docx diff=astextplain 64 | #*.DOCX diff=astextplain 65 | #*.dot diff=astextplain 66 | #*.DOT diff=astextplain 67 | #*.pdf diff=astextplain 68 | #*.PDF diff=astextplain 69 | #*.rtf diff=astextplain 70 | #*.RTF diff=astextplain 71 | -------------------------------------------------------------------------------- /.github/.editorconfig: -------------------------------------------------------------------------------- 1 | [renovate.json*] 2 | indent_style = tab 3 | -------------------------------------------------------------------------------- /.github/actions/publish-artifacts/action.yaml: -------------------------------------------------------------------------------- 1 | name: Publish artifacts 2 | description: Publish artifacts 3 | 4 | runs: 5 | using: composite 6 | steps: 7 | - name: 📥 Collect artifacts 8 | run: tools/artifacts/_stage_all.ps1 9 | shell: pwsh 10 | if: always() 11 | 12 | # TODO: replace this hard-coded list with a loop that utilizes the NPM package at 13 | # https://github.com/actions/toolkit/tree/main/packages/artifact (or similar) to push the artifacts. 14 | 15 | - name: 📢 Upload project.assets.json files 16 | if: always() 17 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 18 | with: 19 | name: projectAssetsJson-${{ runner.os }} 20 | path: ${{ runner.temp }}/_artifacts/projectAssetsJson 21 | continue-on-error: true 22 | - name: 📢 Upload variables 23 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 24 | with: 25 | name: variables-${{ runner.os }} 26 | path: ${{ runner.temp }}/_artifacts/Variables 27 | continue-on-error: true 28 | - name: 📢 Upload build_logs 29 | if: always() 30 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 31 | with: 32 | name: build_logs-${{ runner.os }} 33 | path: ${{ runner.temp }}/_artifacts/build_logs 34 | continue-on-error: true 35 | - name: 📢 Upload testResults 36 | if: always() 37 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 38 | with: 39 | name: testResults-${{ runner.os }} 40 | path: ${{ runner.temp }}/_artifacts/testResults 41 | continue-on-error: true 42 | - name: 📢 Upload coverageResults 43 | if: always() 44 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 45 | with: 46 | name: coverageResults-${{ runner.os }} 47 | path: ${{ runner.temp }}/_artifacts/coverageResults 48 | continue-on-error: true 49 | - name: 📢 Upload symbols 50 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 51 | with: 52 | name: symbols-${{ runner.os }} 53 | path: ${{ runner.temp }}/_artifacts/symbols 54 | continue-on-error: true 55 | - name: 📢 Upload deployables 56 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 57 | with: 58 | name: deployables-${{ runner.os }} 59 | path: ${{ runner.temp }}/_artifacts/deployables 60 | if: always() 61 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>microsoft/vs-renovate-presets:microbuild", 5 | "github>microsoft/vs-renovate-presets:vs_main_dependencies" 6 | ], 7 | "packageRules": [] 8 | } 9 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: 📚 Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | 8 | # Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages 9 | permissions: 10 | actions: read 11 | pages: write 12 | id-token: write 13 | contents: read 14 | 15 | # Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. 16 | # However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. 17 | concurrency: 18 | group: pages 19 | cancel-in-progress: false 20 | 21 | jobs: 22 | publish-docs: 23 | environment: 24 | name: github-pages 25 | url: ${{ steps.deployment.outputs.page_url }} 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4 29 | with: 30 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work. 31 | - name: ⚙ Install prerequisites 32 | run: ./init.ps1 -UpgradePrerequisites 33 | 34 | - run: dotnet docfx docfx/docfx.json 35 | name: 📚 Generate documentation 36 | 37 | - name: Upload artifact 38 | uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa # v3 39 | with: 40 | path: docfx/_site 41 | 42 | - name: Deploy to GitHub Pages 43 | id: deployment 44 | uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4 45 | -------------------------------------------------------------------------------- /.github/workflows/docs_validate.yml: -------------------------------------------------------------------------------- 1 | name: 📃 Docfx Validate 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - main 8 | - microbuild 9 | 10 | jobs: 11 | build: 12 | name: 📚 Doc validation 13 | runs-on: ubuntu-24.04 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work. 18 | - name: 🔗 Markup Link Checker (mlc) 19 | uses: becheran/mlc@v0.21.0 20 | with: 21 | args: --do-not-warn-for-redirect-to https://learn.microsoft.com*,https://dotnet.microsoft.com/*,https://dev.azure.com/*,https://app.codecov.io/* -p docfx -i https://aka.ms/onboardsupport,https://aka.ms/spot,https://msrc.microsoft.com/*,https://www.microsoft.com/msrc*,https://microsoft.com/msrc* 22 | - name: ⚙ Install prerequisites 23 | run: | 24 | ./init.ps1 -UpgradePrerequisites 25 | dotnet --info 26 | shell: pwsh 27 | - name: 📚 Verify docfx build 28 | run: dotnet docfx docfx/docfx.json --warningsAsErrors --disableGitFeatures 29 | if: runner.os == 'Linux' 30 | -------------------------------------------------------------------------------- /.vscode/extensions.json: -------------------------------------------------------------------------------- 1 | { 2 | // See https://go.microsoft.com/fwlink/?LinkId=827846 to learn about workspace recommendations. 3 | // Extension identifier format: ${publisher}.${name}. Example: vscode.csharp 4 | // List of extensions which should be recommended for users of this workspace. 5 | "recommendations": [ 6 | "ms-azure-devops.azure-pipelines", 7 | "ms-dotnettools.csharp", 8 | "k--kato.docomment", 9 | "editorconfig.editorconfig", 10 | "esbenp.prettier-vscode", 11 | "pflannery.vscode-versionlens", 12 | "davidanson.vscode-markdownlint", 13 | "dotjoshjohnson.xml", 14 | "ms-vscode-remote.remote-containers", 15 | "ms-azuretools.vscode-docker", 16 | "tintoy.msbuild-project-tools" 17 | ], 18 | // List of extensions recommended by VS Code that should not be recommended for users of this workspace. 19 | "unwantedRecommendations": [] 20 | } 21 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to find out which attributes exist for C# debugging 3 | // Use hover for the description of the existing attributes 4 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": ".NET Core Attach", 9 | "type": "coreclr", 10 | "request": "attach", 11 | "processId": "${command:pickProcess}" 12 | } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.trimTrailingWhitespace": true, 3 | "files.insertFinalNewline": true, 4 | "files.trimFinalNewlines": true, 5 | "azure-pipelines.1ESPipelineTemplatesSchemaFile": true, 6 | "omnisharp.enableEditorConfigSupport": true, 7 | "omnisharp.enableRoslynAnalyzers": true, 8 | "dotnet.completion.showCompletionItemsFromUnimportedNamespaces": true, 9 | "editor.formatOnSave": true, 10 | "[xml]": { 11 | "editor.wordWrap": "off" 12 | }, 13 | // Treat these files as Azure Pipelines files 14 | "files.associations": { 15 | "**/azure-pipelines/**/*.yml": "azure-pipelines", 16 | "azure-pipelines.yml": "azure-pipelines" 17 | }, 18 | // Use Prettier as the default formatter for Azure Pipelines files. 19 | // Needs to be explicitly configured: https://github.com/Microsoft/azure-pipelines-vscode#document-formatting 20 | "[azure-pipelines]": { 21 | "editor.defaultFormatter": "esbenp.prettier-vscode", 22 | "editor.formatOnSave": false // enable this when they conform 23 | }, 24 | } 25 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "build", 6 | "command": "dotnet", 7 | "type": "process", 8 | "args": [ 9 | "build", 10 | "${workspaceFolder}", 11 | "/property:GenerateFullPaths=true", 12 | "/consoleloggerparameters:NoSummary" 13 | ], 14 | "problemMatcher": "$msCompile" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Microsoft Open Source Code of Conduct 2 | 3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 4 | 5 | Resources: 6 | 7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/) 8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) 9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns 10 | -------------------------------------------------------------------------------- /Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Debug 5 | $(MSBuildThisFileDirectory) 6 | $(RepoRootPath)obj\$([MSBuild]::MakeRelative($(RepoRootPath), $(MSBuildProjectDirectory)))\ 7 | $(RepoRootPath)bin\$(MSBuildProjectName)\ 8 | $(RepoRootPath)bin\Packages\$(Configuration)\NuGet\ 9 | $(RepoRootPath)bin\Packages\$(Configuration)\Vsix\$(Platform)\ 10 | enable 11 | enable 12 | latest 13 | true 14 | true 15 | true 16 | 17 | 18 | true 19 | 20 | 21 | 22 | false 23 | 24 | 25 | $(MSBuildThisFileDirectory) 26 | 27 | 28 | embedded 29 | 30 | https://github.com/microsoft/json-document-transforms 31 | Microsoft 32 | Microsoft 33 | © Microsoft Corporation. All rights reserved. 34 | MIT 35 | true 36 | true 37 | true 38 | snupkg 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | $(RepositoryUrl)/releases/tag/v$(Version) 57 | 58 | 59 | 60 | -------------------------------------------------------------------------------- /Directory.Build.rsp: -------------------------------------------------------------------------------- 1 | #------------------------------------------------------------------------------ 2 | # This file contains command-line options that MSBuild will process as part of 3 | # every build, unless the "/noautoresponse" switch is specified. 4 | # 5 | # MSBuild processes the options in this file first, before processing the 6 | # options on the command line. As a result, options on the command line can 7 | # override the options in this file. However, depending on the options being 8 | # set, the overriding can also result in conflicts. 9 | # 10 | # NOTE: The "/noautoresponse" switch cannot be specified in this file, nor in 11 | # any response file that is referenced by this file. 12 | #------------------------------------------------------------------------------ 13 | /nr:false 14 | /m 15 | /verbosity:minimal 16 | /clp:Summary;ForceNoAlign 17 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 13 5 | 16.9 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Directory.Packages.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true 6 | true 7 | 2.0.171 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | JSON Document Transforms 2 | 3 | MIT License 4 | 5 | Copyright (c) Microsoft Corporation. All rights reserved. 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining a copy 8 | of this software and associated documentation files (the "Software"), to deal 9 | in the Software without restriction, including without limitation the rights 10 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | copies of the Software, and to permit persons to whom the Software is 12 | furnished to do so, subject to the following conditions: 13 | 14 | The above copyright notice and this permission notice shall be included in all 15 | copies or substantial portions of the Software. 16 | 17 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | JSON Document Transfoms 2 | ============ 3 | [![NuGet package](https://img.shields.io/nuget/v/Microsoft.VisualStudio.Jdt.svg)](https://nuget.org/packages/Microsoft.VisualStudio.Jdt) 4 | [![Build status](https://ci.appveyor.com/api/projects/status/xi1ufnfhnhh5e31m/branch/master?svg=true)](https://ci.appveyor.com/project/jviau/json-document-transforms/branch/master) 5 | 6 | JSON Document Transforms (JDT) library. Perform transformations on JSON files using another JSON as the specification. This is the C# implementation. 7 | 8 | For more information on how JDT works, see the [JDT Wiki](https://github.com/Microsoft/json-document-transforms/wiki) 9 | 10 | This project has adopted the [Microsoft Open Source Code of 11 | Conduct](https://opensource.microsoft.com/codeofconduct/). 12 | For more information see the [Code of Conduct 13 | FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 14 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) 15 | with any additional questions or comments. 16 | 17 | ## Trademarks 18 | 19 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft trademarks or logos is subject to and must follow [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/legal/intellectualproperty/trademarks/usage/general). Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. Any use of third-party trademarks or logos are subject to those third-party's policies. 20 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Security 4 | 5 | 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/). 6 | 7 | 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. 8 | 9 | ## Reporting Security Issues 10 | 11 | **Please do not report security vulnerabilities through public GitHub issues.** 12 | 13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://msrc.microsoft.com/create-report). 14 | 15 | 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). 16 | 17 | 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). 18 | 19 | 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: 20 | 21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.) 22 | * Full paths of source file(s) related to the manifestation of the issue 23 | * The location of the affected source code (tag/branch/commit or direct URL) 24 | * Any special configuration required to reproduce the issue 25 | * Step-by-step instructions to reproduce the issue 26 | * Proof-of-concept or exploit code (if possible) 27 | * Impact of the issue, including how an attacker might exploit the issue 28 | 29 | This information will help us triage your report more quickly. 30 | 31 | 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. 32 | 33 | ## Preferred Languages 34 | 35 | We prefer all communications to be in English. 36 | 37 | ## Policy 38 | 39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://www.microsoft.com/msrc/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # Support 2 | 3 | ## How to file issues and get help 4 | 5 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 6 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 7 | feature request as a new Issue. 8 | 9 | For help and questions about using this project, please create an issue. 10 | 11 | ## Microsoft Support Policy 12 | 13 | Support for this **json-document-transforms** is limited to the resources listed above. 14 | -------------------------------------------------------------------------------- /azure-pipelines.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | batch: true 3 | branches: 4 | include: 5 | - main 6 | - 'v*.*' 7 | - microbuild 8 | - 'validate/*' 9 | paths: 10 | exclude: 11 | - doc/ 12 | - '*.md' 13 | - .vscode/ 14 | - .github/ 15 | - azure-pipelines/release.yml 16 | 17 | parameters: 18 | - name: EnableMacOSBuild 19 | displayName: Build on macOS 20 | type: boolean 21 | default: false # macOS is often bogged down in Azure Pipelines 22 | - name: RunTests 23 | displayName: Run tests 24 | type: boolean 25 | default: true 26 | 27 | variables: 28 | - template: /azure-pipelines/BuildStageVariables.yml@self 29 | 30 | jobs: 31 | - template: azure-pipelines/build.yml 32 | parameters: 33 | Is1ESPT: false 34 | EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }} 35 | RunTests: ${{ parameters.RunTests }} 36 | -------------------------------------------------------------------------------- /azure-pipelines/BuildStageVariables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true 3 | BuildConfiguration: Release 4 | NUGET_PACKAGES: $(Agent.TempDirectory)/.nuget/packages/ 5 | # codecov_token: 4dc9e7e2-6b01-4932-a180-847b52b43d35 # Get a new one from https://codecov.io/ 6 | -------------------------------------------------------------------------------- /azure-pipelines/Get-InsertionPRId.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Look up the pull request URL of the insertion PR. 4 | #> 5 | $stagingFolder = $env:BUILD_STAGINGDIRECTORY 6 | if (!$stagingFolder) { 7 | $stagingFolder = $env:SYSTEM_DEFAULTWORKINGDIRECTORY 8 | if (!$stagingFolder) { 9 | Write-Error "This script must be run in an Azure Pipeline." 10 | exit 1 11 | } 12 | } 13 | $markdownFolder = Join-Path $stagingFolder (Join-Path 'MicroBuild' 'Output') 14 | $markdownFile = Join-Path $markdownFolder 'PullRequestUrl.md' 15 | if (!(Test-Path $markdownFile)) { 16 | Write-Error "This script should be run after the MicroBuildInsertVsPayload task." 17 | exit 2 18 | } 19 | 20 | $insertionPRUrl = Get-Content $markdownFile 21 | if (!($insertionPRUrl -match 'https:.+?/pullrequest/(\d+)')) { 22 | Write-Error "Failed to parse pull request URL: $insertionPRUrl" 23 | exit 3 24 | } 25 | 26 | $Matches[1] 27 | -------------------------------------------------------------------------------- /azure-pipelines/GlobalVariables.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | # These variables are required for MicroBuild tasks 3 | TeamName: VS IDE 4 | TeamEmail: vsidemicrobuild@microsoft.com 5 | # These variables influence insertion pipelines 6 | ContainsVsix: false # This should be true when the repo builds a VSIX that should be inserted to VS. 7 | -------------------------------------------------------------------------------- /azure-pipelines/Install-NuGetPackage.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Installs a NuGet package. 4 | .PARAMETER PackageID 5 | The Package ID to install. 6 | .PARAMETER Version 7 | The version of the package to install. If unspecified, the latest stable release is installed. 8 | .PARAMETER Source 9 | The package source feed to find the package to install from. 10 | .PARAMETER PackagesDir 11 | The directory to install the package to. By default, it uses the Packages folder at the root of the repo. 12 | .PARAMETER ConfigFile 13 | The nuget.config file to use. By default, it uses :/nuget.config. 14 | .OUTPUTS 15 | System.String. The path to the installed package. 16 | #> 17 | [CmdletBinding(SupportsShouldProcess=$true,ConfirmImpact='Low')] 18 | Param( 19 | [Parameter(Position=1,Mandatory=$true)] 20 | [string]$PackageId, 21 | [Parameter()] 22 | [string]$Version, 23 | [Parameter()] 24 | [string]$Source, 25 | [Parameter()] 26 | [switch]$Prerelease, 27 | [Parameter()] 28 | [string]$PackagesDir="$PSScriptRoot\..\packages", 29 | [Parameter()] 30 | [string]$ConfigFile="$PSScriptRoot\..\nuget.config", 31 | [Parameter()] 32 | [ValidateSet('Quiet','Normal','Detailed')] 33 | [string]$Verbosity='normal' 34 | ) 35 | 36 | $nugetPath = & "$PSScriptRoot\..\tools\Get-NuGetTool.ps1" 37 | 38 | try { 39 | Write-Verbose "Installing $PackageId..." 40 | $nugetArgs = "Install",$PackageId,"-OutputDirectory",$PackagesDir,'-ConfigFile',$ConfigFile 41 | if ($Version) { $nugetArgs += "-Version",$Version } 42 | if ($Source) { $nugetArgs += "-FallbackSource",$Source } 43 | if ($Prerelease) { $nugetArgs += "-Prerelease" } 44 | $nugetArgs += '-Verbosity',$Verbosity 45 | 46 | if ($PSCmdlet.ShouldProcess($PackageId, 'nuget install')) { 47 | $p = Start-Process $nugetPath $nugetArgs -NoNewWindow -Wait -PassThru 48 | if ($null -ne $p.ExitCode -and $p.ExitCode -ne 0) { throw } 49 | } 50 | 51 | # Provide the path to the installed package directory to our caller. 52 | Write-Output (Get-ChildItem "$PackagesDir\$PackageId.*")[0].FullName 53 | } finally { 54 | Pop-Location 55 | } 56 | -------------------------------------------------------------------------------- /azure-pipelines/Merge-CodeCoverage.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .SYNOPSIS 5 | Merges code coverage reports. 6 | .PARAMETER Path 7 | The path(s) to search for Cobertura code coverage reports. 8 | .PARAMETER Format 9 | The format for the merged result. The default is Cobertura 10 | .PARAMETER OutputDir 11 | The directory the merged result will be written to. The default is `coveragereport` in the root of this repo. 12 | #> 13 | [CmdletBinding()] 14 | Param( 15 | [Parameter(Mandatory=$true)] 16 | [string[]]$Path, 17 | [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')] 18 | [string]$Format='Cobertura', 19 | [string]$OutputFile=("$PSScriptRoot/../coveragereport/merged.cobertura.xml") 20 | ) 21 | 22 | $RepoRoot = [string](Resolve-Path $PSScriptRoot/..) 23 | Push-Location $RepoRoot 24 | try { 25 | Write-Verbose "Searching $Path for *.cobertura.xml files" 26 | $reports = Get-ChildItem -Recurse $Path -Filter *.cobertura.xml 27 | 28 | if ($reports) { 29 | $reports |% { $_.FullName } |% { 30 | # 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. 31 | $xml = [xml](Get-Content -LiteralPath $_) 32 | $xml.coverage.packages.package.classes.class |? { $_.filename} |% { 33 | $_.filename = $_.filename.Replace('{reporoot}', $RepoRoot).Replace([IO.Path]::AltDirectorySeparatorChar, [IO.Path]::DirectorySeparatorChar) 34 | } 35 | 36 | $xml.Save($_) 37 | } 38 | 39 | $Inputs = $reports |% { Resolve-Path -relative $_.FullName } 40 | 41 | if ((Split-Path $OutputFile) -and -not (Test-Path (Split-Path $OutputFile))) { 42 | New-Item -Type Directory -Path (Split-Path $OutputFile) | Out-Null 43 | } 44 | 45 | & dotnet dotnet-coverage merge $Inputs -o $OutputFile -f cobertura 46 | } else { 47 | Write-Error "No reports found to merge." 48 | } 49 | } finally { 50 | Pop-Location 51 | } 52 | -------------------------------------------------------------------------------- /azure-pipelines/NuGetSbom.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | $(TargetsForTfmSpecificBuildOutput);IncludeSbomInNupkg 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /azure-pipelines/PoliCheckExclusions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | NODE_MODULES|.STORE 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /azure-pipelines/PostPRMessage.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding(SupportsShouldProcess = $true)] 2 | param( 3 | [Parameter(Mandatory=$true)] 4 | $AccessToken, 5 | [Parameter(Mandatory=$true)] 6 | $Markdown, 7 | [ValidateSet('Active','ByDesign','Closed','Fixed','Pending','Unknown','WontFix')] 8 | $CommentState='Active' 9 | ) 10 | 11 | # See https://docs.microsoft.com/en-us/dotnet/api/microsoft.teamfoundation.sourcecontrol.webapi.commentthreadstatus?view=azure-devops-dotnet 12 | if ($CommentState -eq 'Active') { 13 | $StatusCode = 1 14 | } elseif ($CommentState -eq 'ByDesign') { 15 | $StatusCode = 5 16 | } elseif ($CommentState -eq 'Closed') { 17 | $StatusCode = 4 18 | } elseif ($CommentState -eq 'Fixed') { 19 | $StatusCode = 2 20 | } elseif ($CommentState -eq 'Pending') { 21 | $StatusCode = 6 22 | } elseif ($CommentState -eq 'Unknown') { 23 | $StatusCode = 0 24 | } elseif ($CommentState -eq 'WontFix') { 25 | $StatusCode = 3 26 | } 27 | 28 | # Build the JSON body up 29 | $body = ConvertTo-Json @{ 30 | comments = @(@{ 31 | parentCommentId = 0 32 | content = $Markdown 33 | commentType = 1 34 | }) 35 | status = $StatusCode 36 | } 37 | 38 | Write-Verbose "Posting JSON payload: `n$Body" 39 | 40 | # Post the message to the Pull Request 41 | # https://docs.microsoft.com/en-us/rest/api/azure/devops/git/pull%20request%20threads?view=azure-devops-rest-5.1 42 | $url = "$($env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI)$env:SYSTEM_TEAMPROJECTID/_apis/git/repositories/$($env:BUILD_REPOSITORY_NAME)/pullRequests/$($env:SYSTEM_PULLREQUEST_PULLREQUESTID)/threads?api-version=5.1" 43 | if ($PSCmdlet.ShouldProcess($url, 'Post comment via REST call')) { 44 | try { 45 | if (!$env:SYSTEM_TEAMFOUNDATIONCOLLECTIONURI) { 46 | Write-Error "Posting to the pull request requires that the script is running in an Azure Pipelines context." 47 | exit 1 48 | } 49 | Write-Host "Posting PR comment to: $url" 50 | Invoke-RestMethod -Uri $url -Method POST -Headers @{Authorization = "Bearer $AccessToken"} -Body $Body -ContentType application/json 51 | } 52 | catch { 53 | Write-Error $_ 54 | Write-Error $_.Exception.Message 55 | exit 2 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /azure-pipelines/TSAOptions.json: -------------------------------------------------------------------------------- 1 | { 2 | "tsaVersion": "TsaV2", 3 | "codebase": "NewOrUpdate", 4 | "codebaseName": "json-document-transforms", 5 | "tsaStamp": "DevDiv", 6 | "tsaEnvironment": "PROD", 7 | "notificationAliases": [ 8 | "vsslnx@microsoft.com" 9 | ], 10 | "instanceUrl": "https://devdiv.visualstudio.com", 11 | "projectName": "DevDiv", 12 | "areaPath": "DevDiv\\VS Core\\Project\\SlowCheetah", 13 | "iterationPath": "DevDiv", 14 | "tools": [ 15 | "APIScan", 16 | "CodeQL" 17 | ], 18 | "repositoryName": "json-document-transforms" 19 | } 20 | -------------------------------------------------------------------------------- /azure-pipelines/WIFtoPATauth.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: deadPATServiceConnectionId # The GUID of the PAT-based service connection whose access token must be replaced. 3 | type: string 4 | - name: wifServiceConnectionName # The name of the WIF service connection to use to get the access token. 5 | type: string 6 | - name: resource # The scope for which the access token is requested. 7 | type: string 8 | default: 499b84ac-1321-427f-aa17-267ca6975798 # Azure Artifact feeds (any of them) 9 | 10 | steps: 11 | - task: AzureCLI@2 12 | displayName: 🔏 Authenticate with WIF service connection 13 | inputs: 14 | azureSubscription: ${{ parameters.wifServiceConnectionName }} 15 | scriptType: pscore 16 | scriptLocation: inlineScript 17 | inlineScript: | 18 | $accessToken = az account get-access-token --query accessToken --resource '${{ parameters.resource }}' -o tsv 19 | # Set the access token as a secret, so it doesn't get leaked in the logs 20 | Write-Host "##vso[task.setsecret]$accessToken" 21 | # Override the apitoken of the nuget service connection, for the duration of this stage 22 | Write-Host "##vso[task.setendpoint id=${{ parameters.deadPATServiceConnectionId }};field=authParameter;key=apitoken]$accessToken" 23 | -------------------------------------------------------------------------------- /azure-pipelines/apiscan.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: windowsPool 3 | type: object 4 | - name: RealSign 5 | type: boolean 6 | 7 | jobs: 8 | - job: apiscan 9 | displayName: APIScan 10 | dependsOn: Windows 11 | pool: ${{ parameters.windowsPool }} 12 | timeoutInMinutes: 120 13 | templateContext: 14 | ${{ if not(parameters.RealSign) }}: 15 | mb: 16 | signing: # if the build is test-signed, install the signing plugin so that CSVTestSignPolicy.xml is available 17 | enabled: true 18 | zipSources: false 19 | signType: test 20 | outputs: 21 | - output: pipelineArtifact 22 | displayName: 📢 collect apiscan artifact 23 | targetPath: $(Pipeline.Workspace)/.gdn/.r/apiscan/001/Logs 24 | artifactName: apiscan-logs 25 | condition: succeededOrFailed() 26 | variables: 27 | - name: SymbolsFeatureName 28 | value: $[ dependencies.Windows.outputs['SetPipelineVariables.SymbolsFeatureName'] ] 29 | - name: NBGV_MajorMinorVersion 30 | value: $[ dependencies.Windows.outputs['nbgv.NBGV_MajorMinorVersion'] ] 31 | - ${{ if eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9') }}: 32 | # https://dev.azure.com/devdiv/DevDiv/_wiki/wikis/DevDiv.wiki/25351/APIScan-step-by-step-guide-to-setting-up-a-Pipeline 33 | - group: VSEng sponsored APIScan # Expected to provide ApiScanClientId 34 | steps: 35 | # We need TSAOptions.json 36 | - checkout: self 37 | fetchDepth: 1 38 | 39 | - download: current 40 | artifact: APIScanInputs 41 | displayName: 🔻 Download APIScanInputs artifact 42 | 43 | - task: APIScan@2 44 | displayName: 🔍 Run APIScan 45 | inputs: 46 | softwareFolder: $(Pipeline.Workspace)/APIScanInputs 47 | softwareName: $(SymbolsFeatureName) 48 | softwareVersionNum: $(NBGV_MajorMinorVersion) 49 | isLargeApp: false 50 | toolVersion: Latest 51 | preserveLogsFolder: true 52 | env: 53 | AzureServicesAuthConnectionString: runAs=App;AppId=$(ApiScanClientId) 54 | 55 | # File bugs when APIScan finds issues 56 | - task: TSAUpload@2 57 | displayName: 🪳 TSA upload 58 | inputs: 59 | GdnPublishTsaOnboard: True 60 | GdnPublishTsaConfigFile: $(Build.SourcesDirectory)\azure-pipelines\TSAOptions.json 61 | condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) 62 | -------------------------------------------------------------------------------- /azure-pipelines/archive-sourcecode.yml: -------------------------------------------------------------------------------- 1 | trigger: none # We only want to trigger manually or based on resources 2 | pr: none 3 | 4 | # Source archival requirements come from a compliance tenet. Review a sample task here: https://devdiv.visualstudio.com/DevDiv/_workitems/edit/1550985 5 | # 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. 6 | # If your sources on GitHub are public open source project, then using GitHub Public Archive is sufficient. 7 | schedules: 8 | - cron: "13 13 13 */3 *" # Every three months 9 | displayName: Periodic source archival 10 | branches: 11 | include: 12 | - main 13 | 14 | resources: 15 | repositories: 16 | - repository: MicroBuildTemplate 17 | type: git 18 | name: 1ESPipelineTemplates/MicroBuildTemplate 19 | ref: refs/tags/release 20 | 21 | parameters: 22 | - name: notes 23 | displayName: Notes to include in the SCA request 24 | type: string 25 | default: ' ' # optional parameters require a non-empty default. 26 | - name: whatif 27 | displayName: Only simulate the request 28 | type: boolean 29 | default: false 30 | 31 | variables: 32 | - group: VS Core team # Expected to provide ManagerAlias, SourceCodeArchivalUri 33 | - template: GlobalVariables.yml 34 | 35 | extends: 36 | template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate 37 | parameters: 38 | sdl: 39 | sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES 40 | 41 | stages: 42 | - stage: archive 43 | jobs: 44 | - job: archive 45 | pool: 46 | name: AzurePipelines-EO 47 | demands: 48 | - ImageOverride -equals 1ESPT-Ubuntu22.04 49 | os: Linux 50 | 51 | steps: 52 | - checkout: self 53 | clean: true 54 | fetchDepth: 0 55 | - powershell: tools/Install-DotNetSdk.ps1 56 | displayName: ⚙ Install .NET SDK 57 | - task: NuGetAuthenticate@1 58 | displayName: 🔏 Authenticate NuGet feeds 59 | inputs: 60 | forceReinstallCredentialProvider: true 61 | - script: dotnet tool restore 62 | displayName: ⚙️ Restore CLI tools 63 | - powershell: tools/variables/_define.ps1 64 | failOnStderr: true 65 | displayName: ⚙ Set pipeline variables based on source 66 | - task: AzureCLI@2 67 | displayName: 🔏 Authenticate with WIF service connection 68 | inputs: 69 | azureSubscription: VS Core Source Code Archival 70 | scriptType: pscore 71 | scriptLocation: inlineScript 72 | inlineScript: | 73 | $accessToken = az account get-access-token --query accessToken --resource api://177cf50a-4bf5-4481-8b7e-f32900dfc8e6 -o tsv 74 | Write-Host "##vso[task.setvariable variable=scaToken;issecret=true]$accessToken" 75 | - pwsh: > 76 | $TeamAlias = '$(TeamEmail)'.Substring(0, '$(TeamEmail)'.IndexOf('@')) 77 | 78 | azure-pipelines/Archive-SourceCode.ps1 79 | -ManagerAlias '$(ManagerAlias)' 80 | -TeamAlias $TeamAlias 81 | -BusinessGroupName '$(BusinessGroupName)' 82 | -ProductName '$(SymbolsFeatureName)' 83 | -ProductLanguage English 84 | -Notes '${{ parameters.notes }}' 85 | -AccessToken '$(scaToken)' 86 | -Verbose 87 | -WhatIf:$${{ parameters.whatif }} 88 | displayName: 🗃️ Submit archival request 89 | -------------------------------------------------------------------------------- /azure-pipelines/dotnet.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: RunTests 3 | - name: IsOptProf 4 | type: boolean 5 | default: false 6 | - name: Is1ESPT 7 | type: boolean 8 | 9 | steps: 10 | 11 | - script: dotnet build src -t:build,pack --no-restore -c $(BuildConfiguration) /bl:"$(Build.ArtifactStagingDirectory)/build_logs/build.binlog" 12 | displayName: 🛠 dotnet build 13 | 14 | - ${{ if not(parameters.IsOptProf) }}: 15 | - powershell: tools/dotnet-test-cloud.ps1 -Configuration $(BuildConfiguration) -Agent $(Agent.JobName) -PublishResults 16 | displayName: 🧪 dotnet test 17 | condition: and(succeeded(), ${{ parameters.RunTests }}) 18 | 19 | - ${{ if parameters.IsOptProf }}: 20 | - script: dotnet pack src\VSInsertionMetadata -c $(BuildConfiguration) -warnaserror /bl:"$(Build.ArtifactStagingDirectory)/build_logs/VSInsertion-Pack.binlog" 21 | displayName: 🔧 dotnet pack VSInsertionMetadata 22 | 23 | - powershell: tools/variables/_define.ps1 24 | failOnStderr: true 25 | displayName: ⚙ Update pipeline variables based on build outputs 26 | condition: succeededOrFailed() 27 | 28 | - ${{ if parameters.Is1ESPT }}: 29 | - powershell: azure-pipelines/publish_artifacts.ps1 -StageOnly -AvoidSymbolicLinks -ArtifactNameSuffix "-$(Agent.JobName)" -Verbose 30 | failOnStderr: true 31 | displayName: 📢 Stage artifacts 32 | condition: succeededOrFailed() 33 | - ${{ else }}: 34 | - powershell: azure-pipelines/publish_artifacts.ps1 -ArtifactNameSuffix "-$(Agent.JobName)" -Verbose 35 | failOnStderr: true 36 | displayName: 📢 Publish artifacts 37 | condition: succeededOrFailed() 38 | 39 | - ${{ if and(ne(variables['codecov_token'], ''), parameters.RunTests) }}: 40 | - powershell: | 41 | $ArtifactStagingFolder = & "tools/Get-ArtifactsStagingDirectory.ps1" 42 | $CoverageResultsFolder = Join-Path $ArtifactStagingFolder "coverageResults-$(Agent.JobName)" 43 | tools/publish-CodeCov.ps1 -CodeCovToken "$(codecov_token)" -PathToCodeCoverage "$CoverageResultsFolder" -Name "$(Agent.JobName) Coverage Results" -Flags "$(Agent.JobName)" 44 | displayName: 📢 Publish code coverage results to codecov.io 45 | timeoutInMinutes: 3 46 | continueOnError: true 47 | -------------------------------------------------------------------------------- /azure-pipelines/falsepositives.gdnsuppress: -------------------------------------------------------------------------------- 1 | { 2 | "version": "latest", 3 | "suppressionSets": { 4 | "falsepositives": { 5 | "name": "falsepositives", 6 | "createdDate": "2021-12-03 00:23:08Z", 7 | "lastUpdatedDate": "2021-12-03 00:23:08Z" 8 | } 9 | }, 10 | "results": { 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /azure-pipelines/install-dependencies.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: initArgs 3 | type: string 4 | default: '' 5 | - name: needsAzurePublicFeeds 6 | type: boolean 7 | default: true # If nuget.config pulls from the azure-public account, we need to authenticate when building on the devdiv account. 8 | 9 | steps: 10 | - ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}: 11 | - template: WIFtoPATauth.yml 12 | parameters: 13 | wifServiceConnectionName: azure-public/vside package pull 14 | deadPATServiceConnectionId: 0ae39abc-4d06-4436-a7b5-865833df49db # azure-public/msft_consumption 15 | 16 | - task: NuGetAuthenticate@1 17 | displayName: 🔏 Authenticate NuGet feeds 18 | inputs: 19 | ${{ if and(parameters.needsAzurePublicFeeds, eq(variables['system.collectionId'], '011b8bdf-6d56-4f87-be0d-0092136884d9')) }}: 20 | nuGetServiceConnections: azure-public/msft_consumption 21 | 22 | - powershell: | 23 | $AccessToken = '$(System.AccessToken)' # Avoid specifying the access token directly on the init.ps1 command line to avoid it showing up in errors 24 | .\init.ps1 -AccessToken $AccessToken ${{ parameters['initArgs'] }} -UpgradePrerequisites -NoNuGetCredProvider 25 | dotnet --info 26 | 27 | # Print mono version if it is present. 28 | if (Get-Command mono -ErrorAction SilentlyContinue) { 29 | mono --version 30 | } 31 | displayName: ⚙ Install prerequisites 32 | 33 | - powershell: tools/variables/_define.ps1 34 | failOnStderr: true 35 | displayName: ⚙ Set pipeline variables based on source 36 | name: SetPipelineVariables 37 | -------------------------------------------------------------------------------- /azure-pipelines/microbuild.after.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableOptProf 3 | type: boolean 4 | default: false 5 | - name: IsOptProf 6 | type: boolean 7 | default: false 8 | - name: SkipCodesignVerify 9 | type: boolean 10 | 11 | steps: 12 | - ${{ if not(parameters.SkipCodesignVerify) }}: # skip CodesignVerify on validation builds because we don't even test-sign nupkg's. 13 | - task: MicroBuildCodesignVerify@3 14 | displayName: 🔍 Verify Signed Files 15 | inputs: 16 | ApprovalListPathForSigs: $(Build.SourcesDirectory)\azure-pipelines\no_strongname.txt 17 | ApprovalListPathForCerts: $(Build.SourcesDirectory)\azure-pipelines\no_authenticode.txt 18 | TargetFolders: | 19 | $(Build.SourcesDirectory)/bin/Packages/$(BuildConfiguration) 20 | condition: and(succeeded(), eq(variables['Agent.OS'], 'Windows_NT')) 21 | 22 | - ${{ if parameters.IsOptProf }}: 23 | - task: ms-vscs-artifact.build-tasks.artifactDropTask-1.artifactDropTask@0 24 | inputs: 25 | dropServiceURI: https://devdiv.artifacts.visualstudio.com 26 | buildNumber: $(ProfilingInputsDropName) 27 | sourcePath: $(Build.ArtifactStagingDirectory)\OptProf\ProfilingInputs 28 | toLowerCase: false 29 | usePat: true 30 | displayName: 📢 Publish to Artifact Services - ProfilingInputs 31 | condition: and(succeeded(), ne(variables['Build.Reason'], 'PullRequest')) 32 | 33 | - task: PublishBuildArtifacts@1 34 | inputs: 35 | PathtoPublish: $(Build.ArtifactStagingDirectory)/InsertionOutputs 36 | ArtifactName: InsertionOutputs 37 | ArtifactType: Container 38 | displayName: 📢 Publish InsertionOutputs as Azure DevOps artifacts 39 | -------------------------------------------------------------------------------- /azure-pipelines/microbuild.before.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableLocalization 3 | type: boolean 4 | default: false 5 | - name: EnableOptProf 6 | type: boolean 7 | default: false 8 | - name: IsOptProf 9 | type: boolean 10 | default: false 11 | - name: ShouldSkipOptimize 12 | type: boolean 13 | default: false 14 | - name: RealSign 15 | type: boolean 16 | 17 | steps: 18 | - ${{ if and(not(parameters.IsOptProf), ne(variables['Build.Reason'], 'PullRequest')) }}: 19 | # notice@0 requires CG detection to run first, and non-default branches don't inject it automatically. 20 | - task: ComponentGovernanceComponentDetection@0 21 | displayName: 🔍 Component Detection 22 | 23 | - task: notice@0 24 | displayName: 🛠️ Generate NOTICE file 25 | inputs: 26 | outputfile: $(System.DefaultWorkingDirectory)/obj/NOTICE 27 | outputformat: text 28 | retryCountOnTaskFailure: 3 # fails when the cloud service is overloaded 29 | continueOnError: ${{ not(parameters.RealSign) }} # Tolerate failures when we're not building something that may ship. 30 | 31 | - ${{ if parameters.IsOptProf }}: 32 | # We have to install these plugins ourselves for Optprof runs because those pipelines haven't migrated to 1ES PT yet. 33 | - task: MicroBuildOptProfPlugin@6 34 | inputs: 35 | ProfilingInputsDropName: $(ProfilingInputsDropName) 36 | OptimizationInputsLookupMethod: DropPrefix 37 | DropNamePrefix: OptimizationInputs/$(System.TeamProject)/$(Build.Repository.Name) 38 | ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }} 39 | AccessToken: $(System.AccessToken) 40 | displayName: 🔧 Install OptProf Plugin 41 | 42 | - task: MicroBuildSigningPlugin@4 43 | inputs: 44 | signType: Real 45 | zipSources: false 46 | displayName: 🔧 Install MicroBuild Signing Plugin 47 | 48 | - ${{ if parameters.EnableLocalization }}: 49 | - task: MicroBuildLocalizationPlugin@4 50 | inputs: 51 | languages: $(LocLanguages) 52 | displayName: 🔧 Install MicroBuild Localization Plugin 53 | -------------------------------------------------------------------------------- /azure-pipelines/no_authenticode.txt: -------------------------------------------------------------------------------- 1 | bin\packages\release\vsix\_manifest\manifest.cat,sbom signed 2 | bin\packages\release\vsix\_manifest\spdx_2.2\manifest.cat,sbom signed 3 | -------------------------------------------------------------------------------- /azure-pipelines/no_strongname.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/json-document-transforms/6b1170757c9c032fce38e46b0deaf9817dfa96b9/azure-pipelines/no_strongname.txt -------------------------------------------------------------------------------- /azure-pipelines/official.yml: -------------------------------------------------------------------------------- 1 | trigger: none # We only want to trigger manually or based on a schedule 2 | pr: none 3 | #schedules: 4 | #- cron: "0 3 * * *" # Daily @ 8 PM PST 5 | # displayName: Daily vs-insertion 6 | # branches: 7 | # include: 8 | # - microbuild 9 | 10 | parameters: 11 | # As an entrypoint pipeline yml file, all parameters here show up in the Queue Run dialog. 12 | # If any paramaters should NOT be queue-time options, they should be removed from here 13 | # and references to them in this file replaced with hard-coded values. 14 | # - name: ShouldSkipOptimize # Uncomment this and references to it below when setting EnableOptProf to true in build.yml. 15 | # displayName: Skip OptProf optimization 16 | # type: boolean 17 | # default: false 18 | - name: EnableMacOSBuild 19 | displayName: Build on macOS 20 | type: boolean 21 | default: false # macOS is often bogged down in Azure Pipelines 22 | - name: RunTests 23 | displayName: Run tests 24 | type: boolean 25 | default: true 26 | - name: EnableAPIScan 27 | displayName: Include APIScan with compliance tools 28 | type: boolean 29 | default: false # enable in individual repos only AFTER updating TSAOptions.json with your own values 30 | - name: PublishCodeCoverage 31 | displayName: Publish code coverage 32 | type: boolean 33 | default: true 34 | 35 | resources: 36 | repositories: 37 | - repository: MicroBuildTemplate 38 | type: git 39 | name: 1ESPipelineTemplates/MicroBuildTemplate 40 | ref: refs/tags/release 41 | 42 | variables: 43 | - template: GlobalVariables.yml 44 | 45 | extends: 46 | template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate 47 | parameters: 48 | sdl: 49 | sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES 50 | codeSignValidation: 51 | enabled: true 52 | break: true 53 | additionalTargetsGlobPattern: -|Variables-*\*.ps1;-|LocBin-*\**;-|APIScanInputs-*\**;-|test_symbols-*\**;-|MicroBuild\** 54 | policheck: 55 | enabled: true 56 | exclusionsFile: $(System.DefaultWorkingDirectory)\azure-pipelines\PoliCheckExclusions.xml 57 | suppression: 58 | suppressionFile: $(System.DefaultWorkingDirectory)\azure-pipelines\falsepositives.gdnsuppress 59 | sbom: 60 | enabled: false # Skip 1ES SBOM because microbuild has our own sbom system 61 | stages: 62 | - stage: Build 63 | variables: 64 | - template: /azure-pipelines/BuildStageVariables.yml@self 65 | jobs: 66 | - template: /azure-pipelines/build.yml@self 67 | parameters: 68 | Is1ESPT: true 69 | RealSign: true 70 | # ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }} 71 | EnableAPIScan: ${{ parameters.EnableAPIScan }} 72 | windowsPool: VSEngSS-MicroBuild2022-1ES 73 | linuxPool: 74 | name: AzurePipelines-EO 75 | demands: 76 | - ImageOverride -equals 1ESPT-Ubuntu22.04 77 | os: Linux 78 | macOSPool: 79 | name: Azure Pipelines 80 | vmImage: macOS-14 81 | os: macOS 82 | EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }} 83 | RunTests: ${{ parameters.RunTests }} 84 | PublishCodeCoverage: ${{ parameters.PublishCodeCoverage }} 85 | - template: /azure-pipelines/prepare-insertion-stages.yml@self 86 | parameters: 87 | RealSign: true 88 | -------------------------------------------------------------------------------- /azure-pipelines/prepare-insertion-stages.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: ArchiveSymbols 3 | type: boolean 4 | default: true 5 | - name: RealSign 6 | displayName: Real sign? 7 | type: boolean 8 | - name: PackagePush 9 | type: boolean 10 | default: false # Switch to true to enable the push job below 11 | 12 | stages: 13 | - ${{ if or(parameters.ArchiveSymbols, parameters.PackagePush) }}: 14 | - stage: release 15 | displayName: Publish 16 | jobs: 17 | - ${{ if parameters.ArchiveSymbols }}: 18 | - job: symbol_archive 19 | displayName: Archive symbols 20 | pool: VSEngSS-MicroBuild2022-1ES 21 | steps: 22 | - checkout: none 23 | - download: current 24 | artifact: Variables-Windows 25 | displayName: 🔻 Download Variables-Windows artifact 26 | - powershell: $(Pipeline.Workspace)/Variables-Windows/_define.ps1 27 | displayName: ⚙️ Set pipeline variables based on artifacts 28 | - download: current 29 | artifact: symbols-legacy 30 | displayName: 🔻 Download symbols-legacy artifact 31 | - task: MicroBuildArchiveSymbols@5 32 | displayName: 🔣 Archive symbols to Symweb 33 | inputs: 34 | SymbolsFeatureName: $(SymbolsFeatureName) 35 | SymbolsProject: VS 36 | SymbolsAgentPath: $(Pipeline.Workspace)/symbols-legacy 37 | 38 | - ${{ if parameters.PackagePush }}: 39 | - job: push 40 | ${{ if parameters.RealSign }}: 41 | displayName: azure-public/vs-impl feed 42 | ${{ else }}: 43 | displayName: devdiv/vs-impl feed # Leave this as-is, since non-signed builds must not be pushed to public feeds. 44 | ${{ if parameters.ArchiveSymbols }}: 45 | dependsOn: symbol_archive 46 | pool: 47 | name: AzurePipelines-EO 48 | demands: 49 | - ImageOverride -equals 1ESPT-Ubuntu22.04 50 | os: Linux 51 | templateContext: 52 | outputs: 53 | - output: nuget 54 | displayName: 📦 Push nuget packages 55 | packagesToPush: '$(Pipeline.Workspace)/deployables-Windows/NuGet/*.nupkg' 56 | packageParentPath: $(Pipeline.Workspace)/deployables-Windows/NuGet 57 | allowPackageConflicts: true 58 | ${{ if parameters.RealSign }}: 59 | nuGetFeedType: external 60 | publishFeedCredentials: azure-public/vs-impl 61 | ${{ else }}: 62 | nuGetFeedType: internal 63 | publishVstsFeed: vs-impl # Leave this as-is, since non-signed builds must not be pushed to public feeds. 64 | steps: 65 | - checkout: none 66 | - download: current 67 | artifact: Variables-Windows 68 | displayName: 🔻 Download Variables-Windows artifact 69 | - powershell: $(Pipeline.Workspace)/Variables-Windows/_define.ps1 70 | displayName: ⚙️ Set pipeline variables based on artifacts 71 | - download: current 72 | artifact: deployables-Windows 73 | displayName: 🔻 Download deployables-Windows artifact 74 | - ${{ if parameters.RealSign }}: 75 | - template: WIFtoPATauth.yml 76 | parameters: 77 | wifServiceConnectionName: azure-public/vside package push 78 | deadPATServiceConnectionId: 207efd62-fd0f-43e7-aeae-17c4febcc660 # azure-public/vs-impl 79 | -------------------------------------------------------------------------------- /azure-pipelines/publish-codecoverage.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableMacOSBuild 3 | type: boolean 4 | - name: EnableLinuxBuild 5 | type: boolean 6 | 7 | steps: 8 | - download: current 9 | artifact: coverageResults-Windows 10 | displayName: 🔻 Download Windows code coverage results 11 | continueOnError: true 12 | - ${{ if parameters.EnableLinuxBuild }}: 13 | - download: current 14 | artifact: coverageResults-Linux 15 | displayName: 🔻 Download Linux code coverage results 16 | continueOnError: true 17 | - ${{ if parameters.EnableMacOSBuild }}: 18 | - download: current 19 | artifact: coverageResults-macOS 20 | displayName: 🔻 Download macOS code coverage results 21 | continueOnError: true 22 | - powershell: azure-pipelines/Merge-CodeCoverage.ps1 -Path '$(Pipeline.Workspace)' -OutputFile coveragereport/merged.cobertura.xml -Format Cobertura -Verbose 23 | displayName: ⚙ Merge coverage 24 | - task: PublishCodeCoverageResults@2 25 | displayName: 📢 Publish code coverage results to Azure DevOps 26 | inputs: 27 | summaryFileLocation: coveragereport/merged.cobertura.xml 28 | failIfCoverageEmpty: true 29 | -------------------------------------------------------------------------------- /azure-pipelines/publish-symbols.yml: -------------------------------------------------------------------------------- 1 | parameters: 2 | - name: EnableMacOSBuild 3 | type: boolean 4 | - name: EnableLinuxBuild 5 | type: boolean 6 | 7 | steps: 8 | - task: DownloadPipelineArtifact@2 9 | inputs: 10 | artifact: symbols-Windows 11 | path: $(Pipeline.Workspace)/symbols/Windows 12 | displayName: 🔻 Download Windows symbols 13 | continueOnError: true 14 | - ${{ if parameters.EnableLinuxBuild }}: 15 | - task: DownloadPipelineArtifact@2 16 | inputs: 17 | artifact: symbols-Linux 18 | path: $(Pipeline.Workspace)/symbols/Linux 19 | displayName: 🔻 Download Linux symbols 20 | continueOnError: true 21 | - ${{ if parameters.EnableMacOSBuild }}: 22 | - task: DownloadPipelineArtifact@2 23 | inputs: 24 | artifact: symbols-macOS 25 | path: $(Pipeline.Workspace)/symbols/macOS 26 | displayName: 🔻 Download macOS symbols 27 | continueOnError: true 28 | 29 | - task: DownloadPipelineArtifact@2 30 | inputs: 31 | artifact: test_symbols-Windows 32 | path: $(Pipeline.Workspace)/test_symbols/Windows 33 | displayName: 🔻 Download Windows test symbols 34 | continueOnError: true 35 | - ${{ if parameters.EnableLinuxBuild }}: 36 | - task: DownloadPipelineArtifact@2 37 | inputs: 38 | artifact: test_symbols-Linux 39 | path: $(Pipeline.Workspace)/test_symbols/Linux 40 | displayName: 🔻 Download Linux test symbols 41 | continueOnError: true 42 | - ${{ if parameters.EnableMacOSBuild }}: 43 | - task: DownloadPipelineArtifact@2 44 | inputs: 45 | artifact: test_symbols-macOS 46 | path: $(Pipeline.Workspace)/test_symbols/macOS 47 | displayName: 🔻 Download macOS test symbols 48 | continueOnError: true 49 | 50 | - task: PublishSymbols@2 51 | inputs: 52 | SymbolsFolder: $(Pipeline.Workspace)/symbols 53 | SearchPattern: '**/*.pdb' 54 | IndexSources: false 55 | SymbolServerType: TeamServices 56 | displayName: 📢 Publish symbols 57 | 58 | - task: PublishSymbols@2 59 | inputs: 60 | SymbolsFolder: $(Pipeline.Workspace)/test_symbols 61 | SearchPattern: '**/*.pdb' 62 | IndexSources: false 63 | SymbolServerType: TeamServices 64 | displayName: 📢 Publish test symbols 65 | 66 | - powershell: tools/Prepare-Legacy-Symbols.ps1 -Path $(Pipeline.Workspace)/symbols/Windows 67 | displayName: ⚙ Prepare symbols for symbol archival 68 | -------------------------------------------------------------------------------- /azure-pipelines/publish_artifacts.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script translates all the artifacts described by _all.ps1 4 | into commands that instruct Azure Pipelines to actually collect those artifacts. 5 | #> 6 | 7 | [CmdletBinding()] 8 | param ( 9 | [string]$ArtifactNameSuffix, 10 | [switch]$StageOnly, 11 | [switch]$AvoidSymbolicLinks 12 | ) 13 | 14 | Function Set-PipelineVariable($name, $value) { 15 | if ((Test-Path "Env:\$name") -and (Get-Item "Env:\$name").Value -eq $value) { 16 | return # already set 17 | } 18 | 19 | #New-Item -LiteralPath "Env:\$name".ToUpper() -Value $value -Force | Out-Null 20 | Write-Host "##vso[task.setvariable variable=$name]$value" 21 | } 22 | 23 | Function Test-ArtifactUploaded($artifactName) { 24 | $varName = "ARTIFACTUPLOADED_$($artifactName.ToUpper())" 25 | Test-Path "env:$varName" 26 | } 27 | 28 | & "$PSScriptRoot/../tools/artifacts/_stage_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix -AvoidSymbolicLinks:$AvoidSymbolicLinks |% { 29 | # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts 30 | # will skip this one from a check in the _all.ps1 script. 31 | Set-PipelineVariable "ARTIFACTSTAGED_$($_.Name.ToUpper())" 'true' 32 | Write-Host "Staged artifact $($_.Name) to $($_.Path)" 33 | 34 | if (!$StageOnly) { 35 | if (Test-ArtifactUploaded $_.Name) { 36 | Write-Host "Skipping $($_.Name) because it has already been uploaded." -ForegroundColor DarkGray 37 | } else { 38 | Write-Host "##vso[artifact.upload containerfolder=$($_.Name);artifactname=$($_.Name);]$($_.Path)" 39 | 40 | # Set a variable which will out-live this script so that a subsequent attempt to collect and upload artifacts 41 | # will skip this one from a check in the _all.ps1 script. 42 | Set-PipelineVariable "ARTIFACTUPLOADED_$($_.Name.ToUpper())" 'true' 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /azure-pipelines/release-deployment-prep.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - download: CI 3 | artifact: Variables-Windows 4 | displayName: 🔻 Download Variables-Windows artifact 5 | - powershell: $(Pipeline.Workspace)/CI/Variables-Windows/_define.ps1 6 | displayName: ⚙️ Set pipeline variables based on artifacts 7 | -------------------------------------------------------------------------------- /azure-pipelines/release.yml: -------------------------------------------------------------------------------- 1 | trigger: none # We only want to trigger manually or based on resources 2 | pr: none 3 | 4 | resources: 5 | repositories: 6 | - repository: MicroBuildTemplate 7 | type: git 8 | name: 1ESPipelineTemplates/MicroBuildTemplate 9 | ref: refs/tags/release 10 | pipelines: 11 | - pipeline: CI 12 | source: json-document-transforms-ci # TODO: This should match the name of your CI pipeline 13 | trigger: 14 | tags: 15 | - auto-release 16 | 17 | variables: 18 | - template: GlobalVariables.yml 19 | 20 | extends: 21 | template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate 22 | parameters: 23 | sdl: 24 | sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES 25 | 26 | stages: 27 | - stage: release 28 | jobs: 29 | - job: release 30 | pool: 31 | name: AzurePipelines-EO 32 | demands: 33 | - ImageOverride -equals 1ESPT-Ubuntu22.04 34 | os: Linux 35 | templateContext: 36 | outputs: 37 | - output: nuget 38 | displayName: 📦 Push packages to nuget.org 39 | packagesToPush: '$(Pipeline.Workspace)/CI/deployables-Windows/NuGet/*.nupkg' 40 | packageParentPath: $(Pipeline.Workspace)/CI/deployables-Windows/NuGet 41 | allowPackageConflicts: true 42 | nuGetFeedType: external 43 | publishFeedCredentials: VisualStudioExtensibility (nuget.org) 44 | steps: 45 | - checkout: none 46 | - powershell: | 47 | Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" 48 | if ('$(resources.pipeline.CI.runName)'.Contains('-')) { 49 | Write-Host "##vso[task.setvariable variable=IsPrerelease]true" 50 | } else { 51 | Write-Host "##vso[task.setvariable variable=IsPrerelease]false" 52 | } 53 | displayName: ⚙ Set up pipeline 54 | - download: CI 55 | artifact: deployables-Windows 56 | displayName: 🔻 Download deployables-Windows artifact 57 | patterns: 'NuGet/*' 58 | - task: GitHubRelease@1 59 | displayName: 📢 GitHub release (create) 60 | inputs: 61 | gitHubConnection: ttstanley # TODO: fill in service connection here 62 | repositoryName: $(Build.Repository.Name) 63 | target: $(resources.pipeline.CI.sourceCommit) 64 | tagSource: userSpecifiedTag 65 | tag: v$(resources.pipeline.CI.runName) 66 | title: v$(resources.pipeline.CI.runName) 67 | isDraft: true # After running this step, visit the new draft release, edit, and publish. 68 | isPreRelease: $(IsPrerelease) 69 | assets: $(Pipeline.Workspace)/CI/deployables-Windows/NuGet/*.nupkg 70 | changeLogCompareToRelease: lastNonDraftRelease 71 | changeLogType: issueBased 72 | changeLogLabels: | 73 | [ 74 | { "label" : "breaking change", "displayName" : "Breaking changes", "state" : "closed" }, 75 | { "label" : "bug", "displayName" : "Fixes", "state" : "closed" }, 76 | { "label" : "enhancement", "displayName": "Enhancements", "state" : "closed" } 77 | ] 78 | -------------------------------------------------------------------------------- /azure-pipelines/schedule-only-steps.yml: -------------------------------------------------------------------------------- 1 | steps: 2 | - powershell: echo "##vso[build.addbuildtag]auto-insertion" 3 | displayName: Tag for auto-insertion 4 | -------------------------------------------------------------------------------- /azure-pipelines/unofficial.yml: -------------------------------------------------------------------------------- 1 | trigger: 2 | batch: true 3 | branches: 4 | include: 5 | - main 6 | - microbuild 7 | - 'validate/*' 8 | paths: 9 | exclude: 10 | - doc/ 11 | - '*.md' 12 | - .vscode/ 13 | - azure-pipelines/release.yml 14 | - azure-pipelines/vs-insertion.yml 15 | 16 | parameters: 17 | # As an entrypoint pipeline yml file, all parameters here show up in the Queue Run dialog. 18 | # If any paramaters should NOT be queue-time options, they should be removed from here 19 | # and references to them in this file replaced with hard-coded values. 20 | # - name: ShouldSkipOptimize # Uncomment this and references to it below when setting EnableOptProf to true in build.yml. 21 | # displayName: Skip OptProf optimization 22 | # type: boolean 23 | # default: false 24 | - name: EnableMacOSBuild 25 | displayName: Build on macOS 26 | type: boolean 27 | default: false # macOS is often bogged down in Azure Pipelines 28 | - name: RunTests 29 | displayName: Run tests 30 | type: boolean 31 | default: true 32 | - name: EnableAPIScan 33 | displayName: Include APIScan with compliance tools 34 | type: boolean 35 | default: false 36 | - name: EnableProductionSDL 37 | displayName: Enable Production SDL 38 | type: boolean 39 | default: false 40 | - name: PublishCodeCoverage 41 | displayName: Publish code coverage 42 | type: boolean 43 | default: true 44 | 45 | resources: 46 | repositories: 47 | - repository: MicroBuildTemplate 48 | type: git 49 | name: 1ESPipelineTemplates/MicroBuildTemplate 50 | ref: refs/tags/release 51 | 52 | variables: 53 | - template: GlobalVariables.yml 54 | 55 | extends: 56 | template: azure-pipelines/MicroBuild.1ES.Unofficial.yml@MicroBuildTemplate 57 | parameters: 58 | sdl: 59 | sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES 60 | suppression: 61 | suppressionFile: $(System.DefaultWorkingDirectory)\azure-pipelines\falsepositives.gdnsuppress 62 | enableProductionSDL: ${{ parameters.EnableProductionSDL }} 63 | codeSignValidation: 64 | enabled: ${{ parameters.EnableProductionSDL }} 65 | break: true 66 | additionalTargetsGlobPattern: -|Variables-*\*.ps1;-|APIScanInputs-*\**;-|test_symbols-*\**;-|MicroBuild\** 67 | policyFile: $(MBSIGN_APPFOLDER)\CSVTestSignPolicy.xml 68 | policheck: 69 | enabled: ${{ parameters.EnableProductionSDL }} 70 | exclusionsFile: $(System.DefaultWorkingDirectory)\azure-pipelines\PoliCheckExclusions.xml 71 | sbom: 72 | enabled: false # Skip 1ES SBOM because microbuild has our own sbom system 73 | stages: 74 | - stage: Build 75 | variables: 76 | - template: /azure-pipelines/BuildStageVariables.yml@self 77 | jobs: 78 | - template: /azure-pipelines/build.yml@self 79 | parameters: 80 | Is1ESPT: true 81 | RealSign: false 82 | # ShouldSkipOptimize: ${{ parameters.ShouldSkipOptimize }} 83 | EnableAPIScan: ${{ parameters.EnableAPIScan }} 84 | windowsPool: VSEngSS-MicroBuild2022-1ES 85 | linuxPool: 86 | name: AzurePipelines-EO 87 | demands: 88 | - ImageOverride -equals 1ESPT-Ubuntu22.04 89 | os: Linux 90 | macOSPool: 91 | name: Azure Pipelines 92 | vmImage: macOS-14 93 | os: macOS 94 | EnableMacOSBuild: ${{ parameters.EnableMacOSBuild }} 95 | RunTests: ${{ parameters.RunTests }} 96 | PublishCodeCoverage: ${{ parameters.PublishCodeCoverage }} 97 | -------------------------------------------------------------------------------- /azure-pipelines/vs-insertion.yml: -------------------------------------------------------------------------------- 1 | trigger: none # We only want to trigger manually or based on resources 2 | pr: none 3 | 4 | resources: 5 | repositories: 6 | - repository: MicroBuildTemplate 7 | type: git 8 | name: 1ESPipelineTemplates/MicroBuildTemplate 9 | ref: refs/tags/release 10 | pipelines: 11 | - pipeline: CI 12 | source: Library # TODO: This should match the name of your CI pipeline 13 | tags: 14 | - Real signed 15 | trigger: 16 | tags: 17 | - Real signed 18 | - auto-insertion 19 | 20 | variables: 21 | - template: GlobalVariables.yml 22 | 23 | extends: 24 | template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate 25 | parameters: 26 | sdl: 27 | sourceAnalysisPool: VSEngSS-MicroBuild2022-1ES 28 | 29 | stages: 30 | - stage: insertion 31 | jobs: 32 | - job: insertion 33 | displayName: VS insertion 34 | pool: VSEngSS-MicroBuild2022-1ES 35 | templateContext: 36 | outputParentDirectory: $(Pipeline.Workspace)/CI 37 | steps: 38 | - checkout: none 39 | - powershell: Write-Host "##vso[build.updatebuildnumber]$(resources.pipeline.CI.runName)" 40 | displayName: ⚙️ Set pipeline name 41 | - template: azure-pipelines/release-deployment-prep.yml@self 42 | - download: CI 43 | artifact: VSInsertion-Windows 44 | displayName: 🔻 Download VSInsertion-Windows artifact 45 | - ${{ if eq(variables['ContainsVsix'], 'true') }}: 46 | - task: 1ES.MicroBuildVstsDrop@1 47 | displayName: 🔺 Upload VSTS Drop 48 | inputs: 49 | dropFolder: $(Pipeline.Workspace)/CI/VSInsertion-windows/Vsix 50 | dropName: $(VstsDropNames) 51 | accessToken: $(System.AccessToken) 52 | - task: 1ES.PublishNuget@1 53 | displayName: 📦 Push VS-repo packages to VS feed 54 | inputs: 55 | packagesToPush: '$(Pipeline.Workspace)/CI/VSInsertion-Windows/*.nupkg' 56 | packageParentPath: $(Pipeline.Workspace)/CI/VSInsertion-Windows 57 | allowPackageConflicts: true 58 | publishVstsFeed: VS 59 | - task: MicroBuildInsertVsPayload@5 60 | displayName: 🏭 Insert VS Payload 61 | inputs: 62 | TeamName: $(TeamName) 63 | TeamEmail: $(TeamEmail) 64 | InsertionPayloadName: $(Build.Repository.Name) $(Build.BuildNumber) 65 | InsertionBuildPolicies: Request Perf DDRITs 66 | InsertionReviewers: $(Build.RequestedFor) # Append `,Your team name` (without quotes) 67 | AutoCompletePR: true 68 | AutoCompleteMergeStrategy: Squash 69 | ShallowClone: true 70 | - powershell: | 71 | $contentType = 'application/json'; 72 | $headers = @{ Authorization = 'Bearer $(System.AccessToken)' }; 73 | $rawRequest = @{ daysValid = 365 * 2; definitionId = $(resources.pipeline.CI.pipelineID); ownerId = 'User:$(Build.RequestedForId)'; protectPipeline = $false; runId = $(resources.pipeline.CI.runId) }; 74 | $request = ConvertTo-Json @($rawRequest); 75 | Write-Host $request 76 | $uri = "$(System.CollectionUri)$(System.TeamProject)/_apis/build/retention/leases?api-version=6.0-preview.1"; 77 | Invoke-RestMethod -uri $uri -method POST -Headers $headers -ContentType $contentType -Body $request; 78 | displayName: 🗻 Retain inserted builds 79 | -------------------------------------------------------------------------------- /docfx/.gitignore: -------------------------------------------------------------------------------- 1 | _site/ 2 | api/ 3 | -------------------------------------------------------------------------------- /docfx/docfx.json: -------------------------------------------------------------------------------- 1 | { 2 | "metadata": [ 3 | { 4 | "src": [ 5 | { 6 | "src": "../src", 7 | "files": [ 8 | "**/*.csproj" 9 | ] 10 | } 11 | ], 12 | "dest": "api" 13 | } 14 | ], 15 | "build": { 16 | "content": [ 17 | { 18 | "files": [ 19 | "**/*.{md,yml}" 20 | ], 21 | "exclude": [ 22 | "_site/**" 23 | ] 24 | } 25 | ], 26 | "resource": [ 27 | { 28 | "files": [ 29 | "images/**" 30 | ] 31 | } 32 | ], 33 | "xref": [ 34 | "https://learn.microsoft.com/en-us/dotnet/.xrefmap.json" 35 | ], 36 | "output": "_site", 37 | "template": [ 38 | "default", 39 | "modern" 40 | ], 41 | "globalMetadata": { 42 | "_appName": "Library", 43 | "_appTitle": "Library", 44 | "_enableSearch": true, 45 | "pdf": false 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /docfx/docs/features.md: -------------------------------------------------------------------------------- 1 | # Features 2 | 3 | TODO 4 | -------------------------------------------------------------------------------- /docfx/docs/getting-started.md: -------------------------------------------------------------------------------- 1 | # Getting Started 2 | 3 | ## Installation 4 | 5 | Consume this library via its NuGet Package. 6 | Click on the badge to find its latest version and the instructions for consuming it that best apply to your project. 7 | 8 | [![NuGet package](https://img.shields.io/nuget/v/Library.svg)](https://nuget.org/packages/Library) 9 | 10 | ## Usage 11 | 12 | TODO 13 | -------------------------------------------------------------------------------- /docfx/docs/toc.yml: -------------------------------------------------------------------------------- 1 | items: 2 | - name: Features 3 | href: features.md 4 | - name: Getting Started 5 | href: getting-started.md 6 | -------------------------------------------------------------------------------- /docfx/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | _layout: landing 3 | --- 4 | 5 | # Overview 6 | 7 | This is your docfx landing page. 8 | 9 | Click "Docs" across the top to get started. 10 | -------------------------------------------------------------------------------- /docfx/toc.yml: -------------------------------------------------------------------------------- 1 | items: 2 | - name: Docs 3 | href: docs/ 4 | - name: API 5 | href: api/ 6 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "9.0.202", 4 | "rollForward": "patch", 5 | "allowPrerelease": false 6 | }, 7 | "msbuild-sdks": { 8 | "Microsoft.Build.NoTargets": "3.7.56" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /init.cmd: -------------------------------------------------------------------------------- 1 | @echo off 2 | SETLOCAL 3 | set PS1UnderCmd=1 4 | 5 | :: Get the datetime in a format that can go in a filename. 6 | set _my_datetime=%date%_%time% 7 | set _my_datetime=%_my_datetime: =_% 8 | set _my_datetime=%_my_datetime::=% 9 | set _my_datetime=%_my_datetime:/=_% 10 | set _my_datetime=%_my_datetime:.=_% 11 | set CmdEnvScriptPath=%temp%\envvarscript_%_my_datetime%.cmd 12 | 13 | powershell.exe -NoProfile -NoLogo -ExecutionPolicy bypass -Command "try { & '%~dpn0.ps1' %*; exit $LASTEXITCODE } catch { write-host $_; exit 1 }" 14 | 15 | :: Set environment variables in the parent cmd.exe process. 16 | IF EXIST "%CmdEnvScriptPath%" ( 17 | ENDLOCAL 18 | CALL "%CmdEnvScriptPath%" 19 | DEL "%CmdEnvScriptPath%" 20 | ) 21 | -------------------------------------------------------------------------------- /nuget.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /src/.editorconfig: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/microsoft/json-document-transforms/6b1170757c9c032fce38e46b0deaf9817dfa96b9/src/.editorconfig -------------------------------------------------------------------------------- /src/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | using System.Runtime.InteropServices; 5 | 6 | [assembly: DefaultDllImportSearchPaths(DllImportSearchPath.SafeDirectories)] 7 | -------------------------------------------------------------------------------- /src/AssemblyInfo.vb: -------------------------------------------------------------------------------- 1 | ' Copyright (c) Microsoft Corporation. All rights reserved. 2 | ' Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | Imports System.Runtime.InteropServices 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | README.md 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /src/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/JdtException.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using Newtonsoft.Json; 8 | 9 | /// 10 | /// The file that caused the exception. 11 | /// 12 | public enum ErrorLocation 13 | { 14 | /// 15 | /// Represents no location set. 16 | /// 17 | None, 18 | 19 | /// 20 | /// Represents the source file. 21 | /// 22 | Source, 23 | 24 | /// 25 | /// Represents the transform file. 26 | /// 27 | Transform, 28 | } 29 | 30 | /// 31 | /// Exception thrown on JDT error. 32 | /// 33 | [Serializable] 34 | public class JdtException : Exception 35 | { 36 | /// 37 | /// Initializes a new instance of the class. 38 | /// 39 | /// The exception message. 40 | public JdtException(string message) 41 | : base(message) 42 | { 43 | } 44 | 45 | /// 46 | /// Initializes a new instance of the class. 47 | /// 48 | /// The exception message. 49 | /// The file that generated the exception. 50 | public JdtException(string message, ErrorLocation location) 51 | : this(message) 52 | { 53 | this.Location = location; 54 | } 55 | 56 | /// 57 | /// Initializes a new instance of the class. 58 | /// 59 | /// The exception message. 60 | /// The file that generated the exception. 61 | /// The line that caused the error. 62 | /// The position in the lite that caused the error. 63 | public JdtException(string message, ErrorLocation location, int lineNumber, int linePosition) 64 | : this(message, location) 65 | { 66 | this.LineNumber = lineNumber; 67 | this.LinePosition = linePosition; 68 | } 69 | 70 | /// 71 | /// Gets the line number of the exception. 72 | /// 73 | public int LineNumber { get; } 74 | 75 | /// 76 | /// Gets the line position of the exception. 77 | /// 78 | public int LinePosition { get; } 79 | 80 | /// 81 | /// Gets the name of the file that generated the exception. 82 | /// 83 | public ErrorLocation Location { get; } = ErrorLocation.None; 84 | 85 | /// 86 | /// Returns a with line info. 87 | /// 88 | /// The exception message. 89 | /// The file that generated the exception. 90 | /// The line info of the object that caused the error. 91 | /// A new instance of . 92 | internal static JdtException FromLineInfo(string message, ErrorLocation location, IJsonLineInfo lineInfo) 93 | { 94 | return new JdtException(message, location, lineInfo?.LineNumber ?? 0, lineInfo?.LinePosition ?? 0); 95 | } 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/JdtExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using Newtonsoft.Json.Linq; 10 | 11 | /// 12 | /// Defines extension methods used in JDT. 13 | /// 14 | internal static class JdtExtensions 15 | { 16 | /// 17 | /// Gets all the properties within the object that correspond to JDT syntax. 18 | /// 19 | /// The object to search. 20 | /// An enumerable of properties that start with the JDT prefix. 21 | internal static IEnumerable GetJdtProperties(this JObject objectToSearch) 22 | { 23 | if (objectToSearch == null) 24 | { 25 | throw new ArgumentNullException(nameof(objectToSearch)); 26 | } 27 | 28 | return objectToSearch.Properties().Where(p => JdtUtilities.IsJdtSyntax(p.Name)); 29 | } 30 | 31 | /// 32 | /// Checks if an exception is critical. 33 | /// 34 | /// The exception to check. 35 | /// True if the exception is critical and should not be caught. 36 | internal static bool IsCriticalException(this Exception ex) 37 | { 38 | return ex is NullReferenceException 39 | || ex is OutOfMemoryException 40 | || ex is IndexOutOfRangeException 41 | #if NET45 42 | || ex is StackOverflowException 43 | || ex is AccessViolationException 44 | || ex is System.Threading.ThreadAbortException 45 | #endif 46 | ; 47 | } 48 | 49 | /// 50 | /// Clones a preserving the line information. 51 | /// 52 | /// The object to clone. 53 | /// A clone of the object with its line info. 54 | internal static JObject CloneWithLineInfo(this JObject objectToClone) 55 | { 56 | var loadSettings = new JsonLoadSettings() 57 | { 58 | LineInfoHandling = JdtUtilities.GetLineInfoHandling(), 59 | }; 60 | 61 | using (Newtonsoft.Json.JsonReader objectReader = objectToClone.CreateReader()) 62 | { 63 | return JObject.Load(objectReader, loadSettings); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Microsoft.VisualStudio.Jdt.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | library 5 | netstandard2.0;net472 6 | 7 | 8 | 9 | Microsoft 10 | Microsoft, VisualStudioExtensibility 11 | Transform json files using a json transformation schema 12 | © Microsoft Corporation. All rights reserved. 13 | json transformation transforms file-transform jdt 14 | https://aka.ms/VsExtensibilityIcon 15 | true 16 | https://github.com/Microsoft/json-document-transforms 17 | https://github.com/Microsoft/json-document-transforms 18 | True 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | True 39 | True 40 | Resources.resx 41 | 42 | 43 | 44 | 45 | 46 | ResXFileCodeGenerator 47 | Resources.Designer.cs 48 | 49 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Processors/Attributes/JdtAttributeExtensions.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | 10 | /// 11 | /// Implements extensions for . 12 | /// 13 | internal static class JdtAttributeExtensions 14 | { 15 | /// 16 | /// Get the full name of an attribute, with the JDT prefix. 17 | /// 18 | /// The attribute. 19 | /// A string with the full name of the requested attribute. 20 | internal static string FullName(this JdtAttributes attribute) 21 | { 22 | if (attribute == JdtAttributes.None) 23 | { 24 | return JdtUtilities.JdtSyntaxPrefix; 25 | } 26 | 27 | return JdtUtilities.JdtSyntaxPrefix + Enum.GetName(typeof(JdtAttributes), attribute).ToLower(); 28 | } 29 | 30 | /// 31 | /// Gets a from an enumerable based on name. 32 | /// 33 | /// The enumerable to search. 34 | /// The name of the attribute. 35 | /// The attribute with that name of if no attribute was found. 36 | internal static JdtAttributes GetByName(this IEnumerable collection, string name) 37 | { 38 | // The default value for the enum is 0, which is None 39 | return collection.SingleOrDefault(a => a.FullName().Equals(name)); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Processors/JdtArrayProcessor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using Newtonsoft.Json.Linq; 8 | 9 | /// 10 | /// Base for a processor that handles array values. 11 | /// 12 | internal abstract class JdtArrayProcessor : JdtProcessor 13 | { 14 | /// 15 | internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) 16 | { 17 | if (source == null) 18 | { 19 | throw new ArgumentNullException(nameof(source)); 20 | } 21 | 22 | if (transform == null) 23 | { 24 | throw new ArgumentNullException(nameof(transform)); 25 | } 26 | 27 | JToken transformValue; 28 | if (transform.TryGetValue(this.FullVerb, out transformValue)) 29 | { 30 | if (!this.Transform(source, transformValue, logger)) 31 | { 32 | // If the transformation returns false, 33 | // it performed an operation that halts transforms 34 | return; 35 | } 36 | } 37 | 38 | this.Successor.Process(source, transform, logger); 39 | } 40 | 41 | /// 42 | /// The core transformation logic. Arrays are treated as the transform values. 43 | /// 44 | /// Object to be transformed. 45 | /// Value of the transform. 46 | /// The transformation context logger. 47 | /// True if transforms should continue. 48 | protected abstract bool ProcessCore(JObject source, JToken transformValue, JsonTransformationContextLogger logger); 49 | 50 | /// 51 | /// Performs the initial logic of processing arrays. 52 | /// Arrays cause the transform to be applied to each value in them. 53 | /// 54 | /// Object to be transformed. 55 | /// Value of the transform. 56 | /// The transformation context logger. 57 | /// True if transforms should continue. 58 | private bool Transform(JObject source, JToken transformValue, JsonTransformationContextLogger logger) 59 | { 60 | if (transformValue.Type == JTokenType.Array) 61 | { 62 | // If the value is an array, perform the transformation for each object in the array 63 | // From here, arrays are handled as the transformation value 64 | foreach (JToken arrayValue in (JArray)transformValue) 65 | { 66 | if (!this.ProcessCore(source, arrayValue, logger)) 67 | { 68 | // If the core transformation indicates a halt, we halt 69 | return true; 70 | } 71 | } 72 | 73 | // If we are not told to stop, we continue with transformations 74 | return true; 75 | } 76 | else 77 | { 78 | // If it is not an array, perform the transformation as normal 79 | return this.ProcessCore(source, transformValue, logger); 80 | } 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Processors/JdtDefault.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using System.Linq; 8 | using Newtonsoft.Json.Linq; 9 | 10 | /// 11 | /// Represents the default JDT transformation. 12 | /// 13 | internal class JdtDefault : JdtProcessor 14 | { 15 | /// 16 | public override string Verb { get; } = null; 17 | 18 | /// 19 | internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) 20 | { 21 | if (source == null) 22 | { 23 | throw new ArgumentNullException(nameof(source)); 24 | } 25 | 26 | if (transform == null) 27 | { 28 | throw new ArgumentNullException(nameof(transform)); 29 | } 30 | 31 | // JDT Verbs are not handled here 32 | foreach (JProperty transformNode in transform.Properties() 33 | .Where(p => !JdtUtilities.IsJdtSyntax(p.Name))) 34 | { 35 | JToken nodeToTransform; 36 | if (source.TryGetValue(transformNode.Name, out nodeToTransform)) 37 | { 38 | // If the node is present in both transform and source, analyze the types 39 | // If both are objects, that is a recursive transformation, not handled here 40 | if (nodeToTransform.Type == JTokenType.Array && transformNode.Value.Type == JTokenType.Array) 41 | { 42 | // If the original and transform are arrays, merge the contents together 43 | ((JArray)nodeToTransform).Merge(transformNode.Value.DeepClone()); 44 | } 45 | else if (nodeToTransform.Type != JTokenType.Object || transformNode.Value.Type != JTokenType.Object) 46 | { 47 | // TO DO: Verify if object has JDT verbs. They shouldn't be allowed here because they won't be processed 48 | // If the contents are different, execute the replace 49 | source[transformNode.Name] = transformNode.Value.DeepClone(); 50 | } 51 | } 52 | else 53 | { 54 | // If the node is not present in the original, add it 55 | source.Add(transformNode.DeepClone()); 56 | } 57 | } 58 | 59 | this.Successor.Process(source, transform, logger); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.ProcessorChain.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using Newtonsoft.Json.Linq; 10 | 11 | /// 12 | /// The JdtProcessor chain. 13 | /// 14 | internal abstract partial class JdtProcessor 15 | { 16 | private class JdtProcessorChain 17 | { 18 | // This is a a list of supported transformations 19 | // It is in order of execution 20 | private readonly List processors = new List() 21 | { 22 | // Supported transformations 23 | new JdtRecurse(), 24 | new JdtRemove(), 25 | new JdtReplace(), 26 | new JdtRename(), 27 | new JdtMerge(), 28 | new JdtDefault(), 29 | }; 30 | 31 | public JdtProcessorChain() 32 | { 33 | var validator = new JdtValidator(); 34 | 35 | // The first step of a transformation is validating the verbs 36 | this.processors.Insert(0, validator); 37 | 38 | // The successor of each transform processor should be the next one on the list 39 | // The last processor defaults to the end of chain processor 40 | List.Enumerator processorsEnumerator = this.processors.GetEnumerator(); 41 | processorsEnumerator.MoveNext(); 42 | foreach (JdtProcessor? successor in this.processors.Skip(1)) 43 | { 44 | if (!string.IsNullOrEmpty(successor.Verb)) 45 | { 46 | // If the transformation has a corresponding verb, 47 | // add it to the list of verbs to be validated 48 | validator.ValidVerbs.Add(successor.Verb); 49 | } 50 | 51 | processorsEnumerator.Current.Successor = successor; 52 | processorsEnumerator.MoveNext(); 53 | } 54 | } 55 | 56 | public void Start(JObject source, JObject transform, JsonTransformationContextLogger logger) 57 | { 58 | if (source == null) 59 | { 60 | throw new ArgumentNullException(nameof(source)); 61 | } 62 | 63 | if (transform == null) 64 | { 65 | throw new ArgumentNullException(nameof(transform)); 66 | } 67 | 68 | this.processors.First().Process(source, transform, logger); 69 | } 70 | } 71 | 72 | /// 73 | /// Represents the end of the transformation chain. 74 | /// 75 | private class JdtEndOfChain : JdtProcessor 76 | { 77 | private JdtEndOfChain() 78 | { 79 | } 80 | 81 | public static JdtEndOfChain Instance { get; } = new JdtEndOfChain(); 82 | 83 | public override string Verb { get; } = null; 84 | 85 | internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) 86 | { 87 | // Do nothing, the chain is done 88 | } 89 | } 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Processors/JdtProcessor.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using Newtonsoft.Json.Linq; 8 | 9 | /// 10 | /// Represents a transformation. 11 | /// 12 | internal abstract partial class JdtProcessor 13 | { 14 | private static readonly JdtProcessorChain ProcessorChain = new JdtProcessorChain(); 15 | 16 | private JdtProcessor successor; 17 | 18 | /// 19 | /// Gets the JDT verb corresponding to this transformation. 20 | /// Can be null or empty. 21 | /// Does not include the preffix (@jdt.) 22 | /// 23 | public abstract string Verb { get; } 24 | 25 | /// 26 | /// Gets the full verb corresponding the to the transformation. 27 | /// 28 | protected string FullVerb 29 | { 30 | get 31 | { 32 | return this.Verb == null ? null : JdtUtilities.JdtSyntaxPrefix + this.Verb; 33 | } 34 | } 35 | 36 | /// 37 | /// Gets the successor of the current transformation. 38 | /// 39 | protected JdtProcessor Successor 40 | { 41 | get 42 | { 43 | // Defaults to the end of chain processor 44 | return this.successor ?? JdtEndOfChain.Instance; 45 | } 46 | 47 | private set 48 | { 49 | this.successor = value; 50 | } 51 | } 52 | 53 | /// 54 | /// Executes the entire transformation with the given objects 55 | /// Mutates the source object. 56 | /// 57 | /// Object to be transformed. 58 | /// Object that specifies the transformation. 59 | /// The logger for the transformation. 60 | internal static void ProcessTransform(JObject source, JObject transform, JsonTransformationContextLogger logger) 61 | { 62 | if (source == null) 63 | { 64 | throw new ArgumentNullException(nameof(source)); 65 | } 66 | 67 | if (transform == null) 68 | { 69 | throw new ArgumentNullException(nameof(transform)); 70 | } 71 | 72 | // Passes in a clone of the transform object because it can be altered during the transformation process 73 | ProcessorChain.Start(source, (JObject)transform.CloneWithLineInfo(), logger); 74 | } 75 | 76 | /// 77 | /// Executes the transformation. 78 | /// 79 | /// Object to be transformed. 80 | /// Object specifying the transformation. 81 | /// The logger for the transformation. 82 | internal abstract void Process(JObject source, JObject transform, JsonTransformationContextLogger logger); 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Processors/JdtRecurse.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using Newtonsoft.Json.Linq; 10 | 11 | /// 12 | /// Represents a recursive JDT transformation. 13 | /// 14 | internal class JdtRecurse : JdtProcessor 15 | { 16 | /// 17 | public override string Verb { get; } = null; 18 | 19 | /// 20 | internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) 21 | { 22 | if (source == null) 23 | { 24 | throw new ArgumentNullException(nameof(source)); 25 | } 26 | 27 | if (transform == null) 28 | { 29 | throw new ArgumentNullException(nameof(transform)); 30 | } 31 | 32 | // Nodes that should be removed from the transform after they are handled 33 | var nodesToRemove = new List(); 34 | 35 | foreach (JProperty transformNode in transform.Properties() 36 | .Where(p => p.Value.Type == JTokenType.Object && !JdtUtilities.IsJdtSyntax(p.Name))) 37 | { 38 | // We recurse into objects that do not correspond to JDT verbs and that exist in both source and transform 39 | JToken sourceChild; 40 | if (source.TryGetValue(transformNode.Name, out sourceChild) && sourceChild.Type == JTokenType.Object) 41 | { 42 | ProcessTransform((JObject)sourceChild, (JObject)transformNode.Value, logger); 43 | 44 | // If we have already recursed into that node, it should be removed from the transform 45 | nodesToRemove.Add(transformNode.Name); 46 | } 47 | } 48 | 49 | // Remove all of the previously handled nodes 50 | // This is necessary so that a rename does not cause a node to be hadled twice 51 | nodesToRemove.ForEach(node => transform.Remove(node)); 52 | 53 | // Continue to next transformation 54 | this.Successor.Process(source, transform, logger); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Microsoft.VisualStudio.Jdt/Processors/JdtValidator.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt 5 | { 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Linq; 9 | using Newtonsoft.Json.Linq; 10 | 11 | /// 12 | /// Validates the JDT verbs in the transformation. 13 | /// 14 | internal class JdtValidator : JdtProcessor 15 | { 16 | /// 17 | /// Gets set of the valid verbs for the transformation. 18 | /// 19 | public HashSet ValidVerbs { get; } = new HashSet(); 20 | 21 | /// 22 | public override string Verb { get; } = null; 23 | 24 | /// 25 | internal override void Process(JObject source, JObject transform, JsonTransformationContextLogger logger) 26 | { 27 | if (source == null) 28 | { 29 | throw new ArgumentNullException(nameof(source)); 30 | } 31 | 32 | if (transform == null) 33 | { 34 | throw new ArgumentNullException(nameof(transform)); 35 | } 36 | 37 | foreach (JProperty transformNode in transform.Properties() 38 | .Where(p => JdtUtilities.IsJdtSyntax(p.Name))) 39 | { 40 | string verb = JdtUtilities.GetJdtSyntax(transformNode.Name); 41 | if (verb != null) 42 | { 43 | if (!this.ValidVerbs.Contains(verb)) 44 | { 45 | throw JdtException.FromLineInfo(string.Format(Resources.ErrorMessage_InvalidVerb, verb), ErrorLocation.Transform, transformNode); 46 | } 47 | } 48 | } 49 | 50 | this.Successor.Process(source, transform, logger); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/OptProf.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | IBC 5 | Common7\IDE\PrivateAssemblies\$(TargetFileName) 6 | /ExeConfig:"%VisualStudio.InstallationUnderTest.Path%\Common7\IDE\vsn.exe" 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/VSInsertionMetadata/Library.VSInsertionMetadata.proj: -------------------------------------------------------------------------------- 1 | 2 | 3 | netstandard2.0 4 | true 5 | $(RepoRootPath)bin\Packages\$(Configuration)\VSRepo\ 6 | false 7 | false 8 | Contains metadata for insertion into VS. 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/VSInsertionMetadata/ProfilingInputs.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/VSInsertionMetadata/VSInsertionMetadata.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | $(TargetsForTfmSpecificContentInPackage); 27 | SubstituteProfilingInputsMacro; 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 43 | 44 | 47 | 49 | 50 | 51 | 52 | 53 | 54 | 57 | 64 | 65 | $(PackageVersion).$(Build_BuildId) 66 | 67 | 68 | 69 | 70 | 71 | 72 | -------------------------------------------------------------------------------- /src/jdt.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.13.35505.181 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.Jdt", "Microsoft.VisualStudio.Jdt\Microsoft.VisualStudio.Jdt.csproj", "{E4517B62-6E49-47A9-93A3-889B2E0A92B5}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{386BAD62-57B8-4AEB-AEE5-D122A8330656}" 9 | ProjectSection(SolutionItems) = preProject 10 | Directory.Build.props = Directory.Build.props 11 | Directory.Build.targets = Directory.Build.targets 12 | ..\Directory.Packages.props = ..\Directory.Packages.props 13 | stylecop.json = stylecop.json 14 | version.json = version.json 15 | EndProjectSection 16 | EndProject 17 | 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}" 18 | EndProject 19 | Global 20 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 21 | Debug|Any CPU = Debug|Any CPU 22 | Release|Any CPU = Release|Any CPU 23 | EndGlobalSection 24 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 25 | {E4517B62-6E49-47A9-93A3-889B2E0A92B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 26 | {E4517B62-6E49-47A9-93A3-889B2E0A92B5}.Debug|Any CPU.Build.0 = Debug|Any CPU 27 | {E4517B62-6E49-47A9-93A3-889B2E0A92B5}.Release|Any CPU.ActiveCfg = Release|Any CPU 28 | {E4517B62-6E49-47A9-93A3-889B2E0A92B5}.Release|Any CPU.Build.0 = Release|Any CPU 29 | {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 30 | {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Debug|Any CPU.Build.0 = Debug|Any CPU 31 | {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Release|Any CPU.ActiveCfg = Release|Any CPU 32 | {DC4029BB-86FD-AC0B-8024-03ECD0301F86}.Release|Any CPU.Build.0 = Release|Any CPU 33 | EndGlobalSection 34 | GlobalSection(SolutionProperties) = preSolution 35 | HideSolutionNode = FALSE 36 | EndGlobalSection 37 | GlobalSection(ExtensibilityGlobals) = postSolution 38 | SolutionGuid = {F194D4D1-A28A-4C19-941E-BF828EA6DD8C} 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /src/stylecop.json: -------------------------------------------------------------------------------- 1 | { 2 | // https://github.com/DotNetAnalyzers/StyleCopAnalyzers/blob/master/documentation/EnableConfiguration.md 3 | "$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json", 4 | "settings": { 5 | "documentationRules": { 6 | "companyName": "Microsoft Corporation", 7 | "copyrightText": "Copyright (c) {companyName}. All rights reserved.\nLicensed under the {licenseName} license. See {licenseFile} file in the project root for full license information.", 8 | "variables": { 9 | "licenseName": "MIT", 10 | "licenseFile": "LICENSE" 11 | }, 12 | "xmlHeader": false 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/AArnott/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "0.9", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/main$" // we release out of main 6 | ], 7 | "cloudBuild": { 8 | "buildNumber": { 9 | "enabled": true 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.cs] 2 | 3 | # SA1600: Elements should be documented 4 | dotnet_diagnostic.SA1600.severity = silent 5 | 6 | # SA1601: Partial elements should be documented 7 | dotnet_diagnostic.SA1601.severity = silent 8 | 9 | # SA1602: Enumeration items should be documented 10 | dotnet_diagnostic.SA1602.severity = silent 11 | 12 | # SA1615: Element return value should be documented 13 | dotnet_diagnostic.SA1615.severity = silent 14 | 15 | # VSTHRD103: Call async methods when in an async method 16 | dotnet_diagnostic.VSTHRD103.severity = silent 17 | 18 | # VSTHRD111: Use .ConfigureAwait(bool) 19 | dotnet_diagnostic.VSTHRD111.severity = none 20 | 21 | # VSTHRD200: Use Async suffix for async methods 22 | dotnet_diagnostic.VSTHRD200.severity = silent 23 | 24 | # CA1014: Mark assemblies with CLSCompliant 25 | dotnet_diagnostic.CA1014.severity = none 26 | 27 | # CA1050: Declare types in namespaces 28 | dotnet_diagnostic.CA1050.severity = none 29 | 30 | # CA1303: Do not pass literals as localized parameters 31 | dotnet_diagnostic.CA1303.severity = none 32 | 33 | # CS1591: Missing XML comment for publicly visible type or member 34 | dotnet_diagnostic.CS1591.severity = silent 35 | 36 | # CA1707: Identifiers should not contain underscores 37 | dotnet_diagnostic.CA1707.severity = silent 38 | 39 | # CA1062: Validate arguments of public methods 40 | dotnet_diagnostic.CA1062.severity = suggestion 41 | 42 | # CA1063: Implement IDisposable Correctly 43 | dotnet_diagnostic.CA1063.severity = silent 44 | 45 | # CA1816: Dispose methods should call SuppressFinalize 46 | dotnet_diagnostic.CA1816.severity = silent 47 | 48 | # CA2007: Consider calling ConfigureAwait on the awaited task 49 | dotnet_diagnostic.CA2007.severity = none 50 | 51 | # SA1401: Fields should be private 52 | dotnet_diagnostic.SA1401.severity = silent 53 | 54 | # SA1133: Do not combine attributes 55 | dotnet_diagnostic.SA1133.severity = silent 56 | -------------------------------------------------------------------------------- /test/Directory.Build.props: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | false 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/Directory.Build.targets: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Added": true } 4 | ], 5 | "B": [ 6 | { 7 | "Name": "B1", 8 | "Value": 1 9 | }, 10 | { 11 | "Name": "B2", 12 | "Value": 2 13 | }, 14 | { 15 | "Name": "B2", 16 | "Value": 3 17 | } 18 | ], 19 | "C": [ 20 | {}, 21 | { "Empty": false }, 22 | { "Array": [ { "Inception": true } ] }, 23 | { "Empty": false } 24 | ], 25 | "D": { 26 | "D1": [ 27 | { "Value": 1 }, 28 | { "Value": 0 } 29 | ] 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Merge.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Added": true } 4 | ], 5 | "B": [ 6 | { 7 | "Name": "B2", 8 | "Value": 2 9 | }, 10 | { 11 | "Name": "B2", 12 | "Value": 3 13 | } 14 | ], 15 | "C": [ 16 | { "Empty": false } 17 | ], 18 | "D": { 19 | "D1": [ { "Value": 0 } ] 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "Replaced": true 4 | }, 5 | "B": [ 6 | { 7 | "Name": "B1", 8 | "Value": 1 9 | } 10 | ], 11 | "C": "Replaced", 12 | "D": { 13 | "D1": null 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Replace.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "Replaced": true 4 | }, 5 | "C": "Replaced", 6 | "D": { 7 | "D1": null 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Array.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [], 3 | "B": [ 4 | { 5 | "Name": "B1", 6 | "Value": 1 7 | } 8 | ], 9 | "C": [ 10 | {}, 11 | { "Empty": false }, 12 | { "Array": [ { "Inception": true } ] } 13 | ], 14 | "D": { 15 | "D1": [ { "Value": 1 } ] 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "A1": "New" 4 | }, 5 | "B": { 6 | "B1": 10, 7 | "B2": 2, 8 | "B3": 30 9 | }, 10 | "C": { 11 | "C1": { 12 | "C11": true, 13 | "C12": false, 14 | "C13": [ 15 | { "Name": "C131" }, 16 | { "Name": "C132" } 17 | ] 18 | }, 19 | "C2": 2, 20 | "C3": { 21 | "Added": true 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Merge.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "A1": "New" 4 | }, 5 | "B": { 6 | "B1": 10, 7 | "B3": 30 8 | }, 9 | "C": { 10 | "C1": { 11 | "C12": false, 12 | "C13": [ 13 | { "Name": "C131" }, 14 | { "Name": "C132" } 15 | ] 16 | }, 17 | "C3": { 18 | "Added": true 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": null, 3 | "B": "Replaced", 4 | "C": { 5 | "C1": [ { "C11": true } ], 6 | "C2": 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Replace.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": null, 3 | "B": "Replaced", 4 | "C": { 5 | "C1": [ {"C11": true} ] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Object.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "B": { 5 | "B1": 1, 6 | "B2": 2 7 | }, 8 | "C": { 9 | "C1": { 10 | "C11": true 11 | }, 12 | "C2": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4", 6 | "E": [ 7 | { 8 | "String": "string", 9 | "Primitive": null 10 | }, 11 | { "Object": { "Value": 10 } }, 12 | { "Array": [ { "Inception": true } ] }, 13 | {} 14 | ], 15 | "F": [ 16 | { "Repeat": true }, 17 | { "Repeat": true } 18 | ], 19 | "G": [] 20 | } 21 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddArray.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "E": [ 3 | { 4 | "String": "string", 5 | "Primitive": null 6 | }, 7 | { "Object": { "Value": 10 } }, 8 | { "Array": [ {"Inception": true} ] }, 9 | {} 10 | ], 11 | "F": [ 12 | { "Repeat": true }, 13 | { "Repeat": true } 14 | ], 15 | "G": [] 16 | } 17 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4", 6 | "E": { 7 | }, 8 | "F": { 9 | "F1": 1, 10 | "F2": true, 11 | "F3": "F3" 12 | }, 13 | "G": { 14 | "G1": { 15 | }, 16 | "G2": null, 17 | "G3": { 18 | "G31": 10, 19 | "G32": null 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddObject.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "E": { 3 | }, 4 | "F": { 5 | "F1": 1, 6 | "F2": true, 7 | "F3": "F3" 8 | }, 9 | "G": { 10 | "G1": { 11 | }, 12 | "G2": null, 13 | "G3": { 14 | "G31": 10, 15 | "G32": null 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4", 6 | "E": true, 7 | "F": 6, 8 | "G": null, 9 | "H": "8" 10 | } 11 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.AddPrimitive.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "E": true, 3 | "F": 6, 4 | "G": null, 5 | "H": "8" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 10, 3 | "B": null, 4 | "C": "Replaced", 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Replace.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 10, 3 | "B": null, 4 | "C": "Replaced" 5 | } 6 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Default/Primitive.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": { 4 | "B1": 1, 5 | "B2": 20, 6 | "B3": 3 7 | }, 8 | "C": { 9 | "C1": { 10 | "C11": 1, 11 | "C12": 2 12 | }, 13 | "C2": null 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.MergeObjects.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "@jdt.merge": 1 4 | }, 5 | "B": { 6 | "@jdt.merge": { 7 | "B2": 20, 8 | "B3": 3 9 | } 10 | }, 11 | "C": { 12 | "@jdt.merge": { 13 | "C1": { 14 | "C12": 2, 15 | "C11": 1 16 | }, 17 | "C2": null 18 | }, 19 | "C1": { 20 | "@jdt.merge": { 21 | "C12": false 22 | }, 23 | "C11": true 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": {}, 3 | "B": { 4 | "B1": 1, 5 | "B2": 2 6 | }, 7 | "C": { 8 | "C1": { 9 | "C11": true 10 | }, 11 | "C2": 2 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": {}, 3 | "B": { 4 | "B1": 1, 5 | "B2": { 6 | "B21": 1, 7 | "B22": 2 8 | } 9 | }, 10 | "C": { 11 | "C1": { 12 | "C11": 1, 13 | "C12": 2 14 | }, 15 | "C2": 2 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Object.UsingDirectPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.merge": { 3 | "@jdt.path": "$.B.B2", 4 | "@jdt.value": { 5 | "B21": 1, 6 | "B22": 2 7 | } 8 | }, 9 | "C": { 10 | "@jdt.merge": { 11 | "@jdt.path": "$.C1", 12 | "@jdt.value": { 13 | "C11": 1, 14 | "C12": 2 15 | } 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "A1": 1 4 | }, 5 | "B": true, 6 | "C": {}, 7 | "D": "4", 8 | "E": { 9 | "Added": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergeObjects.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.merge": { 3 | "A": { 4 | "A1": 1 5 | }, 6 | "C": {}, 7 | "E": { 8 | "Added": true 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": false, 4 | "C": null, 5 | "D": "4", 6 | "E": "new", 7 | "F": 10 8 | } 9 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.MergePrimitives.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.merge": { 3 | "B": false, 4 | "E": "new", 5 | "F": 10 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": "One", 3 | "B": true, 4 | "C": null, 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Merge/Primitive.UsingSimplePath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.merge": { 3 | "@jdt.path": "$.A", 4 | "@jdt.value": "One" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Index": 1 }, 4 | { "Index": 3 } 5 | ], 6 | "B": [ 7 | { "Remove": true }, 8 | { "Remove": false }, 9 | { "Remove": "WrongValue" }, 10 | { "HasRemove": false }, 11 | { "Remove": true } 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.DirectPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": { 3 | "@jdt.path": "$.A[1]" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Index": 1 }, 4 | { "Index": 2 }, 5 | { "Index": 3 } 6 | ], 7 | "B": [ 8 | { "Remove": false }, 9 | { "Remove": "WrongValue" }, 10 | { "HasRemove": false } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.ScriptPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": { 3 | "@jdt.path": "$.B[?(@.Remove == true)]" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Array.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Index": 1 }, 4 | { "Index": 2 }, 5 | { "Index": 3 } 6 | ], 7 | "B": [ 8 | { "Remove": true }, 9 | { "Remove": false }, 10 | { "Remove": "WrongValue" }, 11 | { "HasRemove": false }, 12 | { "Remove": true } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "B": { 5 | "B1": 1 6 | }, 7 | "C": { 8 | "C2": 2 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.DirectPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": { 3 | "@jdt.path": "$.B.B2" 4 | }, 5 | "C": { 6 | "@jdt.remove": { 7 | "@jdt.path": "$.C1" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "B": { 3 | "B2": 2 4 | }, 5 | "C": { 6 | "C2": 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.InObject.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": "A", 3 | "B": { 4 | "@jdt.remove": "B1" 5 | }, 6 | "C": { 7 | "@jdt.remove": "C1", 8 | "C1": { 9 | "@jdt.remove": "C11" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": null, 3 | "B": { 4 | "B1": 1, 5 | "B2": 2 6 | }, 7 | "C": { 8 | "C1": { 9 | "C11": true 10 | }, 11 | "C2": 2 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.PathToItself.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "@jdt.remove": { 4 | "@jdt.path": "$" 5 | } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "B": { 5 | "B1": 1, 6 | "B2": 2 7 | }, 8 | "C": { 9 | "C1": { 10 | "C11": true 11 | }, 12 | "C2": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": null, 3 | "B": { 4 | "B1": 1, 5 | "B2": 2 6 | }, 7 | "C": { 8 | "C1": null, 9 | "C2": 2 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Object.WithBool.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "@jdt.remove": true 4 | }, 5 | "B": { 6 | "@jdt.remove": false 7 | }, 8 | "C": { 9 | "C1": { 10 | "@jdt.remove": true, 11 | "C12": 3 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "B": true, 3 | "C": null, 4 | "D": "4" 5 | } 6 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.FromRoot.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": "A" 3 | } 4 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "C": null 4 | } 5 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingPathArray.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": [ 3 | { 4 | "@jdt.path": "$.D" 5 | }, 6 | { 7 | "@jdt.path": "B" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "C": null, 3 | "D": "4" 4 | } 5 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimpleArray.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": ["A", "B"] 3 | } 4 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "D": "4" 5 | } 6 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Primitive.UsingSimplePath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": { 3 | "@jdt.path": "C" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "C": { 5 | "C1": { 6 | "C11": true 7 | }, 8 | "C2": 2 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Remove/Skipped/Object.ScriptPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.remove": { 3 | "@jdt.path": "$[?(@.B1)]" 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Ind": 1 }, 4 | { "Index": 2 }, 5 | { "Ind": 3 } 6 | ], 7 | "B": [ 8 | { "Rename": true, "ToChange": 1 }, 9 | { "Rename": false, "ToChange": 1 }, 10 | { "Rename": "WrongValue", "ToChange": 1 }, 11 | { "HasRename": false, "ToChange": 1 }, 12 | { "Rename": true, "ToChange": 1 } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.DirectPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": { 3 | "@jdt.path": "$.A[0,2].Index", 4 | "@jdt.value": "Ind" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Index": 1 }, 4 | { "Index": 2 }, 5 | { "Index": 3 } 6 | ], 7 | "B": [ 8 | { "Rename": true, "Changed": 1 }, 9 | { "Rename": false, "ToChange": 2 }, 10 | { "Rename": "WrongValue", "ToChange": 3 }, 11 | { "HasRename": false, "ToChange": 4 }, 12 | { "Rename": true, "Changed": 5 } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.ScriptPath.Transform .json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": { 3 | "@jdt.path": "$.B[?(@.Rename == true)].ToChange", 4 | "@jdt.value": "Changed" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Array.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Index": 1 }, 4 | { "Index": 2 }, 5 | { "Index": 3 } 6 | ], 7 | "B": [ 8 | { "Rename": true, "ToChange": 1 }, 9 | { "Rename": false, "ToChange": 1 }, 10 | { "Rename": "WrongValue", "ToChange": 1 }, 11 | { "HasRename": false, "ToChange": 1 }, 12 | { "Rename": true, "ToChange": 1 } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "Bee": { 5 | "B1": 1, 6 | "B2": 2 7 | }, 8 | "Cstar": { 9 | "C01": { 10 | "C11": true 11 | }, 12 | "C02": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.InObject.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": { 3 | "C": "Cstar", 4 | "B": "Bee" 5 | }, 6 | 7 | "C": { 8 | "@jdt.rename": { 9 | "C1": "C01", 10 | "C2": "C02" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "B": { 5 | "B1": 1, 6 | "B2": 2 7 | }, 8 | "C": { 9 | "C1": { 10 | "C11": true 11 | }, 12 | "C2": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "B": { 5 | "B1": 1, 6 | "B2": 2 7 | }, 8 | "C": { 9 | "C01": { 10 | "C11": true 11 | }, 12 | "C2": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.UsingSimplePath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": { 3 | "@jdt.path": "$.C.C1", 4 | "@jdt.value": "C01" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "B": { 5 | "B1": 1, 6 | "B2": 2 7 | }, 8 | "C": { 9 | "C01": { 10 | "Cee11": true 11 | }, 12 | "C2": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Object.WithChangingNames.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": { 3 | "@jdt.path": "$.C.C1", 4 | "@jdt.value": "C01" 5 | }, 6 | "C": { 7 | "@jdt.rename": { 8 | "@jdt.path": "$.C1.C11", 9 | "@jdt.value": "Cee11" 10 | } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "Astar": 1, 3 | "B": true, 4 | "NewC": null, 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.FromRoot.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": { 3 | "A": "Astar", 4 | "C": "NewC" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "Astar": 1, 3 | "B": true, 4 | "C": null, 5 | "Dee": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimpleArray.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": [ 3 | { 4 | "A": "Astar" 5 | }, 6 | { 7 | "D" : "Dee" 8 | } 9 | ] 10 | } 11 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "Eh": 1, 3 | "B": true, 4 | "C": null, 5 | "D": "4" 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Rename/Primitive.UsingSimplePath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.rename": { 3 | "@jdt.path": "$.A", 4 | "@jdt.value": "Eh" 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | 1, 4 | { "Index": 2 }, 5 | { "StringIndex": "03", "Replaced" : true } 6 | ], 7 | "B": [ 8 | { "Replace": true }, 9 | { "Replace": false }, 10 | { "Replace": "WrongValue" }, 11 | { "HasReplace": true }, 12 | { "Replace": true } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.DirectPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.replace": [ 3 | { 4 | "@jdt.path": "$.A[0]", 5 | "@jdt.value": 1 6 | }, 7 | { 8 | "@jdt.path": "$.A[2]", 9 | "@jdt.value": { 10 | "StringIndex": "03", 11 | "Replaced" : true 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Index": 1 }, 4 | { "Index": 2 }, 5 | { "Index": 3 } 6 | ], 7 | "B": [ 8 | { "Replaced": "Yes" }, 9 | { "Replace": false }, 10 | { "Replace": "WrongValue" }, 11 | { "HasReplace": true }, 12 | { "Replaced": "Yes" } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.ScriptPath.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "@jdt.replace": { 3 | "@jdt.path": "$.B[?(@.Replace == true)]", 4 | "@jdt.value": {"Replaced": "Yes"} 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Array.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": [ 3 | { "Index": 1 }, 4 | { "Index": 2 }, 5 | { "Index": 3 } 6 | ], 7 | "B": [ 8 | { "Replace": true }, 9 | { "Replace": false }, 10 | { "Replace": "WrongValue" }, 11 | { "HasReplace": true }, 12 | { "Replace": true } 13 | ] 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.Source.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | }, 4 | "B": { 5 | "B1": 1, 6 | "B2": 2 7 | }, 8 | "C": { 9 | "C1": { 10 | "C11": true 11 | }, 12 | "C2": 2 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": 1, 3 | "B": { 4 | "B1": 1, 5 | "B2": 2 6 | }, 7 | "C": [ 8 | { "C1": { "C11": 1 } }, 9 | { "C2": 2 } 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithArray.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "@jdt.replace": [ 4 | 1, 5 | "Skipped" 6 | ] 7 | }, 8 | "C": { 9 | "@jdt.replace": [ 10 | [ 11 | { "C1": { "C11": 1 } }, 12 | { "C2": 2 } 13 | ] 14 | ] 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "A1": 1, 4 | "A2": 2 5 | }, 6 | "B": { 7 | "1B": 10, 8 | "2B": 22 9 | }, 10 | "C": { 11 | "C1": { 12 | "Value": 1 13 | }, 14 | "C2": 2 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithObject.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "@jdt.replace": { 4 | "A1": 1, 5 | "A2": 2 6 | } 7 | }, 8 | "B": { 9 | "@jdt.replace": { 10 | "1B": 10, 11 | "2B": 22 12 | } 13 | }, 14 | "C": { 15 | "C1": { 16 | "@jdt.replace": { 17 | "Value": 1 18 | } 19 | }, 20 | "C2": 2 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Expected.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": true, 3 | "B": 20, 4 | "C": { 5 | "C1": 1, 6 | "C2": 2 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Inputs/Replace/Object.WithPrimitive.Transform.json: -------------------------------------------------------------------------------- 1 | { 2 | "A": { 3 | "@jdt.replace": true 4 | }, 5 | "B": { 6 | "@jdt.replace": 20 7 | }, 8 | "C": { 9 | "C1": { 10 | "@jdt.replace": 1, 11 | "C11": "Skipped" 12 | }, 13 | "C2": 2 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/JdtUtilitiesTest.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt.Tests 5 | { 6 | using Microsoft.VisualStudio.Jdt; 7 | using Xunit; 8 | 9 | /// 10 | /// Test class for . 11 | /// 12 | public class JdtUtilitiesTest 13 | { 14 | /// 15 | /// Tests with invalid JSON syntax. 16 | /// 17 | /// Key to test. 18 | [Theory] 19 | [InlineData(null)] 20 | [InlineData("")] 21 | [InlineData("string")] 22 | [InlineData("jdt.Verb")] 23 | [InlineData("@jdtverb")] 24 | [InlineData("@jdt")] 25 | [InlineData("@JDT.WrongCase")] 26 | public void IsJdtSyntaxInvalid(string key) 27 | { 28 | Assert.False(JdtUtilities.IsJdtSyntax(key)); 29 | } 30 | 31 | /// 32 | /// Tests with valid JSON syntax. 33 | /// 34 | /// Key to test. 35 | [Theory] 36 | [InlineData("@jdt.NotAVerb")] 37 | [InlineData("@jdt.Remove")] 38 | [InlineData("@jdt.merge")] 39 | [InlineData("@jdt.")] 40 | [InlineData("@jdt. ")] 41 | public void IsJdtSyntaxValid(string key) 42 | { 43 | Assert.True(JdtUtilities.IsJdtSyntax(key)); 44 | } 45 | 46 | /// 47 | /// Tests with invalid JSON syntax. 48 | /// 49 | /// Key to test. 50 | [Theory] 51 | [InlineData(null)] 52 | [InlineData("")] 53 | [InlineData("string")] 54 | [InlineData("jdt.Verb")] 55 | [InlineData("@jdtverb")] 56 | [InlineData("@jdt")] 57 | [InlineData("@JDT.WrongCase")] 58 | public void GetInvalidJdtSyntax(string key) 59 | { 60 | Assert.Null(JdtUtilities.GetJdtSyntax(key)); 61 | } 62 | 63 | /// 64 | /// Tests with valid JSON syntax. 65 | /// 66 | [Fact] 67 | public void GetValidJdtSyntax() 68 | { 69 | Assert.Equal(JdtUtilities.GetJdtSyntax("@jdt."), string.Empty); 70 | Assert.Equal(" ", JdtUtilities.GetJdtSyntax("@jdt. ")); 71 | Assert.Equal("verb", JdtUtilities.GetJdtSyntax("@jdt.verb")); 72 | Assert.Equal("NotAVerb", JdtUtilities.GetJdtSyntax("@jdt.NotAVerb")); 73 | } 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/Microsoft.VisualStudio.Jdt.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net472;net5.0 5 | false 6 | $(NoWarn);CS1591 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | all 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/ReadOnlyTempFile.cs: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft Corporation. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | namespace Microsoft.VisualStudio.Jdt.Tests 5 | { 6 | using System; 7 | using System.IO; 8 | 9 | /// 10 | /// Read-Only Temp File. 11 | /// 12 | /// 13 | internal class ReadOnlyTempFile : IDisposable 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The contents. 19 | public ReadOnlyTempFile(string contents) 20 | { 21 | // create temp file 22 | this.FilePath = Path.GetTempFileName(); 23 | 24 | // write contents 25 | File.WriteAllText(this.FilePath, contents); 26 | 27 | // set the file as read-only 28 | File.SetAttributes(this.FilePath, FileAttributes.ReadOnly); 29 | } 30 | 31 | /// 32 | /// Gets the file path. 33 | /// 34 | /// The file path. 35 | public string FilePath { get; private set; } 36 | 37 | /// 38 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 39 | /// 40 | public void Dispose() 41 | { 42 | // delete file 43 | if ((this.FilePath == null) || !File.Exists(this.FilePath)) 44 | { 45 | // nothing to delete 46 | return; 47 | } 48 | 49 | // remove read-only attribute if it exists 50 | FileAttributes attributes = File.GetAttributes(this.FilePath); 51 | if ((attributes & FileAttributes.ReadOnly) == FileAttributes.ReadOnly) 52 | { 53 | // read-only attribute exists 54 | // remove read-only attribute 55 | File.SetAttributes(this.FilePath, attributes ^ FileAttributes.ReadOnly); 56 | } 57 | 58 | // delete the file 59 | File.Delete(this.FilePath); 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /test/Microsoft.VisualStudio.Jdt.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://xunit.net/schema/current/xunit.runner.schema.json", 3 | "shadowCopy": false 4 | } 5 | -------------------------------------------------------------------------------- /tools/Check-DotNetRuntime.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Checks whether a given .NET Core runtime is installed. 4 | #> 5 | [CmdletBinding()] 6 | Param ( 7 | [Parameter()] 8 | [ValidateSet('Microsoft.AspNetCore.App','Microsoft.NETCore.App')] 9 | [string]$Runtime='Microsoft.NETCore.App', 10 | [Parameter(Mandatory=$true)] 11 | [Version]$Version 12 | ) 13 | 14 | $dotnet = Get-Command dotnet -ErrorAction SilentlyContinue 15 | if (!$dotnet) { 16 | # Nothing is installed. 17 | Write-Output $false 18 | exit 1 19 | } 20 | 21 | Function IsVersionMatch { 22 | Param( 23 | [Parameter()] 24 | $actualVersion 25 | ) 26 | return $actualVersion -and 27 | $Version.Major -eq $actualVersion.Major -and 28 | $Version.Minor -eq $actualVersion.Minor -and 29 | (($Version.Build -eq -1) -or ($Version.Build -eq $actualVersion.Build)) -and 30 | (($Version.Revision -eq -1) -or ($Version.Revision -eq $actualVersion.Revision)) 31 | } 32 | 33 | $installedRuntimes = dotnet --list-runtimes |? { $_.Split()[0] -ieq $Runtime } |% { $v = $null; [Version]::tryparse($_.Split()[1], [ref] $v); $v } 34 | $matchingRuntimes = $installedRuntimes |? { IsVersionMatch -actualVersion $_ } 35 | if (!$matchingRuntimes) { 36 | Write-Output $false 37 | exit 1 38 | } 39 | 40 | Write-Output $true 41 | exit 0 42 | -------------------------------------------------------------------------------- /tools/Check-DotNetSdk.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Checks whether the .NET Core SDK required by this repo is installed. 4 | #> 5 | [CmdletBinding()] 6 | Param ( 7 | ) 8 | 9 | $dotnet = Get-Command dotnet -ErrorAction SilentlyContinue 10 | if (!$dotnet) { 11 | # Nothing is installed. 12 | Write-Output $false 13 | exit 1 14 | } 15 | 16 | # We need to set the current directory so dotnet considers the SDK required by our global.json file. 17 | Push-Location "$PSScriptRoot\.." 18 | try { 19 | dotnet -h 2>&1 | Out-Null 20 | if (($LASTEXITCODE -eq 129) -or # On Linux 21 | ($LASTEXITCODE -eq -2147450751) # On Windows 22 | ) { 23 | # These exit codes indicate no matching SDK exists. 24 | Write-Output $false 25 | exit 2 26 | } 27 | 28 | # The required SDK is already installed! 29 | Write-Output $true 30 | exit 0 31 | } catch { 32 | # 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. 33 | Write-Output $false 34 | exit 3 35 | } finally { 36 | Pop-Location 37 | } 38 | -------------------------------------------------------------------------------- /tools/Convert-PDB.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Converts between Windows PDB and Portable PDB formats. 4 | .PARAMETER DllPath 5 | The path to the DLL whose PDB is to be converted. 6 | .PARAMETER PdbPath 7 | 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. 8 | .PARAMETER OutputPath 9 | The path of the output PDB to write. 10 | #> 11 | [CmdletBinding()] 12 | Param( 13 | [Parameter(Mandatory=$true,Position=0)] 14 | [string]$DllPath, 15 | [Parameter()] 16 | [string]$PdbPath, 17 | [Parameter(Mandatory=$true,Position=1)] 18 | [string]$OutputPath 19 | ) 20 | 21 | if ($IsMacOS -or $IsLinux) { 22 | Write-Error "This script only works on Windows" 23 | return 24 | } 25 | 26 | $version = '1.1.0-beta2-21101-01' 27 | $baseDir = "$PSScriptRoot/../obj/tools" 28 | $pdb2pdbpath = "$baseDir/Microsoft.DiaSymReader.Pdb2Pdb.$version/tools/Pdb2Pdb.exe" 29 | if (-not (Test-Path $pdb2pdbpath)) { 30 | if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } 31 | $baseDir = (Resolve-Path $baseDir).Path # Normalize it 32 | 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" 33 | & (& $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 34 | } 35 | 36 | $args = $DllPath,'/out',$OutputPath,'/nowarn','0021' 37 | if ($PdbPath) { 38 | $args += '/pdb',$PdbPath 39 | } 40 | 41 | Write-Verbose "$pdb2pdbpath $args" 42 | & $pdb2pdbpath $args 43 | -------------------------------------------------------------------------------- /tools/Get-ArtifactsStagingDirectory.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [switch]$CleanIfLocal 3 | ) 4 | if ($env:BUILD_ARTIFACTSTAGINGDIRECTORY) { 5 | $ArtifactStagingFolder = $env:BUILD_ARTIFACTSTAGINGDIRECTORY 6 | } elseif ($env:RUNNER_TEMP) { 7 | $ArtifactStagingFolder = Join-Path $env:RUNNER_TEMP _artifacts 8 | } else { 9 | $ArtifactStagingFolder = [System.IO.Path]::GetFullPath("$PSScriptRoot/../obj/_artifacts") 10 | if ($CleanIfLocal -and (Test-Path $ArtifactStagingFolder)) { 11 | Remove-Item $ArtifactStagingFolder -Recurse -Force 12 | } 13 | } 14 | 15 | $ArtifactStagingFolder 16 | -------------------------------------------------------------------------------- /tools/Get-CodeCovTool.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads the CodeCov.io uploader tool and returns the path to it. 4 | .PARAMETER AllowSkipVerify 5 | Allows skipping signature verification of the downloaded tool if gpg is not installed. 6 | #> 7 | [CmdletBinding()] 8 | Param( 9 | [switch]$AllowSkipVerify 10 | ) 11 | 12 | if ($IsMacOS) { 13 | $codeCovUrl = "https://uploader.codecov.io/latest/macos/codecov" 14 | $toolName = 'codecov' 15 | } 16 | elseif ($IsLinux) { 17 | $codeCovUrl = "https://uploader.codecov.io/latest/linux/codecov" 18 | $toolName = 'codecov' 19 | } 20 | else { 21 | $codeCovUrl = "https://uploader.codecov.io/latest/windows/codecov.exe" 22 | $toolName = 'codecov.exe' 23 | } 24 | 25 | $shaSuffix = ".SHA256SUM" 26 | $sigSuffix = $shaSuffix + ".sig" 27 | 28 | Function Get-FileFromWeb([Uri]$Uri, $OutDir) { 29 | $OutFile = Join-Path $OutDir $Uri.Segments[-1] 30 | if (!(Test-Path $OutFile)) { 31 | Write-Verbose "Downloading $Uri..." 32 | if (!(Test-Path $OutDir)) { New-Item -ItemType Directory -Path $OutDir | Out-Null } 33 | try { 34 | (New-Object System.Net.WebClient).DownloadFile($Uri, $OutFile) 35 | } finally { 36 | # This try/finally causes the script to abort 37 | } 38 | } 39 | 40 | $OutFile 41 | } 42 | 43 | $toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" 44 | $binaryToolsPath = Join-Path $toolsPath codecov 45 | $testingPath = Join-Path $binaryToolsPath unverified 46 | $finalToolPath = Join-Path $binaryToolsPath $toolName 47 | 48 | if (!(Test-Path $finalToolPath)) { 49 | if (Test-Path $testingPath) { 50 | Remove-Item -Recurse -Force $testingPath # ensure we download all matching files 51 | } 52 | $tool = Get-FileFromWeb $codeCovUrl $testingPath 53 | $sha = Get-FileFromWeb "$codeCovUrl$shaSuffix" $testingPath 54 | $sig = Get-FileFromWeb "$codeCovUrl$sigSuffix" $testingPath 55 | $key = Get-FileFromWeb https://keybase.io/codecovsecurity/pgp_keys.asc $testingPath 56 | 57 | if ((Get-Command gpg -ErrorAction SilentlyContinue)) { 58 | Write-Host "Importing codecov key" -ForegroundColor Yellow 59 | gpg --import $key 60 | Write-Host "Verifying signature on codecov hash" -ForegroundColor Yellow 61 | gpg --verify $sig $sha 62 | } else { 63 | if ($AllowSkipVerify) { 64 | Write-Warning "gpg not found. Unable to verify hash signature." 65 | } else { 66 | throw "gpg not found. Unable to verify hash signature. Install gpg or add -AllowSkipVerify to override." 67 | } 68 | } 69 | 70 | Write-Host "Verifying hash on downloaded tool" -ForegroundColor Yellow 71 | $actualHash = (Get-FileHash -LiteralPath $tool -Algorithm SHA256).Hash 72 | $expectedHash = (Get-Content $sha).Split()[0] 73 | if ($actualHash -ne $expectedHash) { 74 | # Validation failed. Delete the tool so we can't execute it. 75 | #Remove-Item $codeCovPath 76 | throw "codecov uploader tool failed signature validation." 77 | } 78 | 79 | Copy-Item $tool $finalToolPath 80 | 81 | if ($IsMacOS -or $IsLinux) { 82 | chmod u+x $finalToolPath 83 | } 84 | } 85 | 86 | return $finalToolPath 87 | -------------------------------------------------------------------------------- /tools/Get-LibTemplateBasis.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Returns the name of the well-known branch in the Library.Template repository upon which HEAD is based. 4 | #> 5 | [CmdletBinding(SupportsShouldProcess = $true)] 6 | Param( 7 | [switch]$ErrorIfNotRelated 8 | ) 9 | 10 | # This list should be sorted in order of decreasing specificity. 11 | $branchMarkers = @( 12 | @{ commit = 'fd0a7b25ccf030bbd16880cca6efe009d5b1fffc'; branch = 'microbuild' }; 13 | @{ commit = '05f49ce799c1f9cc696d53eea89699d80f59f833'; branch = 'main' }; 14 | ) 15 | 16 | foreach ($entry in $branchMarkers) { 17 | if (git rev-list HEAD | Select-String -Pattern $entry.commit) { 18 | return $entry.branch 19 | } 20 | } 21 | 22 | if ($ErrorIfNotRelated) { 23 | 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." 24 | exit 1 25 | } 26 | -------------------------------------------------------------------------------- /tools/Get-NuGetTool.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads the NuGet.exe tool and returns the path to it. 4 | .PARAMETER NuGetVersion 5 | The version of the NuGet tool to acquire. 6 | #> 7 | Param( 8 | [Parameter()] 9 | [string]$NuGetVersion='6.12.2' 10 | ) 11 | 12 | $toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" 13 | $binaryToolsPath = Join-Path $toolsPath $NuGetVersion 14 | if (!(Test-Path $binaryToolsPath)) { $null = mkdir $binaryToolsPath } 15 | $nugetPath = Join-Path $binaryToolsPath nuget.exe 16 | 17 | if (!(Test-Path $nugetPath)) { 18 | Write-Host "Downloading nuget.exe $NuGetVersion..." -ForegroundColor Yellow 19 | (New-Object System.Net.WebClient).DownloadFile("https://dist.nuget.org/win-x86-commandline/v$NuGetVersion/NuGet.exe", $nugetPath) 20 | } 21 | 22 | return (Resolve-Path $nugetPath).Path 23 | -------------------------------------------------------------------------------- /tools/Get-ProcDump.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Downloads 32-bit and 64-bit procdump executables and returns the path to where they were installed. 4 | #> 5 | $version = '0.0.1' 6 | $baseDir = "$PSScriptRoot\..\obj\tools" 7 | $procDumpToolPath = "$baseDir\procdump.$version\bin" 8 | if (-not (Test-Path $procDumpToolPath)) { 9 | if (-not (Test-Path $baseDir)) { New-Item -Type Directory -Path $baseDir | Out-Null } 10 | $baseDir = (Resolve-Path $baseDir).Path # Normalize it 11 | & (& $PSScriptRoot\Get-NuGetTool.ps1) install procdump -version $version -PackageSaveMode nuspec -OutputDirectory $baseDir -Source https://api.nuget.org/v3/index.json | Out-Null 12 | } 13 | 14 | (Resolve-Path $procDumpToolPath).Path 15 | -------------------------------------------------------------------------------- /tools/Get-SymbolFiles.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Collect the list of PDBs built in this repo. 4 | .PARAMETER Path 5 | The directory to recursively search for PDBs. 6 | .PARAMETER Tests 7 | A switch indicating to find PDBs only for test binaries instead of only for shipping shipping binaries. 8 | #> 9 | [CmdletBinding()] 10 | param ( 11 | [parameter(Mandatory=$true)] 12 | [string]$Path, 13 | [switch]$Tests 14 | ) 15 | 16 | $ActivityName = "Collecting symbols from $Path" 17 | Write-Progress -Activity $ActivityName -CurrentOperation "Discovery PDB files" 18 | $PDBs = Get-ChildItem -rec "$Path/*.pdb" 19 | 20 | # Filter PDBs to product OR test related. 21 | $testregex = "unittest|tests|\.test\." 22 | 23 | Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" 24 | $PDBsByHash = @{} 25 | $i = 0 26 | $PDBs |% { 27 | Write-Progress -Activity $ActivityName -CurrentOperation "De-duplicating symbols" -PercentComplete (100 * $i / $PDBs.Length) 28 | $hash = Get-FileHash $_ 29 | $i++ 30 | Add-Member -InputObject $_ -MemberType NoteProperty -Name Hash -Value $hash.Hash 31 | Write-Output $_ 32 | } | Sort-Object CreationTime |% { 33 | # De-dupe based on hash. Prefer the first match so we take the first built copy. 34 | if (-not $PDBsByHash.ContainsKey($_.Hash)) { 35 | $PDBsByHash.Add($_.Hash, $_.FullName) 36 | Write-Output $_ 37 | } 38 | } |? { 39 | if ($Tests) { 40 | $_.FullName -match $testregex 41 | } else { 42 | $_.FullName -notmatch $testregex 43 | } 44 | } |% { 45 | # Collect the DLLs/EXEs as well. 46 | $rootName = "$($_.Directory)/$($_.BaseName)" 47 | if ($rootName.EndsWith('.ni')) { 48 | $rootName = $rootName.Substring(0, $rootName.Length - 3) 49 | } 50 | 51 | $dllPath = "$rootName.dll" 52 | $exePath = "$rootName.exe" 53 | if (Test-Path $dllPath) { 54 | $BinaryImagePath = $dllPath 55 | } elseif (Test-Path $exePath) { 56 | $BinaryImagePath = $exePath 57 | } else { 58 | Write-Warning "`"$_`" found with no matching binary file." 59 | $BinaryImagePath = $null 60 | } 61 | 62 | if ($BinaryImagePath) { 63 | Write-Output $BinaryImagePath 64 | Write-Output $_.FullName 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /tools/Get-TempToolsPath.ps1: -------------------------------------------------------------------------------- 1 | if ($env:AGENT_TEMPDIRECTORY) { 2 | $path = "$env:AGENT_TEMPDIRECTORY\$env:BUILD_BUILDID" 3 | } elseif ($env:localappdata) { 4 | $path = "$env:localappdata\gitrepos\tools" 5 | } else { 6 | $path = "$PSScriptRoot\..\obj\tools" 7 | } 8 | 9 | if (!(Test-Path $path)) { 10 | New-Item -ItemType Directory -Path $Path | Out-Null 11 | } 12 | 13 | (Resolve-Path $path).Path 14 | -------------------------------------------------------------------------------- /tools/Install-NuGetCredProvider.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .SYNOPSIS 5 | Downloads and installs the Microsoft Artifacts Credential Provider 6 | from https://github.com/microsoft/artifacts-credprovider 7 | to assist in authenticating to Azure Artifact feeds in interactive development 8 | or unattended build agents. 9 | .PARAMETER Force 10 | Forces install of the CredProvider plugin even if one already exists. This is useful to upgrade an older version. 11 | .PARAMETER AccessToken 12 | An optional access token for authenticating to Azure Artifacts authenticated feeds. 13 | #> 14 | [CmdletBinding()] 15 | Param ( 16 | [Parameter()] 17 | [switch]$Force, 18 | [Parameter()] 19 | [string]$AccessToken 20 | ) 21 | 22 | $envVars = @{} 23 | 24 | $toolsPath = & "$PSScriptRoot\Get-TempToolsPath.ps1" 25 | 26 | if ($IsMacOS -or $IsLinux) { 27 | $installerScript = "installcredprovider.sh" 28 | $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.sh" 29 | } else { 30 | $installerScript = "installcredprovider.ps1" 31 | $sourceUrl = "https://raw.githubusercontent.com/microsoft/artifacts-credprovider/master/helpers/installcredprovider.ps1" 32 | } 33 | 34 | $installerScript = Join-Path $toolsPath $installerScript 35 | 36 | if (!(Test-Path $installerScript) -or $Force) { 37 | Invoke-WebRequest $sourceUrl -OutFile $installerScript 38 | } 39 | 40 | $installerScript = (Resolve-Path $installerScript).Path 41 | 42 | if ($IsMacOS -or $IsLinux) { 43 | chmod u+x $installerScript 44 | } 45 | 46 | & $installerScript -Force:$Force -AddNetfx -InstallNet8 47 | 48 | if ($AccessToken) { 49 | $endpoints = @() 50 | 51 | $endpointURIs = @() 52 | Get-ChildItem "$PSScriptRoot\..\nuget.config" -Recurse |% { 53 | $nugetConfig = [xml](Get-Content -LiteralPath $_) 54 | 55 | $nugetConfig.configuration.packageSources.add |? { ($_.value -match '^https://pkgs\.dev\.azure\.com/') -or ($_.value -match '^https://[\w\-]+\.pkgs\.visualstudio\.com/') } |% { 56 | if ($endpointURIs -notcontains $_.Value) { 57 | $endpointURIs += $_.Value 58 | $endpoint = New-Object -TypeName PSObject 59 | Add-Member -InputObject $endpoint -MemberType NoteProperty -Name endpoint -Value $_.value 60 | Add-Member -InputObject $endpoint -MemberType NoteProperty -Name username -Value ado 61 | Add-Member -InputObject $endpoint -MemberType NoteProperty -Name password -Value $AccessToken 62 | $endpoints += $endpoint 63 | } 64 | } 65 | } 66 | 67 | $auth = New-Object -TypeName PSObject 68 | Add-Member -InputObject $auth -MemberType NoteProperty -Name endpointCredentials -Value $endpoints 69 | 70 | $authJson = ConvertTo-Json -InputObject $auth 71 | $envVars += @{ 72 | 'VSS_NUGET_EXTERNAL_FEED_ENDPOINTS'=$authJson; 73 | } 74 | } 75 | 76 | & "$PSScriptRoot/Set-EnvVars.ps1" -Variables $envVars | Out-Null 77 | -------------------------------------------------------------------------------- /tools/MergeFrom-Template.ps1: -------------------------------------------------------------------------------- 1 | 2 | <# 3 | .SYNOPSIS 4 | Merges the latest changes from Library.Template into HEAD of this repo. 5 | .PARAMETER LocalBranch 6 | The name of the local branch to create at HEAD and use to merge into from Library.Template. 7 | #> 8 | [CmdletBinding(SupportsShouldProcess = $true)] 9 | Param( 10 | [string]$LocalBranch = "dev/$($env:USERNAME)/libtemplateUpdate" 11 | ) 12 | 13 | Function Spawn-Tool($command, $commandArgs, $workingDirectory, $allowFailures) { 14 | if ($workingDirectory) { 15 | Push-Location $workingDirectory 16 | } 17 | try { 18 | if ($env:TF_BUILD) { 19 | Write-Host "$pwd >" 20 | Write-Host "##[command]$command $commandArgs" 21 | } 22 | else { 23 | Write-Host "$command $commandArgs" -ForegroundColor Yellow 24 | } 25 | if ($commandArgs) { 26 | & $command @commandArgs 27 | } else { 28 | Invoke-Expression $command 29 | } 30 | if ((!$allowFailures) -and ($LASTEXITCODE -ne 0)) { exit $LASTEXITCODE } 31 | } 32 | finally { 33 | if ($workingDirectory) { 34 | Pop-Location 35 | } 36 | } 37 | } 38 | 39 | $remoteBranch = & $PSScriptRoot\Get-LibTemplateBasis.ps1 -ErrorIfNotRelated 40 | if ($LASTEXITCODE -ne 0) { 41 | exit $LASTEXITCODE 42 | } 43 | 44 | $LibTemplateUrl = 'https://github.com/aarnott/Library.Template' 45 | Spawn-Tool 'git' ('fetch', $LibTemplateUrl, $remoteBranch) 46 | $SourceCommit = Spawn-Tool 'git' ('rev-parse', 'FETCH_HEAD') 47 | $BaseBranch = Spawn-Tool 'git' ('branch', '--show-current') 48 | $SourceCommitUrl = "$LibTemplateUrl/commit/$SourceCommit" 49 | 50 | # To reduce the odds of merge conflicts at this stage, we always move HEAD to the last successful merge. 51 | $basis = Spawn-Tool 'git' ('rev-parse', 'HEAD') # TODO: consider improving this later 52 | 53 | Write-Host "Merging the $remoteBranch branch of Library.Template ($SourceCommit) into local repo $basis" -ForegroundColor Green 54 | 55 | Spawn-Tool 'git' ('checkout', '-b', $LocalBranch, $basis) $null $true 56 | if ($LASTEXITCODE -eq 128) { 57 | Spawn-Tool 'git' ('checkout', $LocalBranch) 58 | Spawn-Tool 'git' ('merge', $basis) 59 | } 60 | 61 | Spawn-Tool 'git' ('merge', 'FETCH_HEAD', '--no-ff', '-m', "Merge the $remoteBranch branch from $LibTemplateUrl`n`nSpecifically, this merges [$SourceCommit from that repo]($SourceCommitUrl).") 62 | if ($LASTEXITCODE -eq 1) { 63 | Write-Error "Merge conflict detected. Manual resolution required." 64 | exit 1 65 | } 66 | elseif ($LASTEXITCODE -ne 0) { 67 | Write-Error "Merge failed with exit code $LASTEXITCODE." 68 | exit $LASTEXITCODE 69 | } 70 | 71 | $result = New-Object PSObject -Property @{ 72 | BaseBranch = $BaseBranch # The original branch that was checked out when the script ran. 73 | LocalBranch = $LocalBranch # The name of the local branch that was created before the merge. 74 | SourceCommit = $SourceCommit # The commit from Library.Template that was merged in. 75 | SourceBranch = $remoteBranch # The branch from Library.Template that was merged in. 76 | } 77 | 78 | Write-Host $result 79 | Write-Output $result 80 | -------------------------------------------------------------------------------- /tools/Prepare-Legacy-Symbols.ps1: -------------------------------------------------------------------------------- 1 | Param( 2 | [string]$Path 3 | ) 4 | 5 | $ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" 6 | $ArtifactStagingFolder += '/symbols-legacy' 7 | robocopy $Path $ArtifactStagingFolder /mir /njh /njs /ndl /nfl 8 | $WindowsPdbSubDirName = 'symstore' 9 | 10 | Get-ChildItem "$ArtifactStagingFolder\*.pdb" -Recurse |% { 11 | $dllPath = "$($_.Directory)/$($_.BaseName).dll" 12 | $exePath = "$($_.Directory)/$($_.BaseName).exe" 13 | if (Test-Path $dllPath) { 14 | $BinaryImagePath = $dllPath 15 | } elseif (Test-Path $exePath) { 16 | $BinaryImagePath = $exePath 17 | } else { 18 | Write-Warning "`"$_`" found with no matching binary file." 19 | $BinaryImagePath = $null 20 | } 21 | 22 | if ($BinaryImagePath) { 23 | # Convert the PDB to legacy Windows PDBs 24 | Write-Host "Converting PDB for $_" -ForegroundColor DarkGray 25 | $WindowsPdbDir = "$($_.Directory.FullName)\$WindowsPdbSubDirName" 26 | if (!(Test-Path $WindowsPdbDir)) { mkdir $WindowsPdbDir | Out-Null } 27 | $legacyPdbPath = "$WindowsPdbDir\$($_.BaseName).pdb" 28 | & "$PSScriptRoot\Convert-PDB.ps1" -DllPath $BinaryImagePath -PdbPath $_ -OutputPath $legacyPdbPath 29 | if ($LASTEXITCODE -ne 0) { 30 | Write-Warning "PDB conversion of `"$_`" failed." 31 | } 32 | 33 | Move-Item $legacyPdbPath $_ -Force 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /tools/Set-EnvVars.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Set environment variables in the environment. 4 | Azure Pipeline and CMD environments are considered. 5 | .PARAMETER Variables 6 | A hashtable of variables to be set. 7 | .PARAMETER PrependPath 8 | A set of paths to prepend to the PATH environment variable. 9 | .OUTPUTS 10 | A boolean indicating whether the environment variables can be expected to propagate to the caller's environment. 11 | .DESCRIPTION 12 | 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. 13 | 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. 14 | #> 15 | [CmdletBinding(SupportsShouldProcess=$true)] 16 | Param( 17 | [Parameter(Mandatory=$true, Position=1)] 18 | $Variables, 19 | [string[]]$PrependPath 20 | ) 21 | 22 | if ($Variables.Count -eq 0) { 23 | return $true 24 | } 25 | 26 | $cmdInstructions = !$env:TF_BUILD -and !$env:GITHUB_ACTIONS -and !$env:CmdEnvScriptPath -and ($env:PS1UnderCmd -eq '1') 27 | if ($cmdInstructions) { 28 | Write-Warning "Environment variables have been set that will be lost because you're running under cmd.exe" 29 | Write-Host "Environment variables that must be set manually:" -ForegroundColor Blue 30 | } else { 31 | Write-Host "Environment variables set:" -ForegroundColor Blue 32 | Write-Host ($Variables | Out-String) 33 | if ($PrependPath) { 34 | Write-Host "Paths prepended to PATH: $PrependPath" 35 | } 36 | } 37 | 38 | if ($env:TF_BUILD) { 39 | Write-Host "Azure Pipelines detected. Logging commands will be used to propagate environment variables and prepend path." 40 | } 41 | 42 | if ($env:GITHUB_ACTIONS) { 43 | Write-Host "GitHub Actions detected. Logging commands will be used to propagate environment variables and prepend path." 44 | } 45 | 46 | $CmdEnvScript = '' 47 | $Variables.GetEnumerator() |% { 48 | Set-Item -LiteralPath env:$($_.Key) -Value $_.Value 49 | 50 | # If we're running in a cloud CI, set these environment variables so they propagate. 51 | if ($env:TF_BUILD) { 52 | Write-Host "##vso[task.setvariable variable=$($_.Key);]$($_.Value)" 53 | } 54 | if ($env:GITHUB_ACTIONS) { 55 | Add-Content -LiteralPath $env:GITHUB_ENV -Value "$($_.Key)=$($_.Value)" 56 | } 57 | 58 | if ($cmdInstructions) { 59 | Write-Host "SET $($_.Key)=$($_.Value)" 60 | } 61 | 62 | $CmdEnvScript += "SET $($_.Key)=$($_.Value)`r`n" 63 | } 64 | 65 | $pathDelimiter = ';' 66 | if ($IsMacOS -or $IsLinux) { 67 | $pathDelimiter = ':' 68 | } 69 | 70 | if ($PrependPath) { 71 | $PrependPath |% { 72 | $newPathValue = "$_$pathDelimiter$env:PATH" 73 | Set-Item -LiteralPath env:PATH -Value $newPathValue 74 | if ($cmdInstructions) { 75 | Write-Host "SET PATH=$newPathValue" 76 | } 77 | 78 | if ($env:TF_BUILD) { 79 | Write-Host "##vso[task.prependpath]$_" 80 | } 81 | if ($env:GITHUB_ACTIONS) { 82 | Add-Content -LiteralPath $env:GITHUB_PATH -Value $_ 83 | } 84 | 85 | $CmdEnvScript += "SET PATH=$_$pathDelimiter%PATH%" 86 | } 87 | } 88 | 89 | if ($env:CmdEnvScriptPath) { 90 | if (Test-Path $env:CmdEnvScriptPath) { 91 | $CmdEnvScript = (Get-Content -LiteralPath $env:CmdEnvScriptPath) + $CmdEnvScript 92 | } 93 | 94 | Set-Content -LiteralPath $env:CmdEnvScriptPath -Value $CmdEnvScript 95 | } 96 | 97 | return !$cmdInstructions 98 | -------------------------------------------------------------------------------- /tools/artifacts/APIScanInputs.ps1: -------------------------------------------------------------------------------- 1 | $inputs = & "$PSScriptRoot/symbols.ps1" 2 | 3 | if (!$inputs) { return } 4 | 5 | # Filter out specific files that target OS's that are not subject to APIScan. 6 | # Files that are subject but are not supported must be scanned and an SEL exception filed. 7 | $outputs = @{} 8 | $forbiddenSubPaths = @( 9 | , 'linux-*' 10 | , 'osx*' 11 | ) 12 | 13 | $inputs.GetEnumerator() | % { 14 | $list = $_.Value | ? { 15 | $path = $_.Replace('\', '/') 16 | return !($forbiddenSubPaths | ? { $path -like "*/$_/*" }) 17 | } 18 | $outputs[$_.Key] = $list 19 | } 20 | 21 | 22 | $outputs 23 | -------------------------------------------------------------------------------- /tools/artifacts/LocBin.ps1: -------------------------------------------------------------------------------- 1 | # Identify LCE files and the binary files they describe 2 | $BinRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\bin") 3 | if (!(Test-Path $BinRoot)) { return } 4 | 5 | $FilesToCopy = @() 6 | $FilesToCopy += Get-ChildItem -Recurse -File -Path $BinRoot |? { $_.FullName -match '\\Localize\\' } 7 | 8 | Get-ChildItem -rec "$BinRoot\*.lce" -File | % { 9 | $FilesToCopy += $_ 10 | $FilesToCopy += $_.FullName.SubString(0, $_.FullName.Length - 4) 11 | } 12 | 13 | $FilesToCopy += Get-ChildItem -rec "$BinRoot\*.lcg" -File | % { [xml](Get-Content $_) } | % { $_.lcx.name } 14 | 15 | @{ 16 | "$BinRoot" = $FilesToCopy; 17 | } 18 | -------------------------------------------------------------------------------- /tools/artifacts/VSInsertion.ps1: -------------------------------------------------------------------------------- 1 | # This artifact captures everything needed to insert into VS (NuGet packages, insertion metadata, etc.) 2 | 3 | [CmdletBinding()] 4 | Param ( 5 | ) 6 | 7 | if ($IsMacOS -or $IsLinux) { 8 | # We only package up for insertions on Windows agents since they are where optprof can happen. 9 | Write-Verbose "Skipping VSInsertion artifact since we're not on Windows." 10 | return @{} 11 | } 12 | 13 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") 14 | $BuildConfiguration = $env:BUILDCONFIGURATION 15 | if (!$BuildConfiguration) { 16 | $BuildConfiguration = 'Debug' 17 | } 18 | 19 | $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" 20 | $NuGetPackages = "$PackagesRoot/NuGet" 21 | $VsixPackages = "$PackagesRoot/Vsix" 22 | 23 | if (!(Test-Path $NuGetPackages)) { 24 | Write-Warning "Skipping because NuGet packages haven't been built yet." 25 | return @{} 26 | } 27 | 28 | $result = @{ 29 | "$NuGetPackages" = (Get-ChildItem $NuGetPackages -Recurse) 30 | } 31 | 32 | if (Test-Path $VsixPackages) { 33 | $result["$PackagesRoot"] += Get-ChildItem $VsixPackages -Recurse 34 | } 35 | 36 | if ($env:IsOptProf) { 37 | $VSRepoPackages = "$PackagesRoot/VSRepo" 38 | $result["$VSRepoPackages"] = (Get-ChildItem "$VSRepoPackages\*.VSInsertionMetadata.*.nupkg"); 39 | } 40 | 41 | $result 42 | -------------------------------------------------------------------------------- /tools/artifacts/Variables.ps1: -------------------------------------------------------------------------------- 1 | # This artifact captures all variables defined in the ..\variables folder. 2 | # It "snaps" the values of these variables where we can compute them during the build, 3 | # and otherwise captures the scripts to run later during an Azure Pipelines environment release. 4 | 5 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot/../..") 6 | $ArtifactBasePath = "$RepoRoot/obj/_artifacts" 7 | $VariablesArtifactPath = Join-Path $ArtifactBasePath variables 8 | if (-not (Test-Path $VariablesArtifactPath)) { New-Item -ItemType Directory -Path $VariablesArtifactPath | Out-Null } 9 | 10 | # Copy variables, either by value if the value is calculable now, or by script 11 | Get-ChildItem "$PSScriptRoot/../variables" |% { 12 | $value = $null 13 | if (-not $_.BaseName.StartsWith('_')) { # Skip trying to interpret special scripts 14 | # First check the environment variables in case the variable was set in a queued build 15 | # Always use all caps for env var access because Azure Pipelines converts variables to upper-case for env vars, 16 | # and on non-Windows env vars are case sensitive. 17 | $envVarName = $_.BaseName.ToUpper() 18 | if (Test-Path env:$envVarName) { 19 | $value = Get-Content "env:$envVarName" 20 | } 21 | 22 | # If that didn't give us anything, try executing the script right now from its original position 23 | if (-not $value) { 24 | $value = & $_.FullName 25 | } 26 | 27 | if ($value) { 28 | # We got something, so wrap it with quotes so it's treated like a literal value. 29 | $value = "'$value'" 30 | } 31 | } 32 | 33 | # If that didn't get us anything, just copy the script itself 34 | if (-not $value) { 35 | $value = Get-Content -LiteralPath $_.FullName 36 | } 37 | 38 | Set-Content -LiteralPath "$VariablesArtifactPath/$($_.Name)" -Value $value 39 | } 40 | 41 | @{ 42 | "$VariablesArtifactPath" = (Get-ChildItem $VariablesArtifactPath -Recurse); 43 | } 44 | -------------------------------------------------------------------------------- /tools/artifacts/_all.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .SYNOPSIS 5 | This script returns all the artifacts that should be collected after a build. 6 | Each powershell artifact is expressed as an object with these properties: 7 | Source - the full path to the source file 8 | ArtifactName - the name of the artifact to upload to 9 | ContainerFolder - the relative path within the artifact in which the file should appear 10 | Each artifact aggregating .ps1 script should return a hashtable: 11 | Key = path to the directory from which relative paths within the artifact should be calculated 12 | Value = an array of paths (absolute or relative to the BaseDirectory) to files to include in the artifact. 13 | FileInfo objects are also allowed. 14 | .PARAMETER Force 15 | Executes artifact scripts even if they have already been staged. 16 | #> 17 | 18 | [CmdletBinding(SupportsShouldProcess = $true)] 19 | param ( 20 | [string]$ArtifactNameSuffix, 21 | [switch]$Force 22 | ) 23 | 24 | Function EnsureTrailingSlash($path) { 25 | if ($path.length -gt 0 -and !$path.EndsWith('\') -and !$path.EndsWith('/')) { 26 | $path = $path + [IO.Path]::DirectorySeparatorChar 27 | } 28 | 29 | $path.Replace('\', [IO.Path]::DirectorySeparatorChar) 30 | } 31 | 32 | Function Test-ArtifactStaged($artifactName) { 33 | $varName = "ARTIFACTSTAGED_$($artifactName.ToUpper())" 34 | Test-Path "env:$varName" 35 | } 36 | 37 | Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" -Recurse | % { 38 | $ArtifactName = $_.BaseName 39 | if ($Force -or !(Test-ArtifactStaged($ArtifactName + $ArtifactNameSuffix))) { 40 | $totalFileCount = 0 41 | Write-Verbose "Collecting file list for artifact $($_.BaseName)" 42 | $fileGroups = & $_ 43 | if ($fileGroups) { 44 | $fileGroups.GetEnumerator() | % { 45 | $BaseDirectory = New-Object Uri ((EnsureTrailingSlash $_.Key.ToString()), [UriKind]::Absolute) 46 | $_.Value | ? { $_ } | % { 47 | if ($_.GetType() -eq [IO.FileInfo] -or $_.GetType() -eq [IO.DirectoryInfo]) { 48 | $_ = $_.FullName 49 | } 50 | 51 | $artifact = New-Object -TypeName PSObject 52 | Add-Member -InputObject $artifact -MemberType NoteProperty -Name ArtifactName -Value $ArtifactName 53 | 54 | $SourceFullPath = New-Object Uri ($BaseDirectory, $_) 55 | Add-Member -InputObject $artifact -MemberType NoteProperty -Name Source -Value $SourceFullPath.LocalPath 56 | 57 | $RelativePath = [Uri]::UnescapeDataString($BaseDirectory.MakeRelative($SourceFullPath)) 58 | Add-Member -InputObject $artifact -MemberType NoteProperty -Name ContainerFolder -Value (Split-Path $RelativePath) 59 | 60 | Write-Output $artifact 61 | $totalFileCount += 1 62 | } 63 | } 64 | } 65 | 66 | if ($totalFileCount -eq 0) { 67 | Write-Warning "No files found for the `"$ArtifactName`" artifact." 68 | } 69 | } else { 70 | Write-Host "Skipping $ArtifactName because it has already been staged." -ForegroundColor DarkGray 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /tools/artifacts/_stage_all.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script links all the artifacts described by _all.ps1 4 | into a staging directory, reading for uploading to a cloud build artifact store. 5 | It returns a sequence of objects with Name and Path properties. 6 | #> 7 | 8 | [CmdletBinding()] 9 | param ( 10 | [string]$ArtifactNameSuffix, 11 | [switch]$AvoidSymbolicLinks 12 | ) 13 | 14 | $ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" -CleanIfLocal 15 | 16 | function Create-SymbolicLink { 17 | param ( 18 | $Link, 19 | $Target 20 | ) 21 | 22 | if ($Link -eq $Target) { 23 | return 24 | } 25 | 26 | if (Test-Path $Link) { Remove-Item $Link } 27 | $LinkContainer = Split-Path $Link -Parent 28 | if (!(Test-Path $LinkContainer)) { mkdir $LinkContainer } 29 | if ($IsMacOS -or $IsLinux) { 30 | ln $Target $Link | Out-Null 31 | } else { 32 | cmd /c "mklink `"$Link`" `"$Target`"" | Out-Null 33 | } 34 | 35 | if ($LASTEXITCODE -ne 0) { 36 | # Windows requires admin privileges to create symbolic links 37 | # unless Developer Mode has been enabled. 38 | throw "Failed to create symbolic link at $Link that points to $Target" 39 | } 40 | } 41 | 42 | # Stage all artifacts 43 | $Artifacts = & "$PSScriptRoot\_all.ps1" -ArtifactNameSuffix $ArtifactNameSuffix 44 | $Artifacts |% { 45 | $DestinationFolder = [System.IO.Path]::GetFullPath("$ArtifactStagingFolder/$($_.ArtifactName)$ArtifactNameSuffix/$($_.ContainerFolder)").TrimEnd('\') 46 | $Name = "$(Split-Path $_.Source -Leaf)" 47 | 48 | #Write-Host "$($_.Source) -> $($_.ArtifactName)\$($_.ContainerFolder)" -ForegroundColor Yellow 49 | 50 | if (-not (Test-Path $DestinationFolder)) { New-Item -ItemType Directory -Path $DestinationFolder | Out-Null } 51 | if (Test-Path -PathType Leaf $_.Source) { # skip folders 52 | $TargetPath = Join-Path $DestinationFolder $Name 53 | if ($AvoidSymbolicLinks) { 54 | Copy-Item -LiteralPath $_.Source -Destination $TargetPath 55 | } else { 56 | Create-SymbolicLink -Link $TargetPath -Target $_.Source 57 | } 58 | } 59 | } 60 | 61 | $ArtifactNames = $Artifacts |% { "$($_.ArtifactName)$ArtifactNameSuffix" } 62 | $ArtifactNames += Get-ChildItem env:ARTIFACTSTAGED_* |% { 63 | # Return from ALLCAPS to the actual capitalization used for the artifact. 64 | $artifactNameAllCaps = "$($_.Name.Substring('ARTIFACTSTAGED_'.Length))" 65 | (Get-ChildItem $ArtifactStagingFolder\$artifactNameAllCaps* -Filter $artifactNameAllCaps).Name 66 | } 67 | $ArtifactNames | Get-Unique |% { 68 | $artifact = New-Object -TypeName PSObject 69 | Add-Member -InputObject $artifact -MemberType NoteProperty -Name Name -Value $_ 70 | Add-Member -InputObject $artifact -MemberType NoteProperty -Name Path -Value (Join-Path $ArtifactStagingFolder $_) 71 | Write-Output $artifact 72 | } 73 | -------------------------------------------------------------------------------- /tools/artifacts/build_logs.ps1: -------------------------------------------------------------------------------- 1 | $ArtifactStagingFolder = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" 2 | 3 | if (!(Test-Path $ArtifactStagingFolder/build_logs)) { return } 4 | 5 | @{ 6 | "$ArtifactStagingFolder/build_logs" = (Get-ChildItem -Recurse "$ArtifactStagingFolder/build_logs") 7 | } 8 | -------------------------------------------------------------------------------- /tools/artifacts/coverageResults.ps1: -------------------------------------------------------------------------------- 1 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") 2 | 3 | $coverageFiles = @(Get-ChildItem "$RepoRoot/test/*.cobertura.xml" -Recurse | Where {$_.FullName -notlike "*/In/*" -and $_.FullName -notlike "*\In\*" }) 4 | 5 | # Prepare code coverage reports for merging on another machine 6 | $repoRoot = $env:SYSTEM_DEFAULTWORKINGDIRECTORY 7 | if (!$repoRoot) { $repoRoot = $env:GITHUB_WORKSPACE } 8 | if ($repoRoot) { 9 | Write-Host "Substituting $repoRoot with `"{reporoot}`"" 10 | $coverageFiles |% { 11 | $content = Get-Content -LiteralPath $_ |% { $_ -Replace [regex]::Escape($repoRoot), "{reporoot}" } 12 | Set-Content -LiteralPath $_ -Value $content -Encoding UTF8 13 | } 14 | } else { 15 | Write-Warning "coverageResults: Cloud build not detected. Machine-neutral token replacement skipped." 16 | } 17 | 18 | if (!((Test-Path $RepoRoot\bin) -and (Test-Path $RepoRoot\obj))) { return } 19 | 20 | @{ 21 | $RepoRoot = ( 22 | $coverageFiles + 23 | (Get-ChildItem "$RepoRoot\obj\*.cs" -Recurse) 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /tools/artifacts/deployables.ps1: -------------------------------------------------------------------------------- 1 | $RepoRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..") 2 | $BuildConfiguration = $env:BUILDCONFIGURATION 3 | if (!$BuildConfiguration) { 4 | $BuildConfiguration = 'Debug' 5 | } 6 | 7 | $PackagesRoot = "$RepoRoot/bin/Packages/$BuildConfiguration" 8 | 9 | if (!(Test-Path $PackagesRoot)) { return } 10 | 11 | @{ 12 | "$PackagesRoot" = (Get-ChildItem $PackagesRoot -Recurse) 13 | } 14 | -------------------------------------------------------------------------------- /tools/artifacts/projectAssetsJson.ps1: -------------------------------------------------------------------------------- 1 | $ObjRoot = [System.IO.Path]::GetFullPath("$PSScriptRoot\..\..\obj") 2 | 3 | if (!(Test-Path $ObjRoot)) { return } 4 | 5 | @{ 6 | "$ObjRoot" = ( 7 | (Get-ChildItem "$ObjRoot\project.assets.json" -Recurse) 8 | ); 9 | } 10 | -------------------------------------------------------------------------------- /tools/artifacts/symbols.ps1: -------------------------------------------------------------------------------- 1 | $BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") 2 | if (!(Test-Path $BinPath)) { return } 3 | $symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath | Get-Unique 4 | 5 | @{ 6 | "$BinPath" = $SymbolFiles; 7 | } 8 | -------------------------------------------------------------------------------- /tools/artifacts/testResults.ps1: -------------------------------------------------------------------------------- 1 | [CmdletBinding()] 2 | Param( 3 | ) 4 | 5 | $result = @{} 6 | 7 | $testRoot = Resolve-Path "$PSScriptRoot\..\..\test" 8 | $result[$testRoot] = (Get-ChildItem "$testRoot\TestResults" -Recurse -Directory | Get-ChildItem -Recurse -File) 9 | 10 | $artifactStaging = & "$PSScriptRoot/../Get-ArtifactsStagingDirectory.ps1" 11 | $testlogsPath = Join-Path $artifactStaging "test_logs" 12 | if (Test-Path $testlogsPath) { 13 | $result[$testlogsPath] = Get-ChildItem $testlogsPath -Recurse; 14 | } 15 | 16 | $result 17 | -------------------------------------------------------------------------------- /tools/artifacts/test_symbols.ps1: -------------------------------------------------------------------------------- 1 | $BinPath = [System.IO.Path]::GetFullPath("$PSScriptRoot/../../bin") 2 | if (!(Test-Path $BinPath)) { return } 3 | $symbolfiles = & "$PSScriptRoot/../Get-SymbolFiles.ps1" -Path $BinPath -Tests | Get-Unique 4 | 5 | @{ 6 | "$BinPath" = $SymbolFiles; 7 | } 8 | -------------------------------------------------------------------------------- /tools/dotnet-test-cloud.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .SYNOPSIS 5 | Runs tests as they are run in cloud test runs. 6 | .PARAMETER Configuration 7 | The configuration within which to run tests 8 | .PARAMETER Agent 9 | The name of the agent. This is used in preparing test run titles. 10 | .PARAMETER PublishResults 11 | A switch to publish results to Azure Pipelines. 12 | .PARAMETER x86 13 | A switch to run the tests in an x86 process. 14 | .PARAMETER dotnet32 15 | The path to a 32-bit dotnet executable to use. 16 | #> 17 | [CmdletBinding()] 18 | Param( 19 | [string]$Configuration = 'Debug', 20 | [string]$Agent = 'Local', 21 | [switch]$PublishResults, 22 | [switch]$x86, 23 | [string]$dotnet32 24 | ) 25 | 26 | $RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path 27 | $ArtifactStagingFolder = & "$PSScriptRoot/Get-ArtifactsStagingDirectory.ps1" 28 | 29 | $dotnet = 'dotnet' 30 | if ($x86) { 31 | $x86RunTitleSuffix = ", x86" 32 | if ($dotnet32) { 33 | $dotnet = $dotnet32 34 | } 35 | else { 36 | $dotnet32Possibilities = "$PSScriptRoot\../obj/tools/x86/.dotnet/dotnet.exe", "$env:AGENT_TOOLSDIRECTORY/x86/dotnet/dotnet.exe", "${env:ProgramFiles(x86)}\dotnet\dotnet.exe" 37 | $dotnet32Matches = $dotnet32Possibilities | ? { Test-Path $_ } 38 | if ($dotnet32Matches) { 39 | $dotnet = Resolve-Path @($dotnet32Matches)[0] 40 | Write-Host "Running tests using `"$dotnet`"" -ForegroundColor DarkGray 41 | } 42 | else { 43 | Write-Error "Unable to find 32-bit dotnet.exe" 44 | return 1 45 | } 46 | } 47 | } 48 | 49 | $testBinLog = Join-Path $ArtifactStagingFolder (Join-Path build_logs test.binlog) 50 | $testDiagLog = Join-Path $ArtifactStagingFolder (Join-Path test_logs diag.log) 51 | 52 | & $dotnet test "$RepoRoot\test\Microsoft.VisualStudio.Jdt.Tests"` 53 | --no-build ` 54 | -c $Configuration ` 55 | --filter "TestCategory!=FailsInCloudTest" ` 56 | --collect "Code Coverage;Format=cobertura" ` 57 | --settings "$PSScriptRoot/test.runsettings" ` 58 | --blame-hang-timeout 60s ` 59 | --blame-crash ` 60 | -bl:"$testBinLog" ` 61 | --diag "$testDiagLog;TraceLevel=info" ` 62 | --logger trx ` 63 | 64 | $unknownCounter = 0 65 | Get-ChildItem -Recurse -Path $RepoRoot\test\*.trx | % { 66 | Copy-Item $_ -Destination $ArtifactStagingFolder/test_logs/ 67 | 68 | if ($PublishResults) { 69 | $x = [xml](Get-Content -LiteralPath $_) 70 | $runTitle = $null 71 | if ($x.TestRun.TestDefinitions -and $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')) { 72 | $storage = $x.TestRun.TestDefinitions.GetElementsByTagName('UnitTest')[0].storage -replace '\\', '/' 73 | if ($storage -match '/(?net[^/]+)/(?:(?[^/]+)/)?(?[^/]+)\.(dll|exe)$') { 74 | if ($matches.rid) { 75 | $runTitle = "$($matches.lib) ($($matches.tfm), $($matches.rid), $Agent)" 76 | } 77 | else { 78 | $runTitle = "$($matches.lib) ($($matches.tfm)$x86RunTitleSuffix, $Agent)" 79 | } 80 | } 81 | } 82 | if (!$runTitle) { 83 | $unknownCounter += 1; 84 | $runTitle = "unknown$unknownCounter ($Agent$x86RunTitleSuffix)"; 85 | } 86 | 87 | Write-Host "##vso[results.publish type=VSTest;runTitle=$runTitle;publishRunAttachments=true;resultFiles=$_;failTaskOnFailedTests=true;testRunSystem=VSTS - PTR;]" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /tools/publish-CodeCov.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Uploads code coverage to codecov.io 4 | .PARAMETER CodeCovToken 5 | Code coverage token to use 6 | .PARAMETER PathToCodeCoverage 7 | Path to root of code coverage files 8 | .PARAMETER Name 9 | Name to upload with codecoverge 10 | .PARAMETER Flags 11 | Flags to upload with codecoverge 12 | #> 13 | [CmdletBinding()] 14 | Param ( 15 | [Parameter(Mandatory=$true)] 16 | [string]$CodeCovToken, 17 | [Parameter(Mandatory=$true)] 18 | [string]$PathToCodeCoverage, 19 | [string]$Name, 20 | [string]$Flags 21 | ) 22 | 23 | $RepoRoot = (Resolve-Path "$PSScriptRoot/..").Path 24 | 25 | Get-ChildItem -Recurse -LiteralPath $PathToCodeCoverage -Filter "*.cobertura.xml" | % { 26 | $relativeFilePath = Resolve-Path -relative $_.FullName 27 | 28 | Write-Host "Uploading: $relativeFilePath" -ForegroundColor Yellow 29 | & (& "$PSScriptRoot/Get-CodeCovTool.ps1") -t $CodeCovToken -f $relativeFilePath -R $RepoRoot -F $Flags -n $Name 30 | } 31 | -------------------------------------------------------------------------------- /tools/test.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | \.dll$ 10 | \.exe$ 11 | 12 | 13 | xunit\..* 14 | 15 | 16 | 17 | 18 | ^System\.Diagnostics\.DebuggerHiddenAttribute$ 19 | ^System\.Diagnostics\.DebuggerNonUserCodeAttribute$ 20 | ^System\.CodeDom\.Compiler\.GeneratedCodeAttribute$ 21 | ^System\.Diagnostics\.CodeAnalysis\.ExcludeFromCodeCoverageAttribute$ 22 | 23 | 24 | 25 | 26 | True 27 | 28 | True 29 | 30 | True 31 | 32 | False 33 | 34 | False 35 | 36 | False 37 | 38 | True 39 | 40 | 41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /tools/variables/BusinessGroupName.ps1: -------------------------------------------------------------------------------- 1 | 'Visual Studio - VS Core' 2 | -------------------------------------------------------------------------------- /tools/variables/DotNetSdkVersion.ps1: -------------------------------------------------------------------------------- 1 | $globalJson = Get-Content -LiteralPath "$PSScriptRoot\..\..\global.json" | ConvertFrom-Json 2 | $globalJson.sdk.version 3 | -------------------------------------------------------------------------------- /tools/variables/InsertJsonValues.ps1: -------------------------------------------------------------------------------- 1 | $vstsDropNames = & "$PSScriptRoot\VstsDropNames.ps1" 2 | $BuildConfiguration = $env:BUILDCONFIGURATION 3 | if (!$BuildConfiguration) { 4 | $BuildConfiguration = 'Debug' 5 | } 6 | 7 | $BasePath = "$PSScriptRoot\..\..\bin\Packages\$BuildConfiguration\Vsix" 8 | 9 | if (Test-Path $BasePath) { 10 | $vsmanFiles = @() 11 | Get-ChildItem $BasePath *.vsman -Recurse -File |% { 12 | $version = (Get-Content $_.FullName | ConvertFrom-Json).info.buildVersion 13 | $fn = $_.Name 14 | $vsmanFiles += "$fn{$version}=https://vsdrop.corp.microsoft.com/file/v1/$vstsDropNames;$fn" 15 | } 16 | 17 | [string]::join(',',$vsmanFiles) 18 | } 19 | -------------------------------------------------------------------------------- /tools/variables/InsertPropsValues.ps1: -------------------------------------------------------------------------------- 1 | $InsertedPkgs = (& "$PSScriptRoot\..\artifacts\VSInsertion.ps1") 2 | 3 | $icv=@() 4 | foreach ($kvp in $InsertedPkgs.GetEnumerator()) { 5 | $kvp.Value |% { 6 | if ($_.Name -match "^(.*?)\.(\d+\.\d+\.\d+(?:\.\d+)?(?:-.*?)?)(?:\.symbols)?\.nupkg$") { 7 | $id = $Matches[1] 8 | $version = $Matches[2] 9 | $icv += "$id=$version" 10 | } 11 | } 12 | } 13 | 14 | Write-Output ([string]::join(',',$icv)) 15 | -------------------------------------------------------------------------------- /tools/variables/InsertTargetBranch.ps1: -------------------------------------------------------------------------------- 1 | # This is the default branch of the VS repo that we will use to insert into VS. 2 | 'main' 3 | -------------------------------------------------------------------------------- /tools/variables/InsertVersionsValues.ps1: -------------------------------------------------------------------------------- 1 | # When you need binding redirects in the VS repo updated to match 2 | # assemblies that you build here, remove the "return" statement 3 | # and update the hashtable below with the T4 macro you'll use for 4 | # your libraries as defined in the src\ProductData\AssemblyVersions.tt file. 5 | return 6 | 7 | $MacroName = 'LibraryNoDotsVersion' 8 | $SampleProject = "$PSScriptRoot\..\..\src\LibraryName" 9 | [string]::join(',',(@{ 10 | ($MacroName) = & { (dotnet nbgv get-version --project $SampleProject --format json | ConvertFrom-Json).AssemblyVersion }; 11 | }.GetEnumerator() |% { "$($_.key)=$($_.value)" })) 12 | -------------------------------------------------------------------------------- /tools/variables/LocLanguages.ps1: -------------------------------------------------------------------------------- 1 | ## For faster PR/CI builds localize only for 2 languages, ENU and JPN provide good enough coverage 2 | if ($env:BUILD_REASON -eq 'PullRequest') { 3 | 'ENU,JPN' 4 | } else { 5 | 'VS' 6 | } 7 | -------------------------------------------------------------------------------- /tools/variables/ProfilingInputsDropName.ps1: -------------------------------------------------------------------------------- 1 | if ($env:SYSTEM_TEAMPROJECT) { 2 | "ProfilingInputs/$env:SYSTEM_TEAMPROJECT/$env:BUILD_REPOSITORY_NAME/$env:BUILD_SOURCEBRANCHNAME/$env:BUILD_BUILDID" 3 | } else { 4 | Write-Warning "No Azure Pipelines build detected. No Azure Pipelines drop name will be computed." 5 | } 6 | -------------------------------------------------------------------------------- /tools/variables/SymbolsFeatureName.ps1: -------------------------------------------------------------------------------- 1 | 'json-document-transforms' 2 | -------------------------------------------------------------------------------- /tools/variables/VstsDropNames.ps1: -------------------------------------------------------------------------------- 1 | "Products/$env:SYSTEM_TEAMPROJECT/$env:BUILD_REPOSITORY_NAME/$env:BUILD_SOURCEBRANCHNAME/$env:BUILD_BUILDID" 2 | -------------------------------------------------------------------------------- /tools/variables/_all.ps1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env pwsh 2 | 3 | <# 4 | .SYNOPSIS 5 | This script returns a hashtable of build variables that should be set 6 | at the start of a build or release definition's execution. 7 | #> 8 | 9 | [CmdletBinding(SupportsShouldProcess = $true)] 10 | param ( 11 | ) 12 | 13 | $vars = @{} 14 | 15 | Get-ChildItem "$PSScriptRoot\*.ps1" -Exclude "_*" |% { 16 | Write-Host "Computing $($_.BaseName) variable" 17 | $vars[$_.BaseName] = & $_ 18 | } 19 | 20 | $vars 21 | -------------------------------------------------------------------------------- /tools/variables/_define.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | This script translates the variables returned by the _all.ps1 script 4 | into commands that instruct Azure Pipelines to actually set those variables for other pipeline tasks to consume. 5 | 6 | The build or release definition may have set these variables to override 7 | what the build would do. So only set them if they have not already been set. 8 | #> 9 | 10 | [CmdletBinding()] 11 | param ( 12 | ) 13 | 14 | (& "$PSScriptRoot\_all.ps1").GetEnumerator() |% { 15 | # 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. 16 | $keyCaps = $_.Key.ToUpper() 17 | if ((Test-Path "env:$keyCaps") -and (Get-Content "env:$keyCaps")) { 18 | Write-Host "Skipping setting $keyCaps because variable is already set to '$(Get-Content env:$keyCaps)'." -ForegroundColor Cyan 19 | } else { 20 | Write-Host "$keyCaps=$($_.Value)" -ForegroundColor Yellow 21 | if ($env:TF_BUILD) { 22 | # Create two variables: the first that can be used by its simple name and accessible only within this job. 23 | Write-Host "##vso[task.setvariable variable=$keyCaps]$($_.Value)" 24 | # and the second that works across jobs and stages but must be fully qualified when referenced. 25 | Write-Host "##vso[task.setvariable variable=$keyCaps;isOutput=true]$($_.Value)" 26 | } elseif ($env:GITHUB_ACTIONS) { 27 | Add-Content -LiteralPath $env:GITHUB_ENV -Value "$keyCaps=$($_.Value)" 28 | } 29 | Set-Item -LiteralPath "env:$keyCaps" -Value $_.Value 30 | } 31 | } 32 | --------------------------------------------------------------------------------