Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ Usage: versionmark [options]
| `-?`, `-h`, `--help` | Display help message |
| `--silent` | Suppress console output |
| `--log <file>` | Write output to log file |
| `--depth <depth>` | Heading depth for validation and `--report-depth` (default: 1) |
| **Lint Mode** | |
| `--lint [<config-file>]` | Check configuration file (default: `.versionmark.yaml`) |
| **Capture Mode** | |
Expand All @@ -98,7 +99,7 @@ Usage: versionmark [options]
| **Publish Mode** | |
| `--publish` | Enable publish mode |
| `--report <file>` | **(Required)** Output markdown file path |
| `--report-depth <depth>` | Heading depth for markdown output (default: 2, min: 1, max: 6) |
| `--report-depth <depth>` | Heading depth for markdown output (default: `--depth` value) |
| `-- <patterns...>` | Glob patterns for JSON files (default: `versionmark-*.json`) |
| **Self-Validation** | |
| `--validate` | Run self-validation tests |
Expand Down Expand Up @@ -186,6 +187,12 @@ its current environment. Run with `--validate`:
versionmark --validate
```

Use `--depth` to control the heading depth of the report (default: 1):

```bash
versionmark --validate --depth 2
```

Example output:

```text
Expand Down
3 changes: 2 additions & 1 deletion docs/design/version-mark/cli/context.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ command-line state and output routing. It is constructed via the `Create` factor
| `ToolNames` | `string[]` | `[]` | Tool names after `--` separator in capture|
| `Publish` | `bool` | `false` | `--publish` flag |
| `ReportFile` | `string?` | `null` | `--report <file>` |
| `ReportDepth` | `int` | `2` | `--report-depth <depth>` |
| `Depth` | `int` | `1` | `--depth <depth>` (heading depth, def: 1) |
| `ReportDepth` | `int` | `Depth` | `--report-depth <depth>` (def: `Depth`) |
| `GlobPatterns`| `string[]` | `[]` | Patterns after `--` separator in publish |
| `ExitCode` | `int` | `0`/`1` | 0 for success, 1 if errors reported |

Expand Down
8 changes: 7 additions & 1 deletion docs/reqstream/version-mark/cli/context.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,19 @@ sections:
- Context_Create_PublishFlag_SetsPublishTrue
- Context_Create_ReportParameter_SetsReportFile
- Context_Create_ReportDepthParameter_SetsReportDepth
- Context_Create_NoReportDepth_DefaultsToTwo
- Context_Create_NoReportDepth_DefaultsToDepthOne
- Context_Create_GlobPatternsAfterSeparator_CapturesPatterns
- Context_Create_PublishWithoutReport_ParsesSuccessfully
- Context_Create_NoGlobPatterns_EmptyArray
- Context_Create_LintFlag_SetsLintTrue
- Context_Create_LintFlag_WithFile_SetsLintFile
- Context_Create_LintFlag_FollowedByFlag_DoesNotConsumeFlagAsFile
- Context_Create_DepthParameter_SetsDepth
- Context_Create_NoDepth_DefaultsToOne
- Context_Create_DepthParameter_SetsDefaultReportDepth
- Context_Create_ExplicitReportDepthOverridesDepth
- Context_Create_DepthZero_ThrowsArgumentException
- Context_Create_DepthNegative_ThrowsArgumentException

- id: VersionMark-Context-WriteLine
title: The Context.WriteLine method shall write output respecting the silent flag.
Expand Down
10 changes: 10 additions & 0 deletions docs/reqstream/version-mark/self-test/validation.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,13 @@ sections:
tests:
- VersionMark_LintPassesForValidConfig
- VersionMark_LintReportsErrorsForInvalidConfig

