diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 2e4a0c6..709eaa4 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -19,6 +19,10 @@ jobs: contents: read steps: + # === INSTALL DEPENDENCIES === + # This section installs all required dependencies for quality checks. + # Downstream projects: Add any additional dependency installations here. + - name: Checkout uses: actions/checkout@v6 @@ -34,15 +38,23 @@ jobs: - name: Capture tool versions shell: bash run: | + mkdir -p artifacts echo "Capturing tool versions..." - dotnet versionmark --capture --job-id "quality" -- dotnet git versionmark + dotnet versionmark --capture --job-id "quality" \ + --output "artifacts/versionmark-quality.json" -- \ + dotnet git versionmark echo "✓ Tool versions captured" - - name: Upload version capture - uses: actions/upload-artifact@v7 - with: - name: version-capture-quality - path: versionmark-quality.json + # === CAPTURE OTS SELF-VALIDATION RESULTS === + # This section captures self-validation results from OTS tools. + # Downstream projects: Add any additional self-validation steps here. + + - name: Run VersionMark self-validation + run: dotnet versionmark --validate --results artifacts/versionmark-self-validation-quality.trx + + # === RUN QUALITY CHECKS === + # This section runs all quality checks for the project. + # Downstream projects: Add any additional quality checks here. - name: Run markdown linter uses: DavidAnson/markdownlint-cli2-action@v22 @@ -60,6 +72,12 @@ jobs: with: config_file: .yamllint.yaml + - name: Upload quality artifacts + uses: actions/upload-artifact@v7 + with: + name: artifacts-quality + path: artifacts/ + # Builds and unit-tests the project on supported operating systems to ensure # unit-tests operate on all platforms and to run SonarScanner for generating # the code quality report. @@ -78,6 +96,10 @@ jobs: steps: + # === INSTALL DEPENDENCIES === + # This section installs all required dependencies for the build. + # Downstream projects: Add any additional dependency installations here. + - name: Checkout uses: actions/checkout@v6 @@ -93,6 +115,34 @@ jobs: run: > dotnet tool restore + # === CAPTURE TOOL VERSIONS === + # This section captures the versions of all tools used in the build process. + # Downstream projects: Add any additional tools to capture here. + + - name: Capture tool versions + shell: bash + run: | + mkdir -p artifacts + echo "Capturing tool versions..." + # Create short job ID: build-win, build-ubuntu + OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/windows-latest/win/;s/ubuntu-latest/ubuntu/') + JOB_ID="build-${OS_SHORT}" + dotnet versionmark --capture --job-id "${JOB_ID}" \ + --output "artifacts/versionmark-${JOB_ID}.json" -- \ + dotnet git dotnet-sonarscanner versionmark + echo "✓ Tool versions captured" + + # === CAPTURE OTS SELF-VALIDATION RESULTS === + # This section captures self-validation results from OTS tools. + # Downstream projects: Add any additional self-validation steps here. + + - name: Run VersionMark self-validation + run: dotnet versionmark --validate --results artifacts/versionmark-self-validation-${{ matrix.os }}.trx + + # === BUILD AND TEST === + # This section builds and tests the project. + # Downstream projects: Add any additional build and test steps here. + - name: Restore Dependencies run: > dotnet restore @@ -119,9 +169,9 @@ jobs: dotnet test --no-build --configuration Release - --verbosity normal --collect "XPlat Code Coverage;Format=opencover" - --logger "trx;LogFileName=test-results-${{ matrix.os }}.trx" + --logger "trx;LogFilePrefix=${{ matrix.os }}" + --results-directory artifacts - name: End Sonar Scanner run: > @@ -135,32 +185,17 @@ jobs: --configuration Release --property:Version=${{ inputs.version }} - - name: Capture tool versions - shell: bash - run: | - echo "Capturing tool versions..." - # Create short job ID: build-win, build-ubuntu - OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/windows-latest/win/;s/ubuntu-latest/ubuntu/') - JOB_ID="build-${OS_SHORT}" - dotnet versionmark --capture --job-id "${JOB_ID}" -- \ - dotnet git dotnet-sonarscanner versionmark - echo "✓ Tool versions captured" - - - name: Upload version capture - uses: actions/upload-artifact@v7 - with: - name: version-capture-${{ matrix.os }} - path: versionmark-build-*.json + # === UPLOAD ARTIFACTS === + # This section uploads all build artifacts. + # Downstream projects: Add any additional artifact uploads here. - - name: Upload Test Results - if: always() + - name: Upload build artifacts uses: actions/upload-artifact@v7 with: - name: test-results-${{ matrix.os }} - path: | - test/**/TestResults/*.trx + name: artifacts-build-${{ matrix.os }} + path: artifacts/ - - name: Upload Artifacts + - name: Upload packages uses: actions/upload-artifact@v7 with: name: packages-${{ matrix.os }} @@ -180,6 +215,10 @@ jobs: security-events: write steps: + # === INSTALL DEPENDENCIES === + # This section installs all required dependencies for CodeQL analysis. + # Downstream projects: Add any additional dependency installations here. + - name: Checkout uses: actions/checkout@v6 with: @@ -209,6 +248,10 @@ jobs: run: > dotnet restore + # === BUILD AND ANALYZE === + # This section builds the project and runs CodeQL analysis. + # Downstream projects: Add any additional analysis steps here. + - name: Build run: > dotnet build @@ -220,14 +263,18 @@ jobs: uses: github/codeql-action/analyze@v4 with: category: "/language:csharp" - output: sarif-results + output: artifacts upload: false - - name: Upload CodeQL SARIF + # === UPLOAD ARTIFACTS === + # This section uploads all CodeQL artifacts. + # Downstream projects: Add any additional artifact uploads here. + + - name: Upload CodeQL artifacts uses: actions/upload-artifact@v7 with: - name: codeql-sarif - path: sarif-results/csharp.sarif + name: artifacts-codeql + path: artifacts/ # Performs integration testing on a matrix of operating systems and .NET runtimes, # involving basic tool execution and running self-validation to ensure compatibility @@ -245,6 +292,10 @@ jobs: dotnet-version: ['8.x', '9.x', '10.x'] steps: + # === INSTALL DEPENDENCIES === + # This section installs all required dependencies and tools for integration testing. + # Downstream projects: Add any additional dependency installations here. + - name: Checkout uses: actions/checkout@v6 with: @@ -276,6 +327,28 @@ jobs: --version ${{ inputs.version }} \ DemaConsulting.ReqStream + # === CAPTURE TOOL VERSIONS === + # This section captures the versions of all tools used in the integration tests. + # Downstream projects: Add any additional tools to capture here. + + - name: Capture tool versions + shell: bash + run: | + mkdir -p artifacts + echo "Capturing tool versions..." + # Create short job ID: int-win-8, int-win-9, int-ubuntu-8, etc. + OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/windows-latest/win/;s/ubuntu-latest/ubuntu/') + DOTNET_SHORT=$(echo "${{ matrix.dotnet-version }}" | sed 's/\.x$//') + JOB_ID="int-${OS_SHORT}-${DOTNET_SHORT}" + dotnet versionmark --capture --job-id "${JOB_ID}" \ + --output "artifacts/versionmark-${JOB_ID}.json" -- \ + dotnet git versionmark + echo "✓ Tool versions captured" + + # === RUN INTEGRATION TESTS === + # This section runs the integration tests for the tool. + # Downstream projects: Add any additional integration test steps here. + - name: Test version display shell: bash run: | @@ -295,33 +368,20 @@ jobs: run: | echo "Running self-validation..." reqstream --validate \ - --results integration-test-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }}.trx \ + --results artifacts/validation-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }}.trx \ || { echo "✗ Self-validation failed"; exit 1; } echo "✓ Self-validation succeeded" - - name: Capture tool versions - shell: bash - run: | - echo "Capturing tool versions..." - # Create short job ID: int-win-8, int-win-9, int-ubuntu-8, etc. - OS_SHORT=$(echo "${{ matrix.os }}" | sed 's/windows-latest/win/;s/ubuntu-latest/ubuntu/') - DOTNET_SHORT=$(echo "${{ matrix.dotnet-version }}" | sed 's/\.x$//') - JOB_ID="int-${OS_SHORT}-${DOTNET_SHORT}" - dotnet versionmark --capture --job-id "${JOB_ID}" -- dotnet git versionmark - echo "✓ Tool versions captured" - - - name: Upload version capture - uses: actions/upload-artifact@v7 - with: - name: version-capture-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }} - path: versionmark-int-*.json + # === UPLOAD ARTIFACTS === + # This section uploads all generated artifacts for use by downstream jobs. + # Downstream projects: Add any additional artifact uploads here. - - name: Upload validation test results + - name: Upload validation artifacts if: always() uses: actions/upload-artifact@v7 with: - name: integration-test-results-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }} - path: integration-test-*.trx + name: artifacts-validation-${{ matrix.os }}-dotnet${{ matrix.dotnet-version }} + path: artifacts/ # Builds the supporting documentation including user guides, requirements, # trace matrices, code quality reports, and build notes. @@ -340,32 +400,20 @@ jobs: - name: Checkout uses: actions/checkout@v6 - - name: Download all test results + - name: Download all job artifacts uses: actions/download-artifact@v8 with: - path: test-results - pattern: '*test-results*' + path: artifacts + pattern: 'artifacts-*' + merge-multiple: true continue-on-error: true - - name: Download ReqStream package + - name: Download packages artifact uses: actions/download-artifact@v8 with: - name: packages-windows-latest + name: packages-ubuntu-latest path: packages - - name: Download CodeQL SARIF - uses: actions/download-artifact@v8 - with: - name: codeql-sarif - path: codeql-results - - - name: Download all version captures - uses: actions/download-artifact@v8 - with: - path: version-captures - pattern: 'version-capture-*' - continue-on-error: true - # === INSTALL DEPENDENCIES === # This section installs all required dependencies and tools for document generation. # Downstream projects: Add any additional dependency installations here. @@ -402,11 +450,32 @@ jobs: - name: Capture tool versions for build-docs shell: bash run: | + mkdir -p artifacts echo "Capturing tool versions..." - dotnet versionmark --capture --job-id "build-docs" -- \ + dotnet versionmark --capture --job-id "build-docs" \ + --output "artifacts/versionmark-build-docs.json" -- \ dotnet git node npm pandoc weasyprint sarifmark sonarmark reqstream buildmark versionmark echo "✓ Tool versions captured" + # === CAPTURE OTS SELF-VALIDATION RESULTS === + # This section captures self-validation results from OTS tools. + # Downstream projects: Add any additional self-validation steps here. + + - name: Run ReqStream self-validation + run: reqstream --validate --results artifacts/reqstream-self-validation.trx + + - name: Run BuildMark self-validation + run: dotnet buildmark --validate --results artifacts/buildmark-self-validation.trx + + - name: Run VersionMark self-validation + run: dotnet versionmark --validate --results artifacts/versionmark-self-validation.trx + + - name: Run SarifMark self-validation + run: dotnet sarifmark --validate --results artifacts/sarifmark-self-validation.trx + + - name: Run SonarMark self-validation + run: dotnet sonarmark --validate --results artifacts/sonarmark-self-validation.trx + # === GENERATE MARKDOWN REPORTS === # This section generates all markdown reports from various tools and sources. # Downstream projects: Add any additional markdown report generation steps here. @@ -415,7 +484,7 @@ jobs: run: > reqstream --requirements requirements.yaml - --tests "test-results/**/*.trx" + --tests "artifacts/**/*.trx" --report docs/requirements/requirements.md --justifications docs/justifications/justifications.md --matrix docs/tracematrix/tracematrix.md @@ -425,7 +494,7 @@ jobs: shell: bash run: > dotnet sarifmark - --sarif codeql-results/csharp.sarif + --sarif artifacts/csharp.sarif --report docs/quality/codeql-quality.md --heading "ReqStream CodeQL Analysis" --report-depth 1 @@ -476,7 +545,7 @@ jobs: run: | echo "Publishing tool versions..." dotnet versionmark --publish --report docs/buildnotes/versions.md --report-depth 1 \ - -- "versionmark-*.json" "version-captures/**/versionmark-*.json" + -- "artifacts/**/versionmark-*.json" echo "✓ Tool versions published" - name: Display Tool Versions Report diff --git a/AGENTS.md b/AGENTS.md index 64c1c2e..9676c4d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -19,7 +19,7 @@ written in YAML files. ## 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) +- **`.editorconfig`** - Code style (file-scoped namespaces, 4-space indent, UTF-8, LF endings) - **`.cspell.json`, `.markdownlint-cli2.jsonc`, `.yamllint.yaml`** - Linting configs ## Requirements diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e0460b0..459c02c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -80,7 +80,7 @@ This project follows the coding standards defined in `.editorconfig`. Key conven - **Indentation**: 4 spaces for C#, 2 spaces for YAML/JSON/XML - **Line endings**: LF (Unix-style) -- **Encoding**: UTF-8 with BOM +- **Encoding**: UTF-8 - **Braces**: Required for all control statements - **Naming**: - Interfaces: `IRequirementParser` diff --git a/README.md b/README.md index c6bd154..094df63 100644 --- a/README.md +++ b/README.md @@ -516,6 +516,8 @@ in this project you agree to abide by its terms. This project is licensed under the MIT License - see the [LICENSE][license] file for details. +By contributing to this project, you agree that your contributions will be licensed under the MIT License. + ## Support - 🐛 **[Report a Bug][bug-report]** - Found an issue? Let us know diff --git a/requirements.yaml b/requirements.yaml index 26a0b54..c16dffb 100644 --- a/requirements.yaml +++ b/requirements.yaml @@ -32,7 +32,7 @@ sections: sections: - title: Command-Line Interface requirements: - - id: CLI-001 + - id: ReqStream-Cmd-Cli title: The tool shall provide a command-line interface. justification: | A CLI interface enables automation in CI/CD pipelines and allows integration with scripts @@ -43,7 +43,7 @@ sections: - Context_Create_NoArguments_ReturnsDefaultContext - Context_Create_MultipleArguments_ParsesAllCorrectly - - id: CLI-002 + - id: ReqStream-Cmd-Version title: The tool shall display version information when requested. justification: | Version information is critical for debugging, support, and ensuring compatibility with @@ -54,7 +54,7 @@ sections: - Program_Run_WithVersionFlag_PrintsVersion - Context_Create_VersionFlag_SetsVersionProperty - - id: CLI-003 + - id: ReqStream-Cmd-Help title: The tool shall display help information when requested. justification: | Help information improves user experience and reduces the learning curve for new users by @@ -65,9 +65,41 @@ sections: - Program_Run_WithHelpFlag_PrintsHelp - Context_Create_HelpFlags_SetsHelpProperty + - id: ReqStream-Cmd-ErrorOutput + title: The tool shall write error messages to stderr. + justification: | + Error messages must be written to stderr so they remain visible to the user + without polluting stdout, which consumers may pipe or redirect for data capture. + tags: + - cli + tests: + - Context_WriteError_NormalMode_WritesToConsole + + - id: ReqStream-Cmd-InvalidArgs + title: The tool shall reject unknown or malformed command-line arguments with a descriptive error. + justification: | + Providing clear feedback for invalid arguments helps users quickly correct + mistakes and prevents silent misconfiguration. + tags: + - cli + tests: + - Context_Create_UnsupportedArgument_ThrowsException + - Context_Create_MissingLogFilename_ThrowsException + - Context_Create_MissingResultsFilename_ThrowsException + + - id: ReqStream-Cmd-ExitCode + title: The tool shall return a non-zero exit code on failure. + justification: | + Callers (scripts, CI/CD pipelines) must be able to detect failure conditions + programmatically via the process exit code. + tags: + - cli + tests: + - Context_WriteError_NormalMode_WritesToConsole + - title: Requirements File Processing requirements: - - id: REQ-001 + - id: ReqStream-Req-YamlProcessing title: The tool shall process YAML requirements files. justification: | YAML provides a human-readable, version-control-friendly format for managing requirements. @@ -79,7 +111,7 @@ sections: - Program_Run_WithRequirementsFiles_ProcessesSuccessfully - Requirements_Read_ComplexStructure_ParsesCorrectly - - id: REQ-002 + - id: ReqStream-Req-GlobPatterns title: The tool shall support glob patterns for requirements files. justification: | Glob patterns enable flexible file selection and reduce the need for explicit file listing, @@ -89,7 +121,7 @@ sections: tests: - Context_Create_WithRequirementsPattern_ExpandsGlobPattern - - id: REQ-003 + - id: ReqStream-Req-Validation title: The tool shall validate requirements file structure. justification: | Early validation prevents runtime errors and ensures requirements data integrity, catching @@ -103,7 +135,7 @@ sections: - Requirements_Read_DuplicateRequirementId_ThrowsException - Requirements_Read_DuplicateRequirementId_ExceptionIncludesFileLocation - - id: REQ-004 + - id: ReqStream-Req-Hierarchy title: The tool shall support hierarchical sections and subsections. justification: | Hierarchical organization allows requirements to be grouped logically by system components, @@ -114,7 +146,7 @@ sections: - Requirements_Read_NestedSections_ParsesHierarchyCorrectly - Requirements_Export_NestedSections_CreatesHierarchy - - id: REQ-005 + - id: ReqStream-Req-Includes title: The tool shall support file includes in requirements files. justification: | File includes enable modular requirements management, allowing teams to organize requirements @@ -126,7 +158,7 @@ sections: - Requirements_Read_MultipleFiles_MergesAllFiles - Requirements_Read_IncludeLoop_DoesNotCauseInfiniteLoop - - id: REQ-006 + - id: ReqStream-Req-SectionMerging title: The tool shall merge sections with the same hierarchy path. justification: | Section merging allows multiple files to contribute to the same logical section, supporting @@ -139,7 +171,7 @@ sections: - title: Requirements Definition requirements: - - id: REQ-007 + - id: ReqStream-Req-UniqueIds title: The tool shall require each requirement to have a unique identifier. justification: | Unique identifiers enable unambiguous referencing of requirements in documentation, test @@ -151,7 +183,7 @@ sections: - Requirements_Read_BlankRequirementId_ThrowsExceptionWithFileLocation - Requirements_Read_MultipleFilesWithDuplicateIds_ThrowsException - - id: REQ-008 + - id: ReqStream-Req-RequiredTitle title: The tool shall require each requirement to have a title. justification: | Titles provide human-readable descriptions of requirements, making them understandable to @@ -161,7 +193,7 @@ sections: tests: - Requirements_Read_BlankRequirementTitle_ThrowsExceptionWithFileLocation - - id: REQ-009 + - id: ReqStream-Req-ParentChild title: The tool shall support parent-child relationships between requirements. justification: | Parent-child relationships enable hierarchical requirement decomposition, allowing high-level @@ -172,7 +204,7 @@ sections: - Requirements_Read_RequirementWithChildren_ParsesChildrenCorrectly - TraceMatrix_Export_WithChildRequirements_ConsidersChildTests - - id: REQ-010 + - id: ReqStream-Req-TestMappings title: The tool shall support test mappings for requirements. justification: | Test mappings establish traceability between requirements and tests, enabling verification @@ -188,7 +220,7 @@ sections: - title: Test Integration requirements: - - id: TEST-001 + - id: ReqStream-Test-ResultFiles title: The tool shall support processing test result files. justification: | Processing test results enables automated verification of requirement satisfaction and @@ -200,7 +232,7 @@ sections: - TraceMatrix_MissingFile_ThrowsFileNotFoundException - TraceMatrix_WithMultipleFiles_AggregatesResults - - id: TEST-002 + - id: ReqStream-Test-TrxFormat title: The tool shall support TRX format test results. justification: | TRX is the native test result format for .NET testing frameworks, enabling seamless @@ -211,7 +243,7 @@ sections: - TraceMatrix_WithTrxFile_ParsesCorrectly - TraceMatrix_WithFailedTests_TracksFailures - - id: TEST-003 + - id: ReqStream-Test-JUnitFormat title: The tool shall support JUnit format test results. justification: | JUnit format is widely used across multiple programming ecosystems, enabling cross-platform @@ -222,7 +254,7 @@ sections: - TraceMatrix_WithJUnitFile_ParsesCorrectly - TraceMatrix_WithJUnitFailedTests_TracksFailures - - id: TEST-004 + - id: ReqStream-Test-GlobPatterns title: The tool shall support glob patterns for test result files. justification: | Glob patterns simplify specification of multiple test result files and enable flexible @@ -233,7 +265,7 @@ sections: - Context_Create_WithTestsPattern_ExpandsGlobPattern - TraceMatrix_WithMixedFormats_ProcessesBoth - - id: TEST-005 + - id: ReqStream-Test-SourceFiltering title: The tool shall support source-specific test matching using filepart@testname pattern. justification: | Source-specific matching enables requirements to reference tests from specific test runs @@ -245,7 +277,7 @@ sections: - TraceMatrix_WithSourceSpecificTests_DoesNotMatchOtherSources - TraceMatrix_WithMultipleSourceSpecifiers_MatchesAllRequirements - - id: TEST-006 + - id: ReqStream-Test-CaseInsensitive title: >- The tool shall perform case-insensitive matching of file parts in source-specific test names. @@ -257,7 +289,7 @@ sections: tests: - TraceMatrix_WithSourceSpecificTests_IsCaseInsensitive - - id: TEST-007 + - id: ReqStream-Test-PartialFilenames title: The tool shall support partial filename matching for source-specific tests. justification: | Partial matching simplifies test specification by allowing short, memorable identifiers @@ -267,7 +299,7 @@ sections: tests: - TraceMatrix_WithSourceSpecificTests_MatchesPartialFilename - - id: TEST-008 + - id: ReqStream-Test-PlainTestNames title: The tool shall support plain test names that aggregate from all sources. justification: | Plain test names enable requirements to aggregate test results across all platforms and @@ -277,7 +309,7 @@ sections: tests: - TraceMatrix_WithPlainTestNames_MatchesAllSources - - id: TEST-009 + - id: ReqStream-Test-MixedTestNames title: >- The tool shall support mixing plain and source-specific test names in the same requirement. @@ -289,7 +321,7 @@ sections: tests: - TraceMatrix_WithMixedTestNames_MatchesAppropriately - - id: TEST-010 + - id: ReqStream-Test-MultipleRequirements title: >- The tool shall match tests to multiple requirements with mixed filter references. @@ -303,7 +335,7 @@ sections: - title: Reporting requirements: - - id: RPT-001 + - id: ReqStream-Rpt-MarkdownExport title: The tool shall export requirements to markdown format. justification: | Markdown export enables requirements to be included in documentation, wikis, and other @@ -316,7 +348,7 @@ sections: - Requirements_Export_MultipleSections_ExportsAll - Requirements_Export_EmptyRequirements_CreatesEmptyFile - - id: RPT-002 + - id: ReqStream-Rpt-HeaderDepth title: The tool shall support configurable markdown header depth for requirements reports. justification: | Configurable header depth allows requirements reports to be embedded in larger documents @@ -327,7 +359,7 @@ sections: - Context_Create_ReportDepth_SetsReportDepthProperty - Requirements_Export_WithCustomDepth_UsesCorrectHeaderLevel - - id: RPT-003 + - id: ReqStream-Rpt-TraceMatrix title: The tool shall export trace matrices to markdown format. justification: | Trace matrix export provides visibility into test coverage and requirement satisfaction, @@ -341,7 +373,7 @@ sections: - TraceMatrix_Export_WithNoTests_ShowsNotSatisfied - TraceMatrix_Export_WithNotExecutedTests_ShowsNotExecuted - - id: RPT-004 + - id: ReqStream-Rpt-TraceMatrixDepth title: The tool shall support configurable markdown header depth for trace matrices. justification: | Configurable header depth allows trace matrices to be embedded in larger documents while @@ -352,7 +384,7 @@ sections: - Context_Create_MatrixDepth_SetsMatrixDepthProperty - Requirements_Export_WithCustomDepth_UsesCorrectHeaderLevel - - id: RPT-005 + - id: ReqStream-Rpt-TagFiltering title: The tool shall support filtering requirements by tags. justification: | Tag-based filtering enables selective export of requirement subsets for focused reports, @@ -370,7 +402,7 @@ sections: - TraceMatrix_CalculateSatisfiedRequirements_WithFilterTags_CountsOnlyMatchingRequirements - TraceMatrix_GetUnsatisfiedRequirements_WithFilterTags_ReturnsOnlyMatchingRequirements - - id: RPT-006 + - id: ReqStream-Rpt-Justifications title: The tool shall export requirement justifications to markdown format. justification: | Justification export enables stakeholders to understand the rationale behind @@ -382,7 +414,7 @@ sections: - Requirements_ExportJustifications_WithoutJustifications_CreatesHeadersOnly - Requirements_ExportJustifications_NestedSections_CreatesHierarchy - - id: RPT-007 + - id: ReqStream-Rpt-JustificationsDepth title: >- The tool shall support configurable markdown header depth for justification reports. @@ -396,7 +428,7 @@ sections: - title: Logging requirements: - - id: LOG-001 + - id: ReqStream-Log-FileOutput title: The tool shall support writing output to a log file. justification: | Log file support enables capturing tool output for debugging, audit trails, and CI/CD @@ -410,7 +442,7 @@ sections: - title: Validation requirements: - - id: VAL-001 + - id: ReqStream-Val-SelfValidation title: The tool shall support self-validation mode. justification: | Self-validation ensures the tool's own integrity and serves as a smoke test for @@ -421,7 +453,7 @@ sections: - Program_Run_WithValidateFlag_RunsValidation - Context_Create_ValidateFlag_SetsValidateProperty - - id: VAL-002 + - id: ReqStream-Val-EnforcementMode title: >- The tool shall support enforcement mode to fail when requirements are not fully tested. @@ -440,7 +472,7 @@ sections: - title: Platform Support requirements: - - id: PLT-001 + - id: ReqStream-Plt-Windows title: The tool shall run on Windows operating systems. justification: | Windows support is essential for .NET developers who primarily work in Windows environments @@ -454,7 +486,7 @@ sections: - "windows@ReqStream_TagsFiltering" - "windows@ReqStream_EnforcementMode" - - id: PLT-002 + - id: ReqStream-Plt-Linux title: The tool shall run on Linux operating systems. justification: | Linux support enables use in containerized CI/CD environments and cloud-based build systems @@ -468,7 +500,7 @@ sections: - "ubuntu@ReqStream_TagsFiltering" - "ubuntu@ReqStream_EnforcementMode" - - id: PLT-004 + - id: ReqStream-Plt-Net8 title: The tool shall support .NET 8.0 runtime. justification: | .NET 8.0 is an LTS release, providing long-term stability and support for enterprise users. @@ -481,7 +513,7 @@ sections: - "dotnet8.x@ReqStream_TagsFiltering" - "dotnet8.x@ReqStream_EnforcementMode" - - id: PLT-005 + - id: ReqStream-Plt-Net9 title: The tool shall support .NET 9.0 runtime. justification: | .NET 9.0 support enables users to leverage the latest .NET features and performance @@ -495,7 +527,7 @@ sections: - "dotnet9.x@ReqStream_TagsFiltering" - "dotnet9.x@ReqStream_EnforcementMode" - - id: PLT-006 + - id: ReqStream-Plt-Net10 title: The tool shall support .NET 10.0 runtime. justification: | .NET 10.0 support ensures the tool remains compatible with the latest .NET ecosystem and @@ -508,3 +540,84 @@ sections: - "dotnet10.x@ReqStream_ReportExport" - "dotnet10.x@ReqStream_TagsFiltering" - "dotnet10.x@ReqStream_EnforcementMode" + + - title: OTS Software + requirements: + - id: ReqStream-OTS-MSTest + title: MSTest shall execute unit tests and report results. + justification: | + MSTest (MSTest.TestFramework and MSTest.TestAdapter) is the unit-testing framework used + by the project. It discovers and runs all test methods and writes TRX result files that + feed into coverage reporting and requirements traceability. Passing tests confirm the + framework is functioning correctly. + tags: [ots] + tests: + - Context_Create_NoArguments_ReturnsDefaultContext + - Context_Create_VersionFlag_SetsVersionProperty + - Context_Create_HelpFlags_SetsHelpProperty + - Context_Create_ValidateFlag_SetsValidateProperty + - Context_Create_EnforceFlag_SetsEnforceProperty + - Requirements_Read_SimpleRequirement_ParsesCorrectly + - Program_Run_WithVersionFlag_PrintsVersion + - Program_Run_WithHelpFlag_PrintsHelp + + - id: ReqStream-OTS-ReqStream + title: ReqStream shall enforce that every requirement is linked to passing test evidence. + justification: | + DemaConsulting.ReqStream processes requirements.yaml and the TRX test-result files to + produce a requirements report, justifications document, and traceability matrix. When + run with --enforce, it exits with a non-zero code if any requirement lacks test evidence, + making unproven requirements a build-breaking condition. A successful pipeline run with + --enforce proves all requirements are covered and that ReqStream is functioning. + tags: [ots] + tests: + - ReqStream_EnforcementMode + + - id: ReqStream-OTS-BuildMark + title: BuildMark shall generate build-notes documentation from GitHub Actions metadata. + justification: | + DemaConsulting.BuildMark queries the GitHub API to capture workflow run details and + renders them as a markdown build-notes document included in the release artifacts. + It runs as part of the same CI pipeline that produces the TRX test results, so a + successful pipeline run is evidence that BuildMark executed without error. + tags: [ots] + tests: + - BuildMark_MarkdownReportGeneration + + - id: ReqStream-OTS-VersionMark + title: VersionMark shall publish captured tool-version information. + justification: | + DemaConsulting.VersionMark reads version metadata for each dotnet tool used in the + pipeline and writes a versions markdown document included in the release artifacts. + It runs in the same CI pipeline that produces the TRX test results, so a successful + pipeline run is evidence that VersionMark executed without error. + tags: [ots] + tests: + - VersionMark_CapturesVersions + - VersionMark_GeneratesMarkdownReport + + - id: ReqStream-OTS-SarifMark + title: SarifMark shall convert CodeQL SARIF results into a markdown report. + justification: | + DemaConsulting.SarifMark reads the SARIF output produced by CodeQL code scanning and + renders it as a human-readable markdown document included in the release artifacts. + It runs in the same CI pipeline that produces the TRX test results, so a successful + pipeline run is evidence that SarifMark executed without error. + tags: [ots] + tests: + - SarifMark_SarifReading + - SarifMark_MarkdownReportGeneration + + - id: ReqStream-OTS-SonarMark + title: SonarMark shall generate a SonarCloud quality report. + justification: | + DemaConsulting.SonarMark retrieves quality-gate and metrics data from SonarCloud and + renders it as a markdown document included in the release artifacts. It runs in the + same CI pipeline that produces the TRX test results, so a successful pipeline run is + evidence that SonarMark executed without error. + tags: [ots] + tests: + - SonarMark_QualityGateRetrieval + - SonarMark_IssuesRetrieval + - SonarMark_HotSpotsRetrieval + - SonarMark_MarkdownReportGeneration diff --git a/src/DemaConsulting.ReqStream/Context.cs b/src/DemaConsulting.ReqStream/Context.cs index a216a2a..a3551c2 100644 --- a/src/DemaConsulting.ReqStream/Context.cs +++ b/src/DemaConsulting.ReqStream/Context.cs @@ -353,7 +353,7 @@ public static Context Create(string[] args) { try { - result._logWriter = new StreamWriter(logFile, append: false); + result._logWriter = new StreamWriter(logFile, append: false) { AutoFlush = true }; } catch (Exception ex) { @@ -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.ReqStream/DemaConsulting.ReqStream.csproj b/src/DemaConsulting.ReqStream/DemaConsulting.ReqStream.csproj index 9c61e99..c58abe8 100644 --- a/src/DemaConsulting.ReqStream/DemaConsulting.ReqStream.csproj +++ b/src/DemaConsulting.ReqStream/DemaConsulting.ReqStream.csproj @@ -46,19 +46,27 @@ Organization: $(Company) + - + + + + - + + + + + + all runtime; build; native; contentfiles; analyzers; buildtransitive @@ -67,11 +75,6 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/src/DemaConsulting.ReqStream/Program.cs b/src/DemaConsulting.ReqStream/Program.cs index b84ce08..4e1067e 100644 --- a/src/DemaConsulting.ReqStream/Program.cs +++ b/src/DemaConsulting.ReqStream/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; } } diff --git a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs index f61fd43..1a47407 100644 --- a/test/DemaConsulting.ReqStream.Tests/ContextTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/ContextTests.cs @@ -353,9 +353,9 @@ public void Context_WriteLine_SilentMode_DoesNotWriteToConsole() [TestMethod] public void Context_WriteError_NormalMode_WritesToConsole() { - var originalOut = Console.Out; + var originalError = Console.Error; using var output = new StringWriter(); - Console.SetOut(output); + Console.SetError(output); try { @@ -367,7 +367,7 @@ public void Context_WriteError_NormalMode_WritesToConsole() } finally { - Console.SetOut(originalOut); + Console.SetError(originalError); } } @@ -377,9 +377,9 @@ public void Context_WriteError_NormalMode_WritesToConsole() [TestMethod] public void Context_WriteError_SilentMode_DoesNotWriteToConsole() { - var originalOut = Console.Out; + var originalError = Console.Error; using var output = new StringWriter(); - Console.SetOut(output); + Console.SetError(output); try { @@ -391,7 +391,7 @@ public void Context_WriteError_SilentMode_DoesNotWriteToConsole() } finally { - Console.SetOut(originalOut); + Console.SetError(originalError); } } diff --git a/test/DemaConsulting.ReqStream.Tests/DemaConsulting.ReqStream.Tests.csproj b/test/DemaConsulting.ReqStream.Tests/DemaConsulting.ReqStream.Tests.csproj index 5f26690..ca0eef7 100644 --- a/test/DemaConsulting.ReqStream.Tests/DemaConsulting.ReqStream.Tests.csproj +++ b/test/DemaConsulting.ReqStream.Tests/DemaConsulting.ReqStream.Tests.csproj @@ -3,7 +3,7 @@ net8.0;net9.0;net10.0 - 12 + latest enable enable diff --git a/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs b/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs index 4815102..5e34bf8 100644 --- a/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs +++ b/test/DemaConsulting.ReqStream.Tests/ProgramTests.cs @@ -489,32 +489,35 @@ public void Program_Run_WithEnforcementAndUnsatisfiedRequirements_Fails() // Save current directory and change to test directory var originalDir = Directory.GetCurrentDirectory(); - var originalOut = Console.Out; - using var output = new StringWriter(); - Console.SetOut(output); + var logFile = Path.Combine(_testDirectory, "enforcement-test.log"); try { Directory.SetCurrentDirectory(_testDirectory); - using var context = Context.Create([ + int exitCode; + using (var context = Context.Create([ "--requirements", "*.yaml", "--tests", "*.trx", - "--enforce" - ]); - Program.Run(context); - - Assert.AreEqual(1, context.ExitCode); - - // Verify error message includes the unsatisfied requirement - var outputText = output.ToString(); - Assert.Contains("Only 1 of 2 requirements are satisfied", outputText); - Assert.Contains("Unsatisfied requirements:", outputText); - Assert.Contains("REQ-002", outputText); + "--enforce", + "--silent", + "--log", logFile + ])) + { + Program.Run(context); + exitCode = context.ExitCode; + } + + Assert.AreEqual(1, exitCode); + + // Verify error message includes the unsatisfied requirement via log file + var logContent = File.ReadAllText(logFile); + Assert.Contains("Only 1 of 2 requirements are satisfied", logContent); + Assert.Contains("Unsatisfied requirements:", logContent); + Assert.Contains("REQ-002", logContent); } finally { - Console.SetOut(originalOut); Directory.SetCurrentDirectory(originalDir); } }