├── .config └── tsaoptions.json ├── .github ├── pull_request_template.md └── workflows │ └── actions-pr.yml ├── .gitignore ├── CODE_OF_CONDUCT.md ├── Directory.Build.props ├── Directory.Build.targets ├── LICENSE.txt ├── README.md ├── SECURITY.md ├── SUPPORT.md ├── VSConfigFinder.Test ├── .editorconfig ├── ExtensionsTests.cs ├── UtilitiesTests.cs └── VSConfigFinder.Test.csproj ├── VSConfigFinder.sln ├── VSConfigFinder ├── .editorconfig ├── CommandLine │ ├── CommandLineOptions.cs │ ├── ICommandLineOptions.cs │ └── VSConfig.cs ├── ConsoleLogger.cs ├── Extensions.cs ├── FileSystem.cs ├── IFileSystem.cs ├── ILogger.cs ├── Program.cs ├── Utilities.cs └── VSConfigFinder.csproj ├── build.yml ├── global.json ├── pkg └── VSConfigFinder │ ├── VSConfigFinder.nuspec │ └── tools │ └── VERIFICATION.txt ├── version.json ├── vsts-ci.yml └── vsts-compliance.yml /.config/tsaoptions.json: -------------------------------------------------------------------------------- 1 | { 2 | "codebaseName": "Microsoft.VSConfigFinder", 3 | "instanceUrl": "https://devdiv.visualstudio.com/defaultcollection", 4 | "projectName": "DevDiv", 5 | "areaPath": "DevDiv\\VS Setup", 6 | "iterationPath": "DevDiv", 7 | "allTools": true 8 | } 9 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## What? 2 | _Include a sentence or two about what the change is trying to accomplish_ 3 | 4 | ## Why? 5 | _Include a sentence or two about why the change is needed_ 6 | 7 | ## How? 8 | _Include a sentence or two about how the change achieves its goal_ 9 | 10 | ## Testing? 11 | - [ ] Added unit tests 12 | - [ ] _Add any manual test scenarios_ 13 | 14 | ## Screenshots (optional) 15 | _Include any screenshots if the change includes UI changes_ 16 | 17 | ## Additional information (optional) 18 | _Include any additional information to help give context on the change_ 19 | -------------------------------------------------------------------------------- /.github/workflows/actions-pr.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information. 3 | 4 | name: PR Build 5 | 6 | on: [ pull_request ] 7 | 8 | env: 9 | # Path to the project source. 10 | PROJECT_PATH: VSConfigFinder 11 | 12 | # Path to the test project source. 13 | TEST_PROJECT_PATH: VSConfigFinder.Test 14 | 15 | # Configuration type to build. 16 | BUILD_CONFIGURATION: Release 17 | 18 | jobs: 19 | build: 20 | runs-on: windows-2022 21 | 22 | steps: 23 | - name: Checkout 24 | uses: actions/checkout@v3 25 | with: 26 | fetch-depth: 0 # avoid shallow clone so nbgv can do its work. 27 | 28 | - name: Install .NET Core SDK 29 | uses: actions/setup-dotnet@v3 30 | with: 31 | global-json-file: global.json 32 | 33 | - name: Restore dependencies 34 | run: dotnet restore 35 | 36 | - name: Build 37 | run: dotnet build --no-restore --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.PROJECT_PATH }} 38 | 39 | - name: Test 40 | run: dotnet test --verbosity normal --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.TEST_PROJECT_PATH }} 41 | 42 | - name: Publish 43 | run: dotnet publish --no-build --configuration ${{ env.BUILD_CONFIGURATION }} ${{ env.PROJECT_PATH }} 44 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | bld/ 19 | [Bb]in/ 20 | [Oo]bj/ 21 | 22 | # Visual Studio 2015 cache/options directory 23 | .vs/ 24 | 25 | # MSTest test Results 26 | [Tt]est[Rr]esult*/ 27 | [Bb]uild[Ll]og.* 28 | *.coverage 29 | 30 | # NUNIT 31 | *.VisualState.xml 32 | TestResult.xml 33 | 34 | # Build Results of an ATL Project 35 | [Dd]ebugPS/ 36 | [Rr]eleasePS/ 37 | dlldata.c 38 | 39 | # DNX 40 | project.lock.json 41 | artifacts/ 42 | 43 | *_i.c 44 | *_p.c 45 | *_i.h 46 | *.ilk 47 | *.meta 48 | *.obj 49 | *.opendb 50 | *.pch 51 | *.pdb 52 | *.pgc 53 | *.pgd 54 | *.rsp 55 | *.sbr 56 | *.tlb 57 | *.tli 58 | *.tlh 59 | *.tmp 60 | *.tmp_proj 61 | *.log 62 | *.binlog 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | *.db 81 | 82 | # Visual Studio profiler 83 | *.psess 84 | *.vsp 85 | *.vspx 86 | 87 | # TFS 2012 Local Workspace 88 | $tf/ 89 | 90 | # Guidance Automation Toolkit 91 | *.gpState 92 | 93 | # ReSharper is a .NET coding add-in 94 | _ReSharper*/ 95 | *.[Rr]e[Ss]harper 96 | *.DotSettings.user 97 | 98 | # JustCode is a .NET coding add-in 99 | .JustCode 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | _NCrunch_* 109 | .*crunch*.local.xml 110 | 111 | # MightyMoose 112 | *.mm.* 113 | AutoTest.Net/ 114 | 115 | # Web workbench (sass) 116 | .sass-cache/ 117 | 118 | # Installshield output folder 119 | [Ee]xpress/ 120 | 121 | # DocProject is a documentation generator add-in 122 | DocProject/buildhelp/ 123 | DocProject/Help/*.HxT 124 | DocProject/Help/*.HxC 125 | DocProject/Help/*.hhc 126 | DocProject/Help/*.hhk 127 | DocProject/Help/*.hhp 128 | DocProject/Help/Html2 129 | DocProject/Help/html 130 | 131 | # Click-Once directory 132 | publish/ 133 | 134 | # Publish Web Output 135 | *.[Pp]ublish.xml 136 | *.azurePubxml 137 | ## TODO: Comment the next line if you want to checkin your 138 | ## web deploy settings but do note that will include unencrypted 139 | ## passwords 140 | #*.pubxml 141 | 142 | *.publishproj 143 | 144 | # NuGet Packages 145 | *.nupkg 146 | *.nuget.* 147 | # The packages folder can be ignored because of Package Restore 148 | **/packages/* 149 | # except build/, which is used as an MSBuild target. 150 | !**/packages/build/ 151 | # Uncomment if necessary however generally it will be regenerated when needed 152 | #!**/packages/repositories.config 153 | 154 | # Windows Azure Build Output 155 | csx/ 156 | *.build.csdef 157 | 158 | # Windows Store app package directory 159 | AppPackages/ 160 | 161 | # Visual Studio cache files 162 | # files ending in .cache can be ignored 163 | *.[Cc]ache 164 | # but keep track of directories ending in .cache 165 | !*.[Cc]ache/ 166 | 167 | # Others 168 | ClientBin/ 169 | ~$* 170 | *~ 171 | *.dbmdl 172 | *.dbproj.schemaview 173 | *.pfx 174 | *.publishsettings 175 | node_modules/ 176 | orleans.codegen.cs 177 | 178 | # RIA/Silverlight projects 179 | Generated_Code/ 180 | 181 | # Backup & report files from converting an old project file 182 | # to a newer Visual Studio version. Backup files are not needed, 183 | # because we have git ;-) 184 | _UpgradeReport_Files/ 185 | Backup*/ 186 | UpgradeLog*.XML 187 | UpgradeLog*.htm 188 | 189 | # SQL Server files 190 | *.mdf 191 | *.ldf 192 | 193 | # Business Intelligence projects 194 | *.rdl.data 195 | *.bim.layout 196 | *.bim_*.settings 197 | 198 | # Microsoft Fakes 199 | FakesAssemblies/ 200 | 201 | # Node.js Tools for Visual Studio 202 | .ntvs_analysis.dat 203 | 204 | # Visual Studio 6 build log 205 | *.plg 206 | 207 | # Visual Studio 6 workspace options file 208 | *.opt 209 | launchSettings.json 210 | 211 | # LightSwitch generated files 212 | GeneratedArtifacts/ 213 | _Pvt_Extensions/ 214 | ModelManifest.xml 215 | 216 | # vcpkg generated files 217 | vcpkg_installed/ 218 | -------------------------------------------------------------------------------- /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 | 5 | true 6 | 7 | true 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /Directory.Build.targets: -------------------------------------------------------------------------------- 1 |  2 | 3 | 6 | 7 | 8 | true 9 | Microsoft400 10 | 11 | 12 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) Microsoft Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Visual Studio] VSConfig Finder 2 | 3 | ![build status: main](https://devdiv.visualstudio.com/DevDiv/_apis/build/status/Setup/VSConfigFinder-CI?branchName=main&label=main) 4 | [![github release](https://img.shields.io/github/release/Microsoft/vsconfigfinder.svg?logo=github&logoColor=white)](https://github.com/microsoft/VSConfigFinder/releases/latest) 5 | [![github releases: all](https://img.shields.io/github/downloads/Microsoft/vsconfigfinder/total.svg?logo=github&logoColor=white&label=github)](https://github.com/microsoft/VSConfigFinder/releases) 6 | 7 | When you want to set up Visual Studio from a new environment, `.vsconfig` files can be very useful as they are easy to be created from your [existing installations](https://learn.microsoft.com/en-us/visualstudio/install/import-export-installation-configurations?view=vs-2022) or from a [working solution](https://devblogs.microsoft.com/setup/configure-visual-studio-across-your-organization-with-vsconfig/). However, one existing problem with the `.vsconfig` usage is that the Visual Studio Installer supports importing one `.vsconfig` file at a time, so if you have multiple `.vsconfig`s throughout your solution (e.g. you have a monorepo that is consisted of multiple projects) and you want to apply them while setting up your pipeline, you would have to run an installer operation as many times as you'd want to use the different `.vsconfig`s. One way to get around this problem is to generate a single `.vsconfig` yourself that you put on the root of the solution, but this approach still has its own issues: For example, if you're only interested in a subset of the solution, you'll install far more components than the ones you need, resulting in a longer install and subsequent update time. 8 | 9 | _VSConfigFinder_ is designed to be a redistributable, single-file executable that can be used in build or deployment scripts to use multiple `.vsconfig`s that exist throughout the solution without having to go through multiple installer operations by recursively finding nested `.vsconfig` files and merging them into a single output file, or an installer command line argument, depending on the customer requirement. 10 | 11 | _VSConfigFinder_ is a simple tool and will not be shipped with the Visual Studio Installer, so please feel free to consume the package based on your need and use it for your own deployment setup. 12 | 13 | ## Example 14 | 15 | Imagine that you have a solution or a repository with the folder structure as below: 16 | 17 | ``` 18 | root 19 | - folderA 20 | - folderB 21 | - .vsconfig (packageE) 22 | - folderC 23 | - someProject 24 | - .vsconfig (packageA, packageB) 25 | - folderD 26 | - folderE 27 | - .vsconfig (pacakgeC) 28 | - folderF 29 | - .vsconfig (packageD) 30 | ``` 31 | 32 | If you want to pass in all the components that are needed to build & run `folderC`, you could run the tool with the following parameters: 33 | 34 | `VSConfigFinder.exe --folderpath root\folderC` 35 | 36 | This will generate the following command as a console output that you can simply pass into the installer. 37 | 38 | `--add packageA --add packageB --add packageC --add packageD` 39 | 40 | Remember to add your own verb (e.g. `install` or `modify`) in conjunction with the tool output. 41 | 42 | ## Multi-Root Folders Support 43 | 44 | Say if you want to do something similar to the example above, but you want everything under `folderB` AND `folderC`. You cannot pass in one or the other, because the two do not share a common folder (if you pass in the `root`, `folderA` will also be included). Instead, you can simply pass in the topmost folders as a list to achieve your goal. 45 | 46 | `VSConfigFinder.exe --folderpath root\folderC root\folderB` 47 | 48 | This will generate the following command as a console output that you can simply pass into the installer. 49 | 50 | `--add packageA --add packageB --add packageC --add packageD --add packageE` 51 | 52 | Again, remember to add your own verb (e.g. `install` or `modify`) in conjunction with the tool output. 53 | 54 | ## Alternate Example 55 | 56 | Alternatively, you can pass in additional parameters provided by the tool to get the merged `.vsconfig` as a single file: 57 | 58 | `VSConfigFinder.exe --folderpath root\folderC --createfile --configoutputpath c:\somefolder` 59 | 60 | This will generate an alternate single `.vsconfig` file with all the needed components in the specified `configOutputPath`. If you don't specify a `configOutputPath`, the output directory will default to the current directory. 61 | 62 | Note that if you choose to use `--createfile`, the Visual Studio Installer arguments will no longer be output to the console. 63 | 64 | ## Contributing 65 | 66 | This project welcomes contributions and suggestions. Most contributions require you to agree to a 67 | Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us 68 | the rights to use your contribution. For details, visit https://cla.opensource.microsoft.com. 69 | 70 | When you submit a pull request, a CLA bot will automatically determine whether you need to provide 71 | a CLA and decorate the PR appropriately (e.g., status check, comment). Simply follow the instructions 72 | provided by the bot. You will only need to do this once across all repos using our CLA. 73 | 74 | ## License 75 | 76 | This project is licensed under the [MIT license](LICENSE.txt). 77 | 78 | ## Code of Conduct 79 | 80 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). 81 | For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or 82 | contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments. 83 | 84 | ## Trademarks 85 | 86 | This project may contain trademarks or logos for projects, products, or services. Authorized use of Microsoft 87 | trademarks or logos is subject to and must follow 88 | [Microsoft's Trademark & Brand Guidelines](https://www.microsoft.com/en-us/legal/intellectualproperty/trademarks/usage/general). 89 | Use of Microsoft trademarks or logos in modified versions of this project must not cause confusion or imply Microsoft sponsorship. 90 | Any use of third-party trademarks or logos are subject to those third-party's policies. 91 | -------------------------------------------------------------------------------- /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://aka.ms/opensource/security/definition), 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://aka.ms/opensource/security/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://aka.ms/opensource/security/pgpkey). 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://aka.ms/opensource/security/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://aka.ms/opensource/security/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://aka.ms/opensource/security/cvd). 40 | 41 | 42 | -------------------------------------------------------------------------------- /SUPPORT.md: -------------------------------------------------------------------------------- 1 | # TODO: The maintainer of this repo has not yet edited this file 2 | 3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project? 4 | 5 | - **No CSS support:** Fill out this template with information about how to file issues and get help. 6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps. 7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide. 8 | 9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.* 10 | 11 | # Support 12 | 13 | ## How to file issues and get help 14 | 15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing 16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or 17 | feature request as a new Issue. 18 | 19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE 20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER 21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**. 22 | 23 | ## Microsoft Support Policy 24 | 25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above. 26 | -------------------------------------------------------------------------------- /VSConfigFinder.Test/.editorconfig: -------------------------------------------------------------------------------- 1 | file_header_template = \nCopyright (C) Microsoft Corporation. All rights reserved.\nLicensed under the MIT license. See LICENSE.txt in the project root for license information.\n 2 | 3 | # All files 4 | [*] 5 | indent_style = space 6 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 7 | tab_width = 4 8 | indent_size = 4 9 | end_of_line = crlf 10 | csharp_indent_labels = one_less_than_current 11 | dotnet_style_coalesce_expression = true:suggestion 12 | dotnet_style_null_propagation = true:suggestion 13 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 14 | dotnet_style_prefer_auto_properties = true:silent 15 | dotnet_style_object_initializer = true:suggestion 16 | dotnet_style_collection_initializer = true:suggestion 17 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 18 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 19 | csharp_using_directive_placement = inside_namespace:error 20 | csharp_prefer_simple_using_statement = true:suggestion 21 | csharp_prefer_braces = true:silent 22 | csharp_style_namespace_declarations = block_scoped:silent 23 | csharp_style_prefer_method_group_conversion = true:silent 24 | csharp_style_prefer_top_level_statements = true:silent 25 | csharp_style_expression_bodied_methods = false:silent 26 | csharp_style_expression_bodied_constructors = false:silent 27 | csharp_style_expression_bodied_operators = false:silent 28 | csharp_style_expression_bodied_properties = true:silent 29 | csharp_style_expression_bodied_indexers = true:silent 30 | csharp_style_expression_bodied_accessors = true:silent 31 | csharp_style_expression_bodied_lambdas = true:silent 32 | csharp_style_expression_bodied_local_functions = false:silent 33 | csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent 34 | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent 35 | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent 36 | csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent 37 | csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent 38 | csharp_new_line_before_open_brace = all 39 | csharp_style_throw_expression = true:suggestion 40 | csharp_prefer_simple_default_expression = true:suggestion 41 | csharp_style_prefer_null_check_over_type_check = true:suggestion 42 | csharp_style_prefer_local_over_anonymous_function = true:suggestion 43 | csharp_style_prefer_index_operator = true:suggestion 44 | csharp_style_prefer_range_operator = true:suggestion 45 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion 46 | csharp_style_prefer_tuple_swap = true:suggestion 47 | csharp_style_prefer_utf8_string_literals = true:suggestion 48 | csharp_style_inlined_variable_declaration = true:suggestion 49 | csharp_style_deconstructed_variable_declaration = true:suggestion 50 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 51 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 52 | csharp_prefer_static_local_function = true:suggestion 53 | csharp_style_prefer_readonly_struct = true:suggestion 54 | csharp_style_conditional_delegate_call = true:suggestion 55 | csharp_style_prefer_switch_expression = true:suggestion 56 | csharp_style_prefer_pattern_matching = true:silent 57 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 58 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 59 | csharp_style_prefer_not_pattern = true:suggestion 60 | csharp_style_prefer_extended_property_pattern = true:suggestion 61 | csharp_style_var_for_built_in_types = true:silent 62 | csharp_style_var_when_type_is_apparent = true:silent 63 | csharp_style_var_elsewhere = true:silent 64 | 65 | # Xml files 66 | [*.xml] 67 | indent_size = 2 68 | 69 | [*.{cs,vb}] 70 | #### Naming styles #### 71 | 72 | # Naming rules 73 | 74 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 75 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 76 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 77 | 78 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 79 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 80 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 81 | 82 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 83 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 84 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 85 | 86 | # Symbol specifications 87 | 88 | dotnet_naming_symbols.interface.applicable_kinds = interface 89 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 90 | dotnet_naming_symbols.interface.required_modifiers = 91 | 92 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 93 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 94 | dotnet_naming_symbols.types.required_modifiers = 95 | 96 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 97 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 98 | dotnet_naming_symbols.non_field_members.required_modifiers = 99 | 100 | # Naming styles 101 | 102 | dotnet_naming_style.begins_with_i.required_prefix = I 103 | dotnet_naming_style.begins_with_i.required_suffix = 104 | dotnet_naming_style.begins_with_i.word_separator = 105 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 106 | 107 | dotnet_naming_style.pascal_case.required_prefix = 108 | dotnet_naming_style.pascal_case.required_suffix = 109 | dotnet_naming_style.pascal_case.word_separator = 110 | dotnet_naming_style.pascal_case.capitalization = pascal_case 111 | 112 | dotnet_naming_style.pascal_case.required_prefix = 113 | dotnet_naming_style.pascal_case.required_suffix = 114 | dotnet_naming_style.pascal_case.word_separator = 115 | dotnet_naming_style.pascal_case.capitalization = pascal_case 116 | dotnet_style_allow_multiple_blank_lines_experimental = true:silent 117 | dotnet_style_allow_statement_immediately_after_block_experimental = true:silent 118 | 119 | # Diagnostics 120 | 121 | # CS8602: Dereference of a possibly null reference. 122 | dotnet_diagnostic.CS8602.severity = error 123 | # CS8603: Possible null reference return. 124 | dotnet_diagnostic.CS8603.severity = error 125 | dotnet_style_namespace_match_folder = true:suggestion 126 | dotnet_style_prefer_conditional_expression_over_return = true:silent 127 | dotnet_style_explicit_tuple_names = true:suggestion 128 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 129 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 130 | dotnet_style_prefer_compound_assignment = true:suggestion 131 | dotnet_style_prefer_simplified_interpolation = true:suggestion 132 | dotnet_style_readonly_field = true:suggestion 133 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 134 | dotnet_style_predefined_type_for_member_access = true:silent 135 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 136 | dotnet_code_quality_unused_parameters = all:warning 137 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 138 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 139 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 140 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 141 | dotnet_style_qualification_for_field = false:silent 142 | dotnet_style_qualification_for_property = false:silent 143 | dotnet_style_qualification_for_method = false:silent 144 | dotnet_style_qualification_for_event = false:silent -------------------------------------------------------------------------------- /VSConfigFinder.Test/ExtensionsTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder.Test 7 | { 8 | using Moq; 9 | using Xunit; 10 | 11 | public class ExtensionsTests 12 | { 13 | [Fact] 14 | public void GetFileSystemEntries_MultiplePaths_ReturnSet() 15 | { 16 | var path1 = "C:\\path1"; 17 | var subpath1 = Path.Combine(path1, "subpath1", ".vsconfig"); 18 | var subpath2 = Path.Combine(path1, "subpath2", "something.vsconfig"); 19 | var path2 = "C:\\path2"; 20 | var subpath3 = Path.Combine(path2, "subpath3", ".vsconfig"); 21 | var subpath4 = Path.Combine(path2, "subpath4", "something.vsconfig"); 22 | var path3 = path2; 23 | var subpath5 = subpath3; 24 | var subpath6 = subpath4; 25 | 26 | var fileSystem = new Mock(); 27 | fileSystem.Setup(x => x.GetFileSystemEntries(path1, "*.vsconfig", true)).Returns(new[] { subpath1, subpath2 }); 28 | fileSystem.Setup(x => x.GetFileSystemEntries(path2, "*.vsconfig", true)).Returns(new[] { subpath3, subpath4 }); 29 | fileSystem.Setup(x => x.GetFileSystemEntries(path3, "*.vsconfig", true)).Returns(new[] { subpath5, subpath6 }); 30 | 31 | var paths = new[] { path1, path2, path3 }; 32 | 33 | var result = Extensions.GetFileSystemEntries(fileSystem.Object, paths, "*.vsconfig", recursive: true); 34 | 35 | Assert.Equal(4, result.Count()); 36 | Assert.Contains(subpath1, result); 37 | Assert.Contains(subpath2, result); 38 | Assert.Contains(subpath3, result); 39 | Assert.Contains(subpath4, result); 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /VSConfigFinder.Test/UtilitiesTests.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder.Test 7 | { 8 | using Moq; 9 | using System.Text; 10 | using Xunit; 11 | 12 | public class UtilitiesTests 13 | { 14 | const string VSConfig = ".vsconfig"; 15 | 16 | [Fact] 17 | public void ValidateIsNotNullOrEmpty_NullOrEmpty_String_Throws_AppropriateException() 18 | { 19 | string? nullStr = null; 20 | Assert.Throws(() => Utilities.ValidateIsNotNullOrEmpty(nullStr!, nameof(nullStr))); 21 | 22 | var emptyStr = string.Empty; 23 | Assert.Throws(() => Utilities.ValidateIsNotNullOrEmpty(emptyStr, nameof(emptyStr))); 24 | } 25 | 26 | [Fact] 27 | public void ValidateIsNotNullOrEmpty_NotNullOrEmpty_String_Succeeds() 28 | { 29 | var str = "some string"; 30 | Utilities.ValidateIsNotNullOrEmpty(str, nameof(str)); 31 | } 32 | 33 | [Theory] 34 | [InlineData(true)] 35 | [InlineData(false)] 36 | public void CreateOutput_Creates_FileOrArguments_With_Expected_String(bool createFile) 37 | { 38 | var fileSystem = new Mock(); 39 | var logger = new Mock(); 40 | 41 | var finalConfig = new VSConfig 42 | { 43 | Version = new Version("1.0"), 44 | Components = new[] 45 | { 46 | "Microsoft.VisualStudio.Component.NuGet", 47 | "Microsoft.VisualStudio.Component.Roslyn.Compiler", 48 | "Microsoft.Component.MSBuild", 49 | "Microsoft.NetCore.Component.Runtime.6.0" 50 | }, 51 | }; 52 | 53 | var jsonString = """ 54 | { 55 | "Version": "1.0", 56 | "Components": [ 57 | "Microsoft.VisualStudio.Component.NuGet", 58 | "Microsoft.VisualStudio.Component.Roslyn.Compiler", 59 | "Microsoft.Component.MSBuild", 60 | "Microsoft.NetCore.Component.Runtime.6.0" 61 | ] 62 | } 63 | """; 64 | 65 | var options = new CommandLineOptions 66 | { 67 | FolderPath = new[] { "C:\\input" }, 68 | CreateFile = createFile, 69 | ConfigOutputPath = "C:\\output", 70 | }; 71 | 72 | Utilities.CreateOutput(fileSystem.Object, logger.Object, finalConfig, options); 73 | 74 | if (createFile) 75 | { 76 | var outputPath = Path.Combine(options.ConfigOutputPath, VSConfig); 77 | fileSystem.Verify(x => x.WriteAllText(outputPath, jsonString)); 78 | } 79 | else 80 | { 81 | var addArguments = "--add Microsoft.VisualStudio.Component.NuGet --add Microsoft.VisualStudio.Component.Roslyn.Compiler --add Microsoft.Component.MSBuild --add Microsoft.NetCore.Component.Runtime.6.0"; 82 | logger.Verify(x => x.Log(addArguments)); 83 | } 84 | } 85 | 86 | [Fact] 87 | public void ReadComponents_Reads_AllNestedDirectories_And_OutputsAllComponents() 88 | { 89 | /* 90 | * folder structure: 91 | * pathA 92 | * - .vsconfig 93 | * - pathB 94 | * - .vsconfig 95 | */ 96 | 97 | var fileSystem = new Mock(); 98 | 99 | var options = new CommandLineOptions 100 | { 101 | FolderPath = new[] { "C:\\pathA" }, 102 | ConfigOutputPath = "C:\\output", 103 | }; 104 | 105 | // pathA 106 | var pathA = "C:\\pathA"; 107 | var pathAConfigFile = Path.Combine(pathA, VSConfig); 108 | 109 | var pathAConfig = """ 110 | { 111 | "Version": "1.0", 112 | "Components": [ 113 | "Microsoft.VisualStudio.Component.NuGet", 114 | "Microsoft.Component.MSBuild", 115 | ] 116 | } 117 | """; 118 | var pathAReader = new MemoryStream(Encoding.UTF8.GetBytes(pathAConfig)); 119 | 120 | // pathB 121 | var pathB = Path.Combine(pathA, "pathB"); 122 | var pathBConfigFile = Path.Combine(pathB, VSConfig); 123 | 124 | var pathBConfig = """ 125 | { 126 | "Version": "1.0", 127 | "Components": [ 128 | "Microsoft.VisualStudio.Component.NuGet", 129 | "Microsoft.VisualStudio.Component.Roslyn.Compiler", 130 | ] 131 | } 132 | """; 133 | var pathBReader = new MemoryStream(Encoding.UTF8.GetBytes(pathBConfig)); 134 | 135 | fileSystem.Setup(x => x.GetFileSystemEntries("C:\\pathA", "*" + VSConfig, true)).Returns(new[] { pathAConfigFile, pathBConfigFile }); 136 | 137 | fileSystem.Setup(x => x.OpenFile(pathAConfigFile)).Returns(pathAReader); 138 | fileSystem.Setup(x => x.OpenFile(pathBConfigFile)).Returns(pathBReader); 139 | 140 | var components = Utilities.ReadComponents(fileSystem.Object, options); 141 | Assert.Equal(3, components.Length); 142 | Assert.Collection( 143 | components, 144 | x => Assert.Equal("Microsoft.VisualStudio.Component.NuGet", x), 145 | x => Assert.Equal("Microsoft.Component.MSBuild", x), 146 | x => Assert.Equal("Microsoft.VisualStudio.Component.Roslyn.Compiler", x)); 147 | } 148 | } 149 | } -------------------------------------------------------------------------------- /VSConfigFinder.Test/VSConfigFinder.Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net7.0 5 | enable 6 | enable 7 | 8 | false 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | all 18 | 19 | 20 | runtime; build; native; contentfiles; analyzers; buildtransitive 21 | all 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /VSConfigFinder.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 17 4 | VisualStudioVersion = 17.6.33405.23 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "VSConfigFinder", "VSConfigFinder\VSConfigFinder.csproj", "{0F9FDAD0-EF20-4EAE-B37E-2E49975CFED1}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{7E2E70F6-1FBA-48EA-920A-9B4032D280C3}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "VSConfigFinder.Test", "VSConfigFinder.Test\VSConfigFinder.Test.csproj", "{A146B74D-CC67-4ABC-92E6-346784A7D115}" 11 | EndProject 12 | Global 13 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 14 | Debug|Any CPU = Debug|Any CPU 15 | Release|Any CPU = Release|Any CPU 16 | EndGlobalSection 17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 18 | {0F9FDAD0-EF20-4EAE-B37E-2E49975CFED1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 19 | {0F9FDAD0-EF20-4EAE-B37E-2E49975CFED1}.Debug|Any CPU.Build.0 = Debug|Any CPU 20 | {0F9FDAD0-EF20-4EAE-B37E-2E49975CFED1}.Release|Any CPU.ActiveCfg = Release|Any CPU 21 | {0F9FDAD0-EF20-4EAE-B37E-2E49975CFED1}.Release|Any CPU.Build.0 = Release|Any CPU 22 | {A146B74D-CC67-4ABC-92E6-346784A7D115}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 23 | {A146B74D-CC67-4ABC-92E6-346784A7D115}.Debug|Any CPU.Build.0 = Debug|Any CPU 24 | {A146B74D-CC67-4ABC-92E6-346784A7D115}.Release|Any CPU.ActiveCfg = Release|Any CPU 25 | {A146B74D-CC67-4ABC-92E6-346784A7D115}.Release|Any CPU.Build.0 = Release|Any CPU 26 | EndGlobalSection 27 | GlobalSection(SolutionProperties) = preSolution 28 | HideSolutionNode = FALSE 29 | EndGlobalSection 30 | GlobalSection(ExtensibilityGlobals) = postSolution 31 | SolutionGuid = {B8A58883-E63D-4E5D-8797-92039A0EA333} 32 | EndGlobalSection 33 | EndGlobal 34 | -------------------------------------------------------------------------------- /VSConfigFinder/.editorconfig: -------------------------------------------------------------------------------- 1 | file_header_template = \nCopyright (C) Microsoft Corporation. All rights reserved.\nLicensed under the MIT license. See LICENSE.txt in the project root for license information.\n 2 | 3 | # All files 4 | [*] 5 | indent_style = space 6 | dotnet_style_operator_placement_when_wrapping = beginning_of_line 7 | tab_width = 4 8 | indent_size = 4 9 | end_of_line = crlf 10 | csharp_indent_labels = one_less_than_current 11 | dotnet_style_coalesce_expression = true:suggestion 12 | dotnet_style_null_propagation = true:suggestion 13 | dotnet_style_prefer_is_null_check_over_reference_equality_method = true:suggestion 14 | dotnet_style_prefer_auto_properties = true:silent 15 | dotnet_style_object_initializer = true:suggestion 16 | dotnet_style_collection_initializer = true:suggestion 17 | dotnet_style_prefer_simplified_boolean_expressions = true:suggestion 18 | dotnet_style_prefer_conditional_expression_over_assignment = true:silent 19 | csharp_using_directive_placement = inside_namespace:error 20 | csharp_prefer_simple_using_statement = true:suggestion 21 | csharp_prefer_braces = true:silent 22 | csharp_style_namespace_declarations = block_scoped:silent 23 | csharp_style_prefer_method_group_conversion = true:silent 24 | csharp_style_prefer_top_level_statements = true:silent 25 | csharp_style_expression_bodied_methods = false:silent 26 | csharp_style_expression_bodied_constructors = false:silent 27 | csharp_style_expression_bodied_operators = false:silent 28 | csharp_style_expression_bodied_properties = true:silent 29 | csharp_style_expression_bodied_indexers = true:silent 30 | csharp_style_expression_bodied_accessors = true:silent 31 | csharp_style_expression_bodied_lambdas = true:silent 32 | csharp_style_expression_bodied_local_functions = false:silent 33 | csharp_style_allow_embedded_statements_on_same_line_experimental = true:silent 34 | csharp_style_allow_blank_lines_between_consecutive_braces_experimental = true:silent 35 | csharp_style_allow_blank_line_after_colon_in_constructor_initializer_experimental = true:silent 36 | csharp_style_allow_blank_line_after_token_in_conditional_expression_experimental = true:silent 37 | csharp_style_allow_blank_line_after_token_in_arrow_expression_clause_experimental = true:silent 38 | csharp_new_line_before_open_brace = all 39 | csharp_style_throw_expression = true:suggestion 40 | csharp_prefer_simple_default_expression = true:suggestion 41 | csharp_style_prefer_null_check_over_type_check = true:suggestion 42 | csharp_style_prefer_local_over_anonymous_function = true:suggestion 43 | csharp_style_prefer_index_operator = true:suggestion 44 | csharp_style_prefer_range_operator = true:suggestion 45 | csharp_style_implicit_object_creation_when_type_is_apparent = true:suggestion 46 | csharp_style_prefer_tuple_swap = true:suggestion 47 | csharp_style_prefer_utf8_string_literals = true:suggestion 48 | csharp_style_inlined_variable_declaration = true:suggestion 49 | csharp_style_deconstructed_variable_declaration = true:suggestion 50 | csharp_style_unused_value_assignment_preference = discard_variable:suggestion 51 | csharp_style_unused_value_expression_statement_preference = discard_variable:silent 52 | csharp_prefer_static_local_function = true:suggestion 53 | csharp_style_prefer_readonly_struct = true:suggestion 54 | csharp_style_conditional_delegate_call = true:suggestion 55 | csharp_style_prefer_switch_expression = true:suggestion 56 | csharp_style_prefer_pattern_matching = true:silent 57 | csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion 58 | csharp_style_pattern_matching_over_as_with_null_check = true:suggestion 59 | csharp_style_prefer_not_pattern = true:suggestion 60 | csharp_style_prefer_extended_property_pattern = true:suggestion 61 | csharp_style_var_for_built_in_types = true:silent 62 | csharp_style_var_when_type_is_apparent = true:silent 63 | csharp_style_var_elsewhere = true:silent 64 | 65 | # Xml files 66 | [*.xml] 67 | indent_size = 2 68 | 69 | [*.{cs,vb}] 70 | #### Naming styles #### 71 | 72 | # Naming rules 73 | 74 | dotnet_naming_rule.interface_should_be_begins_with_i.severity = suggestion 75 | dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface 76 | dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i 77 | 78 | dotnet_naming_rule.types_should_be_pascal_case.severity = suggestion 79 | dotnet_naming_rule.types_should_be_pascal_case.symbols = types 80 | dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case 81 | 82 | dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = suggestion 83 | dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members 84 | dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case 85 | 86 | # Symbol specifications 87 | 88 | dotnet_naming_symbols.interface.applicable_kinds = interface 89 | dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 90 | dotnet_naming_symbols.interface.required_modifiers = 91 | 92 | dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum 93 | dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 94 | dotnet_naming_symbols.types.required_modifiers = 95 | 96 | dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method 97 | dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected 98 | dotnet_naming_symbols.non_field_members.required_modifiers = 99 | 100 | # Naming styles 101 | 102 | dotnet_naming_style.begins_with_i.required_prefix = I 103 | dotnet_naming_style.begins_with_i.required_suffix = 104 | dotnet_naming_style.begins_with_i.word_separator = 105 | dotnet_naming_style.begins_with_i.capitalization = pascal_case 106 | 107 | dotnet_naming_style.pascal_case.required_prefix = 108 | dotnet_naming_style.pascal_case.required_suffix = 109 | dotnet_naming_style.pascal_case.word_separator = 110 | dotnet_naming_style.pascal_case.capitalization = pascal_case 111 | 112 | dotnet_naming_style.pascal_case.required_prefix = 113 | dotnet_naming_style.pascal_case.required_suffix = 114 | dotnet_naming_style.pascal_case.word_separator = 115 | dotnet_naming_style.pascal_case.capitalization = pascal_case 116 | dotnet_style_allow_multiple_blank_lines_experimental = true:silent 117 | dotnet_style_allow_statement_immediately_after_block_experimental = true:silent 118 | 119 | # Diagnostics 120 | 121 | # CS8602: Dereference of a possibly null reference. 122 | dotnet_diagnostic.CS8602.severity = error 123 | # CS8603: Possible null reference return. 124 | dotnet_diagnostic.CS8603.severity = error 125 | dotnet_style_namespace_match_folder = true:suggestion 126 | dotnet_style_prefer_conditional_expression_over_return = true:silent 127 | dotnet_style_explicit_tuple_names = true:suggestion 128 | dotnet_style_prefer_inferred_tuple_names = true:suggestion 129 | dotnet_style_prefer_inferred_anonymous_type_member_names = true:suggestion 130 | dotnet_style_prefer_compound_assignment = true:suggestion 131 | dotnet_style_prefer_simplified_interpolation = true:suggestion 132 | dotnet_style_readonly_field = true:suggestion 133 | dotnet_style_predefined_type_for_locals_parameters_members = true:silent 134 | dotnet_style_predefined_type_for_member_access = true:silent 135 | dotnet_style_require_accessibility_modifiers = for_non_interface_members:silent 136 | dotnet_code_quality_unused_parameters = all:warning 137 | dotnet_style_parentheses_in_arithmetic_binary_operators = always_for_clarity:silent 138 | dotnet_style_parentheses_in_other_binary_operators = always_for_clarity:silent 139 | dotnet_style_parentheses_in_relational_binary_operators = always_for_clarity:silent 140 | dotnet_style_parentheses_in_other_operators = never_if_unnecessary:silent 141 | dotnet_style_qualification_for_field = false:silent 142 | dotnet_style_qualification_for_property = false:silent 143 | dotnet_style_qualification_for_method = false:silent 144 | dotnet_style_qualification_for_event = false:silent -------------------------------------------------------------------------------- /VSConfigFinder/CommandLine/CommandLineOptions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | using CommandLine; 9 | 10 | /// 11 | public class CommandLineOptions : ICommandLineOptions 12 | { 13 | /// 14 | [Option("folderpath", Required = true, HelpText = "The source folder path to use as the root. The search will start from the root towards the bottom.")] 15 | public IEnumerable? FolderPath { get; set; } 16 | 17 | /// 18 | [Option("createfile", Required = false, Default = false, HelpText = "(Default: false) Bool flag that indicates whether the output gets created as a consolidated .vsconfig file instead of the Visual Studio Installer setup command line arguments.\n" + 19 | "If --createFile is passed in, --configOutputPath can also be passed in to indicate the output directory.")] 20 | public bool CreateFile { get; set; } 21 | 22 | /// 23 | [Option("configoutputpath", Required = false, HelpText = "The optional folder path to use if --createFile is passed in. If empty or null, uses the current directory as the output path.\n" + 24 | "This can only be used in conjunction with --createFile. If passed in without --createFile, the parameter will be ignored.")] 25 | public string? ConfigOutputPath { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /VSConfigFinder/CommandLine/ICommandLineOptions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | /// 9 | /// The interface for the command line options. 10 | /// 11 | public interface ICommandLineOptions 12 | { 13 | /// 14 | /// Gets or sets the folder paths to be used as the root (starting point) of the search. 15 | /// 16 | IEnumerable? FolderPath { get; set; } 17 | 18 | /// 19 | /// Gets or sets the value indicating whether the output gets created as a consolidated .vsconfig file instead of the Visual Studio Installer setup command line arguments. 20 | /// If --createFile is passed in, can also be passed in to indicate the output directory.folder path to output the consolidated .vsconfig instead of the command line arguments. 21 | /// 22 | bool CreateFile { get; set; } 23 | 24 | /// 25 | /// Gets or sets the optional folder path to use if --createFile is passed in. 26 | /// If empty or null, uses the current directory as the output path. 27 | /// This can only be used in conjunction with --createFile. If passed in without --createFile, the parameter will be ignored. 28 | /// 29 | string? ConfigOutputPath { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /VSConfigFinder/CommandLine/VSConfig.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | using System; 9 | 10 | /// 11 | /// The class object that defines a .vsconfig file. 12 | /// 13 | public class VSConfig 14 | { 15 | /// 16 | /// Gets or sets the version of the .vsconfig file. 17 | /// 18 | public Version? Version { get; set; } 19 | 20 | /// 21 | /// Gets or sets the list of component ids. 22 | /// 23 | public string[]? Components { get; set; } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /VSConfigFinder/ConsoleLogger.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | using System; 9 | 10 | /// 11 | internal class ConsoleLogger : ILogger 12 | { 13 | /// 14 | public void Log(string message) => Console.WriteLine(message); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /VSConfigFinder/Extensions.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | using System; 9 | using System.Collections.Generic; 10 | 11 | /// 12 | /// Extensions class for the tool. 13 | /// 14 | public static class Extensions 15 | { 16 | /// 17 | /// The extension method to get entries from multiple paths. 18 | /// 19 | /// The . 20 | /// The list of top-level paths. 21 | /// Pattern to match for file names. To match anything and everything, specify '*' 22 | /// Optional: recursively search sub directories 23 | /// A set of path to files that match the pattern 24 | public static IEnumerable GetFileSystemEntries(this IFileSystem fileSystem, IEnumerable paths, string pattern, bool recursive = false) 25 | { 26 | Utilities.IsNotNull(paths, nameof(paths)); 27 | Utilities.ValidateIsNotNullOrEmpty(pattern, nameof(pattern)); 28 | 29 | var result = new HashSet(StringComparer.OrdinalIgnoreCase); 30 | 31 | foreach (var path in paths) 32 | { 33 | result.UnionWith(fileSystem.GetFileSystemEntries(path, pattern, recursive)); 34 | } 35 | 36 | return result; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /VSConfigFinder/FileSystem.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | using System.IO; 9 | 10 | /// 11 | public class FileSystem : IFileSystem 12 | { 13 | /// 14 | public IEnumerable GetFileSystemEntries(string path, string pattern, bool recursive = false) 15 | { 16 | Utilities.ValidateIsNotNullOrEmpty(path, nameof(path)); 17 | Utilities.ValidateIsNotNullOrEmpty(pattern, nameof(pattern)); 18 | 19 | return Directory.GetFileSystemEntries(path, pattern, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly); 20 | } 21 | 22 | /// 23 | public Stream OpenFile(string path) 24 | { 25 | Utilities.ValidateIsNotNullOrEmpty(path, nameof(Path)); 26 | 27 | return File.OpenRead(path); 28 | } 29 | 30 | /// 31 | public void WriteAllText(string path, string data) 32 | { 33 | Utilities.ValidateIsNotNullOrEmpty(path, nameof(Path)); 34 | 35 | File.WriteAllText(path, data); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /VSConfigFinder/IFileSystem.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | /// 9 | /// The interface for the . 10 | /// 11 | public interface IFileSystem 12 | { 13 | /// 14 | /// Get files and directories within directory. 15 | /// 16 | /// Directory path to search for. 17 | /// Pattern to match for file names. To match anything and everything, specify '*' 18 | /// Optional: recursively search sub directories 19 | /// Array of path to files that match the pattern within the directory. 20 | /// is empty. 21 | /// is null. 22 | public IEnumerable GetFileSystemEntries(string path, string pattern, bool recursive = false); 23 | 24 | /// 25 | /// Opens a file for reading. 26 | /// 27 | /// The path to a file to open. 28 | /// A stream of the opened file. 29 | /// is empty. 30 | /// is null. 31 | public Stream OpenFile(string path); 32 | 33 | /// 34 | /// Writes all text in a path. 35 | /// 36 | /// The path to a file to write. 37 | /// The string data to write. 38 | /// is empty. 39 | /// is null. 40 | public void WriteAllText(string path, string data); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /VSConfigFinder/ILogger.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | /// 9 | /// The interface to log user messages. 10 | /// 11 | public interface ILogger 12 | { 13 | /// 14 | /// Log the message. 15 | /// 16 | /// The message to log. 17 | public void Log(string message); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /VSConfigFinder/Program.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | using CommandLine; 9 | using System.IO; 10 | 11 | /// 12 | /// class for the .vsconfig finder tool. 13 | /// 14 | public class Program 15 | { 16 | /// 17 | /// Main entry point of the tool. 18 | /// 19 | /// The program arguments 20 | public static void Main(string[] args) 21 | { 22 | var parser = new Parser(with => 23 | { 24 | with.CaseSensitive = false; 25 | }); 26 | 27 | parser.ParseArguments(args) 28 | .WithParsed(Run) 29 | .WithNotParsed(HandleParseError); 30 | } 31 | 32 | private static void Run(CommandLineOptions options) 33 | { 34 | var fileSystem = new FileSystem(); 35 | var logger = new ConsoleLogger(); 36 | 37 | ResolveCommandLineOptions(options); 38 | 39 | var finalConfig = new VSConfig() 40 | { 41 | // This is the new final .vsconfig, so version 1.0 is used. 42 | Version = new Version("1.0"), 43 | Components = Utilities.ReadComponents(fileSystem, options), 44 | }; 45 | 46 | Utilities.CreateOutput(fileSystem, logger, finalConfig, options); 47 | } 48 | 49 | private static void ResolveCommandLineOptions(CommandLineOptions options) 50 | { 51 | if (options.CreateFile) 52 | { 53 | options.ConfigOutputPath ??= Directory.GetCurrentDirectory(); 54 | } 55 | } 56 | 57 | private static void HandleParseError(IEnumerable errors) 58 | { 59 | Console.WriteLine("Please make sure that you have provided the correct arguments. Try --help to see all the available arguments and explanations."); 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /VSConfigFinder/Utilities.cs: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright (C) Microsoft Corporation. All rights reserved. 3 | // Licensed under the MIT license. See LICENSE.txt in the project root for license information. 4 | // 5 | 6 | namespace VSConfigFinder 7 | { 8 | using System.Diagnostics.CodeAnalysis; 9 | using System.Text; 10 | using System.Text.Json; 11 | 12 | /// 13 | /// Utilities class for the tool. 14 | /// 15 | public class Utilities 16 | { 17 | private static readonly string ConfigExtension = ".vsconfig"; 18 | private static readonly string Add = "--add"; 19 | 20 | /// 21 | /// Validate whether the parameter is null or empty. 22 | /// 23 | /// The parameter. 24 | /// The nameof(parameter). 25 | public static void ValidateIsNotNullOrEmpty([NotNull] string s, string paramName) 26 | { 27 | IsNotNull(s, paramName); 28 | IsNotEmpty(s, paramName); 29 | } 30 | 31 | /// 32 | /// Validate whether the parameter is null. 33 | /// 34 | /// The parameter object. 35 | /// The nameof(parameter). 36 | /// is null. 37 | public static void IsNotNull([NotNull] object o, string paramName) 38 | { 39 | if (o is null) 40 | { 41 | throw new ArgumentNullException(paramName); 42 | } 43 | } 44 | 45 | /// 46 | /// Validate whether the parameter is empty. 47 | /// 48 | /// The string parameter object. 49 | /// The nameof(parameter). 50 | /// is empty. 51 | public static void IsNotEmpty([NotNull] string s, string paramName) 52 | { 53 | if (s == string.Empty) 54 | { 55 | throw new ArgumentException("The string is empty.", paramName); 56 | } 57 | } 58 | 59 | /// 60 | /// Create an output from the final and given . 61 | /// 62 | /// The . 63 | /// The . 64 | /// The final to export. 65 | /// The command line options. 66 | public static void CreateOutput(IFileSystem fileSystem, ILogger logger, VSConfig finalConfig, CommandLineOptions options) 67 | { 68 | if (options.CreateFile) 69 | { 70 | // Create a file 71 | var serializerOptions = new JsonSerializerOptions { WriteIndented = true }; 72 | var jsonString = JsonSerializer.Serialize(finalConfig, serializerOptions); 73 | var outputPath = Path.Combine(options.ConfigOutputPath!, ConfigExtension); 74 | 75 | fileSystem.WriteAllText(outputPath, jsonString); 76 | logger.Log($"Successfully created the final .vsconfig at {outputPath}"); 77 | } 78 | else 79 | { 80 | // output to a command line 81 | var output = CreateCommandLineOutput(finalConfig); 82 | logger.Log(output); 83 | } 84 | } 85 | 86 | /// 87 | /// Read all the components in the nested .vsconfigs recursively, starting from the given path. 88 | /// 89 | /// The . 90 | /// The command line options. 91 | /// 92 | public static string[] ReadComponents(IFileSystem fileSystem, CommandLineOptions options) 93 | { 94 | var pathsToVsConfigs = fileSystem.GetFileSystemEntries(options.FolderPath, "*" + ConfigExtension, recursive: true); 95 | 96 | var componentsSet = new HashSet(StringComparer.OrdinalIgnoreCase); 97 | var serializerOptions = new JsonSerializerOptions 98 | { 99 | PropertyNameCaseInsensitive = true, 100 | AllowTrailingCommas = true, 101 | }; 102 | 103 | foreach (var path in pathsToVsConfigs) 104 | { 105 | string[]? components; 106 | using (var stream = fileSystem.OpenFile(path)) 107 | { 108 | components = JsonSerializer.Deserialize(stream, serializerOptions)?.Components; 109 | } 110 | 111 | if (components is not null) 112 | { 113 | componentsSet.UnionWith(components); 114 | } 115 | }; 116 | 117 | return componentsSet.ToArray(); 118 | } 119 | 120 | private static string CreateCommandLineOutput(VSConfig finalConfig) 121 | { 122 | var output = new StringBuilder(); 123 | 124 | if (finalConfig.Components is not null) 125 | { 126 | foreach (var component in finalConfig.Components) 127 | { 128 | if (!string.IsNullOrEmpty(component)) 129 | { 130 | output.AppendFormat("{0} {1} ", Add, component); 131 | } 132 | } 133 | } 134 | 135 | return output.ToString().TrimEnd(); 136 | } 137 | } 138 | } -------------------------------------------------------------------------------- /VSConfigFinder/VSConfigFinder.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Exe 5 | net7.0 6 | enable 7 | enable 8 | true 9 | true 10 | 11 | 12 | 13 | 14 | 15 | all 16 | runtime; build; native; contentfiles; analyzers; buildtransitive 17 | 18 | 19 | 20 | 21 | 22 | Microsoft400 23 | 24 | 25 | Microsoft400 26 | 27 | 28 | 3PartySHA2 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /build.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information. 3 | 4 | parameters: 5 | BuildConfiguration: Release 6 | 7 | steps: 8 | - task: UseDotNet@2 9 | displayName: 'Install .NET Core SDK' 10 | inputs: 11 | useGlobalJson: true 12 | 13 | - task: DotNetCoreCLI@2 14 | displayName: Build 15 | inputs: 16 | command: 'build' 17 | projects: 'VSConfigFinder' 18 | arguments: '--configuration $(BuildConfiguration)' 19 | 20 | - task: DotNetCoreCLI@2 21 | displayName: Test 22 | inputs: 23 | command: 'test' 24 | projects: 'VSConfigFinder.Test' 25 | arguments: '--configuration $(BuildConfiguration)' 26 | 27 | - task: DotNetCoreCLI@2 28 | displayName: Publish 29 | inputs: 30 | command: 'publish' 31 | arguments: '--no-build --configuration $(BuildConfiguration)' 32 | publishWebProjects: false 33 | zipAfterPublish: false 34 | 35 | - script: | 36 | choco pack pkg\VSConfigFinder\VSConfigFinder.nuspec --out "VSConfigFinder\bin\${{ parameters.BuildConfiguration }}" --version "$(GitBuildVersion)" "Configuration=${{ parameters.BuildConfiguration }}" "CommitId=$(Build.SourceVersion)" "Tag=$(Build.BuildNumber)" 37 | displayName: 'Package Nupkg' 38 | workingDirectory: $(Build.SourcesDirectory) 39 | 40 | - task: CopyFiles@2 41 | displayName: 'Copy build artifacts' 42 | inputs: 43 | SourceFolder: $(Build.SourcesDirectory)\VSConfigFinder 44 | Contents: | 45 | bin\$(BuildConfiguration)\** 46 | TargetFolder: $(Build.ArtifactStagingDirectory)\out 47 | 48 | - task: 1ES.PublishPipelineArtifact@1 49 | displayName: 'Publish build artifacts' 50 | inputs: 51 | targetPath: $(Build.ArtifactStagingDirectory)\out 52 | artifactName: drop 53 | -------------------------------------------------------------------------------- /global.json: -------------------------------------------------------------------------------- 1 | { 2 | "sdk": { 3 | "version": "7.0.200", 4 | "rollForward": "feature" 5 | } 6 | } -------------------------------------------------------------------------------- /pkg/VSConfigFinder/VSConfigFinder.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | VSConfigFinder 5 | $Version$ 6 | Visual Studio Configuration Finder 7 | Microsoft 8 | VisualStudioSetup 9 | false 10 | https://go.microsoft.com/fwlink/?linkid=839265 11 | https://github.com/Microsoft/VSConfigFinder/tree/$CommitId$/LICENSE.txt 12 | https://github.com/Microsoft/VSConfigFinder 13 | Locate Visual Studio installation configuration files (.vsconfigs) downstream recursively and merge them all together 14 | Locate Visual Studio installation configuration files (.vsconfigs) downstream recursively and merge them all together 15 | © Microsoft Corporation. All rights reserved. 16 | vs vs2022 visualstudio 17 | true 18 | https://github.com/Microsoft/VSConfigFinder/tree/$CommitId$ 19 | https://github.com/Microsoft/VSConfigFinder/tree/$CommitId$/pkg/VSConfigFinder 20 | https://github.com/microsoft/VSConfigFinder/blob/main/README.md 21 | https://github.com/Microsoft/VSConfigFinder/issues 22 | https://github.com/Microsoft/VSConfigFinder/releases/tag/$Tag$ 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /pkg/VSConfigFinder/tools/VERIFICATION.txt: -------------------------------------------------------------------------------- 1 | VERIFICATION 2 | Verification is intended to assist the Chocolatey moderators and community 3 | in verifying that this package's contents are trustworthy. 4 | 5 | tools\VSConfigFinder.exe is produced by us from the same repository as this package: https://github.com/Microsoft/VSConfigFinder -------------------------------------------------------------------------------- /version.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", 3 | "version": "1.0-beta", 4 | "publicReleaseRefSpec": [ 5 | "^refs/heads/main$" 6 | ], 7 | "cloudBuild": { 8 | "buildNumber": { 9 | "enabled": true 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /vsts-ci.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information. 3 | 4 | variables: 5 | BuildConfiguration: Release 6 | SignType: real 7 | TeamName: vssetup 8 | 9 | trigger: 10 | batch: true 11 | branches: 12 | include: 13 | - main 14 | paths: 15 | exclude: 16 | - README.md 17 | 18 | pr: none 19 | 20 | resources: 21 | repositories: 22 | - repository: MicroBuildTemplate 23 | type: git 24 | name: 1ESPipelineTemplates/MicroBuildTemplate 25 | ref: refs/tags/release 26 | 27 | extends: 28 | template: azure-pipelines/MicroBuild.1ES.Official.yml@MicroBuildTemplate 29 | parameters: 30 | pool: 31 | name: VSEngSS-MicroBuild2022-1ES 32 | sdl: 33 | sourceAnalysisPool: 34 | name: AzurePipelines-EO 35 | image: 1ESPT-Windows2022 36 | policheck: 37 | enabled: true 38 | binskim: 39 | enabled: true 40 | scanOutputDirectoryOnly: true # BinSkim scans whole source tree but we only need to scan the output dir. 41 | tsa: 42 | enabled: true 43 | configFile: $(Build.SourcesDirectory)\.config\tsaoptions.json 44 | onboard: false # We already onboarded 45 | 46 | stages: 47 | - stage: Build 48 | jobs: 49 | - job: Build 50 | templateContext: 51 | mb: 52 | signing: 53 | enabled: true 54 | signType: $(SignType) 55 | 56 | steps: 57 | - checkout: self 58 | fetchDepth: 0 # avoid shallow clone so nbgv can do its work. 59 | 60 | - template: /build.yml@self 61 | parameters: 62 | BuildConfiguration: $(BuildConfiguration) 63 | -------------------------------------------------------------------------------- /vsts-compliance.yml: -------------------------------------------------------------------------------- 1 | # Copyright (C) Microsoft Corporation. All rights reserved. 2 | # Licensed under the MIT license. See LICENSE.txt in the project root for license information. 3 | 4 | variables: 5 | - group: vssetup-apiscan 6 | - name: BuildConfiguration 7 | value: Release 8 | - name: TeamName 9 | value: vssetup 10 | 11 | trigger: 12 | batch: true 13 | branches: 14 | include: 15 | - main 16 | paths: 17 | exclude: 18 | - README.md 19 | 20 | pr: none 21 | 22 | schedules: 23 | - cron: "0 12 * * 1" 24 | displayName: 'Run every Monday at 12:00 p.m.' 25 | branches: 26 | include: 27 | - main 28 | always: true 29 | 30 | resources: 31 | repositories: 32 | - repository: MicroBuildTemplate 33 | type: git 34 | name: 1ESPipelineTemplates/MicroBuildTemplate 35 | ref: refs/tags/release 36 | 37 | extends: 38 | template: azure-pipelines/MicroBuild.1ES.Unofficial.yml@MicroBuildTemplate 39 | parameters: 40 | pool: 41 | name: VSEngSS-MicroBuild2022-1ES 42 | sdl: 43 | sourceAnalysisPool: 44 | name: AzurePipelines-EO 45 | image: 1ESPT-Windows2022 46 | antimalwareScan: 47 | enabled: true 48 | armory: 49 | enabled: true 50 | binskim: 51 | enabled: true 52 | scanOutputDirectoryOnly: true 53 | codeql: 54 | compiled: 55 | enabled: true 56 | credscan: 57 | enabled: true 58 | policheck: 59 | enabled: true 60 | psscriptanalyzer: 61 | enabled: true 62 | prefast: 63 | enabled: true 64 | tsa: 65 | enabled: true 66 | configFile: $(Build.SourcesDirectory)\.config\tsaoptions.json 67 | onboard: false # We already onboarded 68 | 69 | stages: 70 | - stage: Compliance 71 | jobs: 72 | - job: Compliance 73 | steps: 74 | - template: /build.yml@self 75 | parameters: 76 | BuildConfiguration: $(BuildConfiguration) 77 | 78 | - task: CopyFiles@2 79 | displayName: Copy files for API scan 80 | inputs: 81 | SourceFolder: $(Build.SourcesDirectory)\VSConfigFinder\bin\$(BuildConfiguration) 82 | Contents: | 83 | **\VSConfigFinder.?(pdb|dll|xml) 84 | **\CommandLine.?(pdb|dll|xml) 85 | !**\*.Test.* 86 | TargetFolder: $(Build.StagingDirectory)\apiscan-inputs 87 | 88 | - task: APIScan@2 89 | displayName: Run APIScan 90 | inputs: 91 | softwareFolder: $(Build.StagingDirectory)\apiscan-inputs 92 | softwareName: 'Microsoft.VSConfigFinder' 93 | softwareVersionNum: '1' 94 | toolVersion: Latest 95 | env: 96 | AzureServicesAuthConnectionString: runAs=App;AppId=$(ApiScanClientId) 97 | 98 | - task: PublishSecurityAnalysisLogs@3 99 | displayName: Publish 'SDLAnalysis-APIScan' artifact 100 | condition: succeededOrFailed() 101 | inputs: 102 | ArtifactName: SDLAnalysis-APIScan 103 | AllTools: false 104 | APIScan: true 105 | 106 | - task: PostAnalysis@2 107 | displayName: Post Analysis 108 | inputs: 109 | GdnBreakAllTools: false 110 | GdnBreakGdnToolApiScan: true 111 | 112 | - task: TSAUpload@2 113 | displayName: Upload APIScan results to TSA 114 | inputs: 115 | GdnPublishTsaOnboard: false 116 | GdnPublishTsaConfigFile: '$(Build.SourcesDirectory)\.config\tsaoptions.json' 117 | GdnPublishTsaExportedResultsPublishable: true 118 | continueOnError: true 119 | condition: succeededOrFailed() 120 | enabled: true 121 | --------------------------------------------------------------------------------