- id: VersionMark-Validation-HeaderDepth
title: >-
The Validation class shall use the context Depth for the self-validation
report heading depth.
justification: |
The --depth argument allows callers to embed the self-validation report
at the appropriate heading level within a larger markdown document.
tests:
- SelfTest_Run_WithDepthTwo_WritesHashHashHeader
15 changes: 13 additions & 2 deletions docs/user_guide/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,7 @@ This generates a markdown file consolidating versions from all jobs.
| `-?`, `-h`, `--help` | Display help message |
| `--silent` | Suppress console output |
| `--log <file>` | Write output to log file |
| `--depth <depth>` | Heading depth for validation and `--report-depth` (default: 1) |
| **Lint Mode** | |
| `--lint [<config-file>]` | Check configuration file (default: `.versionmark.yaml`) |
| **Capture Mode** | |
Expand All @@ -105,7 +106,7 @@ This generates a markdown file consolidating versions from all jobs.
| **Publish Mode** | |
| `--publish` | Enable publish mode |
| `--report <file>` | **(Required)** Output markdown file path |
| `--report-depth <depth>` | Heading depth for markdown output (default: 2, min: 1, max: 6) |
| `--report-depth <depth>` | Heading depth for markdown output (default: `--depth` value) |
| `-- <patterns...>` | Glob patterns for JSON files (default: `versionmark-*.json`) |
| **Self-Validation** | |
| `--validate` | Run self-validation tests |
Expand Down Expand Up @@ -203,9 +204,12 @@ versionmark --publish --report versions.md
# Use custom glob patterns
versionmark --publish --report docs/tool-versions.md -- captured/*.json build/*.json

# Control heading depth (default is ##, depth 2)
# Control heading depth (default is #, depth 1)
versionmark --publish --report versions.md --report-depth 3

# Use --depth to set both self-validation heading and report-depth default
versionmark --publish --report versions.md --depth 3

# Combine options
versionmark --publish --report docs/versions.md --report-depth 1 -- versionmark-*.json
```
Expand Down Expand Up @@ -395,6 +399,13 @@ Use `--silent` to suppress console output while still writing a results file:
versionmark --silent --validate --results results.trx
```

Use `--depth` to embed the self-validation report at a specific heading level within a larger
markdown document:

```bash
versionmark --validate --depth 2
```

## Validation Report

Example output:
Expand Down
33 changes: 29 additions & 4 deletions src/DemaConsulting.VersionMark/Cli/Context.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,15 @@ internal sealed class Context : IDisposable
/// </summary>
public string? ReportFile { get; private init; }

/// <summary>
/// Gets the markdown header depth for the self-validation report and default for publish mode.
/// </summary>
public int Depth { get; private init; } = 1;

/// <summary>
/// Gets the report depth for markdown heading levels in publish mode.
/// </summary>
public int ReportDepth { get; private init; } = 2;
public int ReportDepth { get; private init; } = 1;

/// <summary>
/// Gets the list of glob patterns for JSON files in publish mode.
Expand Down Expand Up @@ -149,6 +154,7 @@ public static Context Create(string[] args)
ToolNames = parser.ToolNames,
Publish = parser.Publish,
ReportFile = parser.ReportFile,
Depth = parser.Depth,
ReportDepth = parser.ReportDepth,
GlobPatterns = parser.GlobPatterns
};
Expand Down Expand Up @@ -256,10 +262,20 @@ private sealed class ArgumentParser
/// </summary>
public string? ReportFile { get; private set; }

/// <summary>
/// Gets the markdown header depth for the self-validation report and default for publish mode.
/// </summary>
public int Depth { get; private set; } = 1;

/// <summary>
/// Backing field for the explicitly-specified report depth.
/// </summary>
private int? _explicitReportDepth;

/// <summary>
/// Gets the report depth for markdown heading levels in publish mode.
/// </summary>
public int ReportDepth { get; private set; } = 2;
public int ReportDepth => _explicitReportDepth ?? Depth;

/// <summary>
/// Gets the list of glob patterns for JSON files in publish mode.
Expand Down Expand Up @@ -371,8 +387,17 @@ private int ParseArgument(string arg, string[] args, int index)
return index + 1;

case "--report-depth":
ReportDepth = GetRequiredIntArgument(arg, args, index, "a depth value");
if (ReportDepth < 1)
_explicitReportDepth = GetRequiredIntArgument(arg, args, index, "a depth value");
if (_explicitReportDepth < 1)
{
throw new ArgumentException($"{arg} requires a positive integer value (minimum 1)", nameof(args));
}

return index + 1;
Comment thread
Malcolmnixon marked this conversation as resolved.

case "--depth":
Depth = GetRequiredIntArgument(arg, args, index, "a depth value");
if (Depth < 1)
{
throw new ArgumentException($"{arg} requires a positive integer value (minimum 1)", nameof(args));
}
Expand Down
3 changes: 2 additions & 1 deletion src/DemaConsulting.VersionMark/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ private static void PrintHelp(Context context)
context.WriteLine(" -v, --version Display version information");
context.WriteLine(" -?, -h, --help Display this help message");
context.WriteLine(" --silent Suppress console output");
context.WriteLine(" --depth <depth> Heading depth for self-validation and --report-depth default (default: 1)");
context.WriteLine(" --validate Run self-validation");
context.WriteLine(" --results <file> Write validation results to file (.trx or .xml)");
context.WriteLine(" --log <file> Write output to log file");
Expand All @@ -191,7 +192,7 @@ private static void PrintHelp(Context context)
context.WriteLine("Publish Mode:");
context.WriteLine(" --publish Generate markdown report from JSON files");
context.WriteLine(" --report <file> Output markdown file (required)");
context.WriteLine(" --report-depth <depth> Heading depth for markdown (default: 2)");
context.WriteLine(" --report-depth <depth> Heading depth for markdown (default: --depth value)");
context.WriteLine(" -- <patterns...> Glob patterns for JSON files (default: versionmark-*.json)");
}

Expand Down
3 changes: 2 additions & 1 deletion src/DemaConsulting.VersionMark/SelfTest/Validation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@
/// <param name="context">The context for output.</param>
private static void PrintValidationHeader(Context context)
{
context.WriteLine("# DEMA Consulting VersionMark");
var headingPrefix = new string('#', context.Depth);
context.WriteLine($"{headingPrefix} DEMA Consulting VersionMark");
context.WriteLine("");
context.WriteLine("| Information | Value |");
context.WriteLine("| :------------------ | :------------------------------------------------- |");
Expand Down Expand Up @@ -125,8 +126,8 @@
// Build command line arguments for capture
var args = new List<string>
{
"--silent",

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--silent' 4 times.

Check warning on line 129 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--silent' 4 times.
"--log", logFile,

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build macos-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build windows-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--log' 4 times.

Check warning on line 130 in src/DemaConsulting.VersionMark/SelfTest/Validation.cs

View workflow job for this annotation

GitHub Actions / Build / Build ubuntu-latest

Define a constant instead of using this literal '--log' 4 times.
"--capture",
"--job-id", "test-job",
"--output", outputFile
Expand Down
103 changes: 98 additions & 5 deletions test/DemaConsulting.VersionMark.Tests/Cli/ContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -468,17 +468,17 @@ public void Context_Create_ReportDepthParameter_SetsReportDepth()
/// <summary>
/// Test creating a context with default report-depth.
/// What is tested: Default report-depth value when not specified
/// What the assertions prove: The default report depth is 2
/// What the assertions prove: The default report depth is 1 (matching the --depth default)
/// </summary>
[TestMethod]
public void Context_Create_NoReportDepth_DefaultsToTwo()
public void Context_Create_NoReportDepth_DefaultsToDepthOne()
{
// Arrange & Act - Create context without --report-depth
using var context = Context.Create(["--publish", "--report", "output.md"]);

// Assert - Verify default report depth is 2
// What is proved: Report depth defaults to 2 when not specified
Assert.AreEqual(2, context.ReportDepth);
// Assert - Verify default report depth is 1 (the default --depth value)
// What is proved: Report depth defaults to the --depth value (1) when not specified
Assert.AreEqual(1, context.ReportDepth);
}

/// <summary>
Expand Down Expand Up @@ -507,6 +507,99 @@ public void Context_Create_ReportDepthNegative_ThrowsArgumentException()
Context.Create(["--publish", "--report", "output.md", "--report-depth", "-1"]));
}

/// <summary>
/// Test creating a context with the depth parameter.
/// What is tested: --depth parameter parsing captures the depth value
/// What the assertions prove: The depth is correctly parsed as an integer
/// </summary>
[TestMethod]
public void Context_Create_DepthParameter_SetsDepth()
{
// Arrange & Act - Create context with --depth flag
using var context = Context.Create(["--depth", "3"]);

// Assert - Verify depth is captured
// What is proved: --depth parameter value is correctly parsed as an integer
Assert.AreEqual(3, context.Depth);
Assert.AreEqual(0, context.ExitCode);
}

/// <summary>
/// Test creating a context with no depth parameter.
/// What is tested: Default depth value when not specified
/// What the assertions prove: The depth defaults to 1
/// </summary>
[TestMethod]
public void Context_Create_NoDepth_DefaultsToOne()
{
// Arrange & Act - Create context without --depth
using var context = Context.Create([]);

// Assert - Verify default depth is 1
// What is proved: Depth defaults to 1 when not specified
Assert.AreEqual(1, context.Depth);
}

/// <summary>
/// Test that --depth sets the default for --report-depth.
/// What is tested: --depth value is used as default for ReportDepth when --report-depth not specified
/// What the assertions prove: ReportDepth equals Depth when --report-depth is not given
/// </summary>
[TestMethod]
public void Context_Create_DepthParameter_SetsDefaultReportDepth()
{
// Arrange & Act - Create context with --depth but no --report-depth
using var context = Context.Create(["--publish", "--report", "output.md", "--depth", "3"]);

// Assert - Verify report depth defaults to the depth value
// What is proved: --depth value is used as the default for ReportDepth
Assert.AreEqual(3, context.ReportDepth);
Assert.AreEqual(0, context.ExitCode);
}

/// <summary>
/// Test that explicit --report-depth overrides --depth.
/// What is tested: --report-depth takes precedence over --depth for ReportDepth
/// What the assertions prove: ReportDepth equals the explicit --report-depth value, not --depth
/// </summary>
[TestMethod]
public void Context_Create_ExplicitReportDepthOverridesDepth()
{
// Arrange & Act - Create context with both --depth and --report-depth
using var context = Context.Create(["--publish", "--report", "output.md", "--depth", "2", "--report-depth", "4"]);

// Assert - Verify explicit --report-depth takes precedence over --depth
// What is proved: --report-depth value (4) overrides --depth value (2) for ReportDepth
Assert.AreEqual(4, context.ReportDepth);
Assert.AreEqual(0, context.ExitCode);
}

/// <summary>
/// Test that --depth 0 throws ArgumentException.
/// What is tested: Validation rejects a depth value less than 1
/// What the assertions prove: ArgumentException is thrown for depth values less than 1
/// </summary>
[TestMethod]
public void Context_Create_DepthZero_ThrowsArgumentException()
{
// Arrange & Act & Assert - Zero is not a valid heading depth
Assert.ThrowsExactly<ArgumentException>(() =>
Context.Create(["--depth", "0"]));
}

/// <summary>
/// Test that a negative --depth throws ArgumentException.
/// What is tested: Validation rejects negative depth values
/// What the assertions prove: ArgumentException is thrown for negative depth values
/// </summary>
[TestMethod]
public void Context_Create_DepthNegative_ThrowsArgumentException()
{
// Arrange & Act & Assert - Negative values are not valid heading depths
Assert.ThrowsExactly<ArgumentException>(() =>
Context.Create(["--depth", "-1"]));
}

/// <summary>
/// Test creating a context with glob patterns after -- separator.
/// What is tested: Glob patterns after -- are captured in GlobPatterns array
Expand Down
2 changes: 1 addition & 1 deletion test/DemaConsulting.VersionMark.Tests/IntegrationTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ public void VersionMark_PublishCommand_GeneratesMarkdownReport()
var reportContent = File.ReadAllText(reportFile);

// Verify markdown structure
Assert.Contains("## Tool Versions", reportContent);
Assert.Contains("# Tool Versions", reportContent);

// Verify tools are present and sorted alphabetically
Assert.Contains("dotnet", reportContent);
Expand Down
2 changes: 1 addition & 1 deletion test/DemaConsulting.VersionMark.Tests/ProgramTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -579,7 +579,7 @@ public void Program_Run_WithPublishCommand_GeneratesMarkdownReport()
Assert.IsTrue(File.Exists(reportFile), "Report file was not created");

var reportContent = File.ReadAllText(reportFile);
Assert.Contains("## Tool Versions", reportContent);
Assert.Contains("# Tool Versions", reportContent);
Assert.Contains("dotnet", reportContent);
Assert.Contains("node", reportContent);
Assert.Contains("8.0.0", reportContent);
Expand Down
30 changes: 30 additions & 0 deletions test/DemaConsulting.VersionMark.Tests/SelfTest/SelfTestTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -110,4 +110,34 @@ public void SelfTest_Run_WithResultsFlag_WritesResultsFile()
}
}
}

/// <summary>
/// Test that the self-validation pipeline writes a ## heading when --depth 2 is specified.
/// What is tested: The --depth argument controls the heading level in the self-validation report
/// What the assertions prove: Output contains "## DEMA Consulting VersionMark" with depth 2
/// </summary>
[TestMethod]
public void SelfTest_Run_WithDepthTwo_WritesHashHashHeader()
{
// Arrange - Redirect console output to capture the validation report
var originalOut = Console.Out;
Comment thread
Malcolmnixon marked this conversation as resolved.
using var writer = new System.IO.StringWriter();
Console.SetOut(writer);
try
{
using var context = Context.Create(["--validate", "--depth", "2"]);

// Act - Run self-validation with --depth 2
Program.Run(context);

// Assert - Output should contain the ## heading for depth 2
var output = writer.ToString();
Assert.IsTrue(output.Contains("## DEMA Consulting VersionMark"),
"Self-validation report should use ## heading when --depth 2 is specified");
}
finally
{
Console.SetOut(originalOut);
}
}
}
Loading