From a03aba872b3d390585ce5740110176b4662796c6 Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 11:36:43 +0100 Subject: [PATCH 01/13] #12 Add version cli option --- CHANGELOG.md | 19 ----------- README.md | 32 +++++++++++++------ SolarWinds.Changesets.sln | 7 +++- .../SpectreConsoleConfiguratorExtensions.cs | 29 +++++++++++++++++ src/SolarWinds.Changesets/Program.cs | 1 + 5 files changed, 58 insertions(+), 30 deletions(-) delete mode 100644 CHANGELOG.md create mode 100644 src/SolarWinds.Changesets/Infrastructure/SpectreConsoleConfiguratorExtensions.cs diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 4ae0db7..0000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,19 +0,0 @@ -# Changelog - -## 0.1.1 - -### Modified - -- Package icon, description, url,... - -## 0.1.0 - -### Added - -- Initial release of NET Changesets tool -- Currently Supported Commands: - - `changeset init` - - `changeset add` - - `changeset version` - - `changeset publish` - - `changeset status` diff --git a/README.md b/README.md index 5feeaa1..4f64cb9 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,7 @@ # NET Changesets +[![NuGet version (SolarWinds.Changesets)](https://img.shields.io/nuget/v/SolarWinds.Changesets.svg)](https://www.nuget.org/packages/SolarWinds.Changesets) + A .NET CLI tool (with interactive support) to manage versioning and changelogs with a focus on multi-package repositories. Key features include: @@ -13,26 +15,36 @@ Key features include: This .NET implementation is port from original `npm` implementation [@changesets/cli](https://www.npmjs.com/package/@changesets/cli) ([GitHub repository](https://github.com/changesets/changesets/blob/main/README.md)). -## Currently Supported Commands +## CLI + +**Usage:** + +`changeset [OPTIONS] [COMMAND]` + +**Options:** + +- `-h, --help` Prints help information +- `-v, --version` Prints version information -- `changeset init` -- `changeset add` -- `changeset version` -- `changeset publish` -- `changeset status` +**Commands:** +- `init` Sets up the .changeset folder and generates a default config file. You should run this command once when you are setting up changesets +- `add` Used by contributors to add information about their changes by creating changeset files +- `version` Takes existing changeset files and updates versions and dependencies of packages, as well as writing changelogs +- `publish` This publishes changes to specified nuget repository +- `status` Provides information about the changesets that currently exist. If there are no changesets present, it exits with an error status code ## Documentation -- [Implementation Details of net-changesets commands](./docs/commands-implementation-details.md) -- [Config file options](./docs/config-file-options.md) +- [Implementation Details of net-changesets commands](https://github.com/solarwinds/net-changesets/blob/main/docs/commands-implementation-details.md) +- [Config file options](https://github.com/solarwinds/net-changesets/blob/main/docs/config-file-options.md) ## Roadmap -You can find the **Roadmap** [here](./ROADMAP.md). +You can find the **Roadmap** [here](https://github.com/solarwinds/net-changesets/blob/main/ROADMAP.md). ## Contributing -You can find the **Contribution Guidelines** [here](./CONTRIBUTING.md). +You can find the **Contribution Guidelines** [here](https://github.com/solarwinds/net-changesets/blob/main/CONTRIBUTING.md). ## Installation diff --git a/SolarWinds.Changesets.sln b/SolarWinds.Changesets.sln index b146166..c78a885 100644 --- a/SolarWinds.Changesets.sln +++ b/SolarWinds.Changesets.sln @@ -15,7 +15,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution .editorconfig = .editorconfig .gitattributes = .gitattributes .gitignore = .gitignore - CHANGELOG.md = CHANGELOG.md CODEOWNERS = CODEOWNERS CONTRIBUTING.md = CONTRIBUTING.md Directory.Build.props = Directory.Build.props @@ -51,6 +50,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "workflows", "workflows", "{ .github\workflows\codeql.yml = .github\workflows\codeql.yml EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".changeset", ".changeset", "{D9292B07-1521-45FF-987C-93AF914C02B8}" + ProjectSection(SolutionItems) = preProject + .changeset\config.json = .changeset\config.json + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -76,6 +80,7 @@ Global {02EA681E-C7D8-13C7-8484-4AC65E1B71E8} = {0ABD51BE-854F-4ADA-BA0B-A53D22E84A2B} {31B2BA1F-7D13-210D-5051-E57059416DA2} = {BC9915A0-AE80-47A7-89E8-841B2220E53B} {00407218-C694-4CF5-AABB-5EAE81B3466F} = {14F3844A-0818-4A24-B210-262CFFC5FD8C} + {D9292B07-1521-45FF-987C-93AF914C02B8} = {0ABD51BE-854F-4ADA-BA0B-A53D22E84A2B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {24D73EE6-7A9E-4AFF-AC21-18B414246B30} diff --git a/src/SolarWinds.Changesets/Infrastructure/SpectreConsoleConfiguratorExtensions.cs b/src/SolarWinds.Changesets/Infrastructure/SpectreConsoleConfiguratorExtensions.cs new file mode 100644 index 0000000..7a87473 --- /dev/null +++ b/src/SolarWinds.Changesets/Infrastructure/SpectreConsoleConfiguratorExtensions.cs @@ -0,0 +1,29 @@ +using System.Reflection; +using Spectre.Console.Cli; + +namespace SolarWinds.Changesets.Infrastructure; + +internal static class SpectreConsoleConfiguratorExtensions +{ + /// + /// Uses the version retrieved from the as the application's version. + /// + /// + /// The InformationalVersion contains version in following format: $(VersionPrefix)-$(VersionSuffix)+$(SourceRevisionId) + /// We are only interested in the $(VersionPrefix)-$(VersionSuffix) part, so we split by '+' and take the first part. + /// + /// The configurator. + /// A configurator that can be used to configure the application further. + public static IConfigurator UseAssemblyInformationalVersionWithoutSourceRevisionId(this IConfigurator configurator) + { + ArgumentNullException.ThrowIfNull(configurator); + + configurator.Settings.ApplicationVersion = Assembly + .GetEntryAssembly() + ?.GetCustomAttribute() + ?.InformationalVersion + ?.Split('+')[0] ?? "Failed to retrieve version."; + + return configurator; + } +} diff --git a/src/SolarWinds.Changesets/Program.cs b/src/SolarWinds.Changesets/Program.cs index 1e9d247..c0143d6 100644 --- a/src/SolarWinds.Changesets/Program.cs +++ b/src/SolarWinds.Changesets/Program.cs @@ -31,6 +31,7 @@ { config .SetApplicationName("changeset") + .UseAssemblyInformationalVersionWithoutSourceRevisionId() .SetExceptionHandler(ExceptionHandler.Handle); config From 85ba4cd802ef67bce25650a68db88ad249494b22 Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 11:39:31 +0100 Subject: [PATCH 02/13] #12 Replace package icon with transparent one --- assets/icon.png | Bin 3717 -> 3518 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/assets/icon.png b/assets/icon.png index 864dabf9d4b1da3f1b79b0e99de399b70d6d0f47..16cd68d01a5d851202191b7ddb4f01990e670f77 100644 GIT binary patch delta 3491 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 R8=U|E002ovPDHLkV1m?Mzs3Ln delta 3691 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 E0JN6TrvLx| From 7f02ef29ff91c0b69aa73238e5feee9807fdbcf4 Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 11:49:35 +0100 Subject: [PATCH 03/13] #12 Show code style analyzers as warning instead of error --- Directory.Build.props | 183 ++++++++++++++++++++++++++++++++---------- 1 file changed, 142 insertions(+), 41 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index 0393668..55424d6 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,50 +1,151 @@ - - + + - - net8.0 - - 12.0 - + + net8.0 + + 12.0 + - - SolarWinds - $(Company) - git - https://github.com/solarwinds/net-changesets - ©$([System.DateTime]::Now.Year) $(Company) Worldwide, LLC. All rights reserved. - + + SolarWinds + $(Company) + git + https://github.com/solarwinds/net-changesets + ©$([System.DateTime]::Now.Year) $(Company) Worldwide, LLC. All rights reserved. + - - - - enable - enable - true - true - false - true - - 8 - all - true + + + + enable + enable + true + true + false + true + + 8 + all + true - - - true - - $(NoWarn); - - + + + true + + $(NoWarn); + + + + + + $(WarningsNotAsErrors); + IDE0003;IDE0005;IDE0007;IDE0008;IDE0011;IDE0016;IDE0017;IDE0018;IDE0019; + IDE0020;IDE0021;IDE0022;IDE0023;IDE0024;IDE0025;IDE0026;IDE0027;IDE0028; + IDE0029;IDE0030;IDE0031;IDE0032;IDE0033;IDE0034;IDE0036;IDE0037;IDE0038; + IDE0039;IDE0040;IDE0041;IDE0042;IDE0044;IDE0045;IDE0046;IDE0049;IDE0053; + IDE0054;IDE0055;IDE0056;IDE0057;IDE0058;IDE0059;IDE0060;IDE0061;IDE0062; + IDE0063;IDE0065;IDE0066;IDE0070;IDE0071;IDE0074;IDE0075;IDE0078;IDE0079; + IDE0083;IDE0090;IDE0130;IDE0150;IDE0161;IDE0170;IDE0180;IDE0200;IDE0210; + IDE0220;IDE0230;IDE0250;IDE0251;IDE0270;IDE0290;IDE0320;IDE0330;IDE0340; + IDE1005;IDE1006;IDE2000;IDE2001;IDE2002;IDE2003;IDE2004;IDE2005;IDE2006; + IDE2007;CS0612;CS0618 + + - - true - + + true + - - $(SolutionDir)\src - $(SolutionDir)\tests - + + $(SolutionDir)\src + $(SolutionDir)\tests + From dcfa2104be27b14d4694633fc9677f91aeb624b5 Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 11:51:27 +0100 Subject: [PATCH 04/13] #12 Remove leftover code and improve the 'not initialized' error message --- src/SolarWinds.Changesets/Shared/ConsoleExtensions.cs | 11 ----------- src/SolarWinds.Changesets/Shared/ExceptionHandler.cs | 7 +++---- 2 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/SolarWinds.Changesets/Shared/ConsoleExtensions.cs b/src/SolarWinds.Changesets/Shared/ConsoleExtensions.cs index a6d829e..b12e647 100644 --- a/src/SolarWinds.Changesets/Shared/ConsoleExtensions.cs +++ b/src/SolarWinds.Changesets/Shared/ConsoleExtensions.cs @@ -4,17 +4,6 @@ namespace SolarWinds.Changesets.Shared; internal static class ConsoleExtensions { - public static void ChangesetsIsNotInitialized(this IAnsiConsole console) - { - const string errorMessage = - """ - There is no .changeset folder. - If this is the first time `changesets` have been used in this project, run `net-changeset init` to get set up. - If you expect changesets to exist, check the Git history for when the folder was removed to ensure the configuration is not lost. - """; - console.MarkupLine($"[red]error[/] {errorMessage}"); - } - /// /// Prints a list of messages to the console, optionally applying a Spectre.Console markup style to each message. /// diff --git a/src/SolarWinds.Changesets/Shared/ExceptionHandler.cs b/src/SolarWinds.Changesets/Shared/ExceptionHandler.cs index 8924e8e..59d4a8c 100644 --- a/src/SolarWinds.Changesets/Shared/ExceptionHandler.cs +++ b/src/SolarWinds.Changesets/Shared/ExceptionHandler.cs @@ -11,11 +11,10 @@ public static int Handle(Exception ex, ITypeResolver? _) if (ex is InitializationException) { - returnCode = ResultCodes.NotInitialized; - AnsiConsole.MarkupLine("[red]Error:[/] The changesets tool is not initialized in this repository."); + AnsiConsole.MarkupLine("[red]error[/] The [yellow]changeset[/] tool is not initialized in this repository."); AnsiConsole.WriteLine(); - AnsiConsole.MarkupLine("Please run [yellow]changeset init[/] first to configure the tool."); - return returnCode; + AnsiConsole.MarkupLine("Please run [yellow]changeset init[/] first in the root of the repository to configure the tool."); + return ResultCodes.NotInitialized; } AnsiConsole.WriteException(ex); From 8e3fbda0d3b182bffdc89b32f843d5c2b8021197 Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 11:54:10 +0100 Subject: [PATCH 05/13] #12 Replace relative links with absolute ones and fix few typos --- .github/PULL_REQUEST_TEMPLATE.md | 4 ++-- CONTRIBUTING.md | 8 ++++---- docs/commands-implementation-details.md | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 1fcce10..28b7996 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -12,9 +12,9 @@ Add the issue number here. e.g. #123 # Checklist -- [ ] I have double checked my own changes +- [ ] I have double-checked my own changes - [ ] I have read the [Contribution Guidelines](https://github.com/solarwinds/net-changesets/blob/main/CONTRIBUTING.md) -- [ ] Include the issue number (#xxx) in branch name and PR title and description +- [ ] Include the issue number (#xxx) in the branch name, PR title, and PR description in the Issue number section above - [ ] Provide a reasonable description of the PR in the [Changes](#Changes) section - [ ] I have commented on the issue above and discussed the intended changes - [ ] All newly added code is adequately covered by tests diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 8305a62..55f08d1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ We do very welcome everyone who wants to contribute to this repository, provided Please **discuss any changes you wish to make** with the net-changesets maintainers via GitHub issues before proceeding. -If you don’t have a specific idea in mind, you can pick an issue from the [roadmap](ROADMAP.md). Your help is greatly appreciated! +If you don’t have a specific idea in mind, you can pick an issue from the [roadmap](https://github.com/solarwinds/net-changesets/blob/main/docs/config-file-options.md). Your help is greatly appreciated! ## Design considerations @@ -31,7 +31,7 @@ Always consider the following aspects: - **Do not make any additional changes unrelated to your GitHub issue.** - **Every change must be covered by a unit or integration test.** - **Write clean, self-documenting code** and add XML comments to newly added code. -- **Edit or add documentation** in the `docs` folder or in [README.md](README.md). +- **Edit or add documentation** in the `docs` folder or in [README.md](https://github.com/solarwinds/net-changesets/blob/main/README.md). #### Local Installation @@ -49,7 +49,7 @@ dotnet tool install solarwinds.changesets --global --add-source ./nupkg --versio This project uses only first-party [.NET source code analysis](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/overview?tabs=net-9) from Microsoft. -The [.editorconfig](.editorconfig) and [Directory.Build.props](Directory.Build.props) files contain the configuration for code style and quality. +The [.editorconfig](https://github.com/solarwinds/net-changesets/blob/main/.editorconfig) and [Directory.Build.props](https://github.com/solarwinds/net-changesets/blob/main/Directory.Build.props) files contain the configuration for code style and quality. - **Code style (`IDE****`) analyzers are disabled during build time.** - They are checked in PR CI as the last step. @@ -85,4 +85,4 @@ Create a pull request only if: - **PR author will reply** (for example, confirm that requested changes have been implemented or discuss why a suggested change may not be appropriate). - **Reviewer will resolve comments** once satisfied with the changes or explanations. -Additional information can be found in [PULL_REQUEST_TEMPLATE](.github/PULL_REQUEST_TEMPLATE.md). +Additional information can be found in [PULL_REQUEST_TEMPLATE](https://github.com/solarwinds/net-changesets/blob/main/.github/PULL_REQUEST_TEMPLATE.md). diff --git a/docs/commands-implementation-details.md b/docs/commands-implementation-details.md index f18a70b..2f8da1f 100644 --- a/docs/commands-implementation-details.md +++ b/docs/commands-implementation-details.md @@ -8,7 +8,7 @@ On this page, we will discuss implementation details that differ slightly from t changeset init ``` -This command works the same, only difference is that we have different configuration schema to satisfy .NET implementation. You can read more about it in [config-file-options.md](./config-file-options.md). +This command works the same, only difference is that we have different configuration schema to satisfy .NET implementation. You can read more about it in [config-file-options.md](https://github.com/solarwinds/net-changesets/blob/main/docs/config-file-options.md). ## `add` From 725b4bcfc6cfda74dd3ab1a4b03e225b247d5849 Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 12:19:45 +0100 Subject: [PATCH 06/13] #12 Fix markdown linter warnings in generated changelogs --- .../Commands/Version/Helpers/ChangelogFileWriter.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs b/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs index ca15aac..2f4d1ca 100644 --- a/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs +++ b/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs @@ -44,7 +44,6 @@ private static string GenerateChangelogFile(ModuleChangelog moduleChangelog) return $""" ## {newVersion} - {string.Join("", groupedDescriptions.Select(groupedDesc => GenerateChangelogBumpTypeSection(groupedDesc.BumpType, groupedDesc.Descriptions)) )} @@ -55,11 +54,11 @@ private static string GenerateChangelogBumpTypeSection(BumpType bumpType, IEnume { return $""" - ### {bumpType} Changes + + **{bumpType} Changes**: {string.Join(Environment.NewLine, descriptions.Select(description => $"- {description}"))} - - + """; } } From cb958d9c04541bc26379351efa2dccf275b42c8e Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 12:22:25 +0100 Subject: [PATCH 07/13] #12 Generate changelog and bump version to 0.1.3 --- src/SolarWinds.Changesets/CHANGELOG.md | 32 +++++++++++++++++-- .../SolarWinds.Changesets.csproj | 4 +-- 2 files changed, 31 insertions(+), 5 deletions(-) diff --git a/src/SolarWinds.Changesets/CHANGELOG.md b/src/SolarWinds.Changesets/CHANGELOG.md index 9491c4b..7220a54 100644 --- a/src/SolarWinds.Changesets/CHANGELOG.md +++ b/src/SolarWinds.Changesets/CHANGELOG.md @@ -1,17 +1,43 @@ # SolarWinds.Changesets +## 0.1.3 + +**Patch Changes**: + +- [[#6](https://github.com/solarwinds/net-changesets/issues/6)] Add Contributor Covenant Code of Conduct ([PR #14](https://github.com/solarwinds/net-changesets/pull/14)) +- [[#12](https://github.com/solarwinds/net-changesets/issues/12)] Add `-v, --version` option to changeset CLI and other small fixes ([PR #15](https://github.com/solarwinds/net-changesets/pull/15)) + - Replace package icon with transparent one + - Fix `MD012/no-multiple-blanks` linter warning in generated changelog that was caused by two new lines at the bottom of a generated section instead of one + - Fix `MD024/no-duplicate-heading` linter warning in generated changelog that was caused by duplicate headings. This `### {bumpType} Changes` was replaced with this `**{bumpType} Changes**:` + - Use absolute links to Markdown documents instead of relative ones, which may not work in some contexts (e.g., NuGet package page) + - `TreatWarningsAsErrors` is changing code style warnings to errors, but we want to keep them as warnings + - Remove leftover code for 'not initialized' error message and improve current 'not initialized' error message + ## 0.1.2 **Patch Changes**: -- Improved error handling when the repository is uninitialized. +- [NO-ISSUE] Add security info file ([PR #5](https://github.com/solarwinds/net-changesets/pull/5)) +- [[#9](https://github.com/solarwinds/net-changesets/issues/9)] Copilot instructions and minor improvements for first start ([PR #10](https://github.com/solarwinds/net-changesets/pull/10)) +- [[#8](https://github.com/solarwinds/net-changesets/issues/8)] Improved error handling when the changeset is not initialized. ([PR #11](https://github.com/solarwinds/net-changesets/pull/11)) ## 0.1.1 **Patch Changes**: -- Metadata and icon improvements +- [[#3](https://github.com/solarwinds/net-changesets/issues/3)] Add missing nuget package metadata ([PR #4](https://github.com/solarwinds/net-changesets/pull/4)) ## 0.1.0 -First release. +**Minor Changes**: + +- [[#1](https://github.com/solarwinds/net-changesets/issues/1)] Initial release of .NET Changesets CLI tool ([PR #2](https://github.com/solarwinds/net-changesets/pull/2)) + - USAGE: `changeset [OPTIONS] [COMMAND]` + - Currently Supported Options: + - `-h, --help` + - Currently Supported Commands: + - `init` + - `add` + - `version` + - `publish` + - `status` diff --git a/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj b/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj index 35acf7a..adf6b2a 100644 --- a/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj +++ b/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj @@ -1,4 +1,4 @@ - + @@ -17,7 +17,7 @@ $(RepositoryUrl)/releases true Exe - 0.1.2 + 0.1.3 embedded true From bb16368efb6391522c90df96fc9ebc6be04af963 Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 13:07:58 +0100 Subject: [PATCH 08/13] #12 Fix formating of json, yml, xml and md files --- .changeset/config.json | 2 +- .editorconfig | 4 + .github/PULL_REQUEST_TEMPLATE.md | 2 +- .github/copilot-instructions.md | 46 +++++-- .github/instructions/coding.instructions.md | 6 + .github/instructions/dotnet.instructions.md | 13 +- .github/workflows/ci.yml | 50 ++++---- .github/workflows/codeql.yml | 52 ++++---- .vscode/extensions.json | 8 ++ .vscode/settings.json | 36 ++++++ Directory.Build.props | 114 +++++++++--------- README.md | 1 + SECURITY.md | 4 +- SolarWinds.Changesets.sln | 8 ++ .../SolarWinds.Changesets.csproj | 34 +++--- .../SolarWinds.Changesets.Tests.csproj | 98 +++++++-------- 16 files changed, 287 insertions(+), 191 deletions(-) create mode 100644 .vscode/extensions.json create mode 100644 .vscode/settings.json diff --git a/.changeset/config.json b/.changeset/config.json index 7bd3e3e..7d0c2ec 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -1,4 +1,4 @@ { "sourcePath": "src", "packageSource": "nuget" -} \ No newline at end of file +} diff --git a/.editorconfig b/.editorconfig index 8f9c51e..042acdd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,10 @@ indent_size = 4 trim_trailing_whitespace = true # end_of_line = crlf # The end_of_line setting is maintained by .gitattributes! Do not set it here! +[*.{json,yml,yaml,xml,md,csproj,props,config}] +indent_style = space +indent_size = 2 + [*.cs] charset = utf-8 max_line_length = 130 diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 28b7996..a32d47c 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -15,7 +15,7 @@ Add the issue number here. e.g. #123 - [ ] I have double-checked my own changes - [ ] I have read the [Contribution Guidelines](https://github.com/solarwinds/net-changesets/blob/main/CONTRIBUTING.md) - [ ] Include the issue number (#xxx) in the branch name, PR title, and PR description in the Issue number section above -- [ ] Provide a reasonable description of the PR in the [Changes](#Changes) section +- [ ] Provide a reasonable description of the PR in the [Changes](#changes) section - [ ] I have commented on the issue above and discussed the intended changes - [ ] All newly added code is adequately covered by tests - [ ] Make sure your PR is passing the CI/CD pipeline diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index bc17de9..3714b68 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -8,14 +8,14 @@ NET Changesets is a .NET CLI tool for managing versioning and changelogs in mult ## Technology stack -**Language:** C# 12.0 with nullable reference types and implicit usings enabled -**Runtime:** .NET 8.0 (SDK 8.0.406) -**CLI Framework:** Spectre.Console v0.50.0 (interactive prompts, tables, markup rendering) -**Dependency Injection:** Microsoft.Extensions.DependencyInjection v9.0.9 -**Testing:** NUnit 4.4.0, Moq 4.20.72, AwesomeAssertions 9.1.0, Spectre.Console.Testing -**Code Analysis:** Microsoft .NET analyzers (all enabled, warnings-as-errors), Spectre.Console.Analyzer -**Package Management:** Central Package Management via `Directory.Packages.props` -**CI/CD:** GitHub Actions (build, test, pack, format verification) +**Language:** C# 12.0 with nullable reference types and implicit usings enabled +**Runtime:** .NET 8.0 (SDK 8.0.406) +**CLI Framework:** Spectre.Console v0.50.0 (interactive prompts, tables, markup rendering) +**Dependency Injection:** Microsoft.Extensions.DependencyInjection v9.0.9 +**Testing:** NUnit 4.4.0, Moq 4.20.72, AwesomeAssertions 9.1.0, Spectre.Console.Testing +**Code Analysis:** Microsoft .NET analyzers (all enabled, warnings-as-errors), Spectre.Console.Analyzer +**Package Management:** Central Package Management via `Directory.Packages.props` +**CI/CD:** GitHub Actions (build, test, pack, format verification) **External Tools:** Git CLI (for diff detection), dotnet CLI (for pack/publish) ## Directory structure @@ -44,6 +44,7 @@ SolarWinds.Changesets.sln # Main solution file **CLI Framework:** Uses Spectre.Console.Cli with `CommandApp` (Add is default). Commands registered in `Program.cs` via `config.AddCommand()`. All commands inherit from `ConfigurationCommandBase` which loads `.changeset/config.json`. **Dependency Injection:** Services registered in `ServiceCollection` and integrated via custom `TypeRegistrar`/`TypeResolver` (required by Spectre.Console.Cli). Main services: + - `IConfigurationService`: Loads/validates `.changeset/config.json` - `IChangesetsRepository`: Reads/writes/deletes changeset markdown files - `ICsProjectsRepository`: Parses .csproj files, updates `` elements @@ -55,6 +56,7 @@ SolarWinds.Changesets.sln # Main solution file **Semantic Versioning:** Custom `Semver` class (Major.Minor.Patch) with methods `RaiseMajor()`, `RaiseMinor()`, `RaisePatch()`. Parses version strings from `` in .csproj files. Version bumps cascade dependencies (updating dependent projects). **Command Flow Example (version command):** + 1. `VersionChangesetCommand.ExecuteCommandAsync()` calls `IChangesetsRepository.GetChangesetsAsync()` 2. Reads all `.md` files from `.changeset/` directory 3. Parses YAML front matter (project names, bump types) and markdown content @@ -69,28 +71,33 @@ SolarWinds.Changesets.sln # Main solution file **Prerequisites:** .NET 8.0 SDK (version 8.0.406 or compatible via rollForward in `global.json`) **Build:** + ```bash dotnet restore --packages ./packages dotnet build -c Release --no-restore ``` **Test:** + ```bash dotnet test -c Release --no-restore --no-build --verbosity normal ``` **Pack:** + ```bash dotnet pack -c Release --no-restore --no-build # Output: ./nupkg/SolarWinds.Changesets.0.1.1.nupkg ``` **Code Style Check:** + ```bash dotnet format --no-restore --verify-no-changes ``` **Local Installation for Testing:** + ```bash dotnet tool uninstall solarwinds.changesets --global dotnet tool install solarwinds.changesets --global --add-source ./nupkg @@ -109,6 +116,7 @@ dotnet run --project .\src\SolarWinds.Changesets\SolarWinds.Changesets.csproj ``` **Verification checklist:** + 1. ✅ Build succeeds: `dotnet build -c Release --no-restore` 2. ✅ All tests pass: `dotnet test -c Release --no-restore --no-build` 3. ✅ Code formatting: `dotnet format --no-restore --verify-no-changes` @@ -118,15 +126,18 @@ dotnet run --project .\src\SolarWinds.Changesets\SolarWinds.Changesets.csproj ## Domain configurations **Changeset Config (`.changeset/config.json`):** + ```json { - "sourcePath": "src", // Relative path to projects folder - "packageSource": "nuget" // NuGet source name from NuGet.config + "sourcePath": "src", // Relative path to projects folder + "packageSource": "nuget" // NuGet source name from NuGet.config } ``` + Created by `changeset init`. Loaded by `ConfigurationService`. Default `packageSource` is `nuget.org`. **NuGet.config:** Optional file for custom package sources. Example: + ```xml @@ -135,6 +146,7 @@ Created by `changeset init`. Loaded by `ConfigurationService`. Default `packageS ``` **Changeset File Format (`.changeset/{randomname}.md`):** + ```markdown --- "ProjectA": minor @@ -143,9 +155,11 @@ Created by `changeset init`. Loaded by `ConfigurationService`. Default `packageS Added new feature X and fixed bug Y in ProjectB ``` + Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Projects listed in YAML front matter with bump type (major/minor/patch). **Project File Requirements:** + - Must contain `` element (e.g., `1.0.0`) - Supported format: `Major.Minor.Patch` (parsed via `System.Version`) - `version` command updates this element in-place using XML manipulation @@ -153,6 +167,7 @@ Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Proje ## Conventions **Code Style:** + - **Implicit usings enabled** (no need for common System namespaces) - **Nullable reference types enabled** (treat null warnings as errors) - **File-scoped namespaces** (e.g., `namespace SolarWinds.Changesets.Commands.Add;`) @@ -161,6 +176,7 @@ Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Proje - **IDE rules enforced in CI** via `dotnet format` (not in build) **Testing:** + - NUnit framework with `[TestFixture]` and `[Test]` attributes - Global using for `NUnit.Framework` (defined in test .csproj) - Test data in `TestData/` folders, copied to output directory @@ -168,23 +184,27 @@ Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Proje - Mock external processes using `Moq` on `IProcessExecutor` **Naming:** + - Commands: `{Action}ChangesetCommand` (e.g., `AddChangesetCommand`) - Interfaces: Standard `I` prefix (e.g., `IConfigurationService`) - Internal classes: Most implementation classes are `internal sealed` - Constants: Defined in `Constants` static class (e.g., `Constants.WorkingDirectoryFullPath`) **Dependency Constraints:** + - **Only allowed third-party dependency:** Spectre.Console (and related packages) - Rationale: Minimize external dependencies for a CLI tool - All other needs met by .NET BCL or Microsoft.Extensions packages **Git Workflow:** + - Branch naming: `{type}/{issueID}-{description}` (e.g., `feature/123-add-new-command`) - Commit messages: Start with issue ID (e.g., `123 Implement status command`) - GPG signing required for commits - PR title format: `{Type} #{issueID} {Description}` **Error Handling:** + - `ExceptionHandler.Handle()` registered in Spectre.Console CLI config - Custom exception: `InitializationException` for config validation errors - Return codes defined in `ResultCodes` class (not yet fully implemented) @@ -192,23 +212,27 @@ Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Proje ## Integration points **Git Integration:** + - `GitService.GetDiff()` calls `git diff --name-only {sourcePath}` to detect modified .csproj files - Used by `publish` command to identify packages needing publication - Requires git executable in PATH **Dotnet CLI Integration:** + - `DotnetService.Pack()` calls `dotnet pack {projectPath} --output {Constants.NupkgOutputFullPath}` - `DotnetService.Publish()` calls `dotnet nuget push {nupkgPath} --source {packageSource}` - NuGet API key expected in environment or nuget.config (standard dotnet behavior) - Output directory: `./nupkg/` (created if not exists) **File System Operations:** + - Changeset files: `.changeset/` directory (created by `init` command) - CHANGELOG.md: Root of repository - .csproj files: Located via recursive search from `sourcePath` config - All paths resolved relative to `Constants.WorkingDirectoryFullPath` (current directory) **NuGet Sources:** + - Resolved via standard dotnet/NuGet.config mechanisms - Default: `nuget` source (typically nuget.org) - Custom sources defined in `NuGet.config` (repository or user-level) @@ -219,11 +243,13 @@ Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Proje **Current State:** MVP stage with manual CLI operations. All 5 commands implemented (`init`, `add`, `version`, `publish`, `status`). **Known Limitations:** + - `add` command supports only single bump type for all selected projects (npm version allows per-project bumps) - No command-line options for `add` (interactive mode only) - Manual execution required (no GitHub Action yet) **Planned Features:** + - **GitHub Action** (primary roadmap item): Automated PR creation for version bumps, reusing existing codebase. See `.NET GitHub Action` documentation. - Future improvements open for discussion via GitHub issues diff --git a/.github/instructions/coding.instructions.md b/.github/instructions/coding.instructions.md index 9faf408..32ecb3f 100644 --- a/.github/instructions/coding.instructions.md +++ b/.github/instructions/coding.instructions.md @@ -5,6 +5,7 @@ applyTo: "**/*.go,**/*.cs,**/*.java,**/*.kt,**/*.py,**/*.js,**/*.ts,**/*.tsx" # Coding Instructions ## General code style and readability + - Write code that is readable, understandable, and maintainable for future readers. - Aim to create software that is not only functional but also readable, maintainable, and efficient throughout its lifecycle. - Prioritize clarity to make reading, understanding, and modifying code easier. @@ -12,26 +13,31 @@ applyTo: "**/*.go,**/*.cs,**/*.java,**/*.kt,**/*.py,**/*.js,**/*.ts,**/*.tsx" - Regularly review and refactor code to improve structure, readability, and maintainability. Always leave the codebase cleaner than you found it. ## Naming conventions + - Choose names for variables, functions, and classes that reflect their purpose and behavior. - A name should tell you why it exists, what it does, and how it is used. If a name requires a comment, then the name does not reveal its intent. - Use specific names that provide a clearer understanding of what the variables represent and how they are used. ## DRY principle + - Follow the DRY (Don't Repeat Yourself) Principle and Avoid Duplicating Code or Logic. - Avoid writing the same code more than once. Instead, reuse your code using functions, classes, modules, libraries, or other abstractions. - Modify code in one place if you need to change or update it. ## Function length and responsibility + - Write short functions that only do one thing. - Follow the single responsibility principle (SRP), which means that a function should have one purpose and perform it effectively. - If a function becomes too long or complex, consider breaking it into smaller, more manageable functions. ## Comments usage + - Use comments sparingly, and when you do, make them meaningful. - Don't comment on obvious things. Excessive or unclear comments can clutter the codebase and become outdated. - Use comments to convey the "why" behind specific actions or explain unusual behavior and potential pitfalls. - Provide meaningful information about the function's behavior and explain unusual behavior and potential pitfalls. ## Conditional encapsulation + - One way to improve the readability and clarity of functions is to encapsulate nested if/else statements into other functions. - Encapsulating such logic into a function with a descriptive name clarifies its purpose and simplifies code comprehension. diff --git a/.github/instructions/dotnet.instructions.md b/.github/instructions/dotnet.instructions.md index ff1ee75..8cbfe32 100644 --- a/.github/instructions/dotnet.instructions.md +++ b/.github/instructions/dotnet.instructions.md @@ -5,6 +5,7 @@ applyTo: "**/*.cs" # Instructions for .NET C# code C# code (besides unit tests) should adhere to the following guidelines: + - Follow SOLID principles - Use dependency injection - Use appropriate configuration formats (JSON, YAML, environment variables) @@ -119,7 +120,7 @@ public async Task ProcessAsync(UserData userData, CancellationTok ## Repository structure -The following are instructions on how to name folders and files and how the basic repository structure should look like +The following are instructions on how to name folders and files and how the basic repository structure should look like - Each project (CSPROJ) should be in its own folder. - Projects with the implementation code should be under "src" folder. @@ -130,19 +131,21 @@ The following are instructions on how to name folders and files and how the basi ### Code Examples #### Async/Await Pattern + ```csharp public async Task GetUserAsync(int userId, CancellationToken cancellationToken = default) { using var httpClient = _httpClientFactory.CreateClient(); var response = await httpClient.GetAsync($"/api/users/{userId}", cancellationToken); response.EnsureSuccessStatusCode(); - + var content = await response.Content.ReadAsStringAsync(cancellationToken); return JsonSerializer.Deserialize(content); } ``` #### String Comparison Example + ```csharp // For culture-sensitive comparisons if (userInput.Equals(expectedValue, StringComparison.InvariantCultureIgnoreCase)) @@ -152,6 +155,7 @@ if (fileName.EndsWith(".txt", StringComparison.Ordinal)) ``` #### StringBuilder Usage + ```csharp // Use StringBuilder for heavy concatenation in loops var builder = new StringBuilder(); @@ -163,6 +167,7 @@ return builder.ToString(); ``` #### Regex Source Generators + ```csharp using System.Text.RegularExpressions; @@ -171,11 +176,11 @@ public partial class MyService // Use regex source generators for compile-time validation and better performance [GeneratedRegex(@"\b(query|mutation)\b\s+(\w+)")] private static partial Regex OperationNameRegex(); - + // For culture-sensitive patterns, specify options [GeneratedRegex(@"[a-zA-Z_:][a-zA-Z0-9_:]*", RegexOptions.IgnoreCase)] private static partial Regex IdentifierRegex(); - + public string ExtractOperationName(string query) { var match = OperationNameRegex().Match(query); diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index abaca15..f724d3f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,41 +3,41 @@ permissions: contents: read on: - pull_request: - branches: [ "main" ] - push: - branches: [ "main" ] + pull_request: + branches: ["main"] + push: + branches: ["main"] jobs: build-and-test: runs-on: ubuntu-latest steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.406 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.406 - - name: Restore dependencies - run: dotnet restore --packages ./packages + - name: Restore dependencies + run: dotnet restore --packages ./packages - - name: Build - run: dotnet build -c Release --no-restore + - name: Build + run: dotnet build -c Release --no-restore - - name: Test - run: dotnet test -c Release --no-restore --no-build --verbosity normal + - name: Test + run: dotnet test -c Release --no-restore --no-build --verbosity normal - - name: Pack - run: dotnet pack -c Release --no-restore --no-build + - name: Pack + run: dotnet pack -c Release --no-restore --no-build - - name: Upload NuGet package as artifact - uses: actions/upload-artifact@v4 - with: - name: nuget-package - path: ./nupkg/*.nupkg + - name: Upload NuGet package as artifact + uses: actions/upload-artifact@v4 + with: + name: nuget-package + path: ./nupkg/*.nupkg - - name: Format - run: dotnet format --no-restore --verify-no-changes + - name: Format + run: dotnet format --no-restore --verify-no-changes diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index cd1bfcf..9b059ba 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,11 +2,11 @@ name: "CodeQL Advanced" on: push: - branches: [ "main" ] + branches: ["main"] pull_request: - branches: [ "main" ] + branches: ["main"] schedule: - - cron: '0 0 * * 1' + - cron: "0 0 * * 1" jobs: analyze: @@ -22,30 +22,30 @@ jobs: fail-fast: false matrix: include: - - language: actions - build-mode: none - - language: csharp - build-mode: none + - language: actions + build-mode: none + - language: csharp + build-mode: none steps: - - name: Checkout repository - uses: actions/checkout@v4 + - name: Checkout repository + uses: actions/checkout@v4 - - name: Setup .NET - uses: actions/setup-dotnet@v4 - with: - dotnet-version: 8.0.406 + - name: Setup .NET + uses: actions/setup-dotnet@v4 + with: + dotnet-version: 8.0.406 - - name: Initialize CodeQL - uses: github/codeql-action/init@v3 - with: - languages: ${{ matrix.language }} - build-mode: ${{ matrix.build-mode }} - queries: security-and-quality + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + queries: security-and-quality - - name: Autobuild - uses: github/codeql-action/autobuild@v3 - - - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@v3 - with: - category: "/language:${{matrix.language}}" + - name: Autobuild + uses: github/codeql-action/autobuild@v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:${{matrix.language}}" diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..eb89390 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,8 @@ +{ + "recommendations": [ + "editorconfig.editorconfig", + "ms-dotnettools.csharp", + "redhat.vscode-xml", + "yzhang.markdown-all-in-one" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..ecdfead --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,36 @@ +{ + // Ensure EditorConfig settings are respected + "editor.detectIndentation": false, + // Format on save + "editor.formatOnSave": true, + // Use EditorConfig for indentation and final newline + "editor.insertSpaces": true, + "editor.tabSize": 4, + "files.insertFinalNewline": true, + "files.trimTrailingWhitespace": true, + // File-specific formatter settings + "[json]": { + "editor.defaultFormatter": "vscode.json-language-features", + "editor.tabSize": 2, + "editor.insertSpaces": true + }, + "[jsonc]": { + "editor.defaultFormatter": "vscode.json-language-features", + "editor.tabSize": 2, + "editor.insertSpaces": true + }, + "[xml]": { + "editor.defaultFormatter": "redhat.vscode-xml", + "editor.tabSize": 2, + "editor.insertSpaces": true + }, + "[markdown]": { + "editor.defaultFormatter": "yzhang.markdown-all-in-one", + "editor.tabSize": 2, + "editor.insertSpaces": true + }, + // C# formatting - respects EditorConfig automatically + "[csharp]": { + "editor.defaultFormatter": "ms-dotnettools.csharp" + } +} diff --git a/Directory.Build.props b/Directory.Build.props index 55424d6..3cea168 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,44 +1,44 @@ - - + + - - net8.0 - - 12.0 - + + net8.0 + + 12.0 + - - SolarWinds - $(Company) - git - https://github.com/solarwinds/net-changesets - ©$([System.DateTime]::Now.Year) $(Company) Worldwide, LLC. All rights reserved. - + + SolarWinds + $(Company) + git + https://github.com/solarwinds/net-changesets + ©$([System.DateTime]::Now.Year) $(Company) Worldwide, LLC. All rights reserved. + - - - - enable - enable - true - true - false - true - - 8 - all - true + + + + enable + enable + true + true + false + true + + 8 + all + true - - - true - - $(NoWarn); - - - - + + true + + $(NoWarn); + + + + - - $(WarningsNotAsErrors); - IDE0003;IDE0005;IDE0007;IDE0008;IDE0011;IDE0016;IDE0017;IDE0018;IDE0019; - IDE0020;IDE0021;IDE0022;IDE0023;IDE0024;IDE0025;IDE0026;IDE0027;IDE0028; - IDE0029;IDE0030;IDE0031;IDE0032;IDE0033;IDE0034;IDE0036;IDE0037;IDE0038; - IDE0039;IDE0040;IDE0041;IDE0042;IDE0044;IDE0045;IDE0046;IDE0049;IDE0053; - IDE0054;IDE0055;IDE0056;IDE0057;IDE0058;IDE0059;IDE0060;IDE0061;IDE0062; - IDE0063;IDE0065;IDE0066;IDE0070;IDE0071;IDE0074;IDE0075;IDE0078;IDE0079; - IDE0083;IDE0090;IDE0130;IDE0150;IDE0161;IDE0170;IDE0180;IDE0200;IDE0210; - IDE0220;IDE0230;IDE0250;IDE0251;IDE0270;IDE0290;IDE0320;IDE0330;IDE0340; - IDE1005;IDE1006;IDE2000;IDE2001;IDE2002;IDE2003;IDE2004;IDE2005;IDE2006; - IDE2007;CS0612;CS0618 - - + + $(WarningsNotAsErrors); + IDE0003;IDE0005;IDE0007;IDE0008;IDE0011;IDE0016;IDE0017;IDE0018;IDE0019; + IDE0020;IDE0021;IDE0022;IDE0023;IDE0024;IDE0025;IDE0026;IDE0027;IDE0028; + IDE0029;IDE0030;IDE0031;IDE0032;IDE0033;IDE0034;IDE0036;IDE0037;IDE0038; + IDE0039;IDE0040;IDE0041;IDE0042;IDE0044;IDE0045;IDE0046;IDE0049;IDE0053; + IDE0054;IDE0055;IDE0056;IDE0057;IDE0058;IDE0059;IDE0060;IDE0061;IDE0062; + IDE0063;IDE0065;IDE0066;IDE0070;IDE0071;IDE0074;IDE0075;IDE0078;IDE0079; + IDE0083;IDE0090;IDE0130;IDE0150;IDE0161;IDE0170;IDE0180;IDE0200;IDE0210; + IDE0220;IDE0230;IDE0250;IDE0251;IDE0270;IDE0290;IDE0320;IDE0330;IDE0340; + IDE1005;IDE1006;IDE2000;IDE2001;IDE2002;IDE2003;IDE2004;IDE2005;IDE2006; + IDE2007;CS0612;CS0618 + + - - true - + + true + - - $(SolutionDir)\src - $(SolutionDir)\tests - + + $(SolutionDir)\src + $(SolutionDir)\tests + diff --git a/README.md b/README.md index 4f64cb9..49573e9 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,7 @@ This .NET implementation is port from original `npm` implementation [@changesets - `-v, --version` Prints version information **Commands:** + - `init` Sets up the .changeset folder and generates a default config file. You should run this command once when you are setting up changesets - `add` Used by contributors to add information about their changes by creating changeset files - `version` Takes existing changeset files and updates versions and dependencies of packages, as well as writing changelogs diff --git a/SECURITY.md b/SECURITY.md index 1482a4f..562a3b1 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,9 +1,11 @@ # Security + SolarWinds is committed to taking our customers security and privacy concerns seriously and makes it a priority. -We strive to implement and maintain security processes, procedures, standards, and take all reasonable care to +We strive to implement and maintain security processes, procedures, standards, and take all reasonable care to prevent unauthorized access to our customer data. For more information see https://www.solarwinds.com/information-security. ## Want to report a security concern? + To report a vulnerability in one of our products or solutions or a vulnerability in one of our corporate websites, please contact our Product Security Incident Response Team (PSIRT) at psirt@solarwinds.com. diff --git a/SolarWinds.Changesets.sln b/SolarWinds.Changesets.sln index c78a885..4318e29 100644 --- a/SolarWinds.Changesets.sln +++ b/SolarWinds.Changesets.sln @@ -26,6 +26,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{14F3844A-0818-4A24-B210-262CFFC5FD8C}" ProjectSection(SolutionItems) = preProject + .github\copilot-instructions.md = .github\copilot-instructions.md .github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md EndProjectSection EndProject @@ -55,6 +56,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".changeset", ".changeset", .changeset\config.json = .changeset\config.json EndProjectSection EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "instructions", "instructions", "{32ECDA7C-AFB5-4446-97BC-47BE1AB7AD78}" + ProjectSection(SolutionItems) = preProject + .github\instructions\coding.instructions.md = .github\instructions\coding.instructions.md + .github\instructions\dotnet.instructions.md = .github\instructions\dotnet.instructions.md + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -81,6 +88,7 @@ Global {31B2BA1F-7D13-210D-5051-E57059416DA2} = {BC9915A0-AE80-47A7-89E8-841B2220E53B} {00407218-C694-4CF5-AABB-5EAE81B3466F} = {14F3844A-0818-4A24-B210-262CFFC5FD8C} {D9292B07-1521-45FF-987C-93AF914C02B8} = {0ABD51BE-854F-4ADA-BA0B-A53D22E84A2B} + {32ECDA7C-AFB5-4446-97BC-47BE1AB7AD78} = {14F3844A-0818-4A24-B210-262CFFC5FD8C} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {24D73EE6-7A9E-4AFF-AC21-18B414246B30} diff --git a/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj b/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj index adf6b2a..68b08ae 100644 --- a/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj +++ b/src/SolarWinds.Changesets/SolarWinds.Changesets.csproj @@ -23,24 +23,24 @@ true - - - - + + + + - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + - - - + + + diff --git a/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj b/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj index 0876afb..87d24dc 100644 --- a/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj +++ b/tests/SolarWinds.Changesets.Tests/SolarWinds.Changesets.Tests.csproj @@ -1,57 +1,57 @@  - - false - true - + + false + true + - - - + + + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + - - - + + + - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - - PreserveNewest - - + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + From fc136dff86bdf8d4c59392efbee5cd8e6173225c Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 13:08:20 +0100 Subject: [PATCH 09/13] #12 Fix codeowners --- CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CODEOWNERS b/CODEOWNERS index 83cf8cf..606a970 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1 +1 @@ -* @solarwinds/eng-changeset-owners \ No newline at end of file +* @solarwinds/eng-pub-changeset-owners From 66619687c6b2e41cf29e3ffaffeedd77240ee05b Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Sun, 16 Nov 2025 13:08:43 +0100 Subject: [PATCH 10/13] #12 Update changelog --- src/SolarWinds.Changesets/CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/src/SolarWinds.Changesets/CHANGELOG.md b/src/SolarWinds.Changesets/CHANGELOG.md index 7220a54..ef9a9b2 100644 --- a/src/SolarWinds.Changesets/CHANGELOG.md +++ b/src/SolarWinds.Changesets/CHANGELOG.md @@ -12,6 +12,7 @@ - Use absolute links to Markdown documents instead of relative ones, which may not work in some contexts (e.g., NuGet package page) - `TreatWarningsAsErrors` is changing code style warnings to errors, but we want to keep them as warnings - Remove leftover code for 'not initialized' error message and improve current 'not initialized' error message + - Fix formatting of JSON, YML, XML and Markdown files to use 2-space indentation ## 0.1.2 From 421290de566551358e084a97d3f962f1d1d4e61b Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Thu, 20 Nov 2025 17:37:10 +0100 Subject: [PATCH 11/13] Fix link in CONTRIBUTING.md Co-authored-by: Jan Vilimek --- CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 55f08d1..d995597 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -6,7 +6,7 @@ We do very welcome everyone who wants to contribute to this repository, provided Please **discuss any changes you wish to make** with the net-changesets maintainers via GitHub issues before proceeding. -If you don’t have a specific idea in mind, you can pick an issue from the [roadmap](https://github.com/solarwinds/net-changesets/blob/main/docs/config-file-options.md). Your help is greatly appreciated! +If you don’t have a specific idea in mind, you can pick an issue from the [roadmap](https://github.com/solarwinds/net-changesets/blob/main/ROADMAP.md). Your help is greatly appreciated! ## Design considerations From a06b926a2ce5fea99286f53b09cf775fa88a1f1a Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Mon, 22 Dec 2025 18:37:29 +0100 Subject: [PATCH 12/13] Fix tests --- .../Version/Helpers/ChangelogFileWriter.cs | 8 ++- .../Version/ChangelogFileWriterTests.cs | 68 ++++++++++++++----- 2 files changed, 56 insertions(+), 20 deletions(-) diff --git a/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs b/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs index 2f4d1ca..2b30a6a 100644 --- a/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs +++ b/src/SolarWinds.Changesets/Commands/Version/Helpers/ChangelogFileWriter.cs @@ -23,7 +23,10 @@ public async Task GenerateChangelogFilesAsync(IEnumerable modul } else { - await File.WriteAllLinesAsync(moduleChangelogFilePath, [$"# {moduleChangelog.ModuleName}", string.Empty, changelogEntry]); + await File.WriteAllLinesAsync( + moduleChangelogFilePath, + [$"# {moduleChangelog.ModuleName}", string.Empty, changelogEntry.TrimEnd('\r', '\n')] // Trim end to avoid extra new lines at the end of the file + ); } } } @@ -39,7 +42,8 @@ private static string GenerateChangelogFile(ModuleChangelog moduleChangelog) BumpType = bumpToChangesGroup.Key, Descriptions = bumpToChangesGroup.Select(change => change.Description) }) - .OrderByDescending(bumpWithChanges => (int)bumpWithChanges.BumpType); + .OrderByDescending(bumpWithChanges => (int)bumpWithChanges.BumpType) + .ToList(); return $""" diff --git a/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs b/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs index d91ca8c..c1077cb 100644 --- a/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs @@ -18,23 +18,21 @@ public async Task GenerateChangelogFilesAsync_GeneratesNewFile_WhenFileDoesNotEx IEnumerable changes = [ new ModuleChangelog() { - ModuleName = "Changesets.Module", + ModuleName = "Project", CurrentVersion = new Semver(1, 0, 0), ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), Changes = [("Something has changed", BumpType.Minor)] }]; string expectedContent = """ -# Changesets.Module +# Project ## 1.1.0 -### Minor Changes +**Minor Changes**: - Something has changed - - """; await fileWriter.GenerateChangelogFilesAsync(changes); @@ -52,7 +50,7 @@ public async Task GenerateChangelogFilesAsync_AmendsExistingFile_WhenFileExists( IEnumerable changes = [ new ModuleChangelog() { - ModuleName = "Changeset.Tests", + ModuleName = "Project", CurrentVersion = new Semver(1, 0, 0), ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), Changes = [ @@ -61,15 +59,51 @@ public async Task GenerateChangelogFilesAsync_AmendsExistingFile_WhenFileExists( ] }]; + IEnumerable changes2 = [ + new ModuleChangelog() + { + ModuleName = "Project", + CurrentVersion = new Semver(2, 0, 0), + ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), + Changes = [ + ("change3", BumpType.Minor), + ("change4", BumpType.Major) + ] + }]; + + string expectedContent = """ +# Project + +## 3.0.0 + +**Major Changes**: + +- change4 + +**Minor Changes**: + +- change3 + +## 2.0.0 + +**Major Changes**: + +- change2 + +**Minor Changes**: + +- change1 + +"""; + await fileWriter.GenerateChangelogFilesAsync(changes); File.Exists(s_changelogFilePath).Should().BeTrue(); - long fileSize = new FileInfo(s_changelogFilePath).Length; - await fileWriter.GenerateChangelogFilesAsync(changes); + await fileWriter.GenerateChangelogFilesAsync(changes2); File.Exists(s_changelogFilePath).Should().BeTrue(); - new FileInfo(s_changelogFilePath).Length.Should().BeGreaterThan(fileSize); + AssertChangelogContent(expectedContent); } [Test] @@ -80,7 +114,7 @@ public async Task GenerateChangelogFilesAsync_GeneratesTwoChangelogs_WhenChangel IEnumerable changes = [ new ModuleChangelog() { - ModuleName = "Changeset.Tests", + ModuleName = "Project", CurrentVersion = new Semver(1, 0, 0), ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), Changes = [ @@ -90,30 +124,28 @@ public async Task GenerateChangelogFilesAsync_GeneratesTwoChangelogs_WhenChangel }, new ModuleChangelog() { - ModuleName = "Changeset.Tests", + ModuleName = "Project1", CurrentVersion = new Semver(1, 0, 0), ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "TestData", "project1.csproj"), Changes = [ - ("change1", BumpType.Minor), - ("change2", BumpType.Major) + ("change3", BumpType.Minor), + ("change4", BumpType.Major) ] }]; string expectedContent = """ -# Changeset.Tests +# Project ## 2.0.0 -### Major Changes +**Major Changes**: - change2 -### Minor Changes +**Minor Changes**: - change1 - - """; await fileWriter.GenerateChangelogFilesAsync(changes); From eba110bd97495fb51d56287029dce17605421ddb Mon Sep 17 00:00:00 2001 From: Marek Magath Date: Mon, 22 Dec 2025 18:53:37 +0100 Subject: [PATCH 13/13] Fix code scanning warnings about Path.Combine --- .../Commands/Add/AddChangesetCommand.cs | 4 ++-- .../Publish/PublishChangesetCommand.cs | 2 +- .../Version/Helpers/CsProjectsRepository.cs | 2 +- .../Services/DotnetService.cs | 2 +- src/SolarWinds.Changesets/Shared/Constants.cs | 6 +++--- .../Version/ChangelogFileWriterTests.cs | 18 +++++++++--------- .../Version/CsProjectsRepositoryTests.cs | 8 ++++---- .../Version/VersionChangesetCommandTests.cs | 16 ++++++++-------- 8 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/SolarWinds.Changesets/Commands/Add/AddChangesetCommand.cs b/src/SolarWinds.Changesets/Commands/Add/AddChangesetCommand.cs index 907b09c..96b0aab 100644 --- a/src/SolarWinds.Changesets/Commands/Add/AddChangesetCommand.cs +++ b/src/SolarWinds.Changesets/Commands/Add/AddChangesetCommand.cs @@ -65,7 +65,7 @@ IChangesetsRepository changesetsRepository /// public override async Task ExecuteCommandAsync(CommandContext context) { - string[] projectNames = _projectFileNamesLocator.GetProjectFileNames(Path.Combine(Constants.WorkingDirectoryFullPath, ChangesetConfig.SourcePath)); + string[] projectNames = _projectFileNamesLocator.GetProjectFileNames(Path.Join(Constants.WorkingDirectoryFullPath, ChangesetConfig.SourcePath)); string[] selectedProjects = _console.Prompt( new MultiSelectionPrompt() @@ -104,7 +104,7 @@ private static string GetChangesetFileFullPath(string changesetFolderPath) { string changesetFileName = GenerateRandomWord(15); string changesetFileNameWithExtension = Path.ChangeExtension(changesetFileName, MarkDownExtension); - changesetFileFullPath = Path.Combine(changesetFolderPath, changesetFileNameWithExtension); + changesetFileFullPath = Path.Join(changesetFolderPath, changesetFileNameWithExtension); } while (File.Exists(changesetFileFullPath)); return changesetFileFullPath; diff --git a/src/SolarWinds.Changesets/Commands/Publish/PublishChangesetCommand.cs b/src/SolarWinds.Changesets/Commands/Publish/PublishChangesetCommand.cs index 0886107..b0b2b53 100644 --- a/src/SolarWinds.Changesets/Commands/Publish/PublishChangesetCommand.cs +++ b/src/SolarWinds.Changesets/Commands/Publish/PublishChangesetCommand.cs @@ -57,7 +57,7 @@ public override async Task ExecuteCommandAsync(CommandContext context) foreach (string csharpProjectName in changedCsharpProjectNames) { - string csharpProjectFullPath = Path.Combine(Constants.WorkingDirectoryFullPath, csharpProjectName); + string csharpProjectFullPath = Path.Join(Constants.WorkingDirectoryFullPath, csharpProjectName); ProcessOutput packOutput = await _dotnetService.Pack(csharpProjectFullPath); diff --git a/src/SolarWinds.Changesets/Commands/Version/Helpers/CsProjectsRepository.cs b/src/SolarWinds.Changesets/Commands/Version/Helpers/CsProjectsRepository.cs index 99d8a2b..e7c5f2b 100644 --- a/src/SolarWinds.Changesets/Commands/Version/Helpers/CsProjectsRepository.cs +++ b/src/SolarWinds.Changesets/Commands/Version/Helpers/CsProjectsRepository.cs @@ -22,7 +22,7 @@ public CsProject[] GetCsProjects(ChangesetConfig changesetConfig) { List csProjects = []; - string[] csprojFilePaths = GetCsprojFilePaths(Path.Combine(Constants.WorkingDirectoryFullPath, changesetConfig.SourcePath)); + string[] csprojFilePaths = GetCsprojFilePaths(Path.Join(Constants.WorkingDirectoryFullPath, changesetConfig.SourcePath)); foreach (string csprojFilePath in csprojFilePaths) { diff --git a/src/SolarWinds.Changesets/Services/DotnetService.cs b/src/SolarWinds.Changesets/Services/DotnetService.cs index e39d04c..af63dae 100644 --- a/src/SolarWinds.Changesets/Services/DotnetService.cs +++ b/src/SolarWinds.Changesets/Services/DotnetService.cs @@ -34,7 +34,7 @@ public async Task Publish(string packageSource) throw new ArgumentException("Source path cannot be null or empty.", nameof(packageSource)); } - string dotnetCommand = $"nuget push {Path.Combine(Constants.NupkgOutputFullPath, "*.nupkg")}"; + string dotnetCommand = $"nuget push {Path.Join(Constants.NupkgOutputFullPath, "*.nupkg")}"; dotnetCommand += $" --source {packageSource}"; diff --git a/src/SolarWinds.Changesets/Shared/Constants.cs b/src/SolarWinds.Changesets/Shared/Constants.cs index e6f5e33..ff78376 100644 --- a/src/SolarWinds.Changesets/Shared/Constants.cs +++ b/src/SolarWinds.Changesets/Shared/Constants.cs @@ -28,15 +28,15 @@ public static class Constants /// /// Gets the full path to the changeset directory. /// - public static string ChangesetDirectoryFullPath { get; } = Path.Combine(WorkingDirectoryFullPath, ChangesetDirectoryName); + public static string ChangesetDirectoryFullPath { get; } = Path.Join(WorkingDirectoryFullPath, ChangesetDirectoryName); /// /// Gets the full path to the changeset configuration file. /// - public static string ChangesetConfigFileFullPath { get; } = Path.Combine(ChangesetDirectoryFullPath, ConfigFileName); + public static string ChangesetConfigFileFullPath { get; } = Path.Join(ChangesetDirectoryFullPath, ConfigFileName); /// /// Gets the full path to the directory where NuGet packages are output. /// - public static string NupkgOutputFullPath { get; } = Path.Combine(WorkingDirectoryFullPath, "nupkg"); + public static string NupkgOutputFullPath { get; } = Path.Join(WorkingDirectoryFullPath, "nupkg"); } diff --git a/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs b/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs index c1077cb..25ffd90 100644 --- a/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Version/ChangelogFileWriterTests.cs @@ -8,7 +8,7 @@ namespace SolarWinds.Changesets.Tests.Version; [TestFixture] internal sealed class ChangelogFileWriterTests { - private static readonly string s_changelogFilePath = Path.Combine(Environment.CurrentDirectory, Constants.ChangelogFileName); + private static readonly string s_changelogFilePath = Path.Join(Environment.CurrentDirectory, Constants.ChangelogFileName); [Test] public async Task GenerateChangelogFilesAsync_GeneratesNewFile_WhenFileDoesNotExist() @@ -20,7 +20,7 @@ public async Task GenerateChangelogFilesAsync_GeneratesNewFile_WhenFileDoesNotEx { ModuleName = "Project", CurrentVersion = new Semver(1, 0, 0), - ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), + ModuleCsProjFilePath = Path.Join(Environment.CurrentDirectory, "project.csproj"), Changes = [("Something has changed", BumpType.Minor)] }]; @@ -52,7 +52,7 @@ public async Task GenerateChangelogFilesAsync_AmendsExistingFile_WhenFileExists( { ModuleName = "Project", CurrentVersion = new Semver(1, 0, 0), - ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), + ModuleCsProjFilePath = Path.Join(Environment.CurrentDirectory, "project.csproj"), Changes = [ ("change1", BumpType.Minor), ("change2", BumpType.Major) @@ -64,7 +64,7 @@ public async Task GenerateChangelogFilesAsync_AmendsExistingFile_WhenFileExists( { ModuleName = "Project", CurrentVersion = new Semver(2, 0, 0), - ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), + ModuleCsProjFilePath = Path.Join(Environment.CurrentDirectory, "project.csproj"), Changes = [ ("change3", BumpType.Minor), ("change4", BumpType.Major) @@ -116,7 +116,7 @@ public async Task GenerateChangelogFilesAsync_GeneratesTwoChangelogs_WhenChangel { ModuleName = "Project", CurrentVersion = new Semver(1, 0, 0), - ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "project.csproj"), + ModuleCsProjFilePath = Path.Join(Environment.CurrentDirectory, "project.csproj"), Changes = [ ("change1", BumpType.Minor), ("change2", BumpType.Major) @@ -126,7 +126,7 @@ public async Task GenerateChangelogFilesAsync_GeneratesTwoChangelogs_WhenChangel { ModuleName = "Project1", CurrentVersion = new Semver(1, 0, 0), - ModuleCsProjFilePath = Path.Combine(Environment.CurrentDirectory, "TestData", "project1.csproj"), + ModuleCsProjFilePath = Path.Join(Environment.CurrentDirectory, "TestData", "project1.csproj"), Changes = [ ("change3", BumpType.Minor), ("change4", BumpType.Major) @@ -151,7 +151,7 @@ public async Task GenerateChangelogFilesAsync_GeneratesTwoChangelogs_WhenChangel await fileWriter.GenerateChangelogFilesAsync(changes); File.Exists(s_changelogFilePath).Should().BeTrue(); - File.Exists(Path.Combine(changes.Last().ModuleDirectoryPath, Constants.ChangelogFileName)).Should().BeTrue(); + File.Exists(Path.Join(changes.Last().ModuleDirectoryPath, Constants.ChangelogFileName)).Should().BeTrue(); AssertChangelogContent(expectedContent); } @@ -164,14 +164,14 @@ public void TearDown() { foreach (string file in mdFiles) { - File.Delete(Path.Combine(Environment.CurrentDirectory, file)); + File.Delete(file); } } } private static void AssertChangelogContent(string expectedChangelogContent) { - string actualContent = File.ReadAllText(Path.Combine(Environment.CurrentDirectory, Constants.ChangelogFileName)); + string actualContent = File.ReadAllText(Path.Join(Environment.CurrentDirectory, Constants.ChangelogFileName)); actualContent.Should().Be(expectedChangelogContent); } diff --git a/tests/SolarWinds.Changesets.Tests/Version/CsProjectsRepositoryTests.cs b/tests/SolarWinds.Changesets.Tests/Version/CsProjectsRepositoryTests.cs index 56277f2..324d586 100644 --- a/tests/SolarWinds.Changesets.Tests/Version/CsProjectsRepositoryTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Version/CsProjectsRepositoryTests.cs @@ -11,9 +11,9 @@ namespace SolarWinds.Changesets.Tests.Version; [TestFixture] internal sealed class CsProjectsRepositoryTests { - private static readonly string s_testProjectWithVersion = Path.Combine(Environment.CurrentDirectory, "TestData", "SubDirectory", "TestProjectWithVersion.csproj"); - private static readonly string s_testProjectWithoutVersion = Path.Combine(Environment.CurrentDirectory, "TestData", "TestProjectWithoutVersion.csproj"); - private static readonly string s_testFilePath = Path.Combine(Environment.CurrentDirectory, "TestData", "test.csproj"); + private static readonly string s_testProjectWithVersion = Path.Join(Environment.CurrentDirectory, "TestData", "SubDirectory", "TestProjectWithVersion.csproj"); + private static readonly string s_testProjectWithoutVersion = Path.Join(Environment.CurrentDirectory, "TestData", "TestProjectWithoutVersion.csproj"); + private static readonly string s_testFilePath = Path.Join(Environment.CurrentDirectory, "TestData", "test.csproj"); [TearDown] public void TearDown() @@ -81,7 +81,7 @@ public void GetCsProjects_OneVersionOneWithoutVersionProjects_ReturnsTwoProjects { ChangesetConfig config = new() { - SourcePath = Path.Combine(Environment.CurrentDirectory, "TestData") + SourcePath = "TestData" }; TestConsole testConsole = new(); diff --git a/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs b/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs index a923e87..2ae67e6 100644 --- a/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs +++ b/tests/SolarWinds.Changesets.Tests/Version/VersionChangesetCommandTests.cs @@ -21,7 +21,7 @@ internal sealed class VersionChangesetCommandTests [SetUp] public void SetUp() { - string testDataDirectoryFullPath = Path.Combine(Environment.CurrentDirectory, "Version", "TestData"); + string testDataDirectoryFullPath = Path.Join(Environment.CurrentDirectory, "Version", "TestData"); CopyDirectory(testDataDirectoryFullPath, Environment.CurrentDirectory, true, true); } @@ -63,15 +63,15 @@ public void VersionCommand_HappyPath_FolderAndFilesAreCreated() private static void AssertVersionOutput() { //changesetfile is deleted - File.Exists(Path.Combine(Environment.CurrentDirectory, ChangesetFolder, ChangesetFile)).Should().BeFalse(); + File.Exists(Path.Join(Environment.CurrentDirectory, ChangesetFolder, ChangesetFile)).Should().BeFalse(); //project files are updated - LoadVersionFromProjectFile(Path.Combine(Environment.CurrentDirectory, SrcFolder, "ProjectA", "ProjectA.csproj")).Should().BeEquivalentTo(new Semver(1, 0, 2)); - LoadVersionFromProjectFile(Path.Combine(Environment.CurrentDirectory, SrcFolder, "ProjectB", "ProjectB.csproj")).Should().BeEquivalentTo(new Semver(1, 1, 0)); + LoadVersionFromProjectFile(Path.Join(Environment.CurrentDirectory, SrcFolder, "ProjectA", "ProjectA.csproj")).Should().BeEquivalentTo(new Semver(1, 0, 2)); + LoadVersionFromProjectFile(Path.Join(Environment.CurrentDirectory, SrcFolder, "ProjectB", "ProjectB.csproj")).Should().BeEquivalentTo(new Semver(1, 1, 0)); //changelogs are created - File.Exists(Path.Combine(Environment.CurrentDirectory, SrcFolder, "ProjectA", ChangelogFile)).Should().BeTrue(); - File.Exists(Path.Combine(Environment.CurrentDirectory, SrcFolder, "ProjectB", ChangelogFile)).Should().BeTrue(); + File.Exists(Path.Join(Environment.CurrentDirectory, SrcFolder, "ProjectA", ChangelogFile)).Should().BeTrue(); + File.Exists(Path.Join(Environment.CurrentDirectory, SrcFolder, "ProjectB", ChangelogFile)).Should().BeTrue(); } private static Semver? LoadVersionFromProjectFile(string path) @@ -102,7 +102,7 @@ private static void CopyDirectory(string sourceDirectory, string destinationDire foreach (FileInfo file in directoryInfo.GetFiles()) { - string targetFilePath = Path.Combine(destinationDirectory, file.Name); + string targetFilePath = Path.Join(destinationDirectory, file.Name); file.CopyTo(targetFilePath); } @@ -110,7 +110,7 @@ private static void CopyDirectory(string sourceDirectory, string destinationDire { foreach (DirectoryInfo subDir in dirs) { - string newDestinationDir = Path.Combine(destinationDirectory, subDir.Name); + string newDestinationDir = Path.Join(destinationDirectory, subDir.Name); CopyDirectory(subDir.FullName, newDestinationDir, true, false); } }