diff --git a/.github/agents/code-quality-agent.md b/.github/agents/code-quality-agent.md index 1e89e27..1506330 100644 --- a/.github/agents/code-quality-agent.md +++ b/.github/agents/code-quality-agent.md @@ -31,7 +31,7 @@ Ensure the project is: 1. **Build**: Zero warnings (TreatWarningsAsErrors=true) 2. **Linting**: - - markdownlint (`.markdownlint.json`) + - markdownlint (`.markdownlint-cli2.jsonc`) - cspell (`.cspell.json`) - yamllint (`.yamllint.yaml`) - dotnet format (`.editorconfig`) diff --git a/.github/agents/repo-consistency-agent.md b/.github/agents/repo-consistency-agent.md index 7f3abcc..c92a053 100644 --- a/.github/agents/repo-consistency-agent.md +++ b/.github/agents/repo-consistency-agent.md @@ -56,7 +56,7 @@ The agent reviews the following areas for consistency with the template: #### Quality Configuration -- **Linting Rules**: `.cspell.json`, `.markdownlint.json`, `.yamllint.yaml` +- **Linting Rules**: `.cspell.json`, `.markdownlint-cli2.jsonc`, `.yamllint.yaml` - Note: Spelling exceptions will be repository-specific - **Editor Config**: `.editorconfig` settings (file-scoped namespaces, 4-space indent, UTF-8+BOM, LF endings) - **Code Style**: C# code style rules and analyzer configuration @@ -88,6 +88,34 @@ The agent reviews the following areas for consistency with the template: 3. **Recommend Updates**: Suggest specific files or patterns that should be updated 4. **Respect Customizations**: Recognize valid project-specific customizations +### Tracking Template Evolution + +To ensure downstream projects benefit from recent template improvements, review recent pull requests +merged into the template repository: + +1. **List Recent PRs**: Retrieve recently merged PRs from `demaconsulting/TemplateDotNetTool` + - Review the last 10-20 PRs to identify template improvements + +2. **Identify Propagatable Changes**: For each PR, determine if changes should apply to downstream + projects: + - Focus on structural changes (workflows, agents, configurations) over content-specific changes + - Note changes to `.github/`, linting configurations, project patterns, and documentation + structure + +3. **Check Downstream Application**: Verify if identified changes exist in the downstream project: + - Check if similar files/patterns exist in downstream + - Compare file contents between template and downstream project + - Look for similar PR titles or commit messages in downstream repository history + +4. **Recommend Missing Updates**: For changes not yet applied, include them in the consistency + review with: + - Description of the template change (reference PR number) + - Explanation of benefits for the downstream project + - Specific files or patterns that need updating + +This technique ensures downstream projects don't miss important template improvements and helps +maintain long-term consistency. + ### What NOT to Flag - Project-specific naming (tool names, package IDs, repository URLs) diff --git a/.github/agents/requirements-agent.md b/.github/agents/requirements-agent.md index 1eee0b9..687e53d 100644 --- a/.github/agents/requirements-agent.md +++ b/.github/agents/requirements-agent.md @@ -49,6 +49,23 @@ Follow the `requirements.yaml` structure: - Linked to appropriate test(s) - Enforced via: `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce` +### Test Source Filters + +Test links in `requirements.yaml` can include a source filter prefix to restrict which test results count as +evidence. This is critical for platform and framework requirements - **never remove these filters**. + +- `windows@TestName` - proves the test passed on a Windows platform +- `ubuntu@TestName` - proves the test passed on a Linux (Ubuntu) platform +- `net8.0@TestName` - proves the test passed under the .NET 8 target framework +- `net9.0@TestName` - proves the test passed under the .NET 9 target framework +- `net10.0@TestName` - proves the test passed under the .NET 10 target framework +- `dotnet8.x@TestName` - proves the self-validation test ran on a machine with .NET 8.x runtime +- `dotnet9.x@TestName` - proves the self-validation test ran on a machine with .NET 9.x runtime +- `dotnet10.x@TestName` - proves the self-validation test ran on a machine with .NET 10.x runtime + +Without the source filter, a test result from any platform/framework satisfies the requirement. Removing a +filter invalidates the evidence for platform/framework requirements. + ## Defer To - **Software Developer Agent**: For implementing self-validation tests diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 70ca9c4..f1dec4a 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -28,6 +28,9 @@ Before submitting this pull request, ensure you have completed the following: - [ ] Code builds successfully: `dotnet build --configuration Release` - [ ] All tests pass: `dotnet test --configuration Release` +- [ ] Self-validation tests pass: + `dotnet run --project src/DemaConsulting.SonarMark --configuration Release --framework net10.0` + `--no-build -- --validate` - [ ] Code produces zero warnings ### Code Quality diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 98d5033..c6ac065 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -201,6 +201,10 @@ jobs: 9.x 10.x + - name: Restore Tools + run: > + dotnet tool restore + - name: Restore Dependencies run: > dotnet restore @@ -419,7 +423,7 @@ jobs: run: | echo "Capturing tool versions..." dotnet versionmark --capture --job-id "build-docs" -- \ - dotnet git node npm pandoc weasyprint sarifmark reqstream buildmark versionmark + dotnet git node npm pandoc weasyprint sarifmark sonarmark reqstream buildmark versionmark echo "✓ Tool versions captured" # === GENERATE MARKDOWN REPORTS === diff --git a/.markdownlint-cli2.jsonc b/.markdownlint-cli2.jsonc index a46ee1a..94acac4 100644 --- a/.markdownlint-cli2.jsonc +++ b/.markdownlint-cli2.jsonc @@ -4,6 +4,7 @@ "MD003": { "style": "atx" }, "MD007": { "indent": 2 }, "MD013": { "line_length": 120 }, + "MD024": { "siblings_only": true }, "MD025": false, "MD033": false, "MD041": false diff --git a/AGENTS.md b/AGENTS.md index b26f912..af7f7b1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -14,13 +14,13 @@ SonarQube/SonarCloud analysis results. ## Tech Stack -- C# 12, .NET 8.0/9.0/10.0, MSTest, dotnet CLI, NuGet +- C# (latest), .NET 8.0/9.0/10.0, MSTest, dotnet CLI, NuGet ## Key Files - **`requirements.yaml`** - All requirements with test linkage (enforced via `dotnet reqstream --enforce`) - **`.editorconfig`** - Code style (file-scoped namespaces, 4-space indent, UTF-8+BOM, LF endings) -- **`.cspell.json`, `.markdownlint.json`, `.yamllint.yaml`** - Linting configs +- **`.cspell.json`, `.markdownlint-cli2.jsonc`, `.yamllint.yaml`** - Linting configs - **`.vscode/tasks.json`** - VS Code tasks for build, test, lint, and quality checks ## Requirements (SonarMark-Specific) diff --git a/README.md b/README.md index dbebff4..2270fe2 100644 --- a/README.md +++ b/README.md @@ -137,29 +137,41 @@ sonarmark --validate sonarmark --validate --results validation-results.trx ``` -### Self-Validation Tests +## Self Validation -SonarMark includes built-in self-validation tests that verify the tool's functionality without requiring -a live SonarQube/SonarCloud server. These tests use mock data to validate core features and generate test -result files in TRX or JUnit format. +Running self-validation produces a report containing the following information: -The self-validation suite includes the following tests: +```text +# DEMA Consulting SonarMark + +| Information | Value | +| :------------------ | :------------------------------------------------- | +| SonarMark Version | | +| Machine Name | | +| OS Version | | +| DotNet Runtime | | +| Time Stamp | UTC | + +✓ SonarMark_QualityGateRetrieval - Passed +✓ SonarMark_IssuesRetrieval - Passed +✓ SonarMark_HotSpotsRetrieval - Passed +✓ SonarMark_MarkdownReportGeneration - Passed + +Total Tests: 4 +Passed: 4 +Failed: 0 +``` -| Test Name | Description | -| :-------- | :---------- | -| `SonarMark_QualityGateRetrieval` | Verifies fetching and processing quality gate status | -| `SonarMark_IssuesRetrieval` | Verifies fetching and processing code issues | -| `SonarMark_HotSpotsRetrieval` | Verifies fetching and processing security hot-spots | -| `SonarMark_MarkdownReportGeneration` | Verifies generating markdown reports with quality metrics | +Each test in the report proves: -These tests provide evidence of the tool's functionality and are particularly useful for: +- **`SonarMark_QualityGateRetrieval`** - Verifies fetching and processing quality gate status from SonarQube/SonarCloud. +- **`SonarMark_IssuesRetrieval`** - Verifies fetching and processing code issues with severity classification. +- **`SonarMark_HotSpotsRetrieval`** - Verifies fetching and processing security hot-spots and vulnerabilities. +- **`SonarMark_MarkdownReportGeneration`** - Verifies generating markdown reports with quality metrics and findings. -- Verifying the installation is working correctly -- Running automated tests in CI/CD pipelines without requiring SonarQube access -- Generating test evidence for compliance and traceability requirements +See the [User Guide][link-guide] for more details on the self-validation tests. -For detailed usage instructions, command-line options, and examples, including tool update instructions, see the -[Usage Guide](https://github.com/demaconsulting/SonarMark/blob/main/docs/guide/guide.md). +On validation failure the tool will exit with a non-zero exit code. ## Report Format @@ -251,6 +263,7 @@ SonarMark is built with the following open-source projects: [link-forks]: https://github.com/demaconsulting/SonarMark/network/members +[link-guide]: https://github.com/demaconsulting/SonarMark/blob/main/docs/guide/guide.md [link-stars]: https://github.com/demaconsulting/SonarMark/stargazers [link-contributors]: https://github.com/demaconsulting/SonarMark/graphs/contributors [link-license]: https://github.com/demaconsulting/SonarMark/blob/main/LICENSE diff --git a/docs/guide/guide.md b/docs/guide/guide.md index c56c3f9..ccf5af1 100644 --- a/docs/guide/guide.md +++ b/docs/guide/guide.md @@ -437,70 +437,64 @@ If no security hot-spots are found: Found no security hot-spots ``` -# Running Self-Validation +# Self-Validation -SonarMark includes built-in self-validation tests to verify functionality without requiring access to a real -SonarQube/SonarCloud server. The validation uses mock data to test core features. +Self-validation produces a report demonstrating that SonarMark is functioning +correctly. This is useful in regulated industries where tool validation evidence is required. ## Running Validation +To perform self-validation: + ```bash sonarmark --validate ``` -## Validation Tests - -The self-validation suite includes the following tests that verify core functionality: - -| Test Name | Description | -| :-------- | :---------- | -| `SonarMark_QualityGateRetrieval` | Verifies fetching and processing quality gate status from SonarQube/SonarCloud | -| `SonarMark_IssuesRetrieval` | Verifies fetching and processing code issues with severity classification | -| `SonarMark_HotSpotsRetrieval` | Verifies fetching and processing security hot-spots and vulnerabilities | -| `SonarMark_MarkdownReportGeneration` | Verifies generating markdown reports with quality metrics and findings | +To save validation results to a file: -These tests provide evidence of the tool's functionality and are particularly useful for: +```bash +sonarmark --validate --results results.trx +``` -- Verifying the installation is working correctly on different platforms and .NET versions -- Running automated tests in CI/CD pipelines without requiring SonarQube access -- Generating test evidence for compliance and traceability requirements -- Validating tool functionality before deployment +The results file format is determined by the file extension: `.trx` for TRX (MSTest) format, +or `.xml` for JUnit format. -**Note**: The test names with the `SonarMark_` prefix are designed for clear identification in test -result files (TRX/JUnit) when integrating with larger projects or test frameworks. +## Validation Report -## Validation Output +The validation report contains the tool version, machine name, operating system version, +.NET runtime version, timestamp, and test results. -Example output: +Example validation report: ```text -SonarMark version 1.0.0 -Copyright (c) DEMA Consulting - # DEMA Consulting SonarMark -## Self-Validation Tests -[PASS] Quality Gate Status Retrieval -[PASS] Issues Retrieval -[PASS] Hot-Spots Retrieval -[PASS] Markdown Report Generation +| Information | Value | +| :------------------ | :------------------------------------------------- | +| SonarMark Version | 1.0.0 | +| Machine Name | BUILD-SERVER | +| OS Version | Ubuntu 22.04.3 LTS | +| DotNet Runtime | .NET 10.0.0 | +| Time Stamp | 2024-01-15 10:30:00 UTC | + +✓ SonarMark_QualityGateRetrieval - Passed +✓ SonarMark_IssuesRetrieval - Passed +✓ SonarMark_HotSpotsRetrieval - Passed +✓ SonarMark_MarkdownReportGeneration - Passed Total Tests: 4 Passed: 4 Failed: 0 ``` -## Saving Validation Results +## Validation Tests -Save results in TRX or JUnit XML format for integration with test reporting tools: +Each test proves specific functionality works correctly: -```bash -# TRX format (for Azure DevOps, Visual Studio) -sonarmark --validate --results validation-results.trx - -# JUnit XML format (for Jenkins, GitLab CI) -sonarmark --validate --results validation-results.xml -``` +- **`SonarMark_QualityGateRetrieval`** - Verifies fetching and processing quality gate status from SonarQube/SonarCloud. +- **`SonarMark_IssuesRetrieval`** - Verifies fetching and processing code issues with severity classification. +- **`SonarMark_HotSpotsRetrieval`** - Verifies fetching and processing security hot-spots and vulnerabilities. +- **`SonarMark_MarkdownReportGeneration`** - Verifies generating markdown reports with quality metrics and findings. # Best Practices diff --git a/requirements.yaml b/requirements.yaml index 3a4b494..a801486 100644 --- a/requirements.yaml +++ b/requirements.yaml @@ -32,7 +32,7 @@ sections: sections: - title: Command-Line Interface requirements: - - id: CLI-001 + - id: SonarMark-Cmd-Cli title: The tool shall provide a command-line interface. justification: | A command-line interface is essential for automation and integration into CI/CD pipelines. @@ -42,7 +42,7 @@ sections: - IntegrationTest_VersionFlag_OutputsVersion - IntegrationTest_HelpFlag_OutputsUsageInformation - - id: CLI-002 + - id: SonarMark-Cmd-Version title: The tool shall display version information when requested. justification: | Version information helps users verify which version of the tool they are running, which is @@ -51,7 +51,7 @@ sections: tests: - IntegrationTest_VersionFlag_OutputsVersion - - id: CLI-003 + - id: SonarMark-Cmd-Help title: The tool shall display help information when requested. justification: | Help information provides users with usage instructions and available options without needing @@ -60,7 +60,7 @@ sections: tests: - IntegrationTest_HelpFlag_OutputsUsageInformation - - id: CLI-004 + - id: SonarMark-Cmd-Silent title: The tool shall support silent mode to suppress console output. justification: | Silent mode is important for automated environments where console output may interfere with @@ -69,7 +69,7 @@ sections: tests: - IntegrationTest_SilentFlag_SuppressesOutput - - id: CLI-005 + - id: SonarMark-Cmd-Log title: The tool shall support writing output to a log file. justification: | Log file output enables persistent recording of tool execution for later review and audit trails. @@ -78,7 +78,7 @@ sections: tests: - Context_Create_WithLogFile_WritesToLogFile - - id: CLI-006 + - id: SonarMark-Cmd-Enforce title: The tool shall support enforcing quality gate checks. justification: | Quality gate enforcement allows the tool to fail builds when quality standards are not met, @@ -89,7 +89,7 @@ sections: - title: SonarQube/SonarCloud Integration requirements: - - id: SONAR-001 + - id: SonarMark-Svr-Connect title: The tool shall connect to SonarQube/SonarCloud servers. justification: | Connection to SonarQube/SonarCloud servers is the core functionality of the tool, enabling @@ -99,7 +99,7 @@ sections: tests: - IntegrationTest_MissingServerParameter_ShowsError - - id: SONAR-002 + - id: SonarMark-Svr-Auth title: The tool shall authenticate with SonarQube/SonarCloud using tokens. justification: | Token-based authentication is the secure and recommended method for accessing SonarQube/SonarCloud @@ -108,7 +108,7 @@ sections: tests: - IntegrationTest_TokenParameter_IsAccepted - - id: SONAR-003 + - id: SonarMark-Svr-QualityGate title: The tool shall fetch quality gate status from SonarQube/SonarCloud. justification: | Quality gate status indicates whether code meets the defined quality standards and is fundamental @@ -117,7 +117,7 @@ sections: tests: - SonarMark_QualityGateRetrieval - - id: SONAR-004 + - id: SonarMark-Svr-Issues title: The tool shall fetch issues from SonarQube/SonarCloud. justification: | Issues represent code quality problems identified by Sonar analysis. Fetching and reporting @@ -126,7 +126,7 @@ sections: tests: - SonarMark_IssuesRetrieval - - id: SONAR-005 + - id: SonarMark-Svr-HotSpots title: The tool shall fetch security hot-spots from SonarQube/SonarCloud. justification: | Security hot-spots highlight code that requires security review, helping teams identify and @@ -135,7 +135,7 @@ sections: tests: - SonarMark_HotSpotsRetrieval - - id: SONAR-006 + - id: SonarMark-Svr-ProjectKey title: The tool shall support filtering by project key. justification: | Project key filtering is essential for identifying which specific project to analyze when @@ -144,7 +144,7 @@ sections: tests: - IntegrationTest_MissingProjectKeyParameter_ShowsError - - id: SONAR-007 + - id: SonarMark-Svr-Branch title: The tool shall support filtering by branch. justification: | Branch filtering enables analysis of specific branches in version control, which is crucial @@ -155,7 +155,7 @@ sections: - title: Report Generation requirements: - - id: RPT-001 + - id: SonarMark-Rpt-Markdown title: The tool shall generate markdown reports. justification: | Markdown reports provide human-readable documentation of code quality that can be easily @@ -166,7 +166,7 @@ sections: - IntegrationTest_ReportParameter_IsAccepted - SonarMark_MarkdownReportGeneration - - id: RPT-002 + - id: SonarMark-Rpt-Depth title: The tool shall support configurable report depth. justification: | Configurable report depth allows users to control the level of detail in generated reports, @@ -178,7 +178,7 @@ sections: - IntegrationTest_ReportDepthWithInvalidValue_ShowsError - IntegrationTest_ReportDepthWithoutValue_ShowsError - - id: RPT-003 + - id: SonarMark-Rpt-QualityGate title: The tool shall include quality gate status in reports. justification: | Quality gate status is the most important metric in the report, providing a clear pass/fail @@ -192,7 +192,7 @@ sections: - SonarQualityResult_ToMarkdown_WarnStatus_ProducesCorrectOutput - SonarQualityResult_ToMarkdown_WithFriendlyNames_UsesFriendlyNames - - id: RPT-004 + - id: SonarMark-Rpt-Issues title: The tool shall categorize and report issues by type and severity. justification: | Categorizing issues by type and severity helps teams prioritize remediation efforts and @@ -202,7 +202,7 @@ sections: - SonarQualityResult_ToMarkdown_WithIssues_ProducesCompilerStyleOutput - SonarQualityResult_ToMarkdown_WithSingularCounts_ShowsCorrectText - - id: RPT-005 + - id: SonarMark-Rpt-HotSpots title: The tool shall report security hot-spots requiring review. justification: | Security hot-spots require manual review to determine if they represent actual vulnerabilities. @@ -213,7 +213,7 @@ sections: - title: Validation and Testing requirements: - - id: VAL-001 + - id: SonarMark-Val-Validate title: The tool shall support self-validation mode. justification: | Self-validation mode allows the tool to verify its own functionality without requiring @@ -227,7 +227,7 @@ sections: - SonarMark_HotSpotsRetrieval - SonarMark_MarkdownReportGeneration - - id: VAL-002 + - id: SonarMark-Val-Results title: The tool shall write validation results to test result files. justification: | Writing validation results to test result files allows integration with standard testing @@ -237,7 +237,7 @@ sections: - Context_Create_ResultsFile_SetsResultsProperty - Context_Create_MissingResultsFilename_ThrowsException - - id: VAL-003 + - id: SonarMark-Val-TrxFormat title: The tool shall support TRX format for test results. justification: | TRX (Test Results XML) is the native test results format for Microsoft testing tools and @@ -246,7 +246,7 @@ sections: tests: - Context_Create_ResultsFile_SetsResultsProperty - - id: VAL-004 + - id: SonarMark-Val-JUnitFormat title: The tool shall support JUnit format for test results. justification: | JUnit format is a widely-supported standard for test results across many platforms and tools, @@ -257,7 +257,7 @@ sections: - title: Quality Enforcement requirements: - - id: ENF-001 + - id: SonarMark-Enf-Mode title: The tool shall support enforcement mode to fail on quality gate failures. justification: | Enforcement mode is critical for maintaining code quality standards by preventing builds @@ -266,7 +266,7 @@ sections: tests: - Context_Create_EnforceFlag_SetsEnforceProperty - - id: ENF-002 + - id: SonarMark-Enf-ExitCode title: The tool shall return non-zero exit code when quality gate fails in enforcement mode. justification: | Returning a non-zero exit code on quality gate failure is the standard mechanism for @@ -277,7 +277,7 @@ sections: - title: Platform Support requirements: - - id: PLT-001 + - id: SonarMark-Plt-Windows title: The tool shall run on Windows operating systems. justification: | Windows is a major development platform, especially for .NET development. Supporting Windows @@ -294,7 +294,7 @@ sections: - windows@SonarMark_HotSpotsRetrieval - windows@SonarMark_MarkdownReportGeneration - - id: PLT-002 + - id: SonarMark-Plt-Linux title: The tool shall run on Linux operating systems. justification: | Linux is the dominant platform for cloud-based CI/CD systems and containerized environments. @@ -311,7 +311,7 @@ sections: - ubuntu@SonarMark_HotSpotsRetrieval - ubuntu@SonarMark_MarkdownReportGeneration - - id: PLT-003 + - id: SonarMark-Plt-Net8 title: The tool shall support .NET 8.0 runtime. justification: | .NET 8.0 is a Long-Term Support (LTS) release with support until November 2026. Supporting @@ -325,7 +325,7 @@ sections: - dotnet8.x@SonarMark_HotSpotsRetrieval - dotnet8.x@SonarMark_MarkdownReportGeneration - - id: PLT-004 + - id: SonarMark-Plt-Net9 title: The tool shall support .NET 9.0 runtime. justification: | .NET 9.0 is a Standard Term Support (STS) release providing access to the latest features @@ -339,7 +339,7 @@ sections: - dotnet9.x@SonarMark_HotSpotsRetrieval - dotnet9.x@SonarMark_MarkdownReportGeneration - - id: PLT-005 + - id: SonarMark-Plt-Net10 title: The tool shall support .NET 10.0 runtime. justification: | .NET 10.0 is the next Long-Term Support (LTS) release scheduled for November 2025. Supporting diff --git a/src/DemaConsulting.SonarMark/Context.cs b/src/DemaConsulting.SonarMark/Context.cs index e2a1f47..a2e1f26 100644 --- a/src/DemaConsulting.SonarMark/Context.cs +++ b/src/DemaConsulting.SonarMark/Context.cs @@ -177,7 +177,7 @@ private void OpenLogFile(string logFile) { try { - _logWriter = new StreamWriter(logFile, append: false); + _logWriter = new StreamWriter(logFile, append: false) { AutoFlush = true }; } // Generic catch is justified here to wrap any file system exception with context. // Expected exceptions include IOException, UnauthorizedAccessException, ArgumentException, @@ -415,7 +415,7 @@ public void WriteError(string message) { var previousColor = Console.ForegroundColor; Console.ForegroundColor = ConsoleColor.Red; - Console.WriteLine(message); + Console.Error.WriteLine(message); Console.ForegroundColor = previousColor; } diff --git a/src/DemaConsulting.SonarMark/DemaConsulting.SonarMark.csproj b/src/DemaConsulting.SonarMark/DemaConsulting.SonarMark.csproj index 952d751..dcdb8b6 100644 --- a/src/DemaConsulting.SonarMark/DemaConsulting.SonarMark.csproj +++ b/src/DemaConsulting.SonarMark/DemaConsulting.SonarMark.csproj @@ -46,11 +46,20 @@ Organization: $(Company) + - + + + + + + + + + - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/DemaConsulting.SonarMark/Program.cs b/src/DemaConsulting.SonarMark/Program.cs index 8c49963..a847f4b 100644 --- a/src/DemaConsulting.SonarMark/Program.cs +++ b/src/DemaConsulting.SonarMark/Program.cs @@ -62,19 +62,19 @@ private static int Main(string[] args) catch (ArgumentException ex) { // Print expected argument exceptions and return error code - Console.WriteLine($"Error: {ex.Message}"); + Console.Error.WriteLine($"Error: {ex.Message}"); return 1; } catch (InvalidOperationException ex) { // Print expected operation exceptions and return error code - Console.WriteLine($"Error: {ex.Message}"); + Console.Error.WriteLine($"Error: {ex.Message}"); return 1; } catch (Exception ex) { // Print unexpected exceptions and re-throw to generate event logs - Console.WriteLine($"Unexpected error: {ex.Message}"); + Console.Error.WriteLine($"Unexpected error: {ex.Message}"); throw; } } @@ -88,7 +88,7 @@ public static void Run(Context context) // Priority 1: Version query if (context.Version) { - Console.WriteLine(Version); + context.WriteLine(Version); return; } diff --git a/src/DemaConsulting.SonarMark/Validation.cs b/src/DemaConsulting.SonarMark/Validation.cs index 5a4227d..6c6ffe4 100644 --- a/src/DemaConsulting.SonarMark/Validation.cs +++ b/src/DemaConsulting.SonarMark/Validation.cs @@ -128,7 +128,6 @@ private static void RunQualityGateRetrievalTest( testResults, mockFactory, "SonarMark_QualityGateRetrieval", - "Quality Gate Retrieval Test", null, (logContent, _) => { @@ -159,7 +158,6 @@ private static void RunIssuesRetrievalTest( testResults, mockFactory, "SonarMark_IssuesRetrieval", - "Issues Retrieval Test", null, (logContent, _) => { @@ -188,7 +186,6 @@ private static void RunHotSpotsRetrievalTest( testResults, mockFactory, "SonarMark_HotSpotsRetrieval", - "Hot-Spots Retrieval Test", null, (logContent, _) => { @@ -217,7 +214,6 @@ private static void RunMarkdownReportGenerationTest( testResults, mockFactory, "SonarMark_MarkdownReportGeneration", - "Markdown Report Generation Test", "quality-report.md", (logContent, reportContent) => { @@ -245,7 +241,6 @@ private static void RunMarkdownReportGenerationTest( /// The test results collection. /// The mock HTTP client factory. /// The name of the test. - /// The display name for console output. /// Optional report file name to generate. /// Function to validate test results. Returns null on success or error message on failure. private static void RunValidationTest( @@ -253,7 +248,6 @@ private static void RunValidationTest( DemaConsulting.TestResults.TestResults testResults, Func mockFactory, string testName, - string displayName, string? reportFileName, Func validator) { @@ -306,26 +300,26 @@ private static void RunValidationTest( if (errorMessage == null) { test.Outcome = DemaConsulting.TestResults.TestOutcome.Passed; - context.WriteLine($"✓ {displayName} - PASSED"); + context.WriteLine($"✓ {testName} - Passed"); } else { test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; test.ErrorMessage = errorMessage; - context.WriteError($"✗ {displayName} - FAILED: {errorMessage}"); + context.WriteError($"✗ {testName} - Failed: {errorMessage}"); } } else { test.Outcome = DemaConsulting.TestResults.TestOutcome.Failed; test.ErrorMessage = $"Program exited with code {exitCode}"; - context.WriteError($"✗ {displayName} - FAILED: Exit code {exitCode}"); + context.WriteError($"✗ {testName} - Failed: Exit code {exitCode}"); } } // Generic catch is justified here to handle any exception during test execution catch (Exception ex) { - HandleTestException(test, context, displayName, ex); + HandleTestException(test, context, testName, ex); } FinalizeTestResult(test, startTime, testResults); diff --git a/test/DemaConsulting.SonarMark.Tests/ContextTests.cs b/test/DemaConsulting.SonarMark.Tests/ContextTests.cs index bda0c57..7878f47 100644 --- a/test/DemaConsulting.SonarMark.Tests/ContextTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/ContextTests.cs @@ -362,21 +362,21 @@ public void Context_WriteLine_SilentMode_DoesNotWriteToConsole() [TestMethod] public void Context_WriteError_NormalMode_WritesToConsole() { - var originalOut = Console.Out; - using var output = new StringWriter(); - Console.SetOut(output); + var originalError = Console.Error; + using var error = new StringWriter(); + Console.SetError(error); try { using var context = Context.Create([]); context.WriteError("Error message"); - Assert.AreEqual("Error message" + Environment.NewLine, output.ToString()); + Assert.AreEqual("Error message" + Environment.NewLine, error.ToString()); Assert.AreEqual(1, context.ExitCode); } finally { - Console.SetOut(originalOut); + Console.SetError(originalError); } } diff --git a/test/DemaConsulting.SonarMark.Tests/DemaConsulting.SonarMark.Tests.csproj b/test/DemaConsulting.SonarMark.Tests/DemaConsulting.SonarMark.Tests.csproj index d8566b4..19fc27f 100644 --- a/test/DemaConsulting.SonarMark.Tests/DemaConsulting.SonarMark.Tests.csproj +++ b/test/DemaConsulting.SonarMark.Tests/DemaConsulting.SonarMark.Tests.csproj @@ -3,7 +3,7 @@ net8.0;net9.0;net10.0 - 12 + latest enable enable diff --git a/test/DemaConsulting.SonarMark.Tests/ProgramTests.cs b/test/DemaConsulting.SonarMark.Tests/ProgramTests.cs index 63cb235..7037e06 100644 --- a/test/DemaConsulting.SonarMark.Tests/ProgramTests.cs +++ b/test/DemaConsulting.SonarMark.Tests/ProgramTests.cs @@ -105,10 +105,13 @@ public void Program_Run_WithValidateFlag_RunsValidationSuccessfully() [TestMethod] public void Program_Run_WithNoArguments_OutputsBannerAndRequiresServerError() { - // Arrange - capture console output + // Arrange - capture console output (stdout for banner, stderr for error messages) var originalOut = Console.Out; + var originalError = Console.Error; using var output = new StringWriter(); + using var errorOutput = new StringWriter(); Console.SetOut(output); + Console.SetError(errorOutput); try { @@ -117,16 +120,16 @@ public void Program_Run_WithNoArguments_OutputsBannerAndRequiresServerError() // Act - run the program with no arguments Program.Run(context); - // Assert - verify banner is shown and error about missing --server parameter + // Assert - verify banner is shown on stdout and error about missing --server parameter on stderr // This test proves that running without required parameters shows appropriate error - var outputText = output.ToString(); - Assert.Contains("SonarMark version", outputText); - Assert.Contains("--server parameter is required", outputText); + Assert.Contains("SonarMark version", output.ToString()); + Assert.Contains("--server parameter is required", errorOutput.ToString()); Assert.AreEqual(1, context.ExitCode); } finally { Console.SetOut(originalOut); + Console.SetError(originalError); } } @@ -136,10 +139,10 @@ public void Program_Run_WithNoArguments_OutputsBannerAndRequiresServerError() [TestMethod] public void Program_Run_WithServerButNoProjectKey_OutputsProjectKeyRequiredError() { - // Arrange - capture console output - var originalOut = Console.Out; - using var output = new StringWriter(); - Console.SetOut(output); + // Arrange - capture console error output + var originalError = Console.Error; + using var errorOutput = new StringWriter(); + Console.SetError(errorOutput); try { @@ -150,13 +153,12 @@ public void Program_Run_WithServerButNoProjectKey_OutputsProjectKeyRequiredError // Assert - verify error about missing --project-key parameter // This test proves that --server requires --project-key to also be specified - var outputText = output.ToString(); - Assert.Contains("--project-key parameter is required", outputText); + Assert.Contains("--project-key parameter is required", errorOutput.ToString()); Assert.AreEqual(1, context.ExitCode); } finally { - Console.SetOut(originalOut); + Console.SetError(originalError); } }