Skip to content

Commit 993fd6b

Browse files
authored
#12 Add -v, --version option to changeset CLI and other small fixes (#15)
1 parent c921e2a commit 993fd6b

35 files changed

Lines changed: 519 additions & 244 deletions

.changeset/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
{
22
"sourcePath": "src",
33
"packageSource": "nuget"
4-
}
4+
}

.editorconfig

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ indent_size = 4
1111
trim_trailing_whitespace = true
1212
# end_of_line = crlf # The end_of_line setting is maintained by .gitattributes! Do not set it here!
1313

14+
[*.{json,yml,yaml,xml,md,csproj,props,config}]
15+
indent_style = space
16+
indent_size = 2
17+
1418
[*.cs]
1519
charset = utf-8
1620
max_line_length = 130

.github/PULL_REQUEST_TEMPLATE.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ Add the issue number here. e.g. #123
1212

1313
# Checklist
1414

15-
- [ ] I have double checked my own changes
15+
- [ ] I have double-checked my own changes
1616
- [ ] I have read the [Contribution Guidelines](https://github.com/solarwinds/net-changesets/blob/main/CONTRIBUTING.md)
17-
- [ ] Include the issue number (#xxx) in branch name and PR title and description
18-
- [ ] Provide a reasonable description of the PR in the [Changes](#Changes) section
17+
- [ ] Include the issue number (#xxx) in the branch name, PR title, and PR description in the Issue number section above
18+
- [ ] Provide a reasonable description of the PR in the [Changes](#changes) section
1919
- [ ] I have commented on the issue above and discussed the intended changes
2020
- [ ] All newly added code is adequately covered by tests
2121
- [ ] Make sure your PR is passing the CI/CD pipeline

.github/copilot-instructions.md

Lines changed: 36 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,14 @@ NET Changesets is a .NET CLI tool for managing versioning and changelogs in mult
88

99
## Technology stack
1010

11-
**Language:** C# 12.0 with nullable reference types and implicit usings enabled
12-
**Runtime:** .NET 8.0 (SDK 8.0.406)
13-
**CLI Framework:** Spectre.Console v0.50.0 (interactive prompts, tables, markup rendering)
14-
**Dependency Injection:** Microsoft.Extensions.DependencyInjection v9.0.9
15-
**Testing:** NUnit 4.4.0, Moq 4.20.72, AwesomeAssertions 9.1.0, Spectre.Console.Testing
16-
**Code Analysis:** Microsoft .NET analyzers (all enabled, warnings-as-errors), Spectre.Console.Analyzer
17-
**Package Management:** Central Package Management via `Directory.Packages.props`
18-
**CI/CD:** GitHub Actions (build, test, pack, format verification)
11+
**Language:** C# 12.0 with nullable reference types and implicit usings enabled
12+
**Runtime:** .NET 8.0 (SDK 8.0.406)
13+
**CLI Framework:** Spectre.Console v0.50.0 (interactive prompts, tables, markup rendering)
14+
**Dependency Injection:** Microsoft.Extensions.DependencyInjection v9.0.9
15+
**Testing:** NUnit 4.4.0, Moq 4.20.72, AwesomeAssertions 9.1.0, Spectre.Console.Testing
16+
**Code Analysis:** Microsoft .NET analyzers (all enabled, warnings-as-errors), Spectre.Console.Analyzer
17+
**Package Management:** Central Package Management via `Directory.Packages.props`
18+
**CI/CD:** GitHub Actions (build, test, pack, format verification)
1919
**External Tools:** Git CLI (for diff detection), dotnet CLI (for pack/publish)
2020

2121
## Directory structure
@@ -44,6 +44,7 @@ SolarWinds.Changesets.sln # Main solution file
4444
**CLI Framework:** Uses Spectre.Console.Cli with `CommandApp<AddChangesetCommand>` (Add is default). Commands registered in `Program.cs` via `config.AddCommand<T>()`. All commands inherit from `ConfigurationCommandBase` which loads `.changeset/config.json`.
4545

4646
**Dependency Injection:** Services registered in `ServiceCollection` and integrated via custom `TypeRegistrar`/`TypeResolver` (required by Spectre.Console.Cli). Main services:
47+
4748
- `IConfigurationService`: Loads/validates `.changeset/config.json`
4849
- `IChangesetsRepository`: Reads/writes/deletes changeset markdown files
4950
- `ICsProjectsRepository`: Parses .csproj files, updates `<VersionPrefix>` elements
@@ -55,6 +56,7 @@ SolarWinds.Changesets.sln # Main solution file
5556
**Semantic Versioning:** Custom `Semver` class (Major.Minor.Patch) with methods `RaiseMajor()`, `RaiseMinor()`, `RaisePatch()`. Parses version strings from `<VersionPrefix>` in .csproj files. Version bumps cascade dependencies (updating dependent projects).
5657

5758
**Command Flow Example (version command):**
59+
5860
1. `VersionChangesetCommand.ExecuteCommandAsync()` calls `IChangesetsRepository.GetChangesetsAsync()`
5961
2. Reads all `.md` files from `.changeset/` directory
6062
3. Parses YAML front matter (project names, bump types) and markdown content
@@ -69,28 +71,33 @@ SolarWinds.Changesets.sln # Main solution file
6971
**Prerequisites:** .NET 8.0 SDK (version 8.0.406 or compatible via rollForward in `global.json`)
7072

7173
**Build:**
74+
7275
```bash
7376
dotnet restore --packages ./packages
7477
dotnet build -c Release --no-restore
7578
```
7679

7780
**Test:**
81+
7882
```bash
7983
dotnet test -c Release --no-restore --no-build --verbosity normal
8084
```
8185

8286
**Pack:**
87+
8388
```bash
8489
dotnet pack -c Release --no-restore --no-build
8590
# Output: ./nupkg/SolarWinds.Changesets.0.1.1.nupkg
8691
```
8792

8893
**Code Style Check:**
94+
8995
```bash
9096
dotnet format --no-restore --verify-no-changes
9197
```
9298

9399
**Local Installation for Testing:**
100+
94101
```bash
95102
dotnet tool uninstall solarwinds.changesets --global
96103
dotnet tool install solarwinds.changesets --global --add-source ./nupkg
@@ -109,6 +116,7 @@ dotnet run --project .\src\SolarWinds.Changesets\SolarWinds.Changesets.csproj
109116
```
110117

111118
**Verification checklist:**
119+
112120
1. ✅ Build succeeds: `dotnet build -c Release --no-restore`
113121
2. ✅ All tests pass: `dotnet test -c Release --no-restore --no-build`
114122
3. ✅ Code formatting: `dotnet format --no-restore --verify-no-changes`
@@ -118,15 +126,18 @@ dotnet run --project .\src\SolarWinds.Changesets\SolarWinds.Changesets.csproj
118126
## Domain configurations
119127

120128
**Changeset Config (`.changeset/config.json`):**
129+
121130
```json
122131
{
123-
"sourcePath": "src", // Relative path to projects folder
124-
"packageSource": "nuget" // NuGet source name from NuGet.config
132+
"sourcePath": "src", // Relative path to projects folder
133+
"packageSource": "nuget" // NuGet source name from NuGet.config
125134
}
126135
```
136+
127137
Created by `changeset init`. Loaded by `ConfigurationService`. Default `packageSource` is `nuget.org`.
128138

129139
**NuGet.config:** Optional file for custom package sources. Example:
140+
130141
```xml
131142
<packageSources>
132143
<add key="nuget" value="https://api.nuget.org/v3/index.json" />
@@ -135,6 +146,7 @@ Created by `changeset init`. Loaded by `ConfigurationService`. Default `packageS
135146
```
136147

137148
**Changeset File Format (`.changeset/{randomname}.md`):**
149+
138150
```markdown
139151
---
140152
"ProjectA": minor
@@ -143,16 +155,19 @@ Created by `changeset init`. Loaded by `ConfigurationService`. Default `packageS
143155

144156
Added new feature X and fixed bug Y in ProjectB
145157
```
158+
146159
Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Projects listed in YAML front matter with bump type (major/minor/patch).
147160

148161
**Project File Requirements:**
162+
149163
- Must contain `<VersionPrefix>` element (e.g., `<VersionPrefix>1.0.0</VersionPrefix>`)
150164
- Supported format: `Major.Minor.Patch` (parsed via `System.Version`)
151165
- `version` command updates this element in-place using XML manipulation
152166

153167
## Conventions
154168

155169
**Code Style:**
170+
156171
- **Implicit usings enabled** (no need for common System namespaces)
157172
- **Nullable reference types enabled** (treat null warnings as errors)
158173
- **File-scoped namespaces** (e.g., `namespace SolarWinds.Changesets.Commands.Add;`)
@@ -161,54 +176,63 @@ Generated by `add` command. Filename: 10 random lowercase letters + `.md`. Proje
161176
- **IDE rules enforced in CI** via `dotnet format` (not in build)
162177

163178
**Testing:**
179+
164180
- NUnit framework with `[TestFixture]` and `[Test]` attributes
165181
- Global using for `NUnit.Framework` (defined in test .csproj)
166182
- Test data in `TestData/` folders, copied to output directory
167183
- Use `Spectre.Console.Testing.TestConsole` for command output assertions
168184
- Mock external processes using `Moq` on `IProcessExecutor`
169185

170186
**Naming:**
187+
171188
- Commands: `{Action}ChangesetCommand` (e.g., `AddChangesetCommand`)
172189
- Interfaces: Standard `I` prefix (e.g., `IConfigurationService`)
173190
- Internal classes: Most implementation classes are `internal sealed`
174191
- Constants: Defined in `Constants` static class (e.g., `Constants.WorkingDirectoryFullPath`)
175192

176193
**Dependency Constraints:**
194+
177195
- **Only allowed third-party dependency:** Spectre.Console (and related packages)
178196
- Rationale: Minimize external dependencies for a CLI tool
179197
- All other needs met by .NET BCL or Microsoft.Extensions packages
180198

181199
**Git Workflow:**
200+
182201
- Branch naming: `{type}/{issueID}-{description}` (e.g., `feature/123-add-new-command`)
183202
- Commit messages: Start with issue ID (e.g., `123 Implement status command`)
184203
- GPG signing required for commits
185204
- PR title format: `{Type} #{issueID} {Description}`
186205

187206
**Error Handling:**
207+
188208
- `ExceptionHandler.Handle()` registered in Spectre.Console CLI config
189209
- Custom exception: `InitializationException` for config validation errors
190210
- Return codes defined in `ResultCodes` class (not yet fully implemented)
191211

192212
## Integration points
193213

194214
**Git Integration:**
215+
195216
- `GitService.GetDiff()` calls `git diff --name-only {sourcePath}` to detect modified .csproj files
196217
- Used by `publish` command to identify packages needing publication
197218
- Requires git executable in PATH
198219

199220
**Dotnet CLI Integration:**
221+
200222
- `DotnetService.Pack()` calls `dotnet pack {projectPath} --output {Constants.NupkgOutputFullPath}`
201223
- `DotnetService.Publish()` calls `dotnet nuget push {nupkgPath} --source {packageSource}`
202224
- NuGet API key expected in environment or nuget.config (standard dotnet behavior)
203225
- Output directory: `./nupkg/` (created if not exists)
204226

205227
**File System Operations:**
228+
206229
- Changeset files: `.changeset/` directory (created by `init` command)
207230
- CHANGELOG.md: Root of repository
208231
- .csproj files: Located via recursive search from `sourcePath` config
209232
- All paths resolved relative to `Constants.WorkingDirectoryFullPath` (current directory)
210233

211234
**NuGet Sources:**
235+
212236
- Resolved via standard dotnet/NuGet.config mechanisms
213237
- Default: `nuget` source (typically nuget.org)
214238
- 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
219243
**Current State:** MVP stage with manual CLI operations. All 5 commands implemented (`init`, `add`, `version`, `publish`, `status`).
220244

221245
**Known Limitations:**
246+
222247
- `add` command supports only single bump type for all selected projects (npm version allows per-project bumps)
223248
- No command-line options for `add` (interactive mode only)
224249
- Manual execution required (no GitHub Action yet)
225250

226251
**Planned Features:**
252+
227253
- **GitHub Action** (primary roadmap item): Automated PR creation for version bumps, reusing existing codebase. See `.NET GitHub Action` documentation.
228254
- Future improvements open for discussion via GitHub issues
229255

.github/instructions/coding.instructions.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,39 @@ applyTo: "**/*.go,**/*.cs,**/*.java,**/*.kt,**/*.py,**/*.js,**/*.ts,**/*.tsx"
55
# Coding Instructions
66

77
## General code style and readability
8+
89
- Write code that is readable, understandable, and maintainable for future readers.
910
- Aim to create software that is not only functional but also readable, maintainable, and efficient throughout its lifecycle.
1011
- Prioritize clarity to make reading, understanding, and modifying code easier.
1112
- Adhere to established coding standards and write well-structured code to reduce errors.
1213
- Regularly review and refactor code to improve structure, readability, and maintainability. Always leave the codebase cleaner than you found it.
1314

1415
## Naming conventions
16+
1517
- Choose names for variables, functions, and classes that reflect their purpose and behavior.
1618
- 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.
1719
- Use specific names that provide a clearer understanding of what the variables represent and how they are used.
1820

1921
## DRY principle
22+
2023
- Follow the DRY (Don't Repeat Yourself) Principle and Avoid Duplicating Code or Logic.
2124
- Avoid writing the same code more than once. Instead, reuse your code using functions, classes, modules, libraries, or other abstractions.
2225
- Modify code in one place if you need to change or update it.
2326

2427
## Function length and responsibility
28+
2529
- Write short functions that only do one thing.
2630
- Follow the single responsibility principle (SRP), which means that a function should have one purpose and perform it effectively.
2731
- If a function becomes too long or complex, consider breaking it into smaller, more manageable functions.
2832

2933
## Comments usage
34+
3035
- Use comments sparingly, and when you do, make them meaningful.
3136
- Don't comment on obvious things. Excessive or unclear comments can clutter the codebase and become outdated.
3237
- Use comments to convey the "why" behind specific actions or explain unusual behavior and potential pitfalls.
3338
- Provide meaningful information about the function's behavior and explain unusual behavior and potential pitfalls.
3439

3540
## Conditional encapsulation
41+
3642
- One way to improve the readability and clarity of functions is to encapsulate nested if/else statements into other functions.
3743
- Encapsulating such logic into a function with a descriptive name clarifies its purpose and simplifies code comprehension.

.github/instructions/dotnet.instructions.md

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ applyTo: "**/*.cs"
55
# Instructions for .NET C# code
66

77
C# code (besides unit tests) should adhere to the following guidelines:
8+
89
- Follow SOLID principles
910
- Use dependency injection
1011
- Use appropriate configuration formats (JSON, YAML, environment variables)
@@ -119,7 +120,7 @@ public async Task<ProcessResult> ProcessAsync(UserData userData, CancellationTok
119120

120121
## Repository structure
121122

122-
The following are instructions on how to name folders and files and how the basic repository structure should look like
123+
The following are instructions on how to name folders and files and how the basic repository structure should look like
123124

124125
- Each project (CSPROJ) should be in its own folder.
125126
- 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
130131
### Code Examples
131132

132133
#### Async/Await Pattern
134+
133135
```csharp
134136
public async Task<User> GetUserAsync(int userId, CancellationToken cancellationToken = default)
135137
{
136138
using var httpClient = _httpClientFactory.CreateClient();
137139
var response = await httpClient.GetAsync($"/api/users/{userId}", cancellationToken);
138140
response.EnsureSuccessStatusCode();
139-
141+
140142
var content = await response.Content.ReadAsStringAsync(cancellationToken);
141143
return JsonSerializer.Deserialize<User>(content);
142144
}
143145
```
144146

145147
#### String Comparison Example
148+
146149
```csharp
147150
// For culture-sensitive comparisons
148151
if (userInput.Equals(expectedValue, StringComparison.InvariantCultureIgnoreCase))
@@ -152,6 +155,7 @@ if (fileName.EndsWith(".txt", StringComparison.Ordinal))
152155
```
153156

154157
#### StringBuilder Usage
158+
155159
```csharp
156160
// Use StringBuilder for heavy concatenation in loops
157161
var builder = new StringBuilder();
@@ -163,6 +167,7 @@ return builder.ToString();
163167
```
164168

165169
#### Regex Source Generators
170+
166171
```csharp
167172
using System.Text.RegularExpressions;
168173

@@ -171,11 +176,11 @@ public partial class MyService
171176
// Use regex source generators for compile-time validation and better performance
172177
[GeneratedRegex(@"\b(query|mutation)\b\s+(\w+)")]
173178
private static partial Regex OperationNameRegex();
174-
179+
175180
// For culture-sensitive patterns, specify options
176181
[GeneratedRegex(@"[a-zA-Z_:][a-zA-Z0-9_:]*", RegexOptions.IgnoreCase)]
177182
private static partial Regex IdentifierRegex();
178-
183+
179184
public string ExtractOperationName(string query)
180185
{
181186
var match = OperationNameRegex().Match(query);

0 commit comments

Comments
 (0)