diff --git a/.cspell.yaml b/.cspell.yaml index 8a47c5c..70bace4 100644 --- a/.cspell.yaml +++ b/.cspell.yaml @@ -39,6 +39,9 @@ words: - unconfigured - unparseable - tagobj + - hotspots + - inclusivity + - Postconditions - wiql - workitems - yamlfix diff --git a/.fileassert.yaml b/.fileassert.yaml index 1e5ea7b..ff60396 100644 --- a/.fileassert.yaml +++ b/.fileassert.yaml @@ -36,7 +36,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Build notes" + contains: "Build Notes for BuildMark" pages: min: 1 text: @@ -69,7 +69,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Code Quality" + contains: "Code Quality Report for BuildMark" pages: min: 1 text: @@ -102,7 +102,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Review Plan" + contains: "Code Review Plan for BuildMark" pages: min: 1 text: @@ -135,7 +135,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Review Report" + contains: "Code Review Report for BuildMark" pages: min: 1 text: @@ -168,7 +168,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "design document" + contains: "Software Design Document for BuildMark" pages: min: 3 text: @@ -201,7 +201,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Verification design document" + contains: "Verification Design Document for BuildMark" pages: min: 3 text: @@ -234,7 +234,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Build Notes Generation" + contains: "User Guide for BuildMark" pages: min: 3 text: @@ -268,7 +268,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Requirements" + contains: "Requirements Document for BuildMark" pages: min: 1 text: @@ -302,7 +302,7 @@ tests: - field: "Author" contains: "DEMA Consulting" - field: "Subject" - contains: "Traceability" + contains: "Trace Matrix for BuildMark" pages: min: 1 text: diff --git a/.github/agents/template-sync.agent.md b/.github/agents/template-sync.agent.md index 44d29ff..c013503 100644 --- a/.github/agents/template-sync.agent.md +++ b/.github/agents/template-sync.agent.md @@ -31,8 +31,15 @@ For each group intersecting the requested scope, call a sub-agent with: - **context**: - Group scope and template URL from the `# Reference Template` section in `AGENTS.md` + - Applicable standards from the `# Standards Application` matrix in `AGENTS.md` + for the file types in the group scope - Project-specific names substitute for placeholders at matching path depth - (e.g. `SystemName` → `{SystemName}`, `system-name` → `{system-name}`) + (e.g. `MySystem` → `{SystemName}`, `my-system` → `{system-name}`) + - For files within `{system-name}/` subtrees in `docs/design/`, `docs/verification/`, + and `docs/reqstream/`: consult `docs/design/introduction.md` to determine whether + each item is a subsystem or unit, then select the appropriate template + (`subsystem-name.*` or `unit-name.*`) regardless of the item's folder depth — + do not infer item type from path depth alone - If a template counterpart cannot be fetched, skip the file and report it - **goal**: - Based on the given mode: @@ -42,15 +49,38 @@ For each group intersecting the requested scope, call a sub-agent with: - **Scaffold** - fetch `repository-map.md` from the template URL in `AGENTS.md` to identify files that should exist but don't; for each, fetch the template, populate all sections, write the file; run `pwsh ./fix.ps1` - - **Recreate** - read the existing file in full, then fetch the template; use - full semantic understanding to map old content onto template sections, - splitting or consolidating as needed; create extra sections for any content - that has no template home; write the rebuilt file; run `pwsh ./fix.ps1` - - When writing any section: HTML comments and TODO placeholders in the template - are instructions - always resolve them to real content; infer from README, - related files, sibling docs, and path; if confident write directly; if - ambiguous offer 2–3 concrete options and ask the user; keep asking until they - answer - never leave a TODO unless the user explicitly requests it + - **Recreate** - fetch the template and use it as the blueprint for a + freshly authored document: + - Work through the template section by section; for each section, find + any `TEMPLATE-DIRECTIVE` blocks (both `` + in markdown and `# ` in YAML) — execute + each directive (read specified standards, apply structural guidance, + substitute content), then **remove the directive block entirely** from + the output; gather the relevant technical details from all available + sources — the old file, README, related docs, sibling files, and any + other repo context — to populate that section correctly; the old file's + structure and headings are irrelevant; only its factual content is mined + as a source + - **Gap-check**: after all template sections are filled, scan the old + file once more for any technical information not yet captured; if + found, preserve it by appending new relevant sections at the end + - **Before writing**: do a mandatory self-check — for every section that + has a `TEMPLATE-DIRECTIVE` block in the template, explicitly state what + format the directive requires, then verify the drafted content matches + that format exactly (e.g. if the directive says "no sub-headings", + confirm there are no `###` headings inside that section; if it says + "bold-name paragraph blocks", confirm each entry is `**Name**: prose` + with no sub-heading); fix any mismatches before writing the file + - Write the rebuilt file; run `pwsh ./fix.ps1` + - When writing any section: `TEMPLATE-DIRECTIVE` blocks are directives — + execute them (read specified standards, apply structural guidance, substitute + content) and **remove the block entirely** from the written file; inline + `TODO:` placeholders in YAML string values (e.g. `title:`, `justification:`) + are content placeholders — always resolve them to real content; infer from + README, related files, sibling docs, and path; if confident write directly; + if ambiguous offer 2–3 concrete options and ask the user; keep asking until + they answer - never leave a TODO or TEMPLATE-DIRECTIVE in the output unless + the user explicitly requests it Collect sub-agent results and assemble the final report. @@ -69,6 +99,8 @@ Collect sub-agent results and assemble the final report. - **Template**: {template path} - **Missing sections**: {list or "none"} - **Heading depth issues**: {list or "none"} +- **Content format issues**: {list of sections where intra-section content did not + match the template comment's prescribed format, or "none"} *(Recreate only)* - **Action**: (Reported | Sections added | Created | Rebuilt | No template found) ## Summary diff --git a/.github/standards/coding-principles.md b/.github/standards/coding-principles.md index 9e67fbb..6797c61 100644 --- a/.github/standards/coding-principles.md +++ b/.github/standards/coding-principles.md @@ -3,11 +3,6 @@ name: Coding Principles description: Follow these standards when developing any software code. --- -# Coding Principles Standards - -This document defines universal coding principles and quality standards for software development within -Continuous Compliance environments. - # Core Principles ## Literate Coding @@ -20,10 +15,9 @@ All code MUST follow literate programming principles: matches design intent without reading the full codebase - **Logical Separation**: Complex functions use block comments to separate and describe logical steps within the implementation -- **Full Symbol Documentation**: ALL symbols have comprehensive documentation - because reviewers and auditors must verify every implementation detail, not - just the public interface - access-level specifics (public, protected, - private, internal, etc.) vary by language; see the language-specific standard +- **Full Symbol Documentation**: ALL symbols have comprehensive documentation — + not just the public interface, because reviewers and auditors must verify every + implementation detail. Access-level specifics vary by language; see the language-specific standard. - **Clarity Over Cleverness**: Code should be immediately understandable by team members ## API Documentation @@ -79,13 +73,13 @@ interface correctly without reading the implementation: ## Universal Anti-Patterns -- **Skip Literate Coding**: Don't skip literate programming comments - they are required for maintainability -- **Ignore Compiler Warnings**: Don't ignore compiler warnings - they exist for quality enforcement +- **Skip Literate Coding**: Don't skip literate programming comments +- **Ignore Compiler Warnings**: Don't ignore compiler warnings - **Hidden Dependencies**: Don't create untestable code with hidden dependencies - **Hidden Functionality**: Don't implement functionality without requirement traceability because untraced functionality cannot be validated during audits - **Monolithic Functions**: Don't write monolithic functions with multiple responsibilities -- **Overcomplicated Solutions**: Don't make solutions more complex than necessary - favor simplicity and clarity +- **Overcomplicated Solutions**: Don't make solutions more complex than necessary - **Premature Optimization**: Don't optimize for performance before establishing correctness - **Copy-Paste Programming**: Don't duplicate logic - extract common functionality into reusable components - **Magic Numbers**: Don't use unexplained constants - either name them or add clear comments diff --git a/.github/standards/csharp-language.md b/.github/standards/csharp-language.md index 6df39cd..ec05a25 100644 --- a/.github/standards/csharp-language.md +++ b/.github/standards/csharp-language.md @@ -12,9 +12,6 @@ Read these standards first before applying this standard: # API Documentation and Literate Coding Example -The example below demonstrates good XmlDoc API documentation combined with -literate coding comments. - ```csharp /// /// Converts a raw sensor reading into a validated measurement ready for downstream consumers. diff --git a/.github/standards/csharp-testing.md b/.github/standards/csharp-testing.md index 181de02..1f93b72 100644 --- a/.github/standards/csharp-testing.md +++ b/.github/standards/csharp-testing.md @@ -66,8 +66,6 @@ These are non-obvious v3 behaviors that differ from v2 or common assumptions: # Quality Checks -Before submitting C# tests, verify: - - [ ] All tests follow AAA pattern with clear section comments - [ ] Test names follow hierarchical naming pattern above - [ ] Each test verifies single, specific behavior (no shared state between tests) diff --git a/.github/standards/design-documentation.md b/.github/standards/design-documentation.md index 635cb6d..e5b7bf9 100644 --- a/.github/standards/design-documentation.md +++ b/.github/standards/design-documentation.md @@ -28,7 +28,9 @@ docs/design/ └── {package-name}.md # heading depth ## ``` -Subsystems may nest recursively. Each file's heading depth equals its folder depth under `docs/design/`. +All sections in every file are mandatory; write "N/A - {justification}" rather than removing any. +Determine subsystem vs. unit classification from `docs/design/introduction.md` — folder depth does not determine classification. +Do not record version numbers anywhere in design documentation — version information is managed in SBOMs. # introduction.md (MANDATORY) @@ -43,8 +45,7 @@ Must include: # System Design (MANDATORY) -Create `{system-name}.md` (`#` heading) and `{system-name}/` folder. All sections mandatory; -write "N/A - {justification}" rather than removing any section: +Create `{system-name}.md` (`#` heading) and `{system-name}/` folder: - **Architecture**: software items, relationships, and collaboration - **External Interfaces**: name, direction, format, constraints @@ -55,8 +56,7 @@ write "N/A - {justification}" rather than removing any section: # Subsystem Design (MANDATORY) -Place `{subsystem-name}.md` in the **parent** folder; create `{subsystem-name}/` for children. -All sections mandatory; write "N/A - {justification}" rather than removing any section: +Place `{subsystem-name}.md` in the **parent** folder; create `{subsystem-name}/` for children: - **Overview**: responsibility, boundaries, contained units - **Interfaces**: what it exposes and consumes @@ -64,28 +64,34 @@ All sections mandatory; write "N/A - {justification}" rather than removing any s # Unit Design (MANDATORY) -Place `{unit-name}.md` in the **parent** folder. All sections mandatory; -write "N/A - {justification}" rather than removing any section: +Place `{unit-name}.md` in the **parent** folder: - **Purpose**: single responsibility - **Data Model**: fields, properties, types, invariants (IEC 62304 §5.4.2) - **Key Methods**: name, purpose, algorithm, preconditions, postconditions, parameter types - **Error Handling**: detection and handling; what is propagated vs. handled locally -- **Interactions**: dependencies on other units/subsystems/OTS; who calls this unit +- **Dependencies**: other units, subsystems, OTS items, and shared packages used +- **Callers**: units or subsystems that call or consume this unit # OTS Integration Design (when OTS items exist) Create `docs/design/ots.md` (`#` heading) covering the overall OTS integration strategy. -For each OTS item, create `docs/design/ots/{ots-name}.md` (`##` heading) covering: -why chosen, which features/APIs used, integration patterns, version constraints. +For each OTS item, create `docs/design/ots/{ots-name}.md` (`##` heading) with sections: + +- **Purpose**: why chosen and what it provides to the local system +- **Features Used**: which specific features, APIs, or capabilities are consumed +- **Integration Pattern**: how it is consumed; initialization, configuration, disposal requirements # Shared Package Integration Design (when Shared Packages exist) Create `docs/design/shared.md` (`#` heading) covering the overall consumption strategy. -For each Shared Package, create `docs/design/shared/{package-name}.md` (`##` heading) covering: -which advertised features are consumed, integration pattern, configuration/initialization. +For each Shared Package, create `docs/design/shared/{package-name}.md` (`##` heading) with sections: + +- **Advertised Features Consumed**: which features the local system relies on +- **Integration Pattern**: how the package is referenced, initialized, and consumed +- **Assumptions**: any assumptions the local system makes about the package's behavior # Writing Guidelines @@ -102,7 +108,7 @@ which advertised features are consumed, integration pattern, configuration/initi - [ ] System design includes all mandatory sections (Architecture, External Interfaces, Dependencies, Risk Control Measures, Data Flow, Design Constraints) - [ ] Subsystem design includes all mandatory sections (Overview, Interfaces, Design) -- [ ] Unit design includes all mandatory sections (Purpose, Data Model, Key Methods, Error Handling, Interactions) +- [ ] Unit design includes all mandatory sections (Purpose, Data Model, Key Methods, Error Handling, Dependencies, Callers) - [ ] Non-applicable mandatory sections contain "N/A - {justification}" - [ ] `docs/design/ots.md` and `docs/design/ots/{ots-name}.md` exist when OTS items are present - [ ] `docs/design/shared.md` and `docs/design/shared/{package-name}.md` exist when Shared Packages are present diff --git a/.github/standards/reqstream-usage.md b/.github/standards/reqstream-usage.md index 95d36a1..2371164 100644 --- a/.github/standards/reqstream-usage.md +++ b/.github/standards/reqstream-usage.md @@ -25,8 +25,8 @@ docs/reqstream/ │ ├── platform-requirements.yaml # Platform support requirements │ ├── {subsystem-name}.yaml # Subsystem requirements │ ├── {subsystem-name}/ # Subsystem folder (kebab-case); may nest recursively -│ │ ├── {child-subsystem}.yaml # Child subsystem requirements -│ │ ├── {child-subsystem}/ # Child subsystem folder +│ │ ├── {subsystem-name}.yaml # Child subsystem requirements +│ │ ├── {subsystem-name}/ # Child subsystem folder │ │ └── {unit-name}.yaml # Unit requirements │ └── {unit-name}.yaml # System-level unit requirements ├── ots/ # OTS items appear as a distinct section in reports @@ -35,62 +35,66 @@ docs/reqstream/ └── {package-name}.yaml # Requirements for Shared Package dependencies ``` -Local items have matching relative paths across `docs/reqstream/`, `docs/design/`, and -`docs/verification/`. OTS items appear in `docs/reqstream/ots/`, `docs/design/ots/`, and -`docs/verification/ots/`. Shared Packages appear in `docs/reqstream/shared/`, -`docs/design/shared/`, and `docs/verification/shared/`. +Local items have matching relative paths across `docs/reqstream/`, `docs/design/`, and `docs/verification/`: + +- Requirements: `{system-name}[/{subsystem-name}...]/{item-name}.yaml` +- Design: `{system-name}[/{subsystem-name}...]/{item-name}.md` +- Verification: `{system-name}[/{subsystem-name}...]/{item-name}.md` # Requirements File Format -```yaml -sections: - - title: Functional Requirements - requirements: - - id: System-Component-Feature # Used as-is in all reports - make it readable - title: The system shall perform the required function. - justification: | - Business rationale and any regulatory references. - # ReqStream extracts this field into the justifications report (--justifications) - children: # ReqStream validates this decomposition chain - - ChildSystem-Feature-Behavior # Downward links only (see requirements-principles.md) - tests: # ReqStream matches these by method name in test results - - TestMethodName - - windows@PlatformSpecificTest # Only test runs on Windows count as evidence -``` +Each file adds requirements at exactly one level of the hierarchy. The file spells out +its full ancestry as nested `{ItemName} Requirements` sections down to that level, then +places requirements there. ReqStream merges identical section title paths across included +files automatically. Always determine item classification from `docs/design/introduction.md` - +folder depth does not determine whether an item is a subsystem or unit. -# OTS Software Requirements +Valid section nestings (names in `{braces}` are placeholders): + +```text +{SystemName} Requirements # system-level requirements +├── {SubsystemName} Requirements # root subsystem requirements +│ ├── {SubsystemName} Requirements # nested subsystem (may recurse) +│ │ └── {UnitName} Requirements # unit under a nested subsystem +│ └── {UnitName} Requirements # unit under a root subsystem +└── {UnitName} Requirements # unit directly under the system +OTS Software Requirements # OTS root section (fixed title) +└── {OtsName} Requirements # requirements for one OTS item +Shared Package Requirements # shared package root section (fixed title) +└── {PackageName} Requirements # requirements for one shared package +``` -Use nested sections in `docs/reqstream/ots/` because ReqStream renders the `ots/` -subtree as a distinct section in generated reports, separate from local -system requirements: +Each file implements one path through this tree: ```yaml sections: - - title: OTS Software Requirements + - title: '{SystemName} Requirements' sections: - - title: System.Text.Json + - title: '{SubsystemName} Requirements' requirements: - - id: SystemTextJson-Core-ReadJson - title: System.Text.Json shall be able to read JSON files. - tests: - - JsonReaderTests.TestReadValidJson + - id: System-Subsystem-Feature # Used as-is in all reports - make it readable + title: The subsystem shall perform the required function. + justification: | # ReqStream extracts this into the justifications report (--justifications) + Business rationale and any regulatory references. + tags: # Optional: categorize for filtering with --filter + - security + children: # Optional: ReqStream validates this decomposition chain + - System-Subsystem-Unit-Feat # Downward links only (see requirements-principles.md) + tests: # ReqStream matches these by method name in test results + - TestMethodName + - windows@PlatformSpecificTest # Only test runs on Windows count as evidence ``` -# Shared Package Requirements +# Tags (OPTIONAL) -Use nested sections in `docs/reqstream/shared/` - ReqStream renders the `shared/` -subtree as a distinct section in reports, separate from local and OTS requirements: +Tags are free-form - no mandatory vocabulary. Common tags: `security`, `safety`, `performance`, +`compliance`, `reliability`, `critical`. Use `--filter` to selectively export or enforce subsets +(OR logic across comma-separated tags): -```yaml -sections: - - title: Shared Package Requirements - sections: - - title: MyOrg.SharedLibrary - requirements: - - id: SharedLibrary-Core-ParseConfig - title: MyOrg.SharedLibrary shall parse configuration files. - tests: - - SharedLibraryIntegrationTests.TestParseValidConfig +```bash +dotnet reqstream --requirements requirements.yaml \ + --filter security,critical \ + --report docs/requirements_doc/generated/security_requirements.md ``` # Semantic IDs (MANDATORY) @@ -145,13 +149,9 @@ dotnet reqstream --requirements requirements.yaml \ Before submitting requirements, verify: -- [ ] All requirements have semantic IDs (`System-Section-Feature` pattern) -- [ ] Every requirement links to at least one passing test +- [ ] All requirements have semantic IDs (`System-Component-Feature` pattern) +- [ ] Every requirement has a justification explaining business/regulatory need +- [ ] Every requirement links to at least one test - [ ] Platform-specific requirements use source filters (`platform@TestName`) -- [ ] Comprehensive justification explains business/regulatory need -- [ ] Files organized under `docs/reqstream/` following the folder structure pattern above -- [ ] All documentation folders use kebab-case names matching source code structure -- [ ] OTS requirements placed in `ots/` subfolder -- [ ] Shared Package requirements placed in `shared/` subfolder -- [ ] Valid YAML syntax passes yamllint validation -- [ ] Test result formats compatible (TRX, JUnit XML) +- [ ] All files and folders use kebab-case names matching source code structure +- [ ] All files are organized under `docs/reqstream/` following the folder structure above diff --git a/.github/standards/reviewmark-usage.md b/.github/standards/reviewmark-usage.md index 990d707..b521433 100644 --- a/.github/standards/reviewmark-usage.md +++ b/.github/standards/reviewmark-usage.md @@ -88,12 +88,11 @@ When constructing review-sets, follow these principles to maintain manageable sc # Review-Set Organization -Organize review-sets using these standard patterns to ensure comprehensive coverage -while keeping each review manageable in scope: - -**Naming conventions**: See `software-items.md` - kebab-case placeholders -(e.g., `{system-name}`) are always kebab-case; cased placeholders -(e.g., `{SystemName}`) follow your language's convention. +**Naming conventions**: Placeholders in documentation, requirements, design, and +verification file paths are kebab-case (e.g., `{system-name}`). Placeholders in +source and test file paths may use the casing conventional for the project's +source language or repository layout (e.g., `{SystemName}`). Review-set name +placeholders are always PascalCase (e.g., `{SystemName}`). ## `Purpose` Review (only one per repository) @@ -110,12 +109,12 @@ Reviews user-facing capabilities and system promises: - Design introduction: `docs/design/introduction.md` - System design: `docs/design/{system-name}.md` -## `{System}-Architecture` Review (one per system) +## `{SystemName}-Architecture` Review (one per system) Reviews system architecture and operational validation: - **Purpose**: Proves that the system is designed and tested to satisfy its requirements -- **Title**: "Review that {System} Architecture Satisfies Requirements" +- **Title**: "Review that {SystemName} Architecture Satisfies Requirements" - **Scope**: Excludes subsystem and unit files, relying on system-level design to describe what subsystems and units it uses - **File Path Patterns**: @@ -126,12 +125,12 @@ Reviews system architecture and operational validation: - System verification design: `docs/verification/{system-name}.md` - System integration tests: `test/{SystemName}.Tests/{SystemName}Tests.{ext}` -## `{System}-Design` Review (one per system) +## `{SystemName}-Design` Review (one per system) Reviews architectural and design consistency: - **Purpose**: Proves the system design is consistent and complete -- **Title**: "Review that {System} Design is Consistent and Complete" +- **Title**: "Review that {SystemName} Design is Consistent and Complete" - **Scope**: Only brings in top-level requirements and relies on brevity of design documentation - **File Path Patterns**: - System requirements: `docs/reqstream/{system-name}.yaml` @@ -142,12 +141,12 @@ Reviews architectural and design consistency: - OTS overview: `docs/design/ots.md` _(only if OTS items exist)_ - Shared Package overview: `docs/design/shared.md` _(only if Shared Package items exist)_ -## `{System}-Verification` Review (one per system) +## `{SystemName}-Verification` Review (one per system) Reviews verification completeness and consistency: - **Purpose**: Proves the system verification design is consistent and covers all requirements -- **Title**: "Review that {System} Verification is Consistent and Complete" +- **Title**: "Review that {SystemName} Verification is Consistent and Complete" - **Scope**: Only brings in top-level requirements and all verification docs for the system - **File Path Patterns**: - System requirements: `docs/reqstream/{system-name}.yaml` @@ -157,45 +156,47 @@ Reviews verification completeness and consistency: - OTS overview: `docs/verification/ots.md` _(only if OTS items exist)_ - Shared Package overview: `docs/verification/shared.md` _(only if Shared Package items exist)_ -## `{System}-AllRequirements` Review (one per system) +## `{SystemName}-AllRequirements` Review (one per system) Reviews requirements quality and traceability: - **Purpose**: Proves the requirements are consistent and complete -- **Title**: "Review that All {System} Requirements are Complete" +- **Title**: "Review that All {SystemName} Requirements are Complete" - **Scope**: Only brings in requirements files to keep review manageable - **File Path Patterns**: - Root requirements: `requirements.yaml` - System requirements: `docs/reqstream/{system-name}.yaml` - Subsystem/unit requirements: `docs/reqstream/{system-name}/**/*.yaml` -## `{System}-{Subsystem[-Child...]}` Review (one per subsystem at any depth) +## `{SystemName}-{SubsystemName}[-{SubsystemName}...]` Review (one per subsystem at any depth) Reviews subsystem architecture and interfaces: - **Purpose**: Proves that the subsystem is designed and tested to satisfy its requirements -- **Title**: "Review that {System} {Subsystem} Satisfies Subsystem Requirements" +- **Title**: "Review that {SystemName} {SubsystemName} Satisfies Subsystem Requirements" - **Scope**: Excludes units under the subsystem, relying on subsystem design to describe what units it uses - **File Path Patterns**: - - Requirements: `docs/reqstream/{system-name}/.../{subsystem-name}.yaml` - - Design: `docs/design/{system-name}/.../{subsystem-name}.md` - - Verification design: `docs/verification/{system-name}/.../{subsystem-name}.md` - - Tests: `test/{SystemName}.Tests/.../{SubsystemName}/{SubsystemName}Tests.{ext}` + - Requirements: `docs/reqstream/{system-name}[/{subsystem-name}...]/{subsystem-name}.yaml` + - Design: `docs/design/{system-name}[/{subsystem-name}...]/{subsystem-name}.md` + - Verification design: `docs/verification/{system-name}[/{subsystem-name}...]/{subsystem-name}.md` + - Tests: `test/{SystemName}.Tests[/{SubsystemName}...]/{SubsystemName}Tests.{ext}` -## `{System}-{Subsystem[-Child...]}-{Unit}` Review (one per unit) +## `{SystemName}-{SubsystemName}[-{SubsystemName}...]-{UnitName}` Review (one per unit) Reviews individual software unit implementation: - **Purpose**: Proves the unit is designed, implemented, and tested to satisfy its requirements -- **Title**: "Review that {System} {Subsystem} {Unit} Implementation is Correct" +- **Title**: "Review that {SystemName} {SubsystemName} {UnitName} Implementation is Correct" - **Scope**: Complete unit review including all artifacts - **File Path Patterns**: - - Requirements: `docs/reqstream/{system-name}/.../{unit-name}.yaml` - - Design: `docs/design/{system-name}/.../{unit-name}.md` - - Verification design: `docs/verification/{system-name}/.../{unit-name}.md` - - Source: `src/{SystemName}/.../{UnitName}.{ext}` - - Tests: `test/{SystemName}.Tests/.../{UnitName}Tests.{ext}` + - Requirements: `docs/reqstream/{system-name}[/{subsystem-name}...]/{unit-name}.yaml` + - Design: `docs/design/{system-name}[/{subsystem-name}...]/{unit-name}.md` + - Verification design: `docs/verification/{system-name}[/{subsystem-name}...]/{unit-name}.md` + - Source (C# example): `src/{SystemName}[/{SubsystemName}...]/{UnitName}.cs` + - Tests (C# example): `test/{SystemName}.Tests[/{SubsystemName}...]/{UnitName}Tests.cs` + - Source (snake_case C++ example): `src/{system_name}[/{subsystem_name}...]/{unit_name}.cpp` + - Tests (snake_case C++ example): `test/{system_name}_tests[/{subsystem_name}...]/{unit_name}_tests.cpp` ## `OTS-{OtsName}` Review (one per OTS item) @@ -208,7 +209,8 @@ Reviews OTS item integration design, requirements, and verification evidence: - OTS requirements: `docs/reqstream/ots/{ots-name}.yaml` - OTS integration design: `docs/design/ots/{ots-name}.md` - OTS verification: `docs/verification/ots/{ots-name}.md` - - Tests (if applicable): `test/{OtsSoftwareTests}/...` (cased per language) + - Tests (if applicable): `test/OtsSoftwareTests/...` (C#) or `test/ots_software_tests/...` + (Python/other) — fixed repo-level name, no system prefix ## `Shared-{PackageName}` Review (one per Shared Package) @@ -231,17 +233,6 @@ Before submitting ReviewMark configuration, verify: - [ ] `.reviewmark.yaml` exists at repository root with proper structure - [ ] Review-set organization follows the standard hierarchy patterns -- [ ] Purpose review-set includes README.md, user guide, system requirements, design introduction, and system design files -- [ ] System-level reviews follow hierarchical scope principle (exclude subsystem/unit details) -- [ ] Subsystem reviews follow hierarchical scope principle (exclude unit source code) -- [ ] Only unit reviews include actual source code files -- [ ] Architecture review-sets include system verification design alongside system design -- [ ] Design review-sets include all system design files -- [ ] Verification review-sets include all system verification files -- [ ] Subsystem review-sets include subsystem verification design -- [ ] Unit review-sets include unit verification design -- [ ] OTS review-sets include OTS requirements, integration design, and verification evidence -- [ ] Shared Package review-sets include Shared Package requirements, integration design, and verification evidence - [ ] Each review-set focuses on a single compliance question (single focus principle) - [ ] File patterns use correct glob syntax and match intended files - [ ] Review-set file counts remain manageable (context management principle) diff --git a/.github/standards/software-items.md b/.github/standards/software-items.md index 328a08e..6c29525 100644 --- a/.github/standards/software-items.md +++ b/.github/standards/software-items.md @@ -3,12 +3,6 @@ name: Software Items description: Follow these standards when categorizing software components. --- -# Software Items Definition Standards - -This document defines standards for categorizing software items within -Continuous Compliance environments because proper categorization determines -requirements management approach, testing strategy, and review scope. - # Software Item Categories Categorize all software into six primary groups: @@ -40,17 +34,28 @@ Categorize all software into six primary groups: # Naming Conventions in File Path Patterns -Two placeholder styles appear in path patterns across these standards: +Three placeholder forms appear in path patterns across these standards: -- **Kebab-case** (`{system-name}`, `{unit-name}`): always kebab-case - - used in documentation and requirements paths -- **Cased** (`{SystemName}`, `{UnitName}`): follow your language's convention - - `PascalCase` for C#/Java, `snake_case` for C++/Python - - used in source and test file paths +- **Kebab-case** (`{system-name}`, `{unit-name}`): always kebab-case — + documentation and requirements file paths +- **PascalCase IDs** (`{SystemName}`, `{UnitName}`): always PascalCase — + requirements IDs, ReviewMark IDs, and other documentation identifiers +- **Language-cased** (`{SystemName}` or `{system_name}`): follow your language's + convention — `PascalCase` for C#/Java, `snake_case` for C++/Python — + source and test file/folder names -# Categorization Guidelines +## Nesting Depth Notation -Choose the appropriate category based on scope and testability: +Subsystems nest to any depth. Patterns use bracket-ellipsis to express this without +enumerating levels — `[/{subsystem-name}...]` in paths, `[-{SubsystemName}...]` in +dash-separated IDs. Examples covering all three forms: + +- `{SystemName}[-{SubsystemName}...]-{UnitName}-Feature` (PascalCase ID) +- `docs/design/{system-name}[/{subsystem-name}...]/{unit-name}.md` (kebab-case doc path) +- `src/{SystemName}[/{SubsystemName}...]/{UnitName}.cs` (C# source path) +- `src/{system_name}[/{subsystem_name}...]/{unit_name}.cpp` (C++/Python source path) + +# Categorization Guidelines ## Software Package @@ -89,13 +94,15 @@ Choose the appropriate category based on scope and testability: - Examples: System.Text.Json, Entity Framework, third-party APIs - **Artifact locations** (OTS items have no internal design documentation): - Requirements: `docs/reqstream/ots/{ots-name}.yaml` - - Design: `docs/design/ots/{ots-name}.md` (integration/usage design - how the local system uses this item) + - Design: `docs/design/ots/{ots-name}.md` (integration/usage design) - Verification: `docs/verification/ots/{ots-name}.md` - These folders sit parallel to system folders (not inside any system folder) - System design documentation records which OTS items each system depends on - **OTS test project**: If no other verification evidence is available (e.g., vendor test results, - published compliance reports), a dedicated test project (`OtsSoftwareTests` / `ots_software_tests`, - cased per language) holds OTS integration tests - one test file per OTS item requiring tests. + published compliance reports), a dedicated test project holds OTS integration tests - one test + file per OTS item requiring tests. OTS items are repo-level (not per-system), so the project + uses a fixed repo-level name: `test/OtsSoftwareTests/` (C#) or `test/ots_software_tests/` + (Python/other) — never prefixed with a system or project name. ## Shared Package @@ -107,10 +114,9 @@ Choose the appropriate category based on scope and testability: downstream integration tests that transitively prove the advertised features are functional - **Artifact locations** (no internal design documentation in the consuming repository): - Requirements: `docs/reqstream/shared/{package-name}.yaml` - - Design: `docs/design/shared/{package-name}.md` (integration/usage design - which features are consumed and how) + - Design: `docs/design/shared/{package-name}.md` (integration/usage design) - Verification: `docs/verification/shared/{package-name}.md` - These folders sit parallel to system and OTS folders -- System design documentation records which Shared Packages each system depends on # Software Item Artifact Model diff --git a/.github/standards/technical-documentation.md b/.github/standards/technical-documentation.md index 0dc4455..23893bd 100644 --- a/.github/standards/technical-documentation.md +++ b/.github/standards/technical-documentation.md @@ -6,9 +6,6 @@ globs: ["docs/**/*.md", "README.md", "!docs/**/generated/**"] # Technical Documentation Standards -This document defines standards for technical documentation within Continuous -Compliance environments. - # Core Principles Technical documentation serves as compliance evidence and must be structured @@ -40,8 +37,7 @@ docs/{collection}/ Without `title.txt` and `definition.yaml` the pipeline cannot generate the document. When creating a new document collection, create these three files together and use -the existing collections under `docs/` as templates - they share a consistent -structure across all collections. +the existing collections under `docs/` as templates. The `generated/` folder is **never committed** to the repository - it is created locally and in CI by the build pipeline. Do not flag its absence as a conformance @@ -85,8 +81,7 @@ elsewhere causes duplicate sections in the compiled PDF. ## Document Ordering -List documents in logical reading order in Pandoc configuration because -readers need coherent information flow from general to specific topics. +List documents in logical reading order in `definition.yaml`. ## Heading Depth Rule (MANDATORY) @@ -110,15 +105,10 @@ available - keep internal structure flat to avoid excessive nesting. Write technical documentation for clarity and compliance verification: - **Clear and Concise**: Use direct language and avoid unnecessary complexity. - Regulatory reviewers must understand content quickly. -- **Structured Sections**: Use consistent heading hierarchy and section - organization. Enables automated processing and review. -- **Specific Examples**: Include concrete examples with actual values rather - than placeholders. Supports implementation verification. +- **Structured Sections**: Use consistent heading hierarchy and section organization. +- **Specific Examples**: Include concrete examples with actual values rather than placeholders. - **Current Information**: Keep documentation synchronized with code changes. - Outdated documentation invalidates compliance evidence. -- **Traceable Content**: Link documentation to requirements and implementation - where applicable for audit trails. +- **Traceable Content**: Link documentation to requirements and implementation where applicable. ## References Sections @@ -138,26 +128,16 @@ Instead use **verbal references** - plain prose that identifies the target by na > > Refer to the *System Requirements* document for the full specification. -Verbal references are readable by both AI agents and humans in any rendering environment. - # Markdown Format Requirements -Markdown documentation in this repository must follow the formatting standards -defined in `.markdownlint-cli2.yaml` (subject to any exclusions configured there) -for consistency and professional presentation: - -- **120 Character Line Limit**: Keep lines 120 characters or fewer for readability. - Break long lines naturally at punctuation or logical breaks. -- **No Trailing Whitespace**: Remove all trailing spaces and tabs from line - endings to prevent formatting inconsistencies. -- **Blank Lines Around Headings**: Include a blank line both before and after - each heading to improve document structure and readability. -- **Blank Lines Around Lists**: Include a blank line both before and after - numbered and bullet lists to ensure proper rendering and visual separation. -- **ATX-Style Headers**: Use `#` syntax for headers instead of underline style - for consistency across all documentation. -- **Consistent List Indentation**: Use 2-space indentation for nested list - items to maintain uniform formatting. +Follow `.markdownlint-cli2.yaml` formatting standards: + +- **120 Character Line Limit**: Keep lines 120 characters or fewer; break at punctuation or logical breaks. +- **No Trailing Whitespace**: Remove all trailing spaces and tabs. +- **Blank Lines Around Headings**: Include a blank line before and after each heading. +- **Blank Lines Around Lists**: Include a blank line before and after numbered and bullet lists. +- **ATX-Style Headers**: Use `#` syntax, not underline style. +- **Consistent List Indentation**: Use 2-space indentation for nested list items. # Auto-Generated Content (CRITICAL) @@ -168,8 +148,6 @@ build outputs that are overwritten on every CI run: respective `docs/` sections, or in `docs/generated/` for final release artifacts - **Source Modification**: Update source files (requirements YAML, `.reviewmark.yaml`, tool configuration) instead of generated output -- **Tool Integration**: Generated content integrates with CI/CD pipelines and - manual changes disrupt automation # README.md Best Practices @@ -192,20 +170,12 @@ Structure README.md for both human readers and AI agent processing: - **Code Block Languages**: Specify language for syntax highlighting and tool processing - **Clear Prerequisites**: List exact version requirements and dependencies -## Quality Guidelines - -- **Scannable Structure**: Use bullet points, headings, and short paragraphs -- **Current Examples**: Verify all code examples work with current version -- **Link Validation**: Ensure all external links are accessible and current -- **Consistent Tone**: Professional, helpful tone appropriate for technical audience - # Quality Checks Before submitting technical documentation, verify: - [ ] Documentation organized under `docs/` following standard folder structure - [ ] Pandoc collections include `introduction.md` with Purpose and Scope sections -- [ ] Content follows clear and concise writing guidelines with specific examples - [ ] No modifications made to auto-generated markdown files in compliance folders - [ ] README.md includes all required sections with absolute URLs and concrete examples - [ ] Documentation integrated into ReviewMark review-sets for formal review diff --git a/.github/standards/testing-principles.md b/.github/standards/testing-principles.md index 73974ff..917463e 100644 --- a/.github/standards/testing-principles.md +++ b/.github/standards/testing-principles.md @@ -3,11 +3,6 @@ name: Testing Principles description: Follow these standards when developing any software tests. --- -# Testing Principles Standards - -This document defines universal testing principles and quality standards for test development within -Continuous Compliance environments. - # Test Dependency Boundaries (MANDATORY) Respect software item hierarchy boundaries to ensure review-sets can validate proper architectural scope. diff --git a/.github/standards/verification-documentation.md b/.github/standards/verification-documentation.md index 8dc4408..494e40f 100644 --- a/.github/standards/verification-documentation.md +++ b/.github/standards/verification-documentation.md @@ -28,7 +28,8 @@ docs/verification/ └── {package-name}.md # heading depth ## ``` -Subsystems may nest recursively. Each file's heading depth equals its folder depth under `docs/verification/`. +All sections in every file are mandatory; write "N/A - {justification}" rather than removing any. +Determine subsystem vs. unit classification from `docs/design/introduction.md` — folder depth does not determine classification. # introduction.md (MANDATORY) @@ -41,50 +42,44 @@ Must include: # System Verification Design (MANDATORY) -Create `{system-name}.md` (`#` heading) and `{system-name}/` folder. All sections mandatory; -write "N/A - {justification}" rather than removing any section: +Create `{system-name}.md` (`#` heading) and `{system-name}/` folder: -- **Verification Strategy**: test types (unit, integration, end-to-end), framework, project structure +- **Verification Approach**: test types (unit, integration, end-to-end), framework, project structure - **Test Environment**: OS, runtime, external services, files, or configuration required - **Acceptance Criteria**: what constitutes a passing system test (IEC 62304 §5.7.2) -- **System-Level Test Scenarios**: named scenarios for each system requirement -- **Requirements Coverage**: requirement → scenario(s) → test method(s) mapping +- **Test Scenarios**: named scenarios for each system requirement # Subsystem Verification Design (MANDATORY) -Place `{subsystem-name}.md` in the **parent** folder; create `{subsystem-name}/` for children. -All sections mandatory; write "N/A - {justification}" rather than removing any section: +Place `{subsystem-name}.md` in the **parent** folder; create `{subsystem-name}/` for children: -- **Verification Strategy**: integration test approach and mocking at subsystem boundary +- **Verification Approach**: integration test approach and mocking at subsystem boundary - **Test Environment**: any environment setup beyond the standard test runner - **Acceptance Criteria**: what constitutes a passing subsystem test (IEC 62304 §5.5.2) - **Test Scenarios**: named scenarios including boundary conditions, error paths, and normal operation -- **Requirements Coverage**: requirement → scenario(s) → test method(s) mapping # Unit Verification Design (MANDATORY) -Place `{unit-name}.md` in the **parent** folder. All sections mandatory; -write "N/A - {justification}" rather than removing any section: +Place `{unit-name}.md` in the **parent** folder: - **Verification Approach**: what is mocked/stubbed and why; injected vs. real dependencies - **Test Environment**: any environment setup beyond the standard test runner - **Acceptance Criteria**: what constitutes passing unit tests (IEC 62304 §5.5.2) - **Test Scenarios**: named scenarios including boundary values, error paths, and normal operation -- **Requirements Coverage**: requirement → scenario(s) → test method(s) mapping # OTS Verification Evidence (when OTS items exist) Create `docs/verification/ots.md` (`#` heading) covering the overall OTS verification strategy. For each OTS item, create `docs/verification/ots/{ots-name}.md` (`##` heading) covering: -verification approach (self-validation, integration tests, vendor evidence) and requirements coverage. +verification approach (self-validation, integration tests, vendor evidence). # Shared Package Verification Evidence (when Shared Packages exist) Create `docs/verification/shared.md` (`#` heading) covering the overall Shared Package verification strategy. For each Shared Package, create `docs/verification/shared/{package-name}.md` (`##` heading) covering: -verification approach and requirements coverage. +verification approach. # Writing Guidelines @@ -97,14 +92,10 @@ verification approach and requirements coverage. - [ ] `introduction.md` includes Companion Artifact Structure - [ ] Each file's heading depth matches its folder depth - [ ] All folders use kebab-case mirroring source structure -- [ ] System verification includes all mandatory sections (Verification Strategy, Test Environment, - Acceptance Criteria, System-Level Test Scenarios, Requirements Coverage) -- [ ] Subsystem verification includes all mandatory sections (Verification Strategy, Test Environment, - Acceptance Criteria, Test Scenarios, Requirements Coverage) -- [ ] Unit verification includes all mandatory sections (Verification Approach, Test Environment, - Acceptance Criteria, Test Scenarios, Requirements Coverage) +- [ ] Each system/subsystem/unit file includes all mandatory sections (Verification Approach, + Test Environment, Acceptance Criteria, Test Scenarios) - [ ] Non-applicable mandatory sections contain "N/A - {justification}" -- [ ] Every requirement is mapped to at least one named test scenario +- [ ] Requirements-to-test coverage is tracked via the ReqStream trace matrix, not in these documents - [ ] `docs/verification/ots.md` and `docs/verification/ots/{ots-name}.md` exist when OTS items are present - [ ] `docs/verification/shared.md` and `docs/verification/shared/{package-name}.md` exist when Shared Packages are present - [ ] Documents are integrated into ReviewMark review-sets diff --git a/.gitignore b/.gitignore index ee4cdc9..90d027d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,19 @@ -.vs +# .gitignore + +# Build outputs +bin/ +obj/ +artifacts/ + +# .NET *.bak *.user *.suo +*.slnx.user *.userosscache *.sln.docstates mono_crash.* - -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Xx]64/ -[Xx]86/ -[Ww]in32/ -[Aa][Rr][Mm]/ -[Aa][Rr][Mm]64/ -bld/ -bin/ -obj/ +.vs/ # ReSharper _ReSharper*/ @@ -48,23 +44,26 @@ test-results/ # Temporary files *.tmp -.DS_Store - -# Node.js dependencies -node_modules/ -package-lock.json -# Python +# Python virtual environment +.venv/ __pycache__/ *.py[cod] -.venv/ -# Generated documentation +# Node +node_modules/ + +# Generated compliance documents (build outputs — never committed) **/generated/ +# Agent logs +.agent-logs/ + +# OS +.DS_Store +Thumbs.db + # VersionMark captures (generated during CI/CD) versionmark-*.json -# Agent report files -AGENT_REPORT_*.md -.agent-logs/ +/package-lock.json diff --git a/.yamlfix.toml b/.yamlfix.toml index 233d73b..9ff1fb6 100644 --- a/.yamlfix.toml +++ b/.yamlfix.toml @@ -1,15 +1,4 @@ # YAML Auto-Fix Configuration -# -# PURPOSE: -# - Configure yamlfix to auto-fix common YAML issues before yamllint checks -# - Settings MUST align with .yamllint.yaml to avoid conflicts -# - Use 'pwsh ./fix.ps1' or run 'yamlfix .' before 'pwsh ./lint.ps1' to auto-fix, then verify with yamllint -# -# RELATIONSHIP TO YAMLLINT: -# - line_length MUST match .yamllint.yaml line-length.max (120) -# - preserve_quotes prevents mangling GitHub Actions 'on:' boolean handling -# - After yamlfix auto-fix, yamllint should only fail on genuinely unresolvable issues - line_length = 120 preserve_quotes = true sequence_style = "keep_style" diff --git a/AGENTS.md b/AGENTS.md index 3eb2e95..104e954 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,8 @@ # Project Overview -- **name**: BuildMark +- **project-name**: BuildMark +- **organization**: DEMA Consulting +- **project-tagline**: Build notes generator for GitHub and Azure DevOps - **description**: Tool for generating Markdown build notes from repositories - **languages**: C# - **technologies**: DotNet, YamlDotNet, xUnit, GraphQL, Pandoc, WeasyPrint @@ -25,6 +27,11 @@ └── DemaConsulting.BuildMark.Tests/ ``` +# Language and Spelling (ALL Agents) + +Always use **US English** spelling in all output (code, comments, documentation, +commit messages, and reports). + # Reference Template This repository follows a reference template for structure and file conventions. @@ -70,7 +77,6 @@ from `.github/standards/`. Use this matrix to determine which to load: - **Verification docs**: `software-items.md`, `verification-documentation.md`, `technical-documentation.md` - **Review configuration**: `software-items.md`, `reviewmark-usage.md` - **Any documentation**: `technical-documentation.md` -- **Structural audit**: `template-sync` agent Load only the standards relevant to your specific task scope. @@ -85,6 +91,7 @@ Delegate to specialized agents only for specific scenarios: - **Formal feature implementation** (complex, multi-step) → Call the implementation agent - **Formal bug resolution** (complex debugging, systematic fixes) → Call the implementation agent - **Formal reviews** (compliance verification, detailed analysis) → Call the formal-review agent +- **Structural audit**: (repository layout vs. template) → Call the template-sync agent # Agent Reporting (Specialized Agents Must Follow) diff --git a/build.ps1 b/build.ps1 index 188d18f..36eea85 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,8 +1,8 @@ # build.ps1 # # PURPOSE: -# Unified cross-platform build script (replaces build.bat and build.sh). -# Builds the solution in Release configuration and runs all unit tests. +# Unified cross-platform build script for BuildMark. +# Restores dependencies, builds the solution in Release configuration, and runs all unit tests. # # EXTENSION POINTS: # Search for "[PROJECT-SPECIFIC]" comments to find the designated locations @@ -12,18 +12,26 @@ # Only modify this file to add project-specific operations at the designated # [PROJECT-SPECIFIC] extension points. -$ErrorActionPreference = 'Stop' +$buildError = $false -Write-Host "Building project..." -dotnet build --configuration Release -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +Write-Host "Restoring dependencies..." +dotnet restore +if ($LASTEXITCODE -ne 0) { $buildError = $true } + +Write-Host "Building..." +dotnet build --no-restore --configuration Release +if ($LASTEXITCODE -ne 0) { $buildError = $true } # [PROJECT-SPECIFIC] Add additional build steps here. Write-Host "Running unit tests..." -dotnet test --configuration Release -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +dotnet test --no-build --configuration Release --logger trx --results-directory artifacts/tests +if ($LASTEXITCODE -ne 0) { $buildError = $true } # [PROJECT-SPECIFIC] Add additional test or post-build steps here. -Write-Host "Build and tests completed successfully!" +if (-not $buildError) { + Write-Host "Build and tests completed successfully!" +} + +exit ($buildError ? 1 : 0) diff --git a/docs/build_notes/definition.yaml b/docs/build_notes/definition.yaml index 708f7fb..99131c3 100644 --- a/docs/build_notes/definition.yaml +++ b/docs/build_notes/definition.yaml @@ -1,15 +1,10 @@ --- -resource-path: - - docs/build_notes - - docs/template - +resource-path: [docs/build_notes, docs/template] input-files: - docs/build_notes/title.txt - docs/build_notes/introduction.md - - docs/build_notes/generated/build_notes.md - - docs/build_notes/generated/versions.md + - docs/build_notes/generated/build_notes.md # Generated by BuildMark (git history, release notes) + - docs/build_notes/generated/versions.md # Generated by VersionMark (tool versions) template: template.html - table-of-contents: true - number-sections: true diff --git a/docs/build_notes/introduction.md b/docs/build_notes/introduction.md index f489e66..62657f3 100644 --- a/docs/build_notes/introduction.md +++ b/docs/build_notes/introduction.md @@ -1,37 +1,27 @@ # Introduction -This document contains the build notes for the BuildMark project. +This document contains the build notes for BuildMark. It is intended for software developers, project +stakeholders, contributors, and users evaluating what has changed in a given release. ## Purpose -This report serves as a comprehensive record of changes and bug fixes for this -release of BuildMark. It provides transparency about what has changed since the -previous version and helps users understand the improvements and fixes included -in this build. +This document provides a record of the changes, new features, and bug fixes included in this release +of BuildMark. It also records the versions of all tools used in the build pipeline, providing +traceability between the software artifacts and the environment that produced them. ## Scope This build notes report covers: -- Version information and commit details -- Changes and new features implemented +- Version information and commit details for this release +- Changes and new features implemented since the previous version - Bugs fixed in this release +- Versions of all tools used in the build and compliance pipeline -## Generation Source - -This report is automatically generated by the BuildMark tool itself, analyzing the -Git repository history and issue tracking information. It serves as evidence that -the BuildMark tool can successfully generate build notes for real-world projects. - -## Audience - -This document is intended for: - -- Software developers working on BuildMark -- Users evaluating what has changed in this release -- Project stakeholders tracking progress -- Contributors understanding recent changes +This report is automatically generated by the BuildMark tool itself, analyzing Git repository history +and issue tracking information. It serves as evidence that BuildMark can successfully generate build +notes for real-world projects. ## References -- [BuildMark Releases](https://github.com/demaconsulting/BuildMark/releases) — compiled compliance documents for each release +- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) diff --git a/docs/build_notes/title.txt b/docs/build_notes/title.txt index ac0de2b..53b4338 100644 --- a/docs/build_notes/title.txt +++ b/docs/build_notes/title.txt @@ -1,14 +1,13 @@ --- -title: BuildMark Tool -subtitle: Build Notes -author: DEMA Consulting -description: Build notes for the BuildMark Tool +title: "BuildMark Build Notes" +subtitle: "Markdown Build Notes Generation Tool" +author: "DEMA Consulting" +description: "Build Notes for BuildMark" lang: en-US keywords: - - BuildMark - Build Notes + - BuildMark - Release Notes - C# - .NET - - Documentation --- diff --git a/docs/code_quality/definition.yaml b/docs/code_quality/definition.yaml index 78f82ee..fed5f02 100644 --- a/docs/code_quality/definition.yaml +++ b/docs/code_quality/definition.yaml @@ -2,14 +2,11 @@ resource-path: - docs/code_quality - docs/template - input-files: - docs/code_quality/title.txt - docs/code_quality/introduction.md - docs/code_quality/generated/codeql-quality.md - docs/code_quality/generated/sonar-quality.md template: template.html - table-of-contents: true - number-sections: true diff --git a/docs/code_quality/introduction.md b/docs/code_quality/introduction.md index 7218e57..0c5bb55 100644 --- a/docs/code_quality/introduction.md +++ b/docs/code_quality/introduction.md @@ -1,40 +1,26 @@ # Introduction -This document contains the code quality analysis report for the BuildMark project. +This document records the static analysis results for BuildMark. ## Purpose -This report serves as evidence that the BuildMark codebase maintains good quality -standards. It provides a comprehensive analysis of code quality metrics, including -quality gate status, code issues, security hot spots, technical debt, and code coverage. +To provide evidence that BuildMark has been analyzed for code quality issues +and that any findings have been reviewed and resolved or accepted. ## Scope -This code quality report covers: +Covers static analysis of all source code in `src/` for BuildMark. +Test code is excluded from static analysis requirements. + +The analysis includes: - Quality gate status and conditions - Code issues categorized by type and severity -- Security hot spots requiring review +- Security hotspots requiring review - Technical debt assessment - Code coverage and duplication metrics -## Analysis Source - -This report contains quality analysis results captured at the time this version of BuildMark -was built. It serves as evidence that the code maintains good quality standards and provides -transparency about the project's code health. The analysis includes results from various -quality tools run during the build process. - -## Audience - -This document is intended for: - -- Software developers working on BuildMark -- Quality assurance teams reviewing code quality -- Project stakeholders evaluating project health -- Contributors understanding quality standards - ## References -- [BuildMark Releases](https://github.com/demaconsulting/BuildMark/releases) — compiled compliance documents for each release +- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) — compiled compliance documents for each release - [SonarCloud Dashboard](https://sonarcloud.io/dashboard?id=demaconsulting_BuildMark) — live code quality and security analysis diff --git a/docs/code_quality/title.txt b/docs/code_quality/title.txt index c4f27f4..f97f33f 100644 --- a/docs/code_quality/title.txt +++ b/docs/code_quality/title.txt @@ -1,16 +1,14 @@ --- title: BuildMark Code Quality Report -subtitle: Code Quality Analysis Report +subtitle: Markdown Build Notes Generation Tool author: DEMA Consulting -description: Code Quality Analysis Report for the BuildMark Tool +description: Code Quality Report for BuildMark lang: en-US keywords: - - BuildMark - Code Quality + - Static Analysis - SonarCloud - CodeQL - - Analysis - C# - .NET - - Documentation --- diff --git a/docs/code_review_plan/definition.yaml b/docs/code_review_plan/definition.yaml index 56989bf..77d01d1 100644 --- a/docs/code_review_plan/definition.yaml +++ b/docs/code_review_plan/definition.yaml @@ -5,7 +5,7 @@ resource-path: input-files: - docs/code_review_plan/title.txt - docs/code_review_plan/introduction.md - - docs/code_review_plan/generated/plan.md + - docs/code_review_plan/generated/plan.md # Generated by ReviewMark (formal review plan) template: template.html table-of-contents: true number-sections: true diff --git a/docs/code_review_plan/introduction.md b/docs/code_review_plan/introduction.md index 3cc5225..d372e0d 100644 --- a/docs/code_review_plan/introduction.md +++ b/docs/code_review_plan/introduction.md @@ -1,39 +1,18 @@ # Introduction -This document contains the review plan for the BuildMark project. +This document defines the formal code review plan for BuildMark. ## Purpose -This review plan provides a comprehensive overview of all files requiring formal review -in the BuildMark project. It identifies which review-sets cover which -files and serves as evidence that every file requiring review is covered by at least -one named review-set. +To define review-sets and the evidence required to demonstrate that each software item +has been reviewed according to the project's compliance requirements. ## Scope -This review plan covers: - -- C# source code files requiring formal review -- YAML configuration and requirements files requiring formal review -- Mapping of reviewed files to named review-sets - -## Generation Source - -This plan is automatically generated by the ReviewMark tool, analyzing the -`.reviewmark.yaml` configuration and the review evidence store. It serves as evidence -that every file requiring review is covered by a current, valid review. - -## Audience - -This document is intended for: - -- Software developers working on BuildMark -- Quality assurance teams validating review coverage -- Project stakeholders reviewing compliance status -- Auditors verifying that all required files have been reviewed +This document covers all review-sets defined in `.reviewmark.yaml` for BuildMark. The review +plan is automatically generated by the ReviewMark tool from the `.reviewmark.yaml` configuration +and included in the compiled document as `generated/plan.md`. ## References -- [BuildMark Releases](https://github.com/demaconsulting/BuildMark/releases) — compiled compliance documents for each release -- [Continuous Compliance](https://github.com/demaconsulting/ContinuousCompliance) — - methodology for continuous compliance evidence generation +- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) diff --git a/docs/code_review_plan/title.txt b/docs/code_review_plan/title.txt index fffd680..3a48731 100644 --- a/docs/code_review_plan/title.txt +++ b/docs/code_review_plan/title.txt @@ -1,13 +1,12 @@ --- -title: BuildMark Review Plan -subtitle: File Review Plan for the BuildMark Tool +title: BuildMark Code Review Plan +subtitle: Markdown Build Notes Generation Tool author: DEMA Consulting -description: File Review Plan for the BuildMark Tool +description: Code Review Plan for BuildMark lang: en-US keywords: + - Code Review - BuildMark - - Review Plan - - File Reviews - .NET - Tool --- diff --git a/docs/code_review_report/definition.yaml b/docs/code_review_report/definition.yaml index b238d43..b097a50 100644 --- a/docs/code_review_report/definition.yaml +++ b/docs/code_review_report/definition.yaml @@ -5,7 +5,7 @@ resource-path: input-files: - docs/code_review_report/title.txt - docs/code_review_report/introduction.md - - docs/code_review_report/generated/report.md + - docs/code_review_report/generated/report.md # Generated by ReviewMark (completed review records) template: template.html table-of-contents: true number-sections: true diff --git a/docs/code_review_report/introduction.md b/docs/code_review_report/introduction.md index 8b6657b..15e97cc 100644 --- a/docs/code_review_report/introduction.md +++ b/docs/code_review_report/introduction.md @@ -1,22 +1,30 @@ # Introduction -This document contains the review report for the BuildMark project. +This document records the completed formal code reviews for BuildMark. ## Purpose -This review report provides evidence that each review-set is current - the review -evidence matches the current file fingerprints. It confirms that all formal reviews -conducted for BuildMark remain valid for the current state of the -reviewed files. +To provide compliance evidence that all required review-sets have been reviewed and approved +according to the project's review plan. It confirms that all formal reviews conducted for +BuildMark remain valid for the current state of the reviewed files. ## Scope -This review report covers: +This document covers all completed reviews for review-sets defined in `.reviewmark.yaml`. + +The review report includes: - Current review-set status (current, stale, or missing) - File fingerprints and review evidence matching - Review coverage verification +## References + +- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) — + compiled compliance documents for each release +- [Continuous Compliance](https://github.com/demaconsulting/ContinuousCompliance) — + methodology for continuous compliance evidence generation + ## Generation Source This report is automatically generated by the ReviewMark tool, comparing the current @@ -31,9 +39,3 @@ This document is intended for: - Quality assurance teams validating review currency - Project stakeholders reviewing compliance status - Auditors verifying that all reviews remain valid for the current release - -## References - -- [BuildMark Releases](https://github.com/demaconsulting/BuildMark/releases) — compiled compliance documents for each release -- [Continuous Compliance](https://github.com/demaconsulting/ContinuousCompliance) — - methodology for continuous compliance evidence generation diff --git a/docs/code_review_report/title.txt b/docs/code_review_report/title.txt index 0dcb038..4fe54e6 100644 --- a/docs/code_review_report/title.txt +++ b/docs/code_review_report/title.txt @@ -1,12 +1,12 @@ --- -title: BuildMark Review Report -subtitle: File Review Report for the BuildMark Tool +title: BuildMark Code Review Report +subtitle: Markdown Build Notes Generation Tool author: DEMA Consulting -description: File Review Report for the BuildMark Tool +description: Code Review Report for BuildMark lang: en-US keywords: - BuildMark - - Review Report + - Code Review Report - File Reviews - .NET - Tool diff --git a/docs/design/build-mark.md b/docs/design/build-mark.md index d7257f5..d3a21a2 100644 --- a/docs/design/build-mark.md +++ b/docs/design/build-mark.md @@ -1,40 +1,137 @@ -# BuildMark System Design +# BuildMark -## Overview +## Architecture -BuildMark is a .NET command-line tool that generates markdown build notes from -Git repository metadata hosted on GitHub or Azure DevOps. It queries the -appropriate platform API - GitHub's GraphQL API or the Azure DevOps REST API — to -retrieve commits, issues or work items, pull requests, and version tags, then -formats the results as a structured markdown report suitable for embedding in -release documentation. +BuildMark is composed of seven subsystems and a top-level entry-point unit. The diagram below +shows the subsystem-level dependency relationships: -## Architecture +```mermaid +flowchart TD + P[Program] --> Cli + P --> Configuration + P --> SelfTest + P --> RepoConnectors + P --> BuildNotes + P --> Version + + RepoConnectors --> BuildNotes + RepoConnectors --> Version + RepoConnectors --> Utilities + + SelfTest --> BuildNotes + SelfTest --> RepoConnectors + SelfTest --> Utilities -BuildMark is composed of seven subsystems and a top-level entry point: + Configuration --> Version + BuildNotes --> Version +``` -- `Program` (Unit) - entry point; dispatches to handlers based on CLI flags -- `Cli` (Subsystem) - command-line argument parsing and output channel control -- `BuildNotes` (Subsystem) - output data model shared by all connectors and `Program` -- `Configuration` (Subsystem) - parses the `.buildmark.yaml` configuration file -- `RepoConnectors` (Subsystem) - repository metadata retrieval, including item-controls - parsing and concrete connectors -- `SelfTest` (Subsystem) - built-in self-validation test framework -- `Utilities` (Subsystem) - shared path combination and process execution helpers -- `Version` (Subsystem) - semantic version processing and comparison engine +- **Program** (Unit) — entry point; dispatches to handlers based on parsed CLI flags. +- **Cli** (Subsystem) — command-line argument parsing, output channel control, and exit code + tracking. +- **BuildNotes** (Subsystem) — output data model shared by all connectors and by `Program`; + contains the markdown renderer. +- **Configuration** (Subsystem) — parses the optional `.buildmark.yaml` configuration file. +- **RepoConnectors** (Subsystem) — repository metadata retrieval, item-controls parsing, and + concrete GitHub and Azure DevOps connectors. +- **SelfTest** (Subsystem) — built-in self-validation test framework invoked by `--validate`. +- **Utilities** (Subsystem) — shared path combination and process execution helpers. +- **Version** (Subsystem) — semantic version parsing, comparison, and interval processing. ## External Interfaces -| Interface | Direction | Protocol / Format | -|----------------------|---------------|----------------------------------------------------------| -| Command line | Input | POSIX-style flags parsed by `Context` | -| `.buildmark.yaml` | Input | YAML file read from the repository root | -| GitHub GraphQL | Bidirectional | HTTPS POST to `https://api.github.com/graphql` | -| Azure DevOps REST | Bidirectional | HTTPS GET/POST to Azure DevOps `_apis` endpoints v6.0 | -| Markdown report | Output | File written to `--report` path, UTF-8 markdown | -| Log file | Output | Optional file written to `--log` path, plain text | -| Test results | Output | TRX or JUnit XML written to `--results` path | -| Exit code | Output | 0 = success, 1 = error | +**Command line**: Standard input interface for operator instructions. + +- *Type*: CLI (POSIX-style flags and arguments) +- *Role*: Consumer — BuildMark reads arguments provided by the calling process. +- *Contract*: `Context.Create(string[] args)` parses flags including `--build-version`, + `--report`, `--depth`, `--validate`, `--lint`, `--include-known-issues`, `--silent`, + `--log`, and `--results`. +- *Constraints*: Unrecognized flags cause `ArgumentException`; missing value arguments cause + `ArgumentException`; depth must be an integer in the range 1–6. + +**`.buildmark.yaml`**: Optional YAML configuration file at the repository root. + +- *Type*: File (YAML) +- *Role*: Consumer — BuildMark reads the file if present. +- *Contract*: Parsed by `BuildMarkConfigReader.ReadAsync`; supplies connector selection, + section definitions, and routing rules. Absence is not an error; default configuration is + used. +- *Constraints*: YAML parse errors and invalid values are reported via + `ConfigurationLoadResult.Issues`; the `--lint` flag validates without running a build. + +**GitHub GraphQL API**: Remote API for querying GitHub repository metadata. + +- *Type*: HTTP/REST (HTTPS POST with GraphQL body) +- *Role*: Consumer — BuildMark queries GitHub for tags, commits, issues, pull requests, and + releases. +- *Contract*: `GitHubGraphQLClient` sends paginated queries to + `https://api.github.com/graphql` using `Authorization: bearer `. +- *Constraints*: Authentication via `GH_TOKEN` or `GITHUB_TOKEN` environment variable, or + `gh auth token` CLI fallback; subject to GitHub API rate limits. + +**Azure DevOps REST API**: Remote API for querying Azure DevOps repository metadata. + +- *Type*: HTTP/REST (HTTPS GET/POST to Azure DevOps `_apis` endpoints v6.0) +- *Role*: Consumer — BuildMark queries Azure DevOps for tags, commits, pull requests, and + work items. +- *Contract*: `AzureDevOpsRestClient` sends paginated requests using `Basic` authorization + (PAT tokens) or `Bearer` authorization (Entra ID / `SYSTEM_ACCESSTOKEN` tokens). +- *Constraints*: Authentication via `AZURE_DEVOPS_PAT`, `AZURE_DEVOPS_TOKEN`, + `AZURE_DEVOPS_EXT_PAT`, or `SYSTEM_ACCESSTOKEN` environment variables, or + `az account get-access-token` CLI fallback. + +**Markdown report**: Output file containing the generated build notes. + +- *Type*: File (UTF-8 Markdown) +- *Role*: Provider — BuildMark writes the report to the path specified by `--report` or + `report.file` in configuration. +- *Contract*: Generated by `BuildInformation.ToMarkdown`; heading depth configurable via + `--depth` (default 1). Absence of `--report` means no file is written. +- *Constraints*: File-system errors during write are caught and reported via + `context.WriteError`; execution continues with exit code 1. + +**Log file**: Optional output file for capturing console output. + +- *Type*: File (plain text) +- *Role*: Provider — BuildMark mirrors all console output to the specified file. +- *Contract*: Written by `Context` to the path specified by `--log`; opened in overwrite mode + with `AutoFlush`. +- *Constraints*: `InvalidOperationException` if the target directory does not exist. + +**Test results file**: Optional output file for self-validation results. + +- *Type*: File (TRX or JUnit XML) +- *Role*: Provider — BuildMark writes self-test results when `--results ` is specified + and `--validate` is active. +- *Contract*: Supports `.trx` (Visual Studio Test Results) or `.xml` (JUnit format) based on + file extension. +- *Constraints*: Unsupported extensions are reported as an error; no file is written. + +**Exit code**: Numeric exit code returned to the calling process. + +- *Type*: Process exit code +- *Role*: Provider +- *Contract*: 0 = success; 1 = any error (invalid arguments, configuration errors, API + errors, or self-test failures). +- *Constraints*: None. + +## Dependencies + +- **YamlDotNet**: used for parsing `.buildmark.yaml` configuration files via the `YamlStream` + representation model — see *YamlDotNet Integration Design* +- **DemaConsulting.TestResults**: used for TRX and JUnit XML test results serialization in the + SelfTest subsystem; no separate design document in this collection +- **System.Net.Http** (.NET built-in): used by `GitHubGraphQLClient` and + `AzureDevOpsRestClient` for HTTPS communication with the GitHub and Azure DevOps APIs; no + separate design document + +## Risk Control Measures + +N/A — BuildMark is a build-tooling utility with no safety-critical functions and no +subsystems that require isolation from each other for risk-control purposes. All subsystems +run in the same process and share the same memory address space; no inter-process or +memory-boundary segregation is required. ## Data Flow @@ -82,147 +179,98 @@ BuildMark is composed of seven subsystems and a top-level entry point: [Markdown Report File] ``` -## Dependencies - -- **YamlDotNet**: used for parsing `.buildmark.yaml` configuration files via the - `YamlStream` representation model - see *YamlDotNet Integration Design* -- **System.Net.Http / System.Net.Http.Json** (.NET built-in): used by - `GitHubGraphQLClient` and `AzureDevOpsRestClient` for HTTPS communication with - the GitHub GraphQL and Azure DevOps REST APIs - -## Risk Control Measures - -N/A - BuildMark is a build-tooling utility with no safety-critical functions and -no subsystems that require isolation from each other for risk-control purposes. All -subsystems run in the same process and share the same memory address space; no -inter-process or memory-boundary segregation is required. - ## Design Constraints - **Target framework**: .NET 8, .NET 9, and .NET 10 - **Platform support**: Windows, Linux, macOS - **Packaging**: Published as a .NET global tool (`dotnet tool install`) -- **Authentication**: GitHub token supplied via `GH_TOKEN` environment variable, - `GITHUB_TOKEN` environment variable, or `gh auth token` CLI fallback; Azure - DevOps token supplied via `AZURE_DEVOPS_PAT`, `AZURE_DEVOPS_TOKEN`, - `AZURE_DEVOPS_EXT_PAT`, or `SYSTEM_ACCESSTOKEN` environment variables, or - `az account get-access-token` CLI fallback +- **Authentication**: GitHub token supplied via `GH_TOKEN` or `GITHUB_TOKEN` environment + variable, or `gh auth token` CLI fallback; Azure DevOps token supplied via + `AZURE_DEVOPS_PAT`, `AZURE_DEVOPS_TOKEN`, `AZURE_DEVOPS_EXT_PAT`, or + `SYSTEM_ACCESSTOKEN` environment variables, or `az account get-access-token` CLI fallback - **No GUI**: All interaction is through the command line; no interactive prompts - **Self-contained**: The tool operates without any configuration file; an optional - `.buildmark.yaml` file in the repository root enables connector selection and - item routing customization -- **Configuration linting**: Malformed configuration file issues are reported to the - user via `ConfigurationLoadResult.ReportTo`; the `--lint` flag validates the - configuration file and exits without performing a build + `.buildmark.yaml` file in the repository root enables connector selection and item routing + customization +- **Configuration linting**: Malformed configuration file issues are reported to the user via + `ConfigurationLoadResult.ReportTo`; the `--lint` flag validates the configuration file and + exits without performing a build ## Integration Patterns ### Configuration File -`BuildMarkConfigReader.ReadAsync(path)` looks for a `.buildmark.yaml` file at the -supplied path (normally the repository root). The file is parsed using the -YamlDotNet library's representation model (`YamlStream`), then the resulting node -tree is walked to build the configuration objects. The method always returns a -`ConfigurationLoadResult`: - -- If the file is absent, `Config` is `null` and `Issues` is empty; the tool - proceeds with default behavior. -- If the file is present but contains YAML errors or invalid values, `Config` may - be `null` and `Issues` contains one or more `ConfigurationIssue` records, each - carrying a `FilePath`, `Line`, `Severity` (`Error` or `Warning`), and - `Description`. `ReportTo(context)` writes each issue to the log and sets the - exit code to 1 when any issue is an error. -- If the file is valid, `Config` is a fully populated `BuildMarkConfig` and - `Issues` is empty. - -`Program` calls `result.ReportTo(context)` immediately after reading the -configuration. The `--lint` flag causes `Program` to stop after this step, -allowing operators to validate the configuration file without running a build. - -When a valid `BuildMarkConfig` is available, its properties are consumed as -follows: - -- `BuildMarkConfig.Connector` - optional `ConnectorConfig` carrying the connector - `Type` (`"github"` or `"azure-devops"`), a `GitHub` property holding a - `GitHubConnectorConfig` for GitHub-based operation, and an `AzureDevOps` - property holding an `AzureDevOpsConnectorConfig` for Azure DevOps-based - operation. The `GitHubConnectorConfig` is passed to `GitHubRepoConnector` - and may supply `Owner`, `Repo`, and `BaseUrl` overrides. The - `AzureDevOpsConnectorConfig` is passed to `AzureDevOpsRepoConnector` and may - supply `OrganizationUrl`, `Project`, and `Repository` overrides. The full - `ConnectorConfig` is also passed to `RepoConnectorFactory` to select the - appropriate connector implementation. -- `BuildMarkConfig.Sections` - ordered list of `SectionConfig` objects (each with - an `Id` and `Title`) that define the report sections. Passed to the active - connector for output structuring. -- `BuildMarkConfig.Rules` - list of `RuleConfig` objects that map item attributes - (labels, work-item types) to report sections. Passed to the active connector for - item routing. +`BuildMarkConfigReader.ReadAsync(path)` looks for a `.buildmark.yaml` file at the supplied +path (normally the repository root). The file is parsed using the YamlDotNet library's +representation model (`YamlStream`), then the resulting node tree is walked to build the +configuration objects. The method always returns a `ConfigurationLoadResult`: + +- If the file is absent, `Config` is `null` and `Issues` is empty; the tool proceeds with + default behavior. +- If the file is present but contains YAML errors or invalid values, `Config` may be `null` + and `Issues` contains one or more `ConfigurationIssue` records, each carrying a `FilePath`, + `Line`, `Severity` (`Error` or `Warning`), and `Description`. `ReportTo(context)` writes + each issue to the log and sets the exit code to 1 when any issue is an error. +- If the file is valid, `Config` is a fully populated `BuildMarkConfig` and `Issues` is empty. + +`Program` calls `result.ReportTo(context)` immediately after reading the configuration. The +`--lint` flag causes `Program` to stop after this step, allowing operators to validate the +configuration file without running a build. + +When a valid `BuildMarkConfig` is available, its properties are consumed as follows: + +- `BuildMarkConfig.Connector` — optional `ConnectorConfig` carrying the connector `Type` + (`"github"` or `"azure-devops"`), a `GitHub` property holding a `GitHubConnectorConfig`, + and an `AzureDevOps` property holding an `AzureDevOpsConnectorConfig`. The connector + config is passed to `RepoConnectorFactory` to select the appropriate connector + implementation. +- `BuildMarkConfig.Sections` — ordered list of `SectionConfig` objects (each with an `Id` + and `Title`) that define the report sections. Passed to the active connector for output + structuring. +- `BuildMarkConfig.Rules` — list of `RuleConfig` objects that map item attributes (labels, + work-item types) to report sections. Passed to the active connector for item routing. ### GitHub GraphQL Client -`GitHubRepoConnector` uses `GitHubGraphQLClient` to issue paginated GraphQL -queries over HTTPS. Authentication is via `Authorization: bearer ` header. -The connector retrieves: - -- All tags (for identifying version boundaries) -- Commits in the requested range -- Issues referenced by commits (including description body) -- Pull requests in the requested range (including description body) -- Releases (for known-issues data) - -The `body` field of issues and pull requests is fetched so that `ItemControlsParser` -can extract embedded `buildmark` blocks. +`GitHubRepoConnector` uses `GitHubGraphQLClient` to issue paginated GraphQL queries over +HTTPS. Authentication is via `Authorization: bearer ` header. The connector retrieves +all tags, commits, issues referenced by commits, pull requests, and releases. The `body` +field of issues and pull requests is fetched so that `ItemControlsParser` can extract +embedded `buildmark` blocks. ### Azure DevOps REST Client -`AzureDevOpsRepoConnector` uses `AzureDevOpsRestClient` to issue paginated REST API -requests over HTTPS against Azure DevOps API v6.0 endpoints. Authentication is via -a `Basic` authorization header (for PAT tokens) or a `Bearer` authorization header -(for Entra ID / `SYSTEM_ACCESSTOKEN` tokens). The connector retrieves: - -- All tags via the refs endpoint (with `peelTags=true` to resolve annotated tags) -- Complete commit history (paginated) -- All pull requests (paginated) -- Work items linked to pull requests -- Open work items via WIQL query (for known-issues data) - -The `System.Description` field of work items and the description body of pull -requests are passed to `ItemControlsParser` for extracting embedded `buildmark` -blocks. Additionally, `Custom.Visibility` and `Custom.AffectedVersions` custom -fields on work items provide an Azure DevOps-native alternative to buildmark blocks. +`AzureDevOpsRepoConnector` uses `AzureDevOpsRestClient` to issue paginated REST API requests +over HTTPS against Azure DevOps API v6.0 endpoints. Authentication is via a `Basic` +authorization header (for PAT tokens) or a `Bearer` authorization header (for Entra ID +tokens). The connector retrieves all tags (with `peelTags=true`), complete commit history, +all pull requests, work items linked to pull requests, and open work items via WIQL query. ### Item Controls -When `GitHubRepoConnector` processes each issue or pull request, it passes the -description body to `ItemControlsParser.Parse`. When `AzureDevOpsRepoConnector` -processes work items and pull requests, `WorkItemMapper` and the connector call -`ItemControlsParser.Parse` on the description body and also read -`Custom.Visibility` and `Custom.AffectedVersions` custom fields. If a `buildmark` -code block is present (including when hidden inside an HTML comment), the parser -returns an `ItemControlsInfo` record that carries optional overrides for -`Visibility`, `Type`, and `AffectedVersions`. For Azure DevOps work items, -custom fields take precedence over buildmark blocks when both are present. +When connectors process each issue, pull request, or work item, they pass the description +body to `ItemControlsParser.Parse`. If a `buildmark` code block is present (including when +hidden inside an HTML comment), the parser returns an `ItemControlsInfo` record carrying +optional overrides for `Visibility`, `Type`, and `AffectedVersions`. Azure DevOps custom +fields (`Custom.Visibility`, `Custom.AffectedVersions`) take precedence over buildmark +blocks when both are present. The connector applies these overrides as follows: -- `visibility: internal` - the item is excluded from all report sections -- `visibility: public` - the item is included regardless of its label-derived type -- `type: bug` or `type: feature` - overrides the label-derived type classification -- `affected-versions` - stored on the `ItemInfo` record for downstream use - -When no `buildmark` block is present, the existing label-based rules apply -unchanged. +- `visibility: internal` — the item is excluded from all report sections +- `visibility: public` — the item is included regardless of its label-derived type +- `type: bug` or `type: feature` — overrides the label-derived type classification +- `affected-versions` — stored on the `ItemInfo` record for downstream use ### Self-Validation -The `--validate` flag invokes `Validation.Run`, which exercises core tool -functionality using a `MockRepoConnector` and writes a standard TRX or JUnit XML -results file. This allows operators to verify the tool works correctly in their -environment without requiring a live GitHub connection. +The `--validate` flag invokes `Validation.Run`, which exercises core tool functionality using +a `MockRepoConnector` and writes a standard TRX or JUnit XML results file. This allows +operators to verify the tool works correctly in their environment without requiring a live +GitHub connection. ### Report Generation -`BuildInformation.ToMarkdown` converts the in-memory build data model into a -markdown string. The heading depth is configurable via `--depth`, allowing -the report to be embedded at any level in a larger document. +`BuildInformation.ToMarkdown` converts the in-memory build data model into a markdown string. +The heading depth is configurable via `--depth`, allowing the report to be embedded at any +level in a larger document. diff --git a/docs/design/build-mark/build-notes.md b/docs/design/build-mark/build-notes.md index 4b29480..d1b8f8e 100644 --- a/docs/design/build-mark/build-notes.md +++ b/docs/design/build-mark/build-notes.md @@ -2,53 +2,60 @@ ### Overview -The BuildNotes subsystem holds the output data model shared by all connectors and -by `Program`. It defines the records that represent a build's version tags, -changed items, bugs, and known issues, together with the logic to render them as -a markdown report. +The BuildNotes subsystem holds the shared output data model consumed by all repository +connectors and by `Program`. It defines the records that represent a build's version tags, +changed items, bugs, and known issues, together with the logic to render them as a markdown +report. -All connectors produce a `BuildInformation` record from these types, and `Program` -calls `BuildInformation.ToMarkdown` to write the final report file. +The subsystem boundaries include only the data records and the rendering method — it does not +fetch data from any repository or perform any I/O. Repository connectors populate the records; +`Program` drives rendering. -### Units +The subsystem contains three units: -| Unit | File | Responsibility | -|--------------------|----------------------------------|--------------------------------------------------| -| `BuildInformation` | `BuildNotes/BuildInformation.cs` | Top-level build data model and markdown renderer | -| `ItemInfo` | `BuildNotes/ItemInfo.cs` | Single issue or pull request in the report | -| `WebLink` | `BuildNotes/WebLink.cs` | Hyperlink used for the full-changelog entry | +- **`BuildInformation`** (`BuildNotes/BuildInformation.cs`) — top-level build data model and + markdown renderer +- **`ItemInfo`** (`BuildNotes/ItemInfo.cs`) — a single issue or pull request entry in the + build report +- **`WebLink`** (`BuildNotes/WebLink.cs`) — a hyperlink for the full-changelog entry ### Interfaces -The primary interface consumed by `Program` is: +**`BuildInformation.ToMarkdown`**: Primary rendering interface consumed by `Program`. -| Member | Kind | Description | -| --- | --- | --- | -| `BuildInformation.ToMarkdown(depth, includeKnownIssues)` | Method | Renders assembled build data as markdown string | +- *Type*: In-process .NET method +- *Role*: Provider — the BuildNotes subsystem exposes this method for consumers. +- *Contract*: `ToMarkdown(int headingDepth = 1, bool includeKnownIssues = false) → string`; + returns a fully formatted markdown string from the assembled build data. +- *Constraints*: Callers must populate all required record fields before calling. The method + does not throw under normal operation. -The data records `BuildInformation`, `ItemInfo`, and `WebLink` are the shared -output types exposed to all connectors for assembly, and to `Program` and -`SelfTest` for consumption. +**`BuildInformation`, `ItemInfo`, `WebLink` record types**: Shared data types for construction +by connectors and consumption by `Program` and `SelfTest`. + +- *Type*: In-process .NET record types +- *Role*: Provider — the subsystem exposes these types for construction and consumption. +- *Contract*: Immutable C# records; all fields are set at construction time. `RoutedSections` + on `BuildInformation` is an optional init-only property populated after construction. +- *Constraints*: Records carry no invariant validation; callers are responsible for providing + valid field values. ### Design -The BuildNotes subsystem is a pure data and rendering layer. Connectors in the -`RepoConnectors` subsystem assemble a `BuildInformation` record by populating its -version tags and item lists (`Changes`, `Bugs`, `KnownIssues`, and optionally -`RoutedSections`). `Program` then calls `BuildInformation.ToMarkdown` to convert -the in-memory model into the final markdown report file. - -`ItemInfo` and `WebLink` are simple immutable records; their construction and -consumption require no additional coordination. The rendering logic in -`ToMarkdown` selects between routed and legacy output modes based on whether -`RoutedSections` is populated, requiring no knowledge of which connector produced -the data. - -### Interactions - -| Unit / Subsystem | Role | -|---------------------|--------------------------------------------------------------------| -| `Version` | Supplies the version types used by `VersionCommitTag` | -| `RepoConnectors` | Connectors construct and populate `BuildInformation` records | -| `Program` | Calls `BuildInformation.ToMarkdown` to produce the report file | -| `SelfTest` | `Validation` creates `BuildInformation` records during self-tests | +The BuildNotes subsystem is a pure data and rendering layer. Connectors in the RepoConnectors +subsystem assemble a `BuildInformation` record by populating its version tags and item lists +(`Changes`, `Bugs`, `KnownIssues`, and optionally `RoutedSections`). `Program` then calls +`BuildInformation.ToMarkdown` to convert the in-memory model into the final markdown report +file. + +`ItemInfo` and `WebLink` are simple immutable records; their construction and consumption +require no additional coordination. The rendering logic in `ToMarkdown` selects between routed +and legacy output modes based on whether `RoutedSections` is populated, requiring no knowledge +of which connector produced the data. + +`Validation` (SelfTest subsystem) also creates `BuildInformation` records during self-tests +using `MockRepoConnector` (RepoConnectors/Mock subsystem) to verify that the rendering logic +produces correct output. + +The subsystem has no dependencies on other BuildMark subsystems beyond the Version subsystem, +which provides the `VersionCommitTag` and `VersionIntervalSet` types used in the records. diff --git a/docs/design/build-mark/build-notes/build-information.md b/docs/design/build-mark/build-notes/build-information.md index e18a60f..b7eeb86 100644 --- a/docs/design/build-mark/build-notes/build-information.md +++ b/docs/design/build-mark/build-notes/build-information.md @@ -2,76 +2,65 @@ #### Purpose -`BuildInformation` is a record in the BuildNotes subsystem that holds all data -needed to produce one markdown build-notes report. It is assembled by connectors -and passed to `Program`, which calls `ToMarkdown` to render the final file. +`BuildInformation` is the top-level data record in the BuildNotes subsystem that holds all +data needed to produce one markdown build-notes report. It is assembled by repository +connectors and passed to `Program`, which calls `ToMarkdown` to render the final file. #### Data Model -```csharp -public record BuildInformation( - VersionCommitTag? BaselineVersionTag, - VersionCommitTag CurrentVersionTag, - List Changes, - List Bugs, - List KnownIssues, - WebLink? CompleteChangelogLink); -``` - -- `BaselineVersionTag` (`VersionCommitTag?`) - the previous version tag, which is the - lower boundary of the reported range -- `CurrentVersionTag` (`VersionCommitTag`) - the version tag being reported -- `Changes` (`List`) - feature and other non-bug items in this build -- `Bugs` (`List`) - bug-fix items in this build -- `KnownIssues` (`List`) - open issues not yet fixed -- `CompleteChangelogLink` (`WebLink?`) - optional link to the full changelog on - the host -- `RoutedSections` (`IReadOnlyList<(string SectionId, string SectionTitle, IReadOnlyList Items)>?`) - - optional ordered list of custom report sections populated by `RepoConnectorBase.ApplyRules` - when routing rules are configured; `null` when no rules are active +**BaselineVersionTag**: `VersionCommitTag?` — the previous version tag, which is the lower +boundary of the reported range; `null` when reporting from the beginning of history. + +**CurrentVersionTag**: `VersionCommitTag` — the version tag being reported. + +**Changes**: `List` — feature and other non-bug items in this build. + +**Bugs**: `List` — bug-fix items in this build. + +**KnownIssues**: `List` — open issues not yet fixed. + +**CompleteChangelogLink**: `WebLink?` — optional link to the full changelog on the host; +`null` when not available. + +**RoutedSections**: `IReadOnlyList<(string SectionId, string SectionTitle, IReadOnlyList Items)>?` — +optional ordered list of custom report sections populated by `RepoConnectorBase.ApplyRules` +when routing rules are configured; `null` when no rules are active. This is an init-only +property set after record construction. #### Key Methods -##### `ToMarkdown(headingDepth, includeKnownIssues) → string` - -Renders the build information as a markdown string. The `headingDepth` parameter -controls the top-level heading depth (default `1`), allowing the report to be -embedded at any level in a larger document. The `includeKnownIssues` flag controls -whether the Known Issues section is emitted. - -When `RoutedSections` is non-null and non-empty, `ToMarkdown` renders each section -from the `RoutedSections` list (using `AppendRoutedSections`) instead of the legacy -`Changes` and `Bugs` lists. Known issues are **always excluded from routing** because -they are not linked to any commit in the build range; when `includeKnownIssues` is -`true`, a `## Known Issues` section is appended after the routed sections regardless -of which rendering mode is active. When `RoutedSections` is `null` or empty, -`ToMarkdown` falls back to the legacy sections. - -The rendered output contains the following sections: - -1. **Version Information** - baseline and current version tags with commit hashes. -2. **Custom sections from `RoutedSections`** *(when rules are configured)* - one - sub-heading per section with the section title and its items. - **OR** the following legacy sections *(when no rules are configured)*: - - **Changes** - list of `ItemInfo` records from `Changes`. - - **Bugs Fixed** - list of `ItemInfo` records from `Bugs`. -3. **Known Issues** *(optional)* - list of `ItemInfo` records from `KnownIssues`, - emitted only when `includeKnownIssues` is `true`. Appears after routed sections - in routed mode and after legacy sections in legacy mode. -4. **Full Changelog** *(optional)* - hyperlink from `CompleteChangelogLink`, emitted - only when the link is non-null. +**ToMarkdown**: Renders the build information as a markdown string. + +- *Parameters*: `int headingDepth` — root markdown heading depth (default `1`); + `bool includeKnownIssues` — flag to include the Known Issues section (default `false`). +- *Returns*: `string` — fully formatted markdown report. +- *Preconditions*: All required record fields are populated by a connector. +- *Postconditions*: Returns a valid UTF-8 markdown string; record state is not mutated. + +When `RoutedSections` is non-null and non-empty, renders each section from the +`RoutedSections` list instead of the legacy `Changes` and `Bugs` lists. Known issues are +always excluded from routing; when `includeKnownIssues` is `true`, a Known Issues section is +appended after the routed sections regardless of which rendering mode is active. When +`RoutedSections` is `null` or empty, falls back to the legacy Changes and Bugs Fixed sections. + +The rendered output includes: (1) Version Information table; (2) custom routed sections or +legacy Changes/Bugs Fixed sections; (3) optional Known Issues section; (4) optional Full +Changelog link. #### Error Handling N/A — `BuildInformation` is an immutable data record. `ToMarkdown` renders content from already-validated data and does not throw under normal operation. -#### Interactions +#### Dependencies + +- **VersionCommitTag** — carries version and commit hash for baseline and current entries + (Version subsystem) +- **ItemInfo** — each item in `Changes`, `Bugs`, `KnownIssues`, and `RoutedSections` +- **WebLink** — optional complete-changelog hyperlink + +#### Callers -| Unit / Subsystem | Role | -| :----------------- | :---------------------------------------------------------------- | -| `VersionCommitTag` | Carries version and commit hash for baseline and current entries | -| `ItemInfo` | Each item in `Changes`, `Bugs`, and `KnownIssues` | -| `WebLink` | Optional complete-changelog hyperlink | -| `RepoConnectors` | Connectors assemble and return a `BuildInformation` record | -| `Program` | Calls `ToMarkdown` to produce the final report file | +- **RepoConnectors** — connectors assemble and return a `BuildInformation` record +- **Program** — calls `ToMarkdown` to produce the final report file +- **Validation** — creates `BuildInformation` records during self-tests to verify rendering diff --git a/docs/design/build-mark/build-notes/item-info.md b/docs/design/build-mark/build-notes/item-info.md index fc92fdc..ffb817a 100644 --- a/docs/design/build-mark/build-notes/item-info.md +++ b/docs/design/build-mark/build-notes/item-info.md @@ -2,45 +2,40 @@ #### Purpose -`ItemInfo` is a record in the BuildNotes subsystem that represents a single issue -or pull request entry in the build report. It is produced by connectors and stored -in the `Changes`, `Bugs`, and `KnownIssues` lists of `BuildInformation`. +`ItemInfo` is a record in the BuildNotes subsystem that represents a single issue or pull +request entry in the build report. It is produced by connectors and stored in the `Changes`, +`Bugs`, and `KnownIssues` lists of `BuildInformation`. #### Data Model -```csharp -public record ItemInfo( - string Id, - string Title, - string Url, - string Type, - int Index = 0, - VersionIntervalSet? AffectedVersions = null); -``` - -| Property | Type | Description | -|--------------------|-----------------------|------------------------------------------------------------| -| `Id` | `string` | Human-readable identifier (e.g., `#42`) | -| `Title` | `string` | Issue or pull request title | -| `Url` | `string` | Link to the issue or pull request on the host | -| `Type` | `string` | Normalized type: `"bug"`, `"feature"`, or a label name | -| `Index` | `int` | Numeric issue/PR number for deterministic sorting | -| `AffectedVersions` | `VersionIntervalSet?` | Interval set from the `affected-versions` field, or `null` | +**Id**: `string` — human-readable identifier shown in the report (e.g., `#42`). + +**Title**: `string` — issue or pull request title. + +**Url**: `string` — link to the issue or pull request on the host. + +**Type**: `string` — normalized type: `"bug"`, `"feature"`, or a label name. + +**Index**: `int` — numeric issue or PR number used for deterministic sort ordering; default `0`. + +**AffectedVersions**: `VersionIntervalSet?` — interval set from the `affected-versions` field +in an embedded `buildmark` block, or `null` when not specified. #### Key Methods -N/A — `ItemInfo` is an immutable data record with no methods beyond those auto-generated -by C#. +N/A — `ItemInfo` is an immutable data record with no methods beyond those auto-generated by C#. #### Error Handling -N/A — This is an immutable data record with no methods that detect or propagate errors. +N/A — immutable data record with no methods that detect or propagate errors. + +#### Dependencies + +- **VersionIntervalSet** — holds the optional affected-versions interval set (Version subsystem) -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|---------------------|-------------------------------------------------------------| -| `BuildInformation` | Contains lists of `ItemInfo` records | -| `VersionIntervalSet`| Holds the optional affected-versions interval set | -| `RepoConnectors` | Connectors create `ItemInfo` records from repository data | -| `ItemRouter` | Routes `ItemInfo` records to report sections | +- **BuildInformation** — contains `List` for `Changes`, `Bugs`, `KnownIssues`, and + the items within `RoutedSections` +- **RepoConnectors** — connectors create `ItemInfo` records from repository data +- **ItemRouter** — routes `ItemInfo` records to named report sections (RepoConnectors subsystem) diff --git a/docs/design/build-mark/build-notes/web-link.md b/docs/design/build-mark/build-notes/web-link.md index 48123da..755f425 100644 --- a/docs/design/build-mark/build-notes/web-link.md +++ b/docs/design/build-mark/build-notes/web-link.md @@ -2,31 +2,30 @@ #### Purpose -`WebLink` is a record in the BuildNotes subsystem that represents a hyperlink. It -is used by `BuildInformation` to carry the optional complete-changelog link that -appears at the end of the rendered markdown report. +`WebLink` is a record in the BuildNotes subsystem that represents a hyperlink. It is used by +`BuildInformation` to carry the optional complete-changelog link that appears at the end of +the rendered markdown report. #### Data Model -```csharp -public record WebLink( - string LinkText, - string TargetUrl); -``` +**LinkText**: `string` — human-readable link label shown in the report. -- `LinkText` (`string`) is the human-readable link label shown in the report. -- `TargetUrl` (`string`) is the fully-qualified URL that the link points to. +**TargetUrl**: `string` — fully-qualified URL that the link points to. #### Key Methods -N/A — `WebLink` is an immutable data record with no methods beyond those auto-generated -by C#. +N/A — `WebLink` is an immutable data record with no methods beyond those auto-generated by C#. #### Error Handling -N/A — This is an immutable data record with no methods that detect or propagate errors. +N/A — immutable data record with no methods that detect or propagate errors. -#### Interactions +#### Dependencies -- `BuildInformation` holds a `WebLink?` as `CompleteChangelogLink`. -- `RepoConnectors` construct the `WebLink` from baseline and current tags. +N/A — `WebLink` has no dependencies on other software items; it is a simple record of two +strings. + +#### Callers + +- **BuildInformation** — holds a `WebLink?` as `CompleteChangelogLink` +- **RepoConnectors** — connectors construct the `WebLink` from baseline and current tags diff --git a/docs/design/build-mark/cli.md b/docs/design/build-mark/cli.md index 33d1286..884902e 100644 --- a/docs/design/build-mark/cli.md +++ b/docs/design/build-mark/cli.md @@ -2,54 +2,41 @@ ### Overview -The Cli subsystem provides the command-line interface layer for BuildMark. It -parses arguments supplied by the user, routes output to the console or a log file, -and exposes the parsed state to the rest of the system via the `Context` object. +The Cli subsystem provides the command-line interface layer for BuildMark. It parses arguments +supplied by the user, routes output to the console or a log file, and exposes the parsed state to +the rest of the system via the `Context` object. -The subsystem has no dependencies on other BuildMark subsystems. All other -subsystems receive a `Context` from the caller rather than creating one themselves. +The subsystem contains one unit: -### Units +- **`Context`** (`Cli/Context.cs`) — argument parsing, output routing, and exit-code tracking -| Unit | File | Responsibility | -|-----------|------------------|---------------------------------------------| -| `Context` | `Cli/Context.cs` | Argument parsing, output routing, exit code | +The Cli subsystem has no dependencies on other BuildMark subsystems. All other subsystems receive a +`Context` from the caller rather than creating one themselves. ### Interfaces -`Context` exposes the following outward-facing interface consumed by `Program`: - -| Member | Kind | Description | -|-----------------------|----------|----------------------------------------------------| -| `Create(args)` | Method | Factory: parse arguments and return a `Context` | -| `Version` | Property | Set when `--version` / `-v` flag is present | -| `Help` | Property | Set when `--help` / `-h` / `-?` flag is present | -| `Silent` | Property | Set when `--silent` flag is present | -| `Validate` | Property | Set when `--validate` flag is present | -| `Lint` | Property | Set when `--lint` flag is present | -| `BuildVersion` | Property | Value of `--build-version` argument | -| `ReportFile` | Property | Value of `--report` argument | -| `Depth` | Property | Value of `--depth`/`--report-depth`; range 1–6 | -| `IncludeKnownIssues` | Property | Set when `--include-known-issues` flag is present | -| `ResultsFile` | Property | Value of `--results` / `--result` argument | -| `ConnectorFactory` | Property | Optional factory for dependency injection in tests | -| `ExitCode` | Property | Returns 0 unless `WriteError` has been called | -| `WriteLine(message)` | Method | Writes a line to console (if not silent) and log | -| `WriteError(message)` | Method | Writes an error line and sets exit code to 1 | -| `Dispose()` | Method | Closes the log file if one was opened | - -> `Create(args)` throws `ArgumentException` for invalid or malformed arguments. +**`Context.Create`**: Factory method for constructing a `Context` from command-line arguments. -### Design +- *Type*: In-process .NET static method +- *Role*: Provider — the Cli subsystem exposes this factory for `Program`. +- *Contract*: `Create(string[] args) → Context` and `Create(string[] args, Func?) → Context`; + parses the argument array, opens any specified log file, and returns a fully initialized `Context`. +- *Constraints*: Throws `ArgumentException` for invalid or unrecognized flags; throws + `InvalidOperationException` if the log file cannot be opened. + +**`Context` output and control methods**: Instance methods consumed by all subsystems for writing +output and tracking errors. -The Cli subsystem contains a single unit (`Context`), so there is no inter-unit -collaboration to describe. `Context.Create` parses the argument array and opens -the optional log file. The resulting `Context` object is then passed by `Program` -to every other subsystem that needs to write output, read flags, or set the exit -code. No other subsystem creates a `Context`; all output and exit-code management -flows through the single instance created at startup. +- *Type*: In-process .NET instance methods +- *Role*: Provider +- *Contract*: `WriteLine(message)` writes to console and log; `WriteError(message)` writes to standard + error and sets `ExitCode` to 1; `Dispose()` flushes and closes the log file. +- *Constraints*: `Context` implements `IDisposable`; callers must dispose after use. -### Interactions +### Design -The Cli subsystem has no dependencies on other BuildMark subsystems. `Program` -creates a `Context` and passes it to other subsystems as needed. +The Cli subsystem contains a single unit (`Context`), so there is no inter-unit collaboration to +describe. `Context.Create` parses the argument array using the private `ArgumentParser` nested class +and opens the optional log file. The resulting `Context` object is passed by `Program` to every other +subsystem that needs to write output, read flags, or set the exit code. No other subsystem creates a +`Context`; all output and exit-code management flows through the single instance created at startup. diff --git a/docs/design/build-mark/cli/context.md b/docs/design/build-mark/cli/context.md index 754b258..f0d281f 100644 --- a/docs/design/build-mark/cli/context.md +++ b/docs/design/build-mark/cli/context.md @@ -2,102 +2,115 @@ #### Purpose -`Context` is the sole unit in the Cli subsystem. It owns the lifecycle of -command-line argument parsing, console and log-file output, and exit-code tracking. -`Program` creates exactly one `Context` per invocation and passes it to all other -units that need to write output or read configuration. +`Context` is the sole unit in the Cli subsystem. It owns the lifecycle of command-line argument +parsing, console and log-file output, and exit-code tracking. `Program` creates exactly one +`Context` per invocation and passes it to all other units that need to write output or read +configuration flags. -`Context` implements `IDisposable`. Callers must dispose of the context after use -so that any open log file is properly flushed and closed. +`Context` implements `IDisposable`. Callers must dispose of the context after use so that any open +log file is properly flushed and closed. #### Data Model -##### Parsed Flags +**`Version`**: `bool` — `true` when `-v` or `--version` is present; default `false`. -| Property | Type | Default | Source | -|----------------------|--------|---------|--------------------------| -| `Version` | `bool` | `false` | `-v` / `--version` | -| `Help` | `bool` | `false` | `-?` / `-h` / `--help` | -| `Silent` | `bool` | `false` | `--silent` | -| `Validate` | `bool` | `false` | `--validate` | -| `Lint` | `bool` | `false` | `--lint` | -| `IncludeKnownIssues` | `bool` | `false` | `--include-known-issues` | +**`Help`**: `bool` — `true` when `-?`, `-h`, or `--help` is present; default `false`. -##### Parsed Arguments +**`Silent`**: `bool` — `true` when `--silent` is present; default `false`. -| Property | Type | Default | Source | -|--------------------|-------------------------|---------|----------------------------------------| -| `BuildVersion` | `string?` | `null` | `--build-version ` | -| `ReportFile` | `string?` | `null` | `--report ` | -| `Depth` | `int?` | `null` | `--depth ` | -| `ResultsFile` | `string?` | `null` | `--result ` / `--results ` | -| `ConnectorFactory` | `Func?` | `null` | Injected via overload | +**`Validate`**: `bool` — `true` when `--validate` is present; default `false`. -##### Derived State +**`Lint`**: `bool` — `true` when `--lint` is present; default `false`. -| Property | Type | Description | -|------------|-------|---------------------------------------------------| -| `ExitCode` | `int` | `0` if no errors have been written; `1` otherwise | +**`IncludeKnownIssues`**: `bool` — `true` when `--include-known-issues` is present; default `false`. -#### Key Methods - -##### `Create(string[] args) → Context` - -Public factory method. Constructs a new `Context` by forwarding to -`ArgumentParser`, then opens a log file if `--log` was specified. -Throws `ArgumentException` for invalid arguments; throws -`InvalidOperationException` if the log file cannot be opened. - -##### `Create(string[] args, Func? connectorFactory) → Context` - -Overload that additionally accepts a connector factory for dependency injection -during testing. The factory is stored on `ConnectorFactory` and used by -`Program.ProcessBuildNotes` instead of the default factory. - -##### `OpenLogFile(string logFile)` +**`BuildVersion`**: `string?` — value of `--build-version `; `null` when not supplied. -Opens the specified file for writing in overwrite mode (truncating any existing -file) with `AutoFlush` enabled. If the directory does not exist, the method -throws `InvalidOperationException`. +**`ReportFile`**: `string?` — value of `--report `; `null` when not supplied. -##### `WriteLine(string message)` +**`Depth`**: `int?` — value of `--depth ` (also accepted as `--report-depth`); must be a +positive integer in the range 1–6; `null` when not supplied. -Writes `message` to standard output (unless `Silent` is set) and to the log file -(if open). +**`ResultsFile`**: `string?` — value of `--result ` or `--results `; `null` when not +supplied. -##### `WriteError(string message)` +**`ConnectorFactory`**: `Func?` — optional factory injected via the testing overload +of `Create`; `null` in production. -Writes `message` to standard error in red (unless `Silent` is set) and to the -log file (if open). Sets the internal error flag so that `ExitCode` returns `1`. +**`ExitCode`**: `int` — returns 0 if no errors have been written; returns 1 after the first call to +`WriteError`. -##### `Dispose()` - -Flushes and closes the log file stream. Safe to call multiple times. - -#### Inner Class: `ArgumentParser` - -`ArgumentParser` is a private nested class used exclusively by `Create`. It -iterates over the argument array and classifies each token: +#### Key Methods -- Short flags (`-v`, `-h`, `-?`) and long flags (`--version`, `--help`, etc.) - are mapped to boolean properties. -- Value arguments (`--build-version`, `--report`, `--depth`, `--results`, - `--log`) expect the next token as their value and throw `ArgumentException` if - no next token is present. -- `--depth` additionally validates that the value is a positive integer. -- The legacy `--report-depth` argument is also accepted as an undocumented alias for `--depth`. +**`Create(string[] args) → Context`**: Public factory method; constructs a new `Context` by +forwarding to `ArgumentParser`, then opens a log file if `--log` was specified. + +- *Parameters*: `string[] args` — command-line arguments. +- *Returns*: `Context` — fully initialized context. +- *Preconditions*: None. +- *Postconditions*: All flags and arguments are parsed; log file is open if `--log` was specified. +- *Throws*: `ArgumentException` for invalid or unrecognized arguments; `InvalidOperationException` + if the log file cannot be opened. + +**`Create(string[] args, Func? connectorFactory) → Context`**: Overload that +additionally stores a connector factory for dependency injection during testing. + +- *Parameters*: `string[] args` — command-line arguments; `Func? connectorFactory` + — optional factory stored on `ConnectorFactory`. +- *Returns*: `Context` — fully initialized context. +- *Preconditions*: None. +- *Postconditions*: Same as the single-argument overload; `ConnectorFactory` is set when non-null. + +**`WriteLine(string message)`**: Writes `message` to standard output (unless `Silent` is set) and to +the log file (if open). + +- *Parameters*: `string message` — line to write. +- *Returns*: void. +- *Preconditions*: None. +- *Postconditions*: Message written to all enabled output channels. + +**`WriteError(string message)`**: Writes `message` to standard error in red (unless `Silent` is set), +to the log file (if open), and sets the internal error flag so that `ExitCode` returns 1. + +- *Parameters*: `string message` — error message to write. +- *Returns*: void. +- *Preconditions*: None. +- *Postconditions*: `ExitCode` returns 1 for this and all subsequent calls. + +**`Dispose()`**: Flushes and closes the log file stream. + +- *Parameters*: None. +- *Returns*: void. +- *Preconditions*: None. +- *Postconditions*: Log file stream is closed and released. Safe to call multiple times. + +**`ArgumentParser` (private nested class)**: Used exclusively by `Create`. Iterates over the +argument array and classifies each token. + +- Short flags (`-v`, `-h`, `-?`) and long flags (`--version`, `--help`, etc.) are mapped to boolean + properties. +- Value arguments (`--build-version`, `--report`, `--depth`, `--results`, `--log`) consume the next + token as their value; `ArgumentException` is thrown if no next token is present. +- `--depth` additionally validates that the value is a positive integer in the range 1–6. +- `--report-depth` is accepted as an undocumented alias for `--depth`. - Any unrecognized token causes `ArgumentException` to be thrown. #### Error Handling -`Create(string[] args)` throws `ArgumentException` when an unrecognized flag or missing -value argument is encountered, and `InvalidOperationException` if the log file path cannot -be opened. `OpenLogFile` throws `InvalidOperationException` if the target directory does -not exist. `WriteError` sets the internal error flag so that `ExitCode` returns `1` but -does not throw. +`Create(string[] args)` throws `ArgumentException` when an unrecognized flag or missing value +argument is encountered, and `InvalidOperationException` if the log file path cannot be opened. +`WriteError` sets the internal error flag so that `ExitCode` returns 1 but does not throw. +`Dispose` is safe to call multiple times. + +#### Dependencies + +- **`IRepoConnector`** — the interface type used for the `ConnectorFactory` delegate (RepoConnectors + subsystem) -#### Interactions +#### Callers -`Program` creates exactly one `Context` per invocation using `Context.Create(args)` and -passes it to `Validation`, `BuildMarkConfigReader`, and all connector subsystems. `Context` -must be disposed after use to flush and close any open log file. +- **`Program`** — creates exactly one `Context` per invocation via `Context.Create(args)` and passes + it to all other subsystems +- **`Validation`** — receives `Context` as input parameter; writes output and reads `ResultsFile` +- **`BuildMarkConfigReader`** — receives `Context` to report configuration issues +- **`RepoConnectors`** — connector subsystems receive `Context` for logging and error reporting diff --git a/docs/design/build-mark/configuration.md b/docs/design/build-mark/configuration.md index 3bbb44a..2c968e1 100644 --- a/docs/design/build-mark/configuration.md +++ b/docs/design/build-mark/configuration.md @@ -1,154 +1,70 @@ -## Configuration Subsystem +## Configuration ### Overview -The Configuration subsystem is responsible for reading and parsing the optional -`.buildmark.yaml` file located in the repository root. It uses the YamlDotNet -library to parse the YAML content, then walks the resulting representation model -to build a strongly-typed `BuildMarkConfig` object. Any parse errors or -validation warnings are surfaced through a `ConfigurationLoadResult` record that -`Program` consumes during startup. +The Configuration subsystem is responsible for reading and parsing the optional `.buildmark.yaml` +file located in the repository root. It uses the YamlDotNet library's representation model to +parse raw YAML content, then manually walks the resulting node tree to produce a strongly-typed +`BuildMarkConfig` object. Any parse errors or validation warnings are captured as +`ConfigurationIssue` records and surfaced through a `ConfigurationLoadResult` that `Program` +consumes during startup. -When no `.buildmark.yaml` file is present, `BuildMarkConfigReader` returns a -`ConfigurationLoadResult` with a `null` configuration and an empty issues list, -and the rest of the system operates with its default behavior unchanged. When -the file is present but malformed, the result carries `null` for the -configuration alongside a list of `ConfigurationIssue` records describing each -problem with its file path, line number, severity, and description. +When no `.buildmark.yaml` file is present, `BuildMarkConfigReader` returns a result with +`Config = null` and an empty issues list, and the rest of the system operates with +`BuildMarkConfig.CreateDefault()` defaults. When the file is present but malformed, the result +carries `Config = null` alongside a list of `ConfigurationIssue` records that describe each +problem with its file path, 1-based line number, severity, and description. -### Units - -| Unit | File | Responsibility | -|-----------------------------|-----------------------------------------------|----------------------------------------| -| `BuildMarkConfig` | `Configuration/BuildMarkConfig.cs` | Top-level configuration data model | -| `BuildMarkConfigReader` | `Configuration/BuildMarkConfigReader.cs` | Reads and parses `.buildmark.yaml` | -| `ConfigurationLoadResult` | `Configuration/ConfigurationLoadResult.cs` | Holds config and any load issues | -| `ConfigurationIssue` | `Configuration/ConfigurationIssue.cs` | Single issue with location and severity| -| `ConnectorConfig` | `Configuration/ConnectorConfig.cs` | Connector envelope data model | -| `GitHubConnectorConfig` | `Configuration/GitHubConnectorConfig.cs` | GitHub connector settings data model | -| `AzureDevOpsConnectorConfig`| `Configuration/AzureDevOpsConnectorConfig.cs` | Azure DevOps connector settings | -| `ReportConfig` | `Configuration/ReportConfig.cs` | Report output settings data model | -| `SectionConfig` | `Configuration/SectionConfig.cs` | Report section definition data model | -| `RuleConfig` | `Configuration/RuleConfig.cs` | Item routing rule data model | -| `RuleMatchConfig` | `Configuration/RuleConfig.cs` | Conditions for an item routing rule | +The subsystem contains the following units: `BuildMarkConfig`, `BuildMarkConfigReader`, +`ConfigurationLoadResult`, `ConfigurationIssue`, `ConnectorConfig`, `GitHubConnectorConfig`, +`AzureDevOpsConnectorConfig`, `ReportConfig`, `SectionConfig`, `RuleConfig`, and +`RuleMatchConfig`. ### Interfaces -`BuildMarkConfigReader` exposes the following outward-facing interface consumed by -`Program`: - -| Member | Kind | Description | -|-------------------|--------|---------------------------------------------------------------------------| -| `ReadAsync(path)` | Method | Reads and deserializes the file; always returns `ConfigurationLoadResult` | - -`ConfigurationLoadResult` carries the following members: - -| Member | Kind | Description | -|---------------------|----------|----------------------------------------------------------| -| `Config` | Property | Parsed `BuildMarkConfig`; `null` if parsing failed | -| `Issues` | Property | Ordered list of `ConfigurationIssue` objects | -| `HasErrors` | Property | `true` when any issue has `Severity` of `Error` | -| `ReportTo(context)` | Method | Writes all issues to `Context`; sets exit code on errors | - -`ConfigurationIssue` carries the following properties: - -| Member | Kind | Description | -|---------------|----------|----------------------------------------------------| -| `FilePath` | Property | Path to the file containing the issue | -| `Line` | Property | Line number (1-based) of the issue | -| `Severity` | Property | `ConfigurationIssueSeverity` enum value | -| `Description` | Property | Human-readable description of the issue | - -`ConfigurationIssueSeverity` is a public enum with two values: - -| Value | Description | -|-----------|----------------------------------------------------------| -| `Warning` | Non-fatal issue; tool continues and exit code is 0 | -| `Error` | Fatal issue; tool reports all errors, exits with code 1 | - -`BuildMarkConfig` carries the following properties: - -| Member | Kind | Description | -|-------------|----------|-------------------------------------------------------| -| `Connector` | Property | Optional `ConnectorConfig`; `null` when not specified | -| `Report` | Property | Optional `ReportConfig`; `null` when not specified | -| `Sections` | Property | Ordered list of `SectionConfig` objects | -| `Rules` | Property | List of `RuleConfig` objects | - -`ConnectorConfig` carries the following properties: - -| Member | Kind | Description | -|---------------|----------|---------------------------------------------------------------------------------| -| `Type` | Property | Connector type: `"github"` or `"azure-devops"` | -| `GitHub` | Property | Optional `GitHubConnectorConfig`; present when `Type` is `"github"` | -| `AzureDevOps` | Property | Optional `AzureDevOpsConnectorConfig`; present when `Type` is `"azure-devops"` | - -`GitHubConnectorConfig` carries the following properties: - -| Member | Kind | Description | -|-----------|----------|---------------------------------------------------------------------| -| `Owner` | Property | Repository owner override | -| `Repo` | Property | Repository name override | -| `BaseUrl` | Property | Optional GitHub Enterprise API base URL; `null` uses the public API | - -`AzureDevOpsConnectorConfig` carries the following properties: - -| Member | Kind | Description | -|-------------------|----------|-------------------------------------------------------------------------------| -| `OrganizationUrl` | Property | Azure DevOps organization URL (e.g. `https://dev.azure.com/myorg`) | -| `Organization` | Property | Optional organization name override; `null` when not specified | -| `Project` | Property | Azure DevOps project name | -| `Repository` | Property | Repository name within the project | - -`ReportConfig` carries the following properties: - -| Member | Kind | Description | -|----------------------|----------|-----------------------------------------------------------------------------------| -| `File` | Property | Optional output file path override; `null` uses the default report path | -| `Depth` | Property | Optional heading depth for report sections; `null` uses the default depth | -| `IncludeKnownIssues` | Property | Optional flag to include known issues in the report; `null` uses the default | - -`SectionConfig` carries the following properties: - -| Member | Kind | Description | -|---------|----------|--------------------------------------| -| `Id` | Property | Unique identifier for the section | -| `Title` | Property | Display title for the report section | - -`RuleConfig` carries the following properties: - -| Member | Kind | Description | -|---------|----------|---------------------------------------------------------| -| `Match` | Property | Match conditions (labels, work-item types) for the rule | -| `Route` | Property | Destination section `Id` for matched items | - -`RuleMatchConfig` carries the following properties: - -| Member | Kind | Description | -|----------------|----------|-------------------------------------------------------------------| -| `Label` | Property | List of label values; the rule matches when any label is present | -| `WorkItemType` | Property | List of work-item type values; rule matches when any type matches | +**BuildMarkConfigReader API**: Public static entry point consumed by `Program` to load +configuration. + +- *Type*: In-process .NET public API. +- *Role*: Provider — `Program` calls this to obtain configuration before any other work. +- *Contract*: `BuildMarkConfigReader.ReadAsync(string path)` accepts a repository root directory + or a direct `.buildmark.yaml` file path and returns `Task`. The result + always contains a non-null `Issues` list. `Config` is non-null only when the file was found and + parsed without errors. +- *Constraints*: Never throws; all error conditions are reported as `ConfigurationIssue` records + in the returned result. + +**YamlDotNet Integration**: Representation-model YAML parsing consumed internally by +`BuildMarkConfigReader`. + +- *Type*: In-process .NET library (OTS). +- *Role*: Consumer — `BuildMarkConfigReader` uses YamlDotNet exclusively for YAML parsing. +- *Contract*: Uses `YamlStream.Load(TextReader)` to parse raw text into a node tree; accesses + `YamlMappingNode`, `YamlSequenceNode`, and `YamlScalarNode` to walk the parsed structure. + Catches `YamlException` and converts it to a `ConfigurationIssue`. +- *Constraints*: Input text must be UTF-8 encoded YAML. `YamlException` is the only expected + exception; all other exceptions propagate to the caller. ### Design -`BuildMarkConfigReader.ReadAsync` is the subsystem's only entry point. It uses -the YamlDotNet `YamlStream` representation model to parse the raw YAML content, -then walks the resulting node tree manually to populate the strongly-typed -configuration objects. Each node walk is guarded so that a missing or invalid -node creates a `ConfigurationIssue` record rather than throwing an exception. - -All constructed objects — `BuildMarkConfig`, `ConnectorConfig`, -`GitHubConnectorConfig`, `AzureDevOpsConnectorConfig`, `ReportConfig`, -`SectionConfig`, `RuleConfig`, and `RuleMatchConfig` — are assembled in a single -pass and returned wrapped in a `ConfigurationLoadResult`. `Program` calls -`result.ReportTo(context)` to surface issues to the user and checks `HasErrors` -before continuing to the connector and report-generation steps. - -### Interactions - -| Unit / Subsystem | Role | -|----------------------------|-------------------------------------------------------------------------------| -| `Program` | Calls `BuildMarkConfigReader.ReadAsync`; calls `result.ReportTo(context)` | -| `RepoConnectorFactory` | Receives `ConnectorConfig` from `result.Config` to select the connector | -| `GitHubRepoConnector` | Reads `GitHubConnectorConfig` from `result.Config.Connector.GitHub` | -| `AzureDevOpsRepoConnector` | Reads `AzureDevOpsConnectorConfig` from `result.Config.Connector.AzureDevOps` | +`BuildMarkConfigReader.ReadAsync` is the subsystem's single entry point. The following steps +describe the flow from call to result: + +1. `Program` calls `BuildMarkConfigReader.ReadAsync(path)` passing the repository root directory. +2. `BuildMarkConfigReader` resolves `path` to the `.buildmark.yaml` file via `ResolveFilePath`; + if the path is a directory, `.buildmark.yaml` is appended. +3. If the resolved file does not exist, a `ConfigurationLoadResult` with `Config = null` and an + empty issues list is returned immediately. +4. If the file exists, its content is read asynchronously and passed to `YamlStream.Load`. An + empty or comment-only file returns a result with a default `BuildMarkConfig` and no issues. +5. On a `YamlException`, a `ConfigurationIssue` with `Severity = Error` is created from the + exception's start position and message, and a result with `Config = null` is returned. +6. For a successful parse, `BuildMarkConfigReader` walks the root `YamlMappingNode`, dispatching + each top-level key (`connector`, `report`, `sections`, `rules`) to a dedicated private parser. + Each parser populates the corresponding data record (`ConnectorConfig`, `ReportConfig`, + `SectionConfig`, `RuleConfig`, `RuleMatchConfig`). Invalid node types or unrecognized keys + produce `Error`-severity `ConfigurationIssue` records. +7. If any `Error`-severity issues were collected, the result is returned with `Config = null`; + otherwise `Config` carries the fully populated `BuildMarkConfig`. +8. `Program` calls `result.ReportTo(context)` to surface all issues to the user, then checks + `result.HasErrors` before proceeding to connector selection and report generation. diff --git a/docs/design/build-mark/configuration/build-mark-config-reader.md b/docs/design/build-mark/configuration/build-mark-config-reader.md index dde9fe9..3b738fc 100644 --- a/docs/design/build-mark/configuration/build-mark-config-reader.md +++ b/docs/design/build-mark/configuration/build-mark-config-reader.md @@ -5,10 +5,9 @@ `BuildMarkConfigReader` is a static utility class responsible for reading and deserializing the optional `.buildmark.yaml` file from the repository root. It uses the YamlDotNet library's representation model (`YamlStream`) to parse YAML content, then walks the resulting node tree -to produce a strongly-typed `BuildMarkConfig` object. - -The method always returns a `ConfigurationLoadResult` and never throws. Parse errors and -validation warnings are captured as `ConfigurationIssue` records within the result. +to produce a strongly-typed `BuildMarkConfig` object. The class always returns a +`ConfigurationLoadResult` and never throws; parse errors and validation warnings are captured +as `ConfigurationIssue` records within the result. #### Data Model @@ -16,31 +15,47 @@ N/A — `BuildMarkConfigReader` is a static utility class with no instance state #### Key Methods -| Member | Kind | Description | -|-------------------|---------------|---------------------------------------------------------------------------| -| `ReadAsync(path)` | Static method | Reads and deserializes `.buildmark.yaml`; always returns a load result | - -##### `ReadAsync(string path) → Task` +**ReadAsync(path)**: Reads and deserializes the `.buildmark.yaml` file at the given path. + +- *Parameters*: `string path` — a repository root directory or a direct `.buildmark.yaml` file + path. +- *Returns*: `Task` — always returns a result; never throws. +- *Preconditions*: `path` must be a valid file system path string (either an existing directory + or a file path). +- *Postconditions*: If the file is absent, `Config = null` and `Issues` is empty. If parsing + fails, `Config = null` and `Issues` contains one or more `Error`-severity records. If the file + is valid, `Config` is a fully populated `BuildMarkConfig` and `Issues` contains any warnings + collected during the walk. + +Resolves `path` to the `.buildmark.yaml` file via `ResolveFilePath` (appending `.buildmark.yaml` +when `path` is a directory). Reads file content asynchronously, then passes it to +`YamlStream.Load`. An empty or comment-only file returns a result with a default +`BuildMarkConfig` and no issues. On a `YamlException`, the exception's start position and +message are captured as an `Error`-severity `ConfigurationIssue` and a `null`-config result is +returned. For a successful parse, `ParseDocument` dispatches each top-level YAML key to a +dedicated private parser that populates the corresponding data record; unrecognized keys and +invalid node types produce `Error`-severity issues. If any errors were collected, `Config` is +returned as `null`. -Looks for a `.buildmark.yaml` file at the supplied path (normally the repository root): +#### Error Handling -- If the file is absent, returns a result with `Config = null` and an empty issues list. -- If the file is present but contains YAML errors or invalid values, returns a result with - `Config = null` and one or more `ConfigurationIssue` records describing each problem. -- If the file is valid, returns a result with a fully populated `BuildMarkConfig` and an empty - issues list. +`ReadAsync` never throws. All `YamlException` parse errors are caught and converted to +`ConfigurationIssue` records with `Severity = Error`. Node-walk failures — including invalid +node types and unsupported configuration keys — also produce `Error`-severity issues. When any +error-severity issue is present, `Config` is `null` in the returned result. -#### Error Handling +#### Dependencies -`ReadAsync` never throws. All YAML parse errors and validation warnings are captured as -`ConfigurationIssue` records within the returned `ConfigurationLoadResult`. This ensures -that `Program` can always inspect issues via `ReportTo` regardless of the file content. +- **YamlDotNet** — provides `YamlStream`, `YamlDocument`, `YamlMappingNode`, + `YamlSequenceNode`, `YamlScalarNode`, and `YamlException` used for YAML parsing. +- **BuildMarkConfig** — produced and returned when parsing succeeds. +- **ConfigurationLoadResult** — always returned as the result of `ReadAsync`. +- **ConfigurationIssue** — created for each parse error or validation warning. +- **ConnectorConfig** — produced by the connector YAML block parser. +- **ReportConfig** — produced by the report YAML block parser. +- **SectionConfig** — produced by the sections YAML sequence parser. +- **RuleConfig** — produced by the rules YAML sequence parser. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|---------------------------|----------------------------------------------------------------------------| -| `BuildMarkConfig` | Produced by `ReadAsync` when parsing succeeds | -| `ConfigurationLoadResult` | Always returned by `ReadAsync`, carries config and any issues | -| `ConfigurationIssue` | Created for each parse error or validation warning encountered | -| `Program` | Calls `ReadAsync(Environment.CurrentDirectory)` via `LoadConfiguration()` | +- **Program** — calls `ReadAsync(Environment.CurrentDirectory)` via `LoadConfiguration()`. diff --git a/docs/design/build-mark/configuration/build-mark-config.md b/docs/design/build-mark/configuration/build-mark-config.md index 93d7dbf..bd9c7b0 100644 --- a/docs/design/build-mark/configuration/build-mark-config.md +++ b/docs/design/build-mark/configuration/build-mark-config.md @@ -3,37 +3,58 @@ #### Purpose `BuildMarkConfig` is the top-level configuration data model for BuildMark. It holds all -settings read from the `.buildmark.yaml` file, including connector configuration, report -settings, section definitions, and item routing rules. - -When no `.buildmark.yaml` file is present, `Program` calls `BuildMarkConfig.CreateDefault()` -to obtain a default configuration with built-in section and rule definitions. +settings read from the `.buildmark.yaml` file, including optional connector configuration, +optional report settings, ordered section definitions, and item routing rules. When no +`.buildmark.yaml` file is present, `Program` calls `BuildMarkConfig.CreateDefault()` to obtain +a configuration populated with built-in sections and routing rules. #### Data Model -| Property | Type | Description | -|-------------|--------------------------|-------------------------------------------------------| -| `Connector` | `ConnectorConfig?` | Optional connector configuration; `null` when absent | -| `Report` | `ReportConfig?` | Optional report settings; `null` when absent | -| `Sections` | `IList` | Ordered list of report section definitions | -| `Rules` | `IList` | List of item routing rules | +**Connector**: `ConnectorConfig?` — Optional connector configuration; `null` when the +`connector:` key is absent from `.buildmark.yaml`. + +**Report**: `ReportConfig?` — Optional report output settings; `null` when the `report:` key +is absent from `.buildmark.yaml`. + +**Sections**: `List` — Ordered list of report section definitions built from the +`sections:` YAML sequence; empty when the key is absent. + +**Rules**: `List` — List of item routing rules built from the `rules:` YAML +sequence; empty when the key is absent. #### Key Methods -- `CreateDefault()` — Static factory returning a `BuildMarkConfig` populated with - built-in section and rule definitions, used when no `.buildmark.yaml` file is - present +**CreateDefault()**: Static factory that returns a `BuildMarkConfig` populated with built-in +section and routing rule definitions, used when no `.buildmark.yaml` file is present. + +- *Parameters*: None. +- *Returns*: `BuildMarkConfig` — a new instance whose `Sections` list contains three entries + (`changes`, `bugs-fixed`, `dependency-updates`) and whose `Rules` list contains six routing + rules (dependency labels → `dependency-updates`; Bug work-item type → `bugs-fixed`; bug + labels → `bugs-fixed`; internal/chore labels → `suppressed`; Task/Epic work-item types → + `suppressed`; catch-all → `changes`). `Connector` and `Report` are `null`. +- *Preconditions*: None. +- *Postconditions*: The returned config has non-empty `Sections` and `Rules` lists; `Connector` + and `Report` are `null`. #### Error Handling -N/A — `BuildMarkConfig` is a configuration data record. No methods on this type detect -or propagate errors; all validation occurs in `BuildMarkConfigReader`. +N/A — `BuildMarkConfig` is a configuration data record. No methods on this type detect or +propagate errors; all parsing and validation occur in `BuildMarkConfigReader`. + +#### Dependencies + +- **ConnectorConfig** — held by the `Connector` property when connector settings are present. +- **ReportConfig** — held by the `Report` property when report settings are present. +- **SectionConfig** — elements of the `Sections` list. +- **RuleConfig** — elements of the `Rules` list. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|--------------------------|----------------------------------------------------------------------------------| -| `BuildMarkConfigReader` | Produces `BuildMarkConfig` instances by parsing `.buildmark.yaml` | -| `Program` | Reads `Connector`, `Report`, `Sections`, and `Rules` to drive build notes output | -| `RepoConnectorBase` | Receives `Rules` and `Sections` via `Configure(rules, sections)` | -| `RepoConnectorFactory` | Receives `Connector` to select the appropriate connector implementation | +- **BuildMarkConfigReader** — creates instances by parsing `.buildmark.yaml` and returns them + inside a `ConfigurationLoadResult`. +- **Program** — calls `CreateDefault()` when no config file is present; reads `Connector`, + `Report`, `Sections`, and `Rules` to drive connector selection and report generation. +- **RepoConnectorBase** — receives `Rules` and `Sections` via `Configure(rules, sections)`. +- **RepoConnectorFactory** — receives `Connector` to select the appropriate connector + implementation. diff --git a/docs/design/build-mark/configuration/configuration-issue.md b/docs/design/build-mark/configuration/configuration-issue.md index e5b94ed..351fcc6 100644 --- a/docs/design/build-mark/configuration/configuration-issue.md +++ b/docs/design/build-mark/configuration/configuration-issue.md @@ -2,38 +2,43 @@ #### Purpose -`ConfigurationIssue` is an immutable record representing a single problem found while reading -or validating the `.buildmark.yaml` file. Each issue carries a file path, line number, -severity, and human-readable description. +`ConfigurationIssue` is an immutable positional record representing a single problem found +while reading or validating the `.buildmark.yaml` file. Each issue carries the source file +path, a 1-based line number, a severity, and a human-readable description. The companion +`ConfigurationIssueSeverity` enum distinguishes non-fatal warnings from fatal errors. #### Data Model -| Property | Type | Description | -|---------------|-----------------------------|----------------------------------------------------| -| `FilePath` | `string` | Path to the file containing the issue | -| `Line` | `int` | Line number (1-based) of the issue | -| `Severity` | `ConfigurationIssueSeverity`| `Warning` or `Error` | -| `Description` | `string` | Human-readable description of the issue | +**FilePath**: `string` — Path to the file in which the issue was found. -`ConfigurationIssueSeverity` is a public enum: +**Line**: `int` — 1-based line number of the issue within the file. -| Value | Description | -|-----------|----------------------------------------------------------| -| `Warning` | Non-fatal issue; tool continues and exit code is 0 | -| `Error` | Fatal issue; tool reports all errors, exits with code 1 | +**Severity**: `ConfigurationIssueSeverity` — `Warning` for non-fatal conditions (tool continues +with exit code 0) or `Error` for fatal conditions (tool reports all errors and exits with +code 1). + +**Description**: `string` — Human-readable explanation of the problem. + +`ConfigurationIssueSeverity` is a public enum defined in the same source file. Its values are +`Warning` (non-fatal; tool continues with exit code 0) and `Error` (fatal; tool reports all +errors and exits with code 1). #### Key Methods -N/A — `ConfigurationIssue` is an immutable data record with no methods beyond those auto-generated by C#. +N/A — `ConfigurationIssue` is an immutable positional record with no methods beyond those +auto-generated by C#. #### Error Handling -N/A — This is an immutable data record with no methods that detect or propagate errors. +N/A — Immutable data record with no methods that detect or propagate errors. + +#### Dependencies + +N/A — `ConfigurationIssue` has no dependencies on other units. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|---------------------------|----------------------------------------------------------------| -| `BuildMarkConfigReader` | Creates `ConfigurationIssue` records for each problem found | -| `ConfigurationLoadResult` | Holds the ordered list of `ConfigurationIssue` records | -| `Program` | Reads issues via `ConfigurationLoadResult.ReportTo(context)` | +- **BuildMarkConfigReader** — creates `ConfigurationIssue` records for each parse error or + validation warning encountered while reading `.buildmark.yaml`. +- **ConfigurationLoadResult** — holds the ordered list of `ConfigurationIssue` records in its + `Issues` property. diff --git a/docs/design/build-mark/configuration/configuration-load-result.md b/docs/design/build-mark/configuration/configuration-load-result.md index 6dcb8b4..beeae4d 100644 --- a/docs/design/build-mark/configuration/configuration-load-result.md +++ b/docs/design/build-mark/configuration/configuration-load-result.md @@ -2,45 +2,55 @@ #### Purpose -`ConfigurationLoadResult` is an immutable record that carries the output of +`ConfigurationLoadResult` is an immutable positional record that carries the output of `BuildMarkConfigReader.ReadAsync`. It holds the parsed configuration (or `null` if parsing -failed) together with an ordered list of issues found during parsing. - -`Program` calls `result.ReportTo(context)` immediately after reading the configuration to -surface any issues to the user and set the exit code when errors are present. +failed or the file was absent) together with an ordered list of issues found during parsing. +`Program` calls `result.ReportTo(context)` immediately after reading configuration to surface +all issues to the user and set the process exit code when errors are present. #### Data Model -| Member | Kind | Description | -|---------------------|----------|----------------------------------------------------------| -| `Config` | Property | Parsed `BuildMarkConfig`; `null` if parsing failed | -| `Issues` | Property | Ordered list of `ConfigurationIssue` objects | -| `HasErrors` | Property | `true` when any issue has `Severity` of `Error` | -| `ReportTo(context)` | Method | Writes all issues to `Context`; sets exit code on errors | +**Config**: `BuildMarkConfig?` — Parsed configuration; `null` when parsing failed or the file +was absent. -##### ReportTo Overview +**Issues**: `IReadOnlyList` — Ordered list of issues encountered during +parsing; empty when none were found. -Iterates `Issues` and writes each one to the context output. If any issue has severity -`Error`, sets `context.ExitCode` to 1. +**HasErrors**: `bool` — Computed property; `true` when any entry in `Issues` has +`Severity == Error`. #### Key Methods -##### `ReportTo(Context context)` +**ReportTo(context)**: Writes all configuration issues to the supplied context and sets the +process exit code to `1` if any error-severity issue is present. + +- *Parameters*: `Context context` — the CLI context that receives issue messages and holds the + exit code. +- *Returns*: `void`. +- *Preconditions*: `context` must not be null. +- *Postconditions*: Each issue is written to `context` using `context.WriteError` for + error-severity issues and `context.WriteLine` for warnings. Calling `context.WriteError` + sets the context's internal error flag, causing `context.ExitCode` to return `1`. Does not + throw exceptions. -Iterates `Issues` and writes each one to the context output. Issues with `Error` severity -are written via `context.WriteError`, which sets the exit code to `1`. Non-error issues are -written via `context.WriteLine`. Does not throw exceptions. +Each issue is formatted as `{FilePath}:{Line}: {Severity}: {Description}` before being written +to the context. #### Error Handling -N/A — `ConfigurationLoadResult` is an immutable record. `ReportTo(context)` writes issues -to the context output and may set the exit code to `1`, but does not throw exceptions. +N/A — `ConfigurationLoadResult` is an immutable record. `ReportTo` writes issues and may +indirectly set the process exit code to `1` via `context.WriteError` but does not throw +exceptions. + +#### Dependencies + +- **BuildMarkConfig** — held by `Config` when parsing succeeds. +- **ConfigurationIssue** — each entry in the `Issues` list. +- **Context** — consumed by `ReportTo` to write issue messages and set the exit code. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|-------------------------|-------------------------------------------------------------------------| -| `BuildMarkConfigReader` | Produces `ConfigurationLoadResult` from `ReadAsync` | -| `BuildMarkConfig` | Held by the `Config` property when parsing succeeds | -| `ConfigurationIssue` | Each issue in the `Issues` list | -| `Program` | Calls `ReportTo(context)` and checks `HasErrors` before proceeding | +- **BuildMarkConfigReader** — creates `ConfigurationLoadResult` instances and returns them from + `ReadAsync`. +- **Program** — calls `ReportTo(context)` and checks `HasErrors` before proceeding to connector + selection and report generation. diff --git a/docs/design/build-mark/configuration/connector-config.md b/docs/design/build-mark/configuration/connector-config.md index bce8639..777fdc1 100644 --- a/docs/design/build-mark/configuration/connector-config.md +++ b/docs/design/build-mark/configuration/connector-config.md @@ -1,59 +1,43 @@ -### ConnectorConfig, GitHubConnectorConfig, AzureDevOpsConnectorConfig +### ConnectorConfig #### Purpose -These three configuration data models define the connector selection and per-connector -settings read from the `connector:` section of `.buildmark.yaml`. - -`ConnectorConfig` is the envelope that carries the connector type and the platform-specific -settings. `GitHubConnectorConfig` holds GitHub-specific overrides. `AzureDevOpsConnectorConfig` -holds Azure DevOps-specific connection details. +`ConnectorConfig` is an immutable record that serves as the connector envelope read from the +`connector:` section of `.buildmark.yaml`. It carries a type discriminator string and optional +platform-specific settings for GitHub and Azure DevOps. `RepoConnectorFactory` reads `Type` to +select the appropriate connector implementation, then passes the platform-specific settings +record to the selected connector. #### Data Model -##### ConnectorConfig - -| Property | Type | Description | -|---------------|-------------------------------|-----------------------------------------------| -| `Type` | `string?` | Connector type: `"github"` or `"azure-devops"`| -| `GitHub` | `GitHubConnectorConfig?` | Optional GitHub connector settings | -| `AzureDevOps` | `AzureDevOpsConnectorConfig?` | Optional Azure DevOps connector settings | - -##### GitHubConnectorConfig +**Type**: `string?` — Connector type discriminator; `"github"` selects the GitHub connector, +`"azure-devops"` selects the Azure DevOps connector; `null` when not specified. -| Property | Type | Description | -|-----------------|-----------|--------------------------------------------------------------------------------------| -| `Owner` | `string?` | Repository owner override | -| `Repo` | `string?` | Repository name override | -| `BaseUrl` | `string?` | Optional GitHub Enterprise API base URL; `null` uses the public API | -| `TokenVariable` | `string?` | Name of the env variable holding the access token; `null` uses well-known names | +**GitHub**: `GitHubConnectorConfig?` — GitHub-specific connection settings; present when +`Type` is `"github"`; `null` otherwise. -##### AzureDevOpsConnectorConfig - -| Property | Type | Description | -|-------------------|-----------|--------------------------------------------------------------------------------------| -| `OrganizationUrl` | `string?` | Azure DevOps organization URL (e.g. `https://dev.azure.com/myorg`) | -| `Organization` | `string?` | Optional organization name override; `null` when not specified | -| `Project` | `string?` | Azure DevOps project name | -| `Repository` | `string?` | Repository name within the project | -| `TokenVariable` | `string?` | Name of the env variable holding the access token; `null` uses well-known names | -| `AreaPath` | `string?` | Scopes WIQL queries to area path; defaults to `{Project}` when `null`; empty = all | +**AzureDevOps**: `AzureDevOpsConnectorConfig?` — Azure DevOps-specific connection settings; +present when `Type` is `"azure-devops"`; `null` otherwise. #### Key Methods -N/A — `ConnectorConfig`, `GitHubConnectorConfig`, and `AzureDevOpsConnectorConfig` are -immutable configuration data records with no methods beyond those auto-generated by C#. +N/A — `ConnectorConfig` is an immutable configuration data record with no methods beyond those +auto-generated by C#. #### Error Handling -N/A — These are immutable configuration data records with no methods that detect or propagate errors. +N/A — Immutable data record. All parsing and validation of the `connector:` YAML block is +performed by `BuildMarkConfigReader`; this type holds only the results. + +#### Dependencies + +- **GitHubConnectorConfig** — held by the `GitHub` property when GitHub settings are present. +- **AzureDevOpsConnectorConfig** — held by the `AzureDevOps` property when Azure DevOps + settings are present. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|-----------------------------|---------------------------------------------------------------------------------| -| `BuildMarkConfig` | Holds `ConnectorConfig` in its `Connector` property | -| `BuildMarkConfigReader` | Parses the `connector:` YAML node and populates these records | -| `RepoConnectorFactory` | Receives `ConnectorConfig` to select the appropriate connector implementation | -| `GitHubRepoConnector` | Reads `GitHubConnectorConfig` for owner, repo, and base URL overrides | -| `AzureDevOpsRepoConnector` | Reads `AzureDevOpsConnectorConfig` for organization URL, project, and repo | +- **BuildMarkConfig** — holds a `ConnectorConfig` instance in its `Connector` property. +- **BuildMarkConfigReader** — parses the `connector:` YAML block and creates instances. +- **RepoConnectorFactory** — receives `ConnectorConfig` to select the appropriate connector + implementation. diff --git a/docs/design/build-mark/configuration/report-config.md b/docs/design/build-mark/configuration/report-config.md index a58fd1d..0193f5d 100644 --- a/docs/design/build-mark/configuration/report-config.md +++ b/docs/design/build-mark/configuration/report-config.md @@ -2,17 +2,22 @@ #### Purpose -`ReportConfig` is a configuration data model holding the optional report output settings -read from the `report:` section of `.buildmark.yaml`. All properties are nullable; when -absent, `Program` uses CLI argument values or built-in defaults. +`ReportConfig` is an immutable record holding optional report output settings read from the +`report:` section of `.buildmark.yaml`. All properties are nullable; when absent, `Program` +falls back to CLI argument values or built-in defaults. #### Data Model -| Property | Type | Description | -|----------------------|-----------|--------------------------------------------------------------------------------| -| `File` | `string?` | Optional output file path override; `null` uses the `--report` CLI argument | -| `Depth` | `int?` | Optional heading depth for report sections; `null` defaults to 1 | -| `IncludeKnownIssues` | `bool?` | Optional flag to include known issues; `null` defaults to `false` | +**File**: `string?` — Optional output file path override; `null` defers to the `--report` CLI +argument. + +**Depth**: `int?` — Optional Markdown heading depth for report sections; `null` defaults to +depth 1; must be a positive integer when specified, otherwise `BuildMarkConfigReader` produces +an `Error`-severity issue. + +**IncludeKnownIssues**: `bool?` — Optional flag to include known issues in the generated +report; `null` defaults to `false`; must be `"true"` or `"false"` in YAML, otherwise +`BuildMarkConfigReader` produces an `Error`-severity issue. #### Key Methods @@ -21,12 +26,17 @@ auto-generated by C#. #### Error Handling -N/A — This is an immutable configuration data record with no methods that detect or propagate errors. +N/A — Immutable data record. `BuildMarkConfigReader` validates the `depth` and +`include-known-issues` YAML fields and produces `ConfigurationIssue` records for invalid +values; this type holds only the successfully parsed results. + +#### Dependencies + +N/A — `ReportConfig` has no dependencies on other units. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|--------------------------|-----------------------------------------------------------------------------------| -| `BuildMarkConfig` | Holds `ReportConfig` in its `Report` property | -| `BuildMarkConfigReader` | Parses the `report:` YAML node and populates this record | -| `Program` | Reads `File`, `Depth`, and `IncludeKnownIssues` as fallbacks to CLI arguments | +- **BuildMarkConfig** — holds a `ReportConfig` instance in its `Report` property. +- **BuildMarkConfigReader** — parses the `report:` YAML block and creates instances. +- **Program** — reads `File`, `Depth`, and `IncludeKnownIssues` as fallbacks to CLI + arguments. diff --git a/docs/design/build-mark/configuration/rule-config.md b/docs/design/build-mark/configuration/rule-config.md index b550c15..cb6e914 100644 --- a/docs/design/build-mark/configuration/rule-config.md +++ b/docs/design/build-mark/configuration/rule-config.md @@ -1,28 +1,31 @@ -### RuleConfig and RuleMatchConfig +### RuleConfig #### Purpose -`RuleConfig` is a configuration data model representing a single item routing rule read from -the `rules:` list in `.buildmark.yaml`. Each rule carries match conditions and a destination -section ID. `RuleMatchConfig` holds the conditions that must be satisfied for a rule to fire. - -Both types are defined in `Configuration/RuleConfig.cs`. +`RuleConfig` is an immutable record representing a single item routing rule read from the +`rules:` list in `.buildmark.yaml`. Each rule carries optional match conditions and a +destination section ID. When `Match` is `null` or its lists are empty the rule acts as a +catch-all that matches any item. `RuleMatchConfig` holds the conditions — label values and +work-item type values — that must be satisfied for a rule to fire. Both types are defined in +`Configuration/RuleConfig.cs`. #### Data Model -##### RuleConfig +**Match**: `RuleMatchConfig?` — Optional match conditions; when `null` the rule is a catch-all +and matches any item regardless of labels or work-item type. + +**Route**: `string?` — Destination section `Id` for matched items; the reserved value +`"suppressed"` removes matching items from the report entirely; `null` is treated as no +routing. -| Property | Type | Description | -|----------|-------------------|---------------------------------------------------------| -| `Match` | `RuleMatchConfig` | Match conditions (labels, work-item types) for the rule | -| `Route` | `string` | Destination section `Id` for matched items | +`RuleMatchConfig` is a companion record defined in the same source file; its fields are: -##### RuleMatchConfig +**RuleMatchConfig.Label**: `List` — Label values to match; the rule fires when the +item carries any of these labels; empty list means label matching is not applied. -| Property | Type | Description | -|----------------|-----------------|-------------------------------------------------------------------| -| `Label` | `IList` | List of label values; rule matches when any label is present | -| `WorkItemType` | `IList` | List of work-item type values; rule matches when any type matches | +**RuleMatchConfig.WorkItemType**: `List` — Work-item type values to match; the rule +fires when the item's type equals any entry; empty list means work-item type matching is not +applied. #### Key Methods @@ -31,13 +34,17 @@ methods beyond those auto-generated by C#. #### Error Handling -N/A — These are immutable configuration data records with no methods that detect or propagate errors. +N/A — Immutable data records with no methods that detect or propagate errors. + +#### Dependencies + +- **RuleMatchConfig** — held by `RuleConfig.Match` when match conditions are present. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|-------------------------|-------------------------------------------------------------------------| -| `BuildMarkConfig` | Holds the list of `RuleConfig` objects in `Rules` | -| `BuildMarkConfigReader` | Parses the `rules:` YAML list and creates `RuleConfig` records | -| `RepoConnectorBase` | Receives the list via `Configure(rules, sections)` | -| `ItemRouter` | Uses `RuleConfig` and `RuleMatchConfig` to route items to sections | +- **BuildMarkConfig** — holds the list of `RuleConfig` objects in its `Rules` property. +- **BuildMarkConfigReader** — parses the `rules:` YAML sequence and creates `RuleConfig` and + `RuleMatchConfig` records. +- **RepoConnectorBase** — receives the list via `Configure(rules, sections)`. +- **ItemRouter** — evaluates `RuleConfig` and `RuleMatchConfig` to route each item to the + appropriate section. diff --git a/docs/design/build-mark/configuration/section-config.md b/docs/design/build-mark/configuration/section-config.md index eb5535a..2a3bf9d 100644 --- a/docs/design/build-mark/configuration/section-config.md +++ b/docs/design/build-mark/configuration/section-config.md @@ -2,16 +2,18 @@ #### Purpose -`SectionConfig` is a configuration data model representing a single report section definition -read from the `sections:` list in `.buildmark.yaml`. Each section has a unique identifier -used by routing rules and a display title used as the markdown heading. +`SectionConfig` is an immutable record representing a single report section definition read +from the `sections:` list in `.buildmark.yaml`. Each section carries a unique identifier used +by routing rules to target the section, and a display title used as the Markdown heading in +the generated report. #### Data Model -| Property | Type | Description | -|----------|----------|--------------------------------------| -| `Id` | `string` | Unique identifier for the section | -| `Title` | `string` | Display title for the report section | +**Id**: `string` — Unique identifier for the section; referenced by `RuleConfig.Route` to +route items here; defaults to empty string when not set. + +**Title**: `string` — Display title for the report section heading; defaults to empty string +when not set. #### Key Methods @@ -20,13 +22,18 @@ auto-generated by C#. #### Error Handling -N/A — This is an immutable configuration data record with no methods that detect or propagate errors. +N/A — Immutable data record with no methods that detect or propagate errors. + +#### Dependencies + +N/A — `SectionConfig` has no dependencies on other units. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|-------------------------|-------------------------------------------------------------------------| -| `BuildMarkConfig` | Holds the ordered list of `SectionConfig` objects in `Sections` | -| `BuildMarkConfigReader` | Parses the `sections:` YAML list and creates `SectionConfig` records | -| `RepoConnectorBase` | Receives the list via `Configure(rules, sections)` for output ordering | -| `ItemRouter` | Uses section IDs to map routed items to display sections | +- **BuildMarkConfig** — holds an ordered list of `SectionConfig` objects in its `Sections` + property. +- **BuildMarkConfigReader** — parses the `sections:` YAML sequence and creates `SectionConfig` + records. +- **RepoConnectorBase** — receives the list via `Configure(rules, sections)` to control report + section ordering. +- **ItemRouter** — uses section IDs to map routed items to their display sections. diff --git a/docs/design/build-mark/program.md b/docs/design/build-mark/program.md index a779cf6..c0372f6 100644 --- a/docs/design/build-mark/program.md +++ b/docs/design/build-mark/program.md @@ -2,117 +2,133 @@ ### Purpose -`Program` is the top-level unit of BuildMark. It owns the application entry point, -creates the `Context` object from command-line arguments, and dispatches execution -to the appropriate handler based on the parsed flags. +`Program` is the top-level unit of BuildMark. It owns the application entry point, creates +the `Context` object from command-line arguments, and dispatches execution to the appropriate +handler based on the parsed flags. -The unit exposes a private entry point `Main`, which is called by the .NET runtime, -and a public method `Run`, which accepts an existing `Context` and performs the main -execution logic. `Run` is exposed separately so that integration tests can inject a -pre-configured `Context` without repeating argument parsing. +The unit exposes a private entry point `Main`, which is called by the .NET runtime, and a +public method `Run`, which accepts an existing `Context` and performs the main execution +logic. `Run` is exposed separately so that integration tests can inject a pre-configured +`Context` without repeating argument parsing. ### Data Model -`Program` exposes a single static property: +**Version**: `string` — The tool version string, resolved from +`AssemblyInformationalVersionAttribute` (preferred; includes pre-release labels and build +metadata), then `assembly.GetName().Version`, and finally `"0.0.0"` when neither attribute +is present. -| Property | Type | Description | -|-----------|----------|------------------------------------------------| -| `Version` | `string` | The tool version read from assembly attributes | +### Key Methods -The version is resolved at startup by inspecting `AssemblyInformationalVersionAttribute` -first, then falling back to `assembly.GetName().Version`, and finally defaulting to -`"0.0.0"` if neither attribute is present. +**Main(string[] args) → int**: Application entry point, declared `private static`. -### Key Methods +- *Parameters*: `string[] args` — command-line arguments from the runtime. +- *Returns*: `int` — exit code; 0 for success, 1 for failure. +- *Preconditions*: Called by the .NET runtime on startup. +- *Postconditions*: Returns an exit code and terminates the process. + +Creates a `Context` from the supplied arguments and delegates to `Run`. `ArgumentException` +and `InvalidOperationException` are caught, written to `Console.Error`, and yield exit code + +1. Any other exception is re-thrown after logging to generate runtime event logs. + +**Run(Context context) → void**: Executes program logic against an already-constructed +`Context`. + +- *Parameters*: `Context context` — pre-constructed context with parsed flags and output + methods. +- *Returns*: void; side effects include writing to `context` and setting `context.ExitCode`. +- *Preconditions*: `context` is non-null and fully initialized. +- *Postconditions*: One execution path has completed; `context.ExitCode` reflects the outcome. + +Applies a priority dispatch order: (1) if `context.Version` is set, print the version string +and return; (2) print the application banner; (3) if `context.Help` is set, print the usage +message and return; (4) if `context.Validate` is set, delegate to `Validation.Run(context)` +and return; (5) if `context.Lint` is set, call `LoadConfiguration()`, call +`result.ReportTo(context)`, and return; (6) otherwise, call `ProcessBuildNotes(context)`. + +**ProcessBuildNotes(Context context)**: Loads configuration and generates the build report. + +- *Parameters*: `Context context` — context for reading flags and writing output. +- *Returns*: void. +- *Preconditions*: `context` is non-null; must be called after banner has been printed. +- *Postconditions*: Report file written (if `--report` is set); exit code set on any error. + +Steps: (1) calls `LoadConfiguration()` and surfaces issues via `result.ReportTo(context)`; +returns early on errors; (2) derives `effectiveConfig` as +`loadResult.Config ?? BuildMarkConfig.CreateDefault()`; (3) resolves effective report options +by preferring CLI arguments over configuration values; (4) creates the connector via +`context.ConnectorFactory` (test injection path) or `RepoConnectorFactory.Create`, then calls +`configurableConnector.Configure(rules, sections)` when using the production factory; +(5) parses `context.BuildVersion` via `VersionTag.Create`, returning early on +`ArgumentException`; (6) calls `connector.GetBuildInformationAsync` synchronously, returning +early on `InvalidOperationException`; (7) writes a build summary to `context`; (8) if +`effectiveReportFile` is set, renders markdown and writes to file — file-system exceptions are +caught and reported via `context.WriteError` without propagating. + +**PrintBanner(Context context)**: Writes the application name, version, and copyright notice +to `context`. + +- *Parameters*: `Context context` — output target. +- *Returns*: void. +- *Preconditions*: None. +- *Postconditions*: Banner lines written to context output. -#### `Main(string[] args) → int` - -The application entry point (declared `private static`). It creates a `Context` from -the supplied command-line arguments and delegates to `Run`. Any `ArgumentException` -or `InvalidOperationException` is caught, written directly to `Console.Error` (no -`Context` object exists yet at this level), and results in an exit code of 1. Any -other exception is re-thrown after logging so the runtime can report an unhandled -exception. - -#### `Run(Context context) → void` - -Executes the main program logic against an already-constructed `Context`. The -method applies the following priority order: - -1. If `context.Version` is set, print the version string and return. -2. Print the application banner (version and copyright). -3. If `context.Help` is set, print the usage message and return. -4. If `context.Validate` is set, delegate to `Validation.Run(context)` and return. -5. If `context.Lint` is set, call `LoadConfiguration()`, call - `result.ReportTo(context)`, and return. -6. Otherwise, call `ProcessBuildNotes(context)` to generate the build report. - -The exit code is managed through `context.ExitCode` rather than as a return value. - -#### `ProcessBuildNotes(Context context)` - -Calls `BuildMarkConfigReader.ReadAsync` to load the optional `.buildmark.yaml` -file, then calls `result.ReportTo(context)` to surface any configuration issues. -If errors occurred, the method returns early. Otherwise: - -1. **Effective configuration**: derives `effectiveConfig` as `loadResult.Config ?? - BuildMarkConfig.CreateDefault()`. When no `.buildmark.yaml` file is present (i.e., - `loadResult.Config` is `null`), `BuildMarkConfig.CreateDefault()` supplies built-in - section and rule definitions so the tool functions without any configuration file. -2. **Effective option resolution**: derives `effectiveReportFile` from `context.ReportFile` if set, - or from `effectiveConfig.Report?.File` as fallback; derives `effectiveReportDepth` from - `context.Depth` if set, or `effectiveConfig.Report?.Depth`, defaulting to 1; derives - `effectiveIncludeKnownIssues` from `context.IncludeKnownIssues` OR - `effectiveConfig.Report?.IncludeKnownIssues`. -3. **ConnectorFactory injection**: if `context.ConnectorFactory` is non-null it is invoked directly - (test injection path); otherwise `RepoConnectorFactory.Create(effectiveConfig.Connector)` is used. -4. **Configuration step**: when the production factory path is used and the connector implements - `RepoConnectorBase`, calls `configurableConnector.Configure(effectiveConfig.Rules, - effectiveConfig.Sections)`. -5. Parses `context.BuildVersion` using `VersionTag.Create`; on `ArgumentException`, - writes an error and returns early. -6. Calls `connector.GetBuildInformationAsync(buildVersion)` synchronously; on - `InvalidOperationException`, writes an error and returns early. -7. Writes a build summary to the context output. -8. If `effectiveReportFile` is non-null, renders the markdown and writes it to that path. - Any file-system exception during write is caught, reported via `context.WriteError`, and - execution continues - the method does not propagate the exception. This graceful-degradation - choice ensures that a report-write failure does not obscure the build summary already written - to the console and allows the exit code to reflect only semantic errors rather than I/O - failures outside the tool's control. - -#### `PrintBanner(Context context)` - -Writes the application name, version, and copyright notice to the context output. Called unconditionally after the version-flag check in `Run`. -#### `PrintHelp(Context context)` +**PrintHelp(Context context)**: Writes the full usage message to `context`. + +- *Parameters*: `Context context` — output target. +- *Returns*: void. +- *Preconditions*: None. +- *Postconditions*: Usage message written to context output. -Writes the full usage message (command syntax, options list) to the context output. Called when any of the `-?`, `-h`, or `--help` flags is set. -#### `LoadConfiguration() → ConfigurationLoadResult` +**LoadConfiguration() → ConfigurationLoadResult**: Synchronously loads the optional +repository configuration. + +- *Parameters*: None. +- *Returns*: `ConfigurationLoadResult` — config (may be `null` if absent) and any issues. +- *Preconditions*: `Environment.CurrentDirectory` is accessible. +- *Postconditions*: Returns a fully populated `ConfigurationLoadResult`. -Synchronously invokes `BuildMarkConfigReader.ReadAsync(Environment.CurrentDirectory)`. -Called from both the lint branch of `Run` and from `ProcessBuildNotes` to keep the -async-to-sync bridging in one place. +Synchronously invokes `BuildMarkConfigReader.ReadAsync(Environment.CurrentDirectory)` via +`GetAwaiter().GetResult()`. Called from both the lint branch of `Run` and from +`ProcessBuildNotes` to keep the async-to-sync bridging in one place. ### Error Handling `Main` catches `ArgumentException` and `InvalidOperationException` from `Context` -construction and writes them directly to `Console.Error`, returning exit code `1`. Any -other exception is re-thrown. `ProcessBuildNotes` catches file-system exceptions during -report writing and reports them via `context.WriteError` without propagating the exception; +construction and writes them directly to `Console.Error`, returning exit code 1. Any other +exception is re-thrown. `ProcessBuildNotes` catches file-system exceptions during report +writing and reports them via `context.WriteError` without propagating; `InvalidOperationException` from `connector.GetBuildInformationAsync` is caught, reported, -and causes early return. - -### Interactions - -| Unit / Subsystem | Role | -|--------------------------|---------------------------------------------------------------------------------| -| `Context` | Provides parsed flags, arguments, and output methods | -| `Validation` | Executes self-validation when `--validate` flag is set | -| `BuildMarkConfigReader` | Called in `Run` (for `--lint`) and `ProcessBuildNotes` to read `.buildmark.yaml`| -| `ConfigurationLoadResult`| Returned by `BuildMarkConfigReader`; `ReportTo(context)` called immediately | -| `RepoConnectorFactory` | Creates the connector via `Create(result.Config?.Connector)` | -| `BuildInformation` | Returned by the connector; converted to markdown via `ToMarkdown` | +and causes early return. The graceful-degradation choice for file-system exceptions ensures +that a report-write failure does not obscure the build summary already written to the console +and allows the exit code to reflect only semantic errors. + +### Dependencies + +- **Context** — provides parsed CLI flags, output methods, and exit code tracking + (Cli subsystem) +- **Validation** — executes self-validation when `--validate` flag is set (SelfTest + subsystem) +- **BuildMarkConfigReader** — reads and parses the optional `.buildmark.yaml` file + (Configuration subsystem) +- **ConfigurationLoadResult** — holds configuration and parse issues; `ReportTo(context)` + surfaces issues to the user +- **BuildMarkConfig** — carries effective configuration; `CreateDefault()` supplies + built-in defaults when no config file is present +- **RepoConnectorFactory** — creates the connector from configuration (RepoConnectors + subsystem) +- **RepoConnectorBase** — used for optional routing configuration when no factory is + injected +- **BuildInformation** — returned by the connector; `ToMarkdown` renders the report + (BuildNotes subsystem) +- **VersionTag** — parses the `--build-version` argument (Version subsystem) + +### Callers + +N/A — entry point, called by the .NET runtime. `Run` is also invoked directly by integration +tests via `Context.Create(args, connectorFactory)`. diff --git a/docs/design/build-mark/repo-connectors.md b/docs/design/build-mark/repo-connectors.md index c00c822..85d8303 100644 --- a/docs/design/build-mark/repo-connectors.md +++ b/docs/design/build-mark/repo-connectors.md @@ -1,85 +1,93 @@ -## RepoConnectors Subsystem +## RepoConnectors ### Overview -The RepoConnectors subsystem abstracts access to repository metadata for BuildMark. -It provides an interface and base class for repository connectors, a factory for -creating the appropriate connector, a shared `ItemRouter` for routing items to -report sections, and `ItemControlsParser` with `ItemControlsInfo` for parsing -metadata embedded in repository item descriptions. - -Concrete connector implementations are organized into subsystems: the `GitHub` -subsystem provides the production GitHub GraphQL connector, the `AzureDevOps` -subsystem provides the production Azure DevOps REST connector, and the `Mock` -subsystem provides the in-memory connector used by the built-in `--validate` -self-test. - -### Units - -- `IRepoConnector` - `RepoConnectors/IRepoConnector.cs` - interface for all - repository connectors -- `RepoConnectorBase` - `RepoConnectors/RepoConnectorBase.cs` - base class with - common connector logic -- `RepoConnectorFactory` - `RepoConnectors/RepoConnectorFactory.cs` - creates - the appropriate connector -- `ItemRouter` - `RepoConnectors/ItemRouter.cs` - shared item-routing logic for - all connectors -- `ItemControlsParser` - `RepoConnectors/ItemControlsParser.cs` - parses - buildmark blocks from item description bodies -- `ItemControlsInfo` - `RepoConnectors/ItemControlsInfo.cs` - data record holding - visibility, type, and version-set values - -### Subsystems - -- **`GitHub`** - `RepoConnectors/GitHub/` - `GitHubRepoConnector`, `GitHubGraphQLClient`, - `GitHubGraphQLTypes` -- **`AzureDevOps`** - `RepoConnectors/AzureDevOps/` - `AzureDevOpsRepoConnector`, - `AzureDevOpsRestClient`, `AzureDevOpsApiTypes`, `WorkItemMapper` -- **`Mock`** - `RepoConnectors/Mock/` - `MockRepoConnector` (used by `--validate` self-test) +The RepoConnectors subsystem abstracts access to repository metadata for BuildMark. It defines the +contract for all repository connectors via `IRepoConnector`, provides shared infrastructure in +`RepoConnectorBase`, and supplies `RepoConnectorFactory` to select the appropriate connector at +runtime. Shared utilities `ItemRouter`, `ItemControlsParser`, and `ItemControlsInfo` are used by +every connector to route items into report sections and apply embedded `buildmark` block overrides. + +The subsystem contains the following units directly: + +- `IRepoConnector` — the connector contract; defines `GetBuildInformationAsync`. +- `RepoConnectorBase` — abstract base class implementing `IRepoConnector`; provides `Configure`, + `ApplyRules`, `FindVersionIndex`, `FindBaselineForPreRelease`, `FindBaselineForRelease`, and + `RunCommandAsync`. +- `RepoConnectorFactory` — static factory that selects the appropriate connector implementation + based on environment variables and the git remote URL. +- `ItemRouter` — static utility that routes `ItemInfo` objects into report sections using + configured `RuleConfig` entries. +- `ItemControlsParser` — static parser that extracts a `buildmark` fenced code block from an item + description and parses its key-value fields. +- `ItemControlsInfo` — immutable record carrying the parsed visibility, type, and affected-version + values. + +The subsystem contains the following child subsystems: + +- **GitHub** — production connector for GitHub and GitHub Enterprise using the GraphQL API. +- **AzureDevOps** — production connector for Azure DevOps Services and Server using the REST API. +- **Mock** — in-memory connector used by the `--validate` self-test. ### Interfaces -`IRepoConnector` defines the contract for all connectors: - -| Member | Kind | Description | -|-------------------------------------|--------|----------------------------------| -| `GetBuildInformationAsync(version)` | Method | Fetch complete build information | +**IRepoConnector**: The in-process .NET contract that all repository connector implementations must +satisfy. + +- *Type*: In-process .NET public API. +- *Role*: Provider — the RepoConnectors subsystem exposes this interface to callers in the Program + unit. +- *Contract*: Single method `GetBuildInformationAsync(VersionTag? version)` returning + `Task`. +- *Constraints*: Callers must invoke `Configure(rules, sections)` on the connector before calling + `GetBuildInformationAsync` if routing rules are required; the method may throw + `InvalidOperationException` when authentication or version resolution fails. + +**RepoConnectorBase.Configure**: The in-process .NET method for supplying routing configuration to +any connector instance before it is used. + +- *Type*: In-process .NET public API. +- *Role*: Provider — exposes routing configuration to the Program unit. +- *Contract*: `Configure(IReadOnlyList rules, IReadOnlyList sections)` + stores the rules and sections on the connector; subsequent calls to `GetBuildInformationAsync` + use these to populate `BuildInformation.RoutedSections`. +- *Constraints*: Must be called before `GetBuildInformationAsync` for routed output to be + populated; calling it after has no effect on an in-progress invocation. ### Design -The RepoConnectors subsystem separates the connector contract, shared -infrastructure, and concrete implementations into three layers: - -1. **Contract layer**: `IRepoConnector` defines the single public method all - connectors must implement. `RepoConnectorFactory` resolves the appropriate - concrete connector at runtime without the caller needing to know which - platform is in use. - -2. **Base layer**: `RepoConnectorBase` provides shared behavior inherited by - all production connectors — token resolution is handled in the concrete - classes, while `Configure`, `HasRules`, `ApplyRules`, `FindVersionIndex`, and - `RunCommandAsync` are provided by the base. `ItemControlsParser` and - `ItemControlsInfo` are shared utilities called by every connector to apply - buildmark block overrides per item. `ItemRouter` is the central routing - engine called by `RepoConnectorBase.ApplyRules` to distribute items into - configured report sections. - -3. **Implementation layer**: `GitHub`, `AzureDevOps`, and `Mock` child subsystems - each contain a connector that inherits from `RepoConnectorBase` together with - platform-specific client and type definitions. Each connector fetches platform - data, normalizes it into `ItemInfo` records, applies item-controls overrides, - calls `ApplyRules` when routing is configured, and returns a `BuildInformation` - record. - -### Interactions - -| Unit / Subsystem | Role | -|------------------------------|------------------------------------------------------------------------| -| `Program` | Creates a connector via `RepoConnectorFactory` and calls it | -| `Program` | Passes `ConnectorConfig` (from `result.Config.Connector`) to | -| | `RepoConnectorFactory`, which forwards platform-specific config to | -| | the appropriate connector implementation | -| `Validation` | Uses `MockRepoConnector` directly for self-tests | -| `ItemControlsParser` | Called by `GitHubRepoConnector` and `AzureDevOpsRepoConnector` | -| | on each description body | -| `BuildInformation` | The data record returned by connectors | +The RepoConnectors subsystem separates the connector contract, shared infrastructure, and concrete +implementations into three layers: + +1. **Contract layer** — `IRepoConnector` defines the single public method all connectors must + implement. `RepoConnectorFactory` resolves the appropriate concrete connector at runtime without + the caller needing to know which platform is in use. + +2. **Base layer** — `RepoConnectorBase` provides shared behavior inherited by all production + connectors: `Configure` and `ApplyRules` for rules-based routing, `FindVersionIndex`, + `FindBaselineForPreRelease`, and `FindBaselineForRelease` for version resolution, and + `RunCommandAsync` for delegating shell commands to `ProcessRunner`. `ItemControlsParser` and + `ItemControlsInfo` are shared utilities called by each connector to apply `buildmark` block + overrides per item. `ItemRouter` is the central routing engine called by + `RepoConnectorBase.ApplyRules` to distribute items into configured report sections. + +3. **Implementation layer** — the `GitHub`, `AzureDevOps`, and `Mock` child subsystems each + contain a connector that inherits from `RepoConnectorBase` together with platform-specific + client and type definitions. Each connector fetches platform data, normalizes it into `ItemInfo` + records, applies item-controls overrides, calls `ApplyRules` when routing is configured, and + returns a `BuildInformation` record. + +```mermaid +sequenceDiagram + Program->>RepoConnectorFactory: Create(config) + RepoConnectorFactory-->>Program: IRepoConnector + Program->>IRepoConnector: Configure(rules, sections) + Program->>IRepoConnector: GetBuildInformationAsync(version) + IRepoConnector->>ItemControlsParser: Parse(description) + ItemControlsParser-->>IRepoConnector: ItemControlsInfo? + IRepoConnector->>RepoConnectorBase: ApplyRules(allItems) + RepoConnectorBase->>ItemRouter: Route(items, rules, sections) + ItemRouter-->>RepoConnectorBase: Dictionary + RepoConnectorBase-->>IRepoConnector: ordered sections + IRepoConnector-->>Program: BuildInformation +``` diff --git a/docs/design/build-mark/repo-connectors/azure-devops.md b/docs/design/build-mark/repo-connectors/azure-devops.md index e801eb0..2718ece 100644 --- a/docs/design/build-mark/repo-connectors/azure-devops.md +++ b/docs/design/build-mark/repo-connectors/azure-devops.md @@ -1,93 +1,52 @@ -### AzureDevOps Subsystem +### AzureDevOps #### Overview -The AzureDevOps subsystem groups the units responsible for querying the Azure DevOps -REST API. It sits within the RepoConnectors subsystem and provides the production -connector used when the repository host is Azure DevOps. +The AzureDevOps subsystem groups the units responsible for querying the Azure DevOps REST API. It +sits within the RepoConnectors subsystem and provides the production connector used when the +repository host is Azure DevOps Services or Azure DevOps Server. -#### Units +The subsystem contains the following units: -- `AzureDevOpsRepoConnector` - `RepoConnectors/AzureDevOps/AzureDevOpsRepoConnector.cs` - - implements `IRepoConnector` for Azure DevOps. -- `AzureDevOpsRestClient` - `RepoConnectors/AzureDevOps/AzureDevOpsRestClient.cs` - - issues paginated REST API requests. -- `AzureDevOpsApiTypes` - `RepoConnectors/AzureDevOps/AzureDevOpsApiTypes.cs` - - provides record types for REST API request and response data. -- `WorkItemMapper` - `RepoConnectors/AzureDevOps/WorkItemMapper.cs` - - maps Azure DevOps work items to `ItemInfo` objects. - -##### `AzureDevOpsRepoConnector` - -The primary production connector. Resolves the repository URL, organization, and project -from the environment or configuration, creates an `AzureDevOpsRestClient`, fetches all -required data via REST APIs, applies item-controls overrides from buildmark blocks and -custom fields, calls `ItemRouter` to assign items to sections, and assembles the -`BuildInformation` record. - -##### `AzureDevOpsRestClient` - -Handles HTTPS communication with the Azure DevOps REST API endpoint. Supports paginated -requests and authenticates via a `Basic` or `Bearer` authorization header. Supports both -cloud (`dev.azure.com`) and on-premises Azure DevOps Server instances via configurable -organization URL. - -##### `AzureDevOpsApiTypes` - -Internal C# records that mirror the REST API response types returned by Azure DevOps. -Used as the deserialization target for responses from `AzureDevOpsRestClient`. - -##### `WorkItemMapper` - -Maps `AzureDevOpsWorkItem` records from the REST API into `ItemInfo` records for the -`BuildInformation` model. Extracts visibility, type, and affected-version controls from -both buildmark code blocks in the work item description and Azure DevOps custom fields -(`Custom.Visibility`, `Custom.AffectedVersions`). Custom fields take precedence over -buildmark blocks when both are present. +- `AzureDevOpsRepoConnector` — implements `IRepoConnector` for Azure DevOps; orchestrates + authentication, REST API calls, and assembly of the `BuildInformation` record. +- `AzureDevOpsRestClient` — issues paginated HTTP requests to the Azure DevOps REST API and + deserializes responses into typed records. +- `AzureDevOpsApiTypes` — C# record definitions that mirror Azure DevOps REST API request and + response payloads; used as deserialization targets by `AzureDevOpsRestClient`. +- `WorkItemMapper` — maps `AzureDevOpsWorkItem` records into `ItemInfo` records, merging + `buildmark` block overrides with Azure DevOps custom fields. #### Interfaces -The AzureDevOps subsystem exposes `AzureDevOpsRepoConnector`, which implements -`IRepoConnector`. All other types in the subsystem are internal. +**AzureDevOpsRepoConnector**: The production `IRepoConnector` implementation for Azure DevOps +repositories. All other types in the subsystem are internal. -| Member | Kind | Description | -| --- | --- | --- | -| `AzureDevOpsRepoConnector(config)` | Constructor | Create the connector with optional configuration overrides | -| `GetBuildInformationAsync(version)` | Method | Fetch complete build information from the Azure DevOps REST API | +- *Type*: In-process .NET public API. +- *Role*: Provider — exposed to `RepoConnectorFactory` and callers of `IRepoConnector`. +- *Contract*: Constructor `AzureDevOpsRepoConnector(AzureDevOpsConnectorConfig?)` accepts optional + configuration overrides; `GetBuildInformationAsync(VersionTag? version)` fetches complete build + information from the Azure DevOps REST API and returns a `BuildInformation` record. +- *Constraints*: Requires a valid Azure DevOps authentication token resolvable from environment + variables or the `az` CLI; throws `InvalidOperationException` when no token is found or when the + remote URL cannot be parsed. #### Design -`AzureDevOpsRepoConnector` orchestrates the subsystem's data flow. It uses -`AzureDevOpsRestClient` for all HTTPS communication, `AzureDevOpsApiTypes` -records as serialization targets, and `WorkItemMapper` to transform raw work -item responses into `ItemInfo` records. - -The connector calls `ItemControlsParser.Parse` on each work item description -body and also reads `Custom.Visibility` and `Custom.AffectedVersions` custom -fields directly. `WorkItemMapper` merges the two sources (custom fields take -precedence) and returns the final `ItemInfo` record or `null` when the item -should be excluded. When routing rules have been configured, the connector passes -all collected items to `ApplyRules` (inherited from `RepoConnectorBase`) to -populate `BuildInformation.RoutedSections`. - -#### Interactions - -| Unit / Subsystem | Role | -|-------------------------------|---------------------------------------------------------------------------| -| `IRepoConnector` | Interface implemented by `AzureDevOpsRepoConnector` | -| `RepoConnectorBase` | Base class for `AzureDevOpsRepoConnector` | -| `ItemRouter` | Called by `AzureDevOpsRepoConnector` to assign items to sections | -| `ProcessRunner` | Used (via `RepoConnectorBase`) to run Git and az CLI commands | -| `AzureDevOpsConnectorConfig` | Supplies organization URL, project, and repository overrides | -| `ItemControlsParser` | Parses buildmark blocks from work item description bodies | -| `BuildInformation` | The output record assembled and returned by `AzureDevOpsRepoConnector` | - -#### Error Handling - -`AzureDevOpsRestClient` propagates HTTP errors and JSON deserialization failures as -`InvalidOperationException`. The exception message includes the Azure DevOps error -message read via `TryReadAdoErrorMessageAsync` when the response body contains an -Azure DevOps error object; otherwise the raw HTTP status code is included. - -`AzureDevOpsRepoConnector` does not suppress these exceptions; a failed REST API call -therefore aborts `GetBuildInformationAsync` and propagates the exception to the caller. +`AzureDevOpsRepoConnector` orchestrates the subsystem's data flow: + +1. Read the git remote URL and current commit hash via `RunCommandAsync` (inherited from + `RepoConnectorBase`). +2. Determine the organization URL, project, and repository name from `AzureDevOpsConnectorConfig` + or by parsing the remote URL. +3. Resolve an Azure DevOps authentication token (PAT or Entra ID Bearer token). +4. Create an `AzureDevOpsRestClient` and fetch tags, commits, pull requests, and work items via + the REST API, using `AzureDevOpsApiTypes` records as deserialization targets. +5. Call `WorkItemMapper.MapWorkItemToItemInfo` for each work item, which internally calls + `ItemControlsParser.Parse` on each description and merges the result with `Custom.Visibility` + and `Custom.AffectedVersions` custom fields (custom fields take precedence). +6. Collect changes and known issues; if routing rules are configured, call `ApplyRules` (inherited + from `RepoConnectorBase`) to distribute all items into the configured sections and populate + `BuildInformation.RoutedSections`. If no rules are configured, items remain in the legacy + `Changes`, `Bugs`, and `KnownIssues` lists. +7. Return the assembled `BuildInformation` record. diff --git a/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md b/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md index 27eb8ce..7bc6104 100644 --- a/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md +++ b/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md @@ -2,135 +2,105 @@ ##### Purpose -`AzureDevOpsApiTypes` is the collection of internal record types used by the -Azure DevOps subsystem to represent REST API request and response payloads. These -types allow `AzureDevOpsRestClient` to deserialize Azure DevOps API responses into -strongly typed objects that `AzureDevOpsRepoConnector` and `WorkItemMapper` can -process safely and predictably. - -##### Responsibilities - -- Represent repository, commit, pull request, and work item response objects -- Carry pagination metadata (`AzureDevOpsCollectionResponse`) -- Preserve work item description (`System.Description`) and custom fields - (`Custom.Visibility`, `Custom.AffectedVersions`) for item-controls parsing -- Provide `System.Text.Json`-compatible record definitions so that - `AzureDevOpsRestClient` can deserialize API responses without reflection - workarounds or third-party JSON libraries +`AzureDevOpsApiTypes` is the collection of internal C# record types used by the AzureDevOps +subsystem to represent REST API request and response payloads. These types allow +`AzureDevOpsRestClient` to deserialize Azure DevOps API responses into strongly typed objects that +`AzureDevOpsRepoConnector` and `WorkItemMapper` can process safely and predictably. + +All record types use conventional PascalCase property names. `AzureDevOpsRestClient` supplies a +`JsonSerializerOptions` instance with `PropertyNamingPolicy = JsonNamingPolicy.CamelCase` and +`NumberHandling = JsonNumberHandling.AllowReadingFromString`, which maps PascalCase names to the +Azure DevOps camelCase JSON field names automatically and handles numeric fields that the API may +return as quoted strings. The sole exception is `AzureDevOpsWorkItem.Fields`, which is +deserialized as a `Dictionary` and preserves the dotted field-reference-name keys +(e.g. `System.WorkItemType`) verbatim. ##### Data Model -All record types are defined as C# `record` types with init-only properties using -conventional PascalCase property names. No `[JsonPropertyName]` attributes are -required for standard Azure DevOps fields because `AzureDevOpsRestClient` supplies a -`JsonSerializerOptions` instance with `PropertyNamingPolicy = JsonNamingPolicy.CamelCase` -and `NumberHandling = JsonNumberHandling.AllowReadingFromString`, -which maps those PascalCase property names to the Azure DevOps camelCase JSON field -names automatically and handles numeric fields that the API may return as quoted -strings. The sole exception is `AzureDevOpsWorkItem.Fields`, which is -deserialized as a `Dictionary` and preserves the dotted -field-reference-name keys (e.g. `System.WorkItemType`) verbatim. +**AzureDevOpsRepository.Id**: `string?` — Repository identifier used in subsequent API calls. -###### `AzureDevOpsRepository` +**AzureDevOpsRepository.Name**: `string?` — Repository display name. -Repository metadata returned by the repository lookup endpoint. +**AzureDevOpsRepository.RemoteUrl**: `string?` — HTTPS clone URL for the repository. -Fields: `id`, `name`, `remoteUrl` +**AzureDevOpsCommit.CommitId**: `string?` — SHA of the commit. -###### `AzureDevOpsCommit` +**AzureDevOpsCommit.Comment**: `string?` — Commit message summary. -Commit data returned by the commits endpoint. +**AzureDevOpsGitCommitRef.CommitId**: `string?` — SHA of the referenced commit; used as the merge +commit reference inside `AzureDevOpsPullRequest`. -Fields: `commitId`, `comment` +**AzureDevOpsPullRequest.PullRequestId**: `int` — Pull request number. -###### `AzureDevOpsGitCommitRef` +**AzureDevOpsPullRequest.Title**: `string?` — Pull request title. -Minimal Git commit reference containing only the commit SHA. +**AzureDevOpsPullRequest.Url**: `string?` — HTML URL of the pull request. -Fields: `commitId` +**AzureDevOpsPullRequest.Status**: `string?` — Pull request status (e.g. `active`, `completed`, +`abandoned`). -###### `AzureDevOpsPullRequest` +**AzureDevOpsPullRequest.LastMergeCommit**: `AzureDevOpsGitCommitRef?` — Reference to the most +recent merge commit; `null` for open pull requests. The computed property `MergeCommitId` returns +`LastMergeCommit?.CommitId`. -Pull request data returned by the pull requests endpoint. +**AzureDevOpsPullRequest.SourceRefName**: `string?` — Full ref name of the source branch (e.g. +`refs/heads/my-feature`). -Fields: `pullRequestId`, `title`, `url`, `status`, `lastMergeCommit`, -`sourceRefName`, `description` +**AzureDevOpsPullRequest.Description**: `string?` — Pull request description body; passed to +`ItemControlsParser`. -The `lastMergeCommit` field is an `AzureDevOpsGitCommitRef` object (or `null`) -representing the commit of the most recent pull request merge. The type exposes -a computed `MergeCommitId` property that returns `LastMergeCommit?.CommitId`, -providing a convenient nullable string accessor for the merge commit SHA. +**AzureDevOpsWorkItem.Id**: `int` — Work item identifier. -###### `AzureDevOpsWorkItem` +**AzureDevOpsWorkItem.Fields**: `Dictionary` — All work item fields keyed by +Azure DevOps field reference name (e.g. `System.Title`, `System.WorkItemType`, +`System.Description`, `Custom.Visibility`, `Custom.AffectedVersions`). -Work item data returned by the work items endpoint with all fields expanded. +**AzureDevOpsWorkItemRef.Id**: `int` — Work item identifier; used in WIQL query results and +pull-request work-item links. -Fields: `id`, `fields` (dictionary) +**AzureDevOpsWorkItemRef.Url**: `string?` — REST API URL for the work item. -Key dictionary entries: +**AzureDevOpsRef.Name**: `string?` — Full reference name (e.g. `refs/tags/v1.0.0`). -| Field Key | Description | -|-------------------------------|---------------------------------------------------| -| `System.Title` | Work item title | -| `System.WorkItemType` | Work item type (e.g. `Bug`, `User Story`) | -| `System.State` | Work item state (e.g. `Active`, `Resolved`) | -| `System.Description` | Work item description body (HTML or plain text) | -| `Custom.Visibility` | Optional visibility override (`public`/`internal`)| -| `Custom.AffectedVersions` | Optional affected version range expression | +**AzureDevOpsRef.ObjectId**: `string?` — SHA the reference points to directly; for annotated tags +this is the tag object SHA, not the commit SHA. -###### `AzureDevOpsWorkItemRef` +**AzureDevOpsRef.PeeledObjectId**: `string?` — Resolved commit SHA for annotated tags; `null` for +lightweight tags. The computed property `CommitId` returns `PeeledObjectId ?? ObjectId`, providing +the commit SHA regardless of tag type. -Work item id reference returned by WIQL queries and pull request work item links. +**AzureDevOpsWorkItemQuery.WorkItems**: `List?` — Work item id references +returned by a WIQL query. -Fields: `id`, `url` +**AzureDevOpsCollectionResponse\.Count**: `int` — Number of items in the current page. -###### `AzureDevOpsRef` +**AzureDevOpsCollectionResponse\.Value**: `List?` — Items in the current page. -Git reference (tag or branch) returned by the Azure DevOps refs endpoint. +**AzureDevOpsApiError.Message**: `string?` — Human-readable error description returned by the +Azure DevOps API on failure. -Fields: `name`, `objectId`, `peeledObjectId` - -The `objectId` field contains the SHA of the object this reference points to -directly - for lightweight tags this is the commit SHA, and for annotated tags -this is the tag object SHA. The `peeledObjectId` field contains the commit SHA -for annotated tags (resolved through the tag object), or `null` for lightweight -tags. The type exposes a computed `CommitId` property that returns -`PeeledObjectId ?? ObjectId`, providing the resolved commit SHA regardless of -tag type. - -###### `AzureDevOpsWorkItemQuery` - -Result of a WIQL query, used to identify open work items matching a given filter. - -Fields: `workItems` (list of id references) - -###### `AzureDevOpsCollectionResponse` - -Generic wrapper for paginated collection responses from the Azure DevOps REST API. - -Fields: `count`, `value` (list of `T`) - -###### `AzureDevOpsApiError` - -Error response body returned by the Azure DevOps REST API when a request fails. -Used by `AzureDevOpsRestClient.TryReadAdoErrorMessageAsync` to extract a human-readable -error message from non-success HTTP responses. - -Fields: `message`, `typeKey` +**AzureDevOpsApiError.TypeKey**: `string?` — Machine-readable error type identifier returned by +the Azure DevOps API on failure. ##### Key Methods -N/A — `AzureDevOpsApiTypes` is a collection of immutable record types used purely for JSON +N/A — `AzureDevOpsApiTypes` is a collection of immutable C# record types used purely for JSON deserialization. No methods beyond C#-generated record members are defined. ##### Error Handling -N/A — These are immutable data record types used purely for JSON deserialization. No -methods detect or propagate errors. +N/A — These are immutable data record types used purely for JSON deserialization. No methods detect +or propagate errors. + +##### Dependencies + +- **System.Text.Json** — runtime library used by `AzureDevOpsRestClient` to deserialize these + records from HTTP response bodies. -##### Interactions +##### Callers -- `AzureDevOpsRestClient` uses these records as serialization and deserialization - targets for REST API HTTP traffic. -- `AzureDevOpsRepoConnector` and `WorkItemMapper` consume the deserialized data - returned by `AzureDevOpsRestClient`. +- **AzureDevOpsRestClient** — uses these records as serialization and deserialization targets for + REST API HTTP traffic. +- **AzureDevOpsRepoConnector** — consumes the deserialized record data returned by + `AzureDevOpsRestClient`. +- **WorkItemMapper** — receives `AzureDevOpsWorkItem` records and reads their `Fields` dictionary. diff --git a/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md b/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md index 68cb2a2..e4a66b6 100644 --- a/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md +++ b/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md @@ -2,194 +2,97 @@ ##### Purpose -`AzureDevOpsRepoConnector` is the production unit in the RepoConnectors/AzureDevOps -subsystem. It implements `RepoConnectorBase` and uses `AzureDevOpsRestClient` to -query the Azure DevOps REST API for commits, tags, pull requests, and work items. +`AzureDevOpsRepoConnector` is the production connector in the AzureDevOps subsystem. It implements +`RepoConnectorBase` and queries the Azure DevOps REST API via `AzureDevOpsRestClient` to fetch +commits, tags, pull requests, and work items needed to construct a `BuildInformation` record. -The unit reads the repository URL and current commit hash from Git, resolves the -Azure DevOps token from environment variables, and fetches all data needed to -construct a `BuildInformation` record. +The unit reads the repository URL and current commit hash from Git, resolves the Azure DevOps +authentication token from environment variables or the `az` CLI, and applies item-controls +overrides from `buildmark` blocks and Azure DevOps custom fields before assembling the result. ##### Data Model -###### Authentication +**_config**: `AzureDevOpsConnectorConfig?` — Optional configuration supplying organization URL, +project, repository, area path, and token variable overrides. Received from `RepoConnectorFactory` +at construction time. -The connector resolves the Azure DevOps token in two modes depending on whether -`AzureDevOpsConnectorConfig.TokenVariable` is set. +Authentication is resolved in two modes. In custom variable mode (when `_config.TokenVariable` is +set), the named environment variable is read exclusively; missing or empty values throw +`InvalidOperationException`. In default mode, the following sources are tried in order: (1) +`AZURE_DEVOPS_PAT` as a Basic PAT credential; (2) `AZURE_DEVOPS_TOKEN` as a Basic PAT credential; +(3) `AZURE_DEVOPS_EXT_PAT` as a Basic PAT credential; (4) `SYSTEM_ACCESSTOKEN` as a Bearer +credential (set automatically by Azure Pipelines); (5) output of `az account get-access-token +--resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv` as a Bearer +credential. If no token is found, `InvalidOperationException` is thrown. -**Custom variable mode** (when `TokenVariable` is set): - -The connector reads the named environment variable exclusively and does not fall back -to well-known names or the az CLI. The token is always treated as a Basic (PAT) credential: - -1. If the variable is not set (null), the connector throws `InvalidOperationException` with - a message identifying the missing variable. -2. If the variable is set but empty, the connector throws `InvalidOperationException` with a - message identifying the empty variable. -3. Otherwise the token value is used directly as a Basic (PAT) credential. - -**Default mode** (when `TokenVariable` is not set): - -1. `AZURE_DEVOPS_PAT` environment variable - authenticated as Basic (PAT) -2. `AZURE_DEVOPS_TOKEN` environment variable - authenticated as Basic (PAT) -3. `AZURE_DEVOPS_EXT_PAT` environment variable - authenticated as Basic (PAT) -4. `SYSTEM_ACCESSTOKEN` environment variable (set automatically by Azure Pipelines) - - authenticated as Bearer -5. Output of `az account get-access-token --resource 499b84ac-1321-427f-aa17-267ca6975798 --query accessToken -o tsv` - - authenticated as Bearer - -If no token is found, the connector throws `InvalidOperationException`. - -###### Work Item Type Mapping - -Azure DevOps work item types are mapped to normalized types: - -| Azure DevOps Work Item Types | Normalized Type | -|-------------------------------------|-----------------| -| `Bug`, `Issue` | `"bug"` | -| `User Story`, `Feature`, `Epic` | `"feature"` | -| `Task`, `Test Case`, etc. | work item type | - -Work items of type `"bug"` are placed in the `Bugs` list; all others go to `Changes`. - -When routing rules are configured via `.buildmark.yaml`, the type-derived -categorization is overridden by `RepoConnectorBase.ApplyRules`, which delegates to -`ItemRouter` to distribute all collected items into the configured report sections. - -###### Item Controls Override - -After the work-item-type-derived categorization is determined, the connector calls -`ItemControlsParser.Parse(description)` on the description body of each work item -and pull request. If the parser returns a non-null `ItemControlsInfo`, the following -overrides are applied: - -1. **`visibility: internal`** - The item is excluded from all report sections, - regardless of its type. -2. **`visibility: public`** - The item is included in the report even if its - type-derived category would otherwise suppress it. -3. **`type: bug`** - The item is placed in the `Bugs` list regardless of work item - type. -4. **`type: feature`** - The item is placed in the `Changes` list regardless of - work item type. -5. **`affected-versions`** - The parsed `VersionIntervalSet` is stored on the - `ItemInfo.AffectedVersions` property. - -In addition, the connector reads the following Azure DevOps custom fields from each -work item: - -- `Custom.Visibility` - overrides the `visibility` control when present. -- `Custom.AffectedVersions` - overrides the `affected-versions` control when present. - -Custom fields take precedence over buildmark blocks when both are present. - -When neither a `buildmark` block nor custom fields are present, the existing -work-item-type-based rules apply unchanged. - -###### REST API Response Types - -The `AzureDevOpsRestClient` returns the following record types: - -- **`AzureDevOpsRepository`** - repository metadata including id, name, and remoteUrl. -- **`AzureDevOpsCommit`** - commit data including commitId and comment. -- **`AzureDevOpsGitCommitRef`** - minimal commit reference containing only commitId. -- **`AzureDevOpsPullRequest`** - pull request data including pullRequestId, title, - url, status, lastMergeCommit (an `AzureDevOpsGitCommitRef` object representing - the most recent merge commit), sourceRefName, and description. Exposes a computed - `MergeCommitId` property that returns `LastMergeCommit?.CommitId`. -- **`AzureDevOpsWorkItem`** - work item data including id and a fields dictionary - containing System.Title, System.WorkItemType, System.State, System.Description, - Custom.Visibility, and Custom.AffectedVersions. -- **`AzureDevOpsWorkItemQuery`** - result of a WIQL query, containing a list of - work item id references. -- **`AzureDevOpsRef`** - git reference including name, objectId, and - peeledObjectId. Exposes a computed `CommitId` property that returns - `PeeledObjectId ?? ObjectId`, resolving annotated tags to their commit SHA. -- **`AzureDevOpsCollectionResponse`** - wraps paginated responses with a count - and value list. +Work item types are normalized before storage in `ItemInfo`: `Bug` and `Issue` map to `"bug"`; +`User Story`, `Feature`, and `Epic` map to `"feature"`; all other types are preserved as-is. +Custom fields `Custom.Visibility` and `Custom.AffectedVersions` take precedence over equivalent +values extracted from `buildmark` blocks when both are present. ##### Key Methods -###### `ParseAzureDevOpsUrl(url) → (organizationUrl, project, repository)` - -Internal utility that parses a Git remote URL into organization URL, project -name, and repository name. Supports the following URL formats: - -| Format | Example | -|----------------------------------------------------------|-----------------------------------| -| `https://dev.azure.com/{org}/{project}/_git/{repo}` | Azure DevOps Services | -| `https://{org}.visualstudio.com/{project}/_git/{repo}` | Legacy VisualStudio.com | -| `https://{server}/{org}/{project}/_git/{repo}` | Azure DevOps Server (on-premises) | -| `git@ssh.dev.azure.com:v3/{org}/{project}/{repo}` | SSH (dev.azure.com) | - -Throws `ArgumentException` when the URL does not match any supported format. - -###### `GetBuildInformationAsync(VersionTag? version) → BuildInformation` - -Main entry point. Performs the following steps: - -1. Get repository metadata (URL, branch, current commit hash) from Git. -2. Determine the organization URL, project, and repository name - from - `AzureDevOpsConnectorConfig` if provided, otherwise parsed from the Git remote - URL (supports `dev.azure.com`, `visualstudio.com`, and on-premises Azure - DevOps Server URL formats by locating the `_git` path segment). -3. Resolve the Azure DevOps authentication token (see Authentication above). -4. Create an `AzureDevOpsRestClient` with the resolved organization URL and token. -5. Fetch all tags via `GET /git/repositories/{id}/refs?filter=tags&peelTags=true`. - The `peelTags=true` parameter resolves annotated tags to their underlying commit - SHA (returned in the `peeledObjectId` field). Using the REST API bypasses - shallow-checkout limitations that would otherwise prevent Git from enumerating - remote tags. -6. Fetch the complete commit history via `GET /git/repositories/{id}/commits`. -7. Fetch all pull requests via - `GET /git/repositories/{id}/pullrequests?searchCriteria.status=all`. -8. Determine the target version tag (highest tag matching `version`, or latest). -9. Determine the baseline version tag (highest tag below the target). -10. Get all commits between the baseline and target tags. -11. Collect changes from pull requests merged in the commit range, applying item - controls from description bodies and custom fields (`Custom.Visibility`, - `Custom.AffectedVersions`). -12. Fetch linked work items for each PR via - `GET /git/repositories/{repositoryName}/pullrequests/{prId}/workitems` (where - `{repositoryName}` is the repository name, **not** the project name) and - batch-fetch work item details via `GET /wit/workitems?ids={ids}&$expand=all`. -13. Collect known issues from **all** bugs (resolved and unresolved), via a WIQL - query, applying item controls from description bodies and custom fields. - The effective area path is computed as follows: if `AzureDevOpsConnectorConfig.AreaPath` - is `null` (not configured), the connector defaults to the project name. Azure DevOps - creates a root area path for every project by default, so this ensures only bugs in the - configured project are returned. If `AreaPath` is set to a non-empty string, the query - is scoped with `AND [System.AreaPath] UNDER '{AreaPath}'` to restrict results to work items - belonging to that area path and its descendants. If `AreaPath` is set to an empty string, - no area-path filter is applied and all bugs in the project are considered. - For each candidate bug: - - If `AffectedVersions` is declared, the bug is a known issue if and only if - `AffectedVersions.Contains(toVersion)` is true, regardless of resolved - state. This covers resolved bugs that were never back-ported to older - branches (LTS back-port gap). - - If no `AffectedVersions` is declared, only unresolved bugs are included. -14. If routing rules are configured, call `ApplyRules` (inherited from - `RepoConnectorBase`) to distribute all collected items into the configured - report sections and populate `BuildInformation.RoutedSections`. If no rules - are configured, items remain in the legacy `Changes`, `Bugs`, and `KnownIssues` - lists. Return the assembled `BuildInformation` record. +**ParseAzureDevOpsUrl**: Internal utility that parses a git remote URL into organization URL, +project name, and repository name. + +- *Parameters*: `string url` — the git remote URL to parse. +- *Returns*: `(string organizationUrl, string project, string repository)`. +- *Preconditions*: `url` must be non-null. +- *Postconditions*: Returns a valid tuple when the URL matches a supported format. + +Supported formats: `https://dev.azure.com/{org}/{project}/_git/{repo}`; +`https://{org}.visualstudio.com/{project}/_git/{repo}`; `https://{server}/{org}/{project}/_git/ +{repo}` (on-premises); `git@ssh.dev.azure.com:v3/{org}/{project}/{repo}` (SSH). Throws +`ArgumentException` for unsupported formats. + +**GetBuildInformationAsync**: Main entry point; fetches all data required to assemble a +`BuildInformation` record. + +- *Parameters*: `VersionTag? version` — optional target version; when omitted, the highest + available tag is used as the target. +- *Returns*: `Task` — fully populated build information record. +- *Preconditions*: A resolvable Azure DevOps token must be available in the environment. +- *Postconditions*: Returns a `BuildInformation` record; throws `InvalidOperationException` or + `ArgumentException` on failure. + +Steps: (1) get repository URL, branch, and current commit hash from Git; (2) determine organization +URL, project, and repository name from config or by parsing the remote URL; (3) resolve the +authentication token; (4) create `AzureDevOpsRestClient`; (5) fetch tags via +`GET /git/repositories/{id}/refs?filter=tags&peelTags=true` (the `peelTags=true` parameter +resolves annotated tags to their commit SHA); (6) fetch commits; (7) fetch all pull requests; (8) +determine target and baseline version tags; (9) collect pull-request changes in the commit range, +calling `WorkItemMapper` for linked work items; (10) collect known issues from a WIQL query scoped +to the configured area path (defaulting to the project name when not configured); (11) if routing +rules are configured, call `ApplyRules` to populate `BuildInformation.RoutedSections`; otherwise +use legacy `Changes`, `Bugs`, and `KnownIssues` lists; (12) return the assembled +`BuildInformation`. + +For each candidate known issue: if `AffectedVersions` is declared, the bug is included if and only +if `AffectedVersions.Contains(targetVersion)` is true (regardless of resolved state, covering LTS +back-port gaps); if no `AffectedVersions` is declared, only unresolved bugs are included. ##### Error Handling -`GetBuildInformationAsync` throws `InvalidOperationException` when no Azure DevOps token -can be resolved, when `ParseAzureDevOpsUrl` receives an unsupported URL format (propagated -as `ArgumentException`), or when a git command fails. These exceptions propagate to -`Program.ProcessBuildNotes`, which catches them, writes an error message via -`context.WriteError`, and returns early without generating a report. - -##### Interactions - -- `AzureDevOpsConnectorConfig` is received from `RepoConnectorFactory` and overrides - the organization URL, project, and repository name. -- `AzureDevOpsRestClient` executes REST API requests against the Azure DevOps API. -- `ProcessRunner` runs Git and `az` CLI commands to get repository metadata and - fall-back authentication tokens. -- `ItemRouter` routes assembled items into report sections. -- `ItemControlsParser` parses buildmark blocks from work item and pull request - description bodies. -- `WorkItemMapper` maps `AzureDevOpsWorkItem` records to `ItemInfo` records. -- `BuildInformation` is the output record assembled from fetched data. +`GetBuildInformationAsync` throws `InvalidOperationException` when no authentication token can be +resolved or when a git command fails. `ParseAzureDevOpsUrl` propagates `ArgumentException` when the +URL format is not supported. These exceptions propagate to `Program.ProcessBuildNotes`, which +catches them, writes an error message via `context.WriteError`, and returns early without +generating a report. + +##### Dependencies + +- **RepoConnectorBase** — base class providing `Configure`, `HasRules`, `ApplyRules`, + `FindVersionIndex`, `FindBaselineForPreRelease`, `FindBaselineForRelease`, and `RunCommandAsync`. +- **AzureDevOpsRestClient** — executes REST API requests against the Azure DevOps API. +- **AzureDevOpsConnectorConfig** — supplies organization URL, project, repository, area path, and + token variable overrides. +- **WorkItemMapper** — maps `AzureDevOpsWorkItem` records to `ItemInfo` records. +- **ItemControlsParser** — parses `buildmark` blocks from pull request description bodies. +- **ProcessRunner** — used via `RunCommandAsync` to run Git and `az` CLI commands. +- **BuildInformation** — the output record assembled and returned by this unit. +- **ItemInfo** — the normalized item representation stored in `BuildInformation`. + +##### Callers + +- **RepoConnectorFactory** — creates `AzureDevOpsRepoConnector` when the environment indicates + Azure DevOps. diff --git a/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md b/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md index f478894..934b795 100644 --- a/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md +++ b/docs/design/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md @@ -2,143 +2,110 @@ ##### Purpose -`AzureDevOpsRestClient` is the Azure DevOps subsystem unit responsible for issuing -paginated REST API requests to the Azure DevOps API and translating the responses -into typed records for connector consumption. `AzureDevOpsRepoConnector` delegates -all Azure DevOps API communication to this client. - -##### Authentication - -The client authenticates using either: - -- **Basic authentication** - the PAT is supplied as the password field of a `Basic` - authorization header (with an empty username), which is the standard Azure DevOps - PAT authentication scheme. -- **Bearer authentication** - an Entra ID (Azure AD) access token is supplied as a - `Bearer` authorization header, used when authenticating via `az account get-access-token` - or the `SYSTEM_ACCESSTOKEN` Azure Pipelines variable with OAuth scope. - -The authentication scheme is selected automatically based on the token source -resolved by `AzureDevOpsRepoConnector`. - -##### JSON Deserialization - -The client uses `System.Net.Http.Json` extension methods (part of the .NET runtime) to -deserialize Azure DevOps REST API responses. Specifically, each HTTP response body is -decoded by calling `HttpContent.ReadFromJsonAsync()` with a shared -`JsonSerializerOptions` instance configured with -`PropertyNamingPolicy = JsonNamingPolicy.CamelCase` and -`NumberHandling = JsonNumberHandling.AllowReadingFromString`. The camelCase policy -matches the camelCase field names returned by the Azure DevOps API without requiring -per-property `[JsonPropertyName]` attributes on the response records. The -`AllowReadingFromString` setting handles numeric fields (such as work item IDs) that -the API may return as JSON string values rather than JSON numbers. - -The sole exception is the `AzureDevOpsWorkItem.Fields` dictionary - its keys are -Azure DevOps field reference names (e.g. `System.WorkItemType`, `Custom.Visibility`) -and are preserved as-is without any naming transformation. +`AzureDevOpsRestClient` is the unit responsible for issuing paginated HTTP requests to the Azure +DevOps REST API and deserializing responses into typed `AzureDevOpsApiTypes` records for +consumption by `AzureDevOpsRepoConnector`. All Azure DevOps API communication is delegated to +this client. + +The client supports both Basic authentication (PAT) and Bearer authentication (Entra ID access +token). It uses `System.Net.Http.Json` extension methods with a shared `JsonSerializerOptions` +instance (`PropertyNamingPolicy = JsonNamingPolicy.CamelCase`, +`NumberHandling = JsonNumberHandling.AllowReadingFromString`) to deserialize API responses without +per-property attributes. The sole exception is `AzureDevOpsWorkItem.Fields`, which is deserialized +as a `Dictionary` preserving dotted field reference keys verbatim. + +When a request returns an HTTP error response, the internal helper `TryReadAdoErrorMessageAsync` +attempts to deserialize the response body as `AzureDevOpsApiError` and extracts the `message` +field to include in the thrown `InvalidOperationException`, providing a human-readable description +instead of a raw HTTP status code. ##### Data Model -`AzureDevOpsRestClient` holds a single `HttpClient` instance configured with the -organization URL as the base address and the resolved authentication header (Basic for -PAT tokens, Bearer for Entra ID tokens). +**_httpClient**: `HttpClient` — HTTP client configured with the organization URL as the base +address and an `Authorization` header set to either `Basic {base64(pat)}` for PAT tokens or +`Bearer {token}` for Entra ID tokens. ##### Key Methods -The client provides the following methods for retrieving the repository data needed -to build a `BuildInformation` record: +**GetRepositoryAsync**: Fetches repository metadata for the specified repository name. -###### `GetRepositoryAsync(repository)` - -Fetches repository metadata for the specified repository. +- *Parameters*: `string repository` — repository name. +- *Returns*: `Task` — repository record containing `Id`, `Name`, and + `RemoteUrl`. +- *Postconditions*: Throws `InvalidOperationException` on HTTP failure or when deserialization + returns null. Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{repository}?api-version=6.0` -Returns an `AzureDevOpsRepository` record containing the repository id, name, and -remote URL. Throws when the request is unsuccessful (including HTTP 404). - -###### `GetTagsAsync(repositoryId)` - -Fetches all tag references for the specified repository. +**GetTagsAsync**: Fetches all tag references for the specified repository, resolving annotated tags +to their commit SHA. -Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{id}/refs?filter=tags&peelTags=true&api-version=6.0` +- *Parameters*: `string repositoryId` — repository identifier. +- *Returns*: `Task>` — list of tag references; `AzureDevOpsRef.CommitId` + returns `PeeledObjectId ?? ObjectId`. -Returns a list of `AzureDevOpsRef` records, each containing the full reference name -(e.g. `refs/tags/v1.0.0`), the object SHA it points to, and for annotated tags the -peeled commit SHA. The `peelTags=true` query parameter instructs the API to resolve -annotated tag objects to their underlying commit SHA, which is returned in the -`peeledObjectId` field. +Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{id}/refs?filter=tags&peelTags=true +&api-version=6.0` -###### `GetCommitsAsync(repositoryId)` +**GetCommitsAsync**: Fetches the complete paginated commit history for the repository. -Fetches the complete paginated commit history for the repository. +- *Parameters*: `string repositoryId` — repository identifier. +- *Returns*: `Task>` — all commits across all pages. Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{id}/commits?api-version=6.0` +Paginates using `$top` and `$skip` query parameters. -Returns a list of `AzureDevOpsCommit` records. Automatically paginates using -`$top` and `$skip` query parameters to retrieve all pages. +**GetPullRequestsAsync**: Fetches all pull requests with the specified status for the repository. -###### `GetPullRequestsAsync(repositoryId, status)` +- *Parameters*: `string repositoryId` — repository identifier; `string status` — filter value + (e.g. `all`, `completed`). +- *Returns*: `Task>` — all pull requests across all pages. -Fetches all pull requests with the specified status for the repository. Supports -`all`, `active`, `completed`, and `abandoned` status values. +Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{id}/pullrequests? +searchCriteria.status={status}&api-version=6.0`. Paginates using `$top` and `$skip`. -Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{id}/pullrequests?searchCriteria.status={status}&api-version=6.0` +**GetPullRequestWorkItemsAsync**: Fetches work item id references linked to a specific pull +request. -Returns a list of `AzureDevOpsPullRequest` records. Automatically paginates using -`$top` and `$skip` query parameters to retrieve all pages. +- *Parameters*: `string repositoryId` — repository identifier; `int pullRequestId` — pull request + number. +- *Returns*: `Task>` — list of linked work item references. -###### `GetPullRequestWorkItemsAsync(repositoryId, pullRequestId)` +Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{id}/pullrequests/{prId}/ +workitems?api-version=6.0` -Fetches the work items linked to a specific pull request. +**GetWorkItemsAsync**: Batch-fetches work item details for a list of work item IDs. Splits +requests into batches of 200 IDs as required by the Azure DevOps API. -Endpoint: `GET /{organization}/{project}/_apis/git/repositories/{id}/pullrequests/{prId}/workitems?api-version=6.0` +- *Parameters*: `IEnumerable workItemIds` — work item IDs to fetch. +- *Returns*: `Task>` — work items with all fields expanded. -Returns a list of work item id references from the -`AzureDevOpsCollectionResponse`. - -###### `GetWorkItemsAsync(workItemIds)` +Endpoint: `GET /{organization}/{project}/_apis/wit/workitems?ids={ids}&$expand=all&api-version=6.0` -Batch-fetches work item details for a list of work item ids. Splits requests into -batches of 200 ids as required by the Azure DevOps API. +**QueryWorkItemsAsync**: Executes a WIQL query and returns matching work item id references. -Endpoint: `GET /{organization}/{project}/_apis/wit/workitems?ids={ids}&$expand=all&api-version=6.0` +- *Parameters*: `string wiql` — the WIQL query string. +- *Returns*: `Task` — result containing the list of matching work item + references. -Returns a list of `AzureDevOpsWorkItem` records with all fields expanded. +Endpoint: `POST /{organization}/{project}/_apis/wit/wiql?api-version=6.0` -###### `QueryWorkItemsAsync(wiql)` +##### Error Handling -Executes a WIQL (Work Item Query Language) query and returns the matching work item -id references. +HTTP and deserialization errors from `HttpClient` propagate to `AzureDevOpsRepoConnector` as +exceptions. `GetRepositoryAsync` additionally throws `InvalidOperationException` when +deserialization succeeds but returns null (guard against an unexpected empty response). When an +error response body is present and parses as `AzureDevOpsApiError`, the `message` field is +included in the `InvalidOperationException` message for human-readable diagnostics. -Endpoint: `POST /{organization}/{project}/_apis/wit/wiql?api-version=6.0` +##### Dependencies -Returns an `AzureDevOpsWorkItemQuery` record containing the list of matching work -item id references. +- **AzureDevOpsApiTypes** — provides the record types used as serialization and deserialization + targets. +- **System.Net.Http.Json** — runtime extension methods used to call `ReadFromJsonAsync` on + HTTP response content. -##### Error Handling +##### Callers -HTTP and deserialization errors from the underlying `HttpClient` are propagated to -`AzureDevOpsRepoConnector`. Network failures, authentication errors (HTTP 401/403), and -malformed JSON responses result in exceptions that propagate up to -`Program.ProcessBuildNotes`. - -`GetRepositoryAsync` additionally throws `InvalidOperationException` when the HTTP -response is successful but JSON deserialization returns `null` (the `result ?? throw` -pattern). This guards against a response body that is valid JSON but does not -deserialize into the expected `AzureDevOpsRepository` record. - -When an HTTP error response includes a JSON body in the Azure DevOps error format, the -internal `TryReadAdoErrorMessageAsync` helper deserializes the body into an -`AzureDevOpsApiError` record and extracts the `message` field to include in the thrown -`InvalidOperationException`. This provides a human-readable error description (e.g., -`"The area path does not exist."`) rather than a raw HTTP status code. - -##### Interactions - -- `AzureDevOpsRepoConnector` creates and calls `AzureDevOpsRestClient`. -- `AzureDevOpsApiTypes` provides the request and response record types used for - serialization and deserialization. -- The Azure DevOps REST API endpoint provides the remote repository data queried by - the client. +- **AzureDevOpsRepoConnector** — creates and calls `AzureDevOpsRestClient` for all REST API + communication. diff --git a/docs/design/build-mark/repo-connectors/azure-devops/work-item-mapper.md b/docs/design/build-mark/repo-connectors/azure-devops/work-item-mapper.md index 653c874..0d86471 100644 --- a/docs/design/build-mark/repo-connectors/azure-devops/work-item-mapper.md +++ b/docs/design/build-mark/repo-connectors/azure-devops/work-item-mapper.md @@ -2,117 +2,83 @@ ##### Purpose -`WorkItemMapper` maps `AzureDevOpsWorkItem` records from the Azure DevOps REST API -into `ItemInfo` records for the `BuildInformation` model. It centralizes work item -type normalization, state-based filtering, and item-controls extraction from both -buildmark code blocks in work item description bodies and Azure DevOps custom fields. +`WorkItemMapper` maps `AzureDevOpsWorkItem` records from the Azure DevOps REST API into `ItemInfo` +records for the `BuildInformation` model. It centralizes work item type normalization, state-based +filtering, and item-controls extraction from both `buildmark` code blocks in work item description +bodies and Azure DevOps custom fields (`Custom.Visibility`, `Custom.AffectedVersions`). Custom +fields take precedence over `buildmark` block values when both are present. ##### Data Model -###### Work Item Type Mapping - -Azure DevOps work item types are mapped to normalized types for the `ItemInfo` model: - -| Azure DevOps Work Item Types | Normalized Type | -|-------------------------------------|-----------------| -| `Bug`, `Issue` | `"bug"` | -| `User Story`, `Feature`, `Epic` | `"feature"` | -| `Task`, `Test Case`, etc. | work item type | - -###### Work Item State Filtering - -When identifying known issues, only work items in an unresolved state are included. -The following state values are treated as resolved and excluded from known-issues -reporting: - -- `Resolved` -- `Closed` -- `Done` - -The following state values are **suppressed** entirely from all sections of build -notes (both changes and known issues). `MapWorkItemToItemInfo` returns `null` for -these states before any other processing: - -- `Removed` - -All other state values (e.g. `Active`, `New`, `In Progress`) are treated as -unresolved and included in known-issues reporting. - -###### Item Controls Extraction - -Item controls are extracted from two sources and merged: - -1. **Buildmark blocks** - `ItemControlsParser.Parse(description)` is called on the - `System.Description` field of the work item. The resulting `ItemControlsInfo` - provides `Visibility`, `Type`, and `AffectedVersions` overrides from embedded - YAML blocks in the description body. -2. **Custom fields** - The `Custom.Visibility` and `Custom.AffectedVersions` fields - in the work item's fields dictionary are read directly. - -**Precedence**: custom fields take priority over buildmark blocks when both are -present for the same control. If a custom field value is non-null, it supersedes -the corresponding value from the buildmark block. +N/A — `WorkItemMapper` is a static utility class with no instance state. ##### Key Methods -###### `MapWorkItemToItemInfo(workItem)` +**MapWorkItemToItemInfo**: Maps a single `AzureDevOpsWorkItem` to an `ItemInfo` record, returning +`null` when the work item should be excluded. -Maps a single `AzureDevOpsWorkItem` to an `ItemInfo` record. +- *Parameters*: `AzureDevOpsWorkItem workItem` — the work item to map. +- *Returns*: `ItemInfo?` — a populated record, or `null` when the work item is in a suppressed + state or has `visibility: internal`. +- *Preconditions*: `workItem` must be non-null. +- *Postconditions*: Returns `null` for suppressed states (e.g. `Removed`) and for + `visibility: internal`; never throws for absent dictionary keys. -Steps: +Steps: (1) read `System.State`; return `null` immediately if the state is in the suppressed set +(`Removed`); (2) read `System.Title` and `System.WorkItemType`; (3) apply work item type mapping +(`Bug`/`Issue` → `"bug"`; `User Story`/`Feature`/`Epic` → `"feature"`; others preserved as-is); +(4) call `ExtractItemControls` to obtain overrides; (5) return `null` if controls specify +`visibility: internal`; (6) apply type override if controls specify one; (7) construct and return +the `ItemInfo` record. -1. Read `System.State` from the work item's fields dictionary. If the state is in the - suppressed-states set (e.g. `Removed`), return `null` immediately. -2. Read `System.Title` and `System.WorkItemType` from the work item's fields dictionary. -3. Apply work item type mapping to determine the normalized type. -4. Call `ExtractItemControls(workItem)` to obtain any item controls overrides. -5. If item controls specify a visibility of `internal`, return `null` to signal that - the item should be excluded. Items with `visibility: public` (or no visibility - override) are included normally; there is no separate "force include" logic. -6. If item controls specify a type override, apply it to the normalized type. -7. Construct and return the `ItemInfo` record with the title, url, type, and - affected versions. +**IsWorkItemResolved**: Checks whether a work item's state is one of the known resolved states. -###### `IsWorkItemResolved(workItem)` +- *Parameters*: `AzureDevOpsWorkItem workItem` — the work item to check. +- *Returns*: `bool` — `true` when `System.State` is `Resolved`, `Closed`, or `Done`; `false` + otherwise. -Checks whether a work item's state is one of the known resolved states -(`Resolved`, `Closed`, `Done`). +Used by `AzureDevOpsRepoConnector` to filter resolved bugs from known-issues reporting when no +`AffectedVersions` is declared. -Returns `true` if the work item is resolved; `false` otherwise. Used by -`AzureDevOpsRepoConnector` to filter out resolved work items when collecting -known issues. +**GetWorkItemTypeForRuleMatching**: Returns the raw `System.WorkItemType` value from the work item +fields dictionary for use in routing rule matching. -###### `GetWorkItemTypeForRuleMatching(workItem)` +- *Parameters*: `AzureDevOpsWorkItem workItem` — the work item to inspect. +- *Returns*: `string?` — the raw Azure DevOps work item type string (e.g. `Bug`, `User Story`). -Returns the work item type string used for routing rule matching. This is the raw -`System.WorkItemType` value from the work item's fields dictionary, allowing routing -rules in `.buildmark.yaml` to match on Azure DevOps-native work item type names. +Allows routing rules in `.buildmark.yaml` to match on Azure DevOps-native work item type names +rather than the normalized type. -###### `ExtractItemControls(workItem)` +**ExtractItemControls**: Merges item controls from `buildmark` blocks and Azure DevOps custom +fields into a single `ItemControlsInfo?` record. -Combines item controls from both buildmark blocks and custom fields into a single -`ItemControlsInfo?` record. +- *Parameters*: `AzureDevOpsWorkItem workItem` — the work item whose controls to extract. +- *Returns*: `ItemControlsInfo?` — merged controls, or `null` when neither source provides any + recognized values. -Steps: - -1. Call `ItemControlsParser.Parse(description)` on `System.Description`. -2. Read `Custom.Visibility` and `Custom.AffectedVersions` from the fields dictionary. -3. If custom fields are present, override the corresponding values from the buildmark - block result. -4. Return the merged `ItemControlsInfo`, or `null` if no controls were found. +Steps: (1) call `ItemControlsParser.Parse(System.Description)`; (2) read `Custom.Visibility` and +`Custom.AffectedVersions` from the fields dictionary; (3) override the corresponding `buildmark` +block values with the custom field values when both are present; (4) return the merged +`ItemControlsInfo`, or `null` if no controls were found. ##### Error Handling -`MapWorkItemToItemInfo` returns `null` rather than throwing when a work item should be -excluded (suppressed state or `visibility: internal`). Missing or unexpected field values -are handled defensively; no exceptions are thrown for absent dictionary keys. +`MapWorkItemToItemInfo` returns `null` rather than throwing when a work item should be excluded +(suppressed state or `visibility: internal`). Missing or unexpected field values in the work item's +`Fields` dictionary are handled defensively; no exceptions are thrown for absent keys. + +##### Dependencies + +- **AzureDevOpsApiTypes** — provides the `AzureDevOpsWorkItem` input type. +- **ItemControlsParser** — called by `ExtractItemControls` to parse `buildmark` blocks from work + item descriptions. +- **ItemControlsInfo** — the record type returned by `ItemControlsParser.Parse` and used within + `ExtractItemControls`. +- **ItemInfo** — the output record type populated by `MapWorkItemToItemInfo`. +- **VersionIntervalSet** — held by `ItemControlsInfo.AffectedVersions` and stored on the returned + `ItemInfo`. -##### Interactions +##### Callers -- `AzureDevOpsRepoConnector` calls `WorkItemMapper` to convert REST API work item - records into `ItemInfo` records. -- `ItemControlsParser` is called by `WorkItemMapper` to parse buildmark blocks - from work item description bodies. -- `AzureDevOpsApiTypes` provides the `AzureDevOpsWorkItem` type that `WorkItemMapper` - receives as input. -- `BuildInformation` consumes the `ItemInfo` records produced by `WorkItemMapper`. +- **AzureDevOpsRepoConnector** — calls `MapWorkItemToItemInfo`, `IsWorkItemResolved`, and + `GetWorkItemTypeForRuleMatching` when processing REST API work item responses. diff --git a/docs/design/build-mark/repo-connectors/github.md b/docs/design/build-mark/repo-connectors/github.md index f3bb7f0..472634b 100644 --- a/docs/design/build-mark/repo-connectors/github.md +++ b/docs/design/build-mark/repo-connectors/github.md @@ -1,70 +1,51 @@ -### GitHub Subsystem +### GitHub #### Overview -The GitHub subsystem groups the units responsible for querying the GitHub -GraphQL API. It sits within the RepoConnectors subsystem and provides the -production connector used when the repository host is GitHub or GitHub Enterprise. +The GitHub subsystem groups the units responsible for querying the GitHub GraphQL API. It sits +within the RepoConnectors subsystem and provides the production connector used when the repository +host is GitHub or GitHub Enterprise Server. -#### Units +The subsystem contains the following units: -- `GitHubRepoConnector` - `RepoConnectors/GitHub/GitHubRepoConnector.cs` - - implements `IRepoConnector` for GitHub. -- `GitHubGraphQLClient` - `RepoConnectors/GitHub/GitHubGraphQLClient.cs` - - issues paginated GraphQL queries. -- `GitHubGraphQLTypes` - `RepoConnectors/GitHub/GitHubGraphQLTypes.cs` - - provides record types for GraphQL request and response data. - -##### `GitHubRepoConnector` - -The primary production connector. Resolves the repository URL and GitHub token from -the environment, creates a `GitHubGraphQLClient`, fetches all required data via -GraphQL, applies item-controls overrides, calls `ItemRouter` to assign items to -sections, and assembles the `BuildInformation` record. - -##### `GitHubGraphQLClient` - -Handles HTTPS communication with the GitHub GraphQL endpoint. Supports paginated -queries and authenticates via an `Authorization: bearer ` header. Also -supports GitHub Enterprise by accepting an alternative base URL. - -##### `GitHubGraphQLTypes` - -Internal C# records that mirror the GraphQL schema types returned by GitHub. Used -as the deserialization target for responses from `GitHubGraphQLClient`. +- `GitHubRepoConnector` — implements `IRepoConnector` for GitHub; orchestrates authentication, + GraphQL queries, and assembly of the `BuildInformation` record. +- `GitHubGraphQLClient` — issues paginated GraphQL requests to the GitHub API and deserializes + responses into typed records; implements `IDisposable` and owns its `HttpClient`. +- `GitHubGraphQLTypes` — C# record definitions that mirror GitHub GraphQL request and response + payloads; used as deserialization targets by `GitHubGraphQLClient`. #### Interfaces -The GitHub subsystem exposes `GitHubRepoConnector`, which implements -`IRepoConnector`. All other types in the subsystem are internal. +**GitHubRepoConnector**: The production `IRepoConnector` implementation for GitHub repositories. +All other types in the subsystem are internal. -| Member | Kind | Description | -| --- | --- | --- | -| `GitHubRepoConnector(config)` | Constructor | Create the connector with optional configuration overrides | -| `GetBuildInformationAsync(version)` | Method | Fetch complete build information from the GitHub GraphQL API | +- *Type*: In-process .NET public API. +- *Role*: Provider — exposed to `RepoConnectorFactory` and callers of `IRepoConnector`. +- *Contract*: Constructor `GitHubRepoConnector(GitHubConnectorConfig?)` accepts optional + configuration overrides; `GetBuildInformationAsync(VersionTag? version)` fetches complete build + information from the GitHub GraphQL API and returns a `BuildInformation` record. +- *Constraints*: Requires a valid GitHub authentication token resolvable from environment variables + or the `gh` CLI; throws `InvalidOperationException` when no token is found or when no release + matches the current commit hash and no version is supplied. #### Design -`GitHubRepoConnector` orchestrates the subsystem's data flow. It uses -`GitHubGraphQLClient` for all HTTPS communication, `GitHubGraphQLTypes` records -as GraphQL deserialization targets, and `ItemControlsParser` to extract buildmark -block overrides from issue and pull request description bodies. - -The connector calls `ItemControlsParser.Parse` on the `body` field of each issue -and pull request. If a non-null `ItemControlsInfo` is returned, the connector -applies visibility, type, and affected-versions overrides before adding the item -to the appropriate list. When routing rules have been configured, the connector -passes all collected items to `ApplyRules` (inherited from `RepoConnectorBase`) -to populate `BuildInformation.RoutedSections`. - -#### Interactions - -| Unit / Subsystem | Role | -|-------------------------|-------------------------------------------------------------------| -| `IRepoConnector` | Interface implemented by `GitHubRepoConnector` | -| `RepoConnectorBase` | Base class for `GitHubRepoConnector` | -| `ItemRouter` | Called by `GitHubRepoConnector` to assign items to sections | -| `ProcessRunner` | Used (via `RepoConnectorBase`) to run Git and gh CLI commands | -| `GitHubConnectorConfig` | Supplies owner, repo, and base-URL overrides | -| `ItemControlsParser` | Parses buildmark blocks from issue and PR description bodies | -| `BuildInformation` | The output record assembled and returned by `GitHubRepoConnector` | +`GitHubRepoConnector` orchestrates the subsystem's data flow: + +1. Read the git remote URL and current commit hash via `RunCommandAsync` (inherited from + `RepoConnectorBase`). +2. Determine the owner and repository name from `GitHubConnectorConfig` or by parsing the remote + URL. +3. Resolve a GitHub authentication token (`GH_TOKEN`, `GITHUB_TOKEN`, or `gh auth token`). +4. Create a `GitHubGraphQLClient` with the resolved token, using `GitHubConnectorConfig.BaseUrl` + as the GraphQL endpoint when set (supports GitHub Enterprise Server); fetch tags, releases, + commits, pull requests (with `body`), and issues (with `body`) via GraphQL, using + `GitHubGraphQLTypes` records as deserialization targets. +5. Call `ItemControlsParser.Parse` on the `body` of each pull request and issue; apply visibility, + type, and affected-version overrides from the returned `ItemControlsInfo`. +6. Collect changes and known issues; if routing rules are configured, call `ApplyRules` (inherited + from `RepoConnectorBase`) to distribute all items into the configured sections and populate + `BuildInformation.RoutedSections`. If no rules are configured, items remain in the legacy + `Changes`, `Bugs`, and `KnownIssues` lists. +7. Return the assembled `BuildInformation` record. diff --git a/docs/design/build-mark/repo-connectors/github/github-graphql-client.md b/docs/design/build-mark/repo-connectors/github/github-graphql-client.md index a226c4d..0632ebf 100644 --- a/docs/design/build-mark/repo-connectors/github/github-graphql-client.md +++ b/docs/design/build-mark/repo-connectors/github/github-graphql-client.md @@ -2,83 +2,101 @@ ##### Purpose -`GitHubGraphQLClient` is the GitHub subsystem unit responsible for issuing -paginated GraphQL requests to the GitHub API and translating the responses into -typed records for connector consumption. `GitHubRepoConnector` delegates all -GitHub API communication to this client. - -##### Constructors - -The class provides two constructors: - -- **Public constructor** - accepts a GitHub authentication token and an optional - `graphqlEndpoint` URL, then creates an owned `HttpClient` configured with the - token and wraps it in a `GraphQLHttpClient` instance (from the `GraphQL.Client.Http` - package). Used by `GitHubRepoConnector` in production. When `graphqlEndpoint` is - omitted, the default GitHub GraphQL API endpoint (`https://api.github.com/graphql`) - is used. For GitHub Enterprise Server, supply the enterprise-specific endpoint - (e.g., `https://your-github-enterprise/api/graphql`). -- **Internal constructor** - accepts an existing `HttpClient` directly and an optional - `graphqlEndpoint` URL. Used by tests to inject a mock `HttpClient` without network - access. - -##### Lifecycle - -`GitHubGraphQLClient` implements `IDisposable`. When created via the public -constructor, the instance owns its `GraphQLHttpClient` (and the `HttpClient` it wraps) -and disposes them when the client is disposed. When created via the internal -constructor, the caller retains ownership of the `HttpClient` and the client does -not dispose it. - -Callers that construct `GitHubGraphQLClient` via the public constructor must -wrap usage in a `using` statement or otherwise dispose the instance to release -the underlying HTTP connection resources. +`GitHubGraphQLClient` is the unit responsible for issuing paginated GraphQL requests to the GitHub +API and deserializing responses into typed `GitHubGraphQLTypes` records for consumption by +`GitHubRepoConnector`. All GitHub API communication is delegated to this client. -##### Error Handling +The client authenticates via an `Authorization: bearer ` header. It accepts an optional +`graphqlEndpoint` URL to support GitHub Enterprise Server (default: +`https://api.github.com/graphql`). The client implements `IDisposable`; when created via the +public constructor, it owns its `GraphQLHttpClient` (and the underlying `HttpClient`) and disposes +them on disposal. When created via the internal constructor (for test injection), the caller retains +ownership of the `HttpClient`. -All API methods catch exceptions from the underlying `GraphQLHttpClient` and return -empty lists rather than propagating the exception to the caller. This allows -the connector to continue with partial data when the GitHub API is transiently -unavailable. +##### Data Model -> **Note**: Because exceptions are silently swallowed and an empty list is returned, -> runtime failures (network errors, authentication failures, malformed responses) are -> not observable by the caller. Diagnostics require inspecting log output or -> correlating an unexpectedly empty result set with network or authentication issues. +**_graphqlClient**: `GraphQLHttpClient` — The GraphQL HTTP client used for all API communication; +configured with the authentication header and the GraphQL endpoint URI. -##### Data Model +**_ownsGraphQLClient**: `bool` — Indicates whether this instance owns the `GraphQLHttpClient` and +must dispose it; `true` when constructed via the public constructor, `false` when constructed via +the internal constructor. -`GitHubGraphQLClient` holds a single `GraphQLHttpClient` instance (from the external -`GraphQL.Client.Http` NuGet package). The `GraphQLHttpClient` internally manages an -`HttpClient` for HTTPS transport. When constructed via the public constructor, the -client owns both the `GraphQLHttpClient` and the underlying `HttpClient` and disposes -them on disposal. When constructed via the internal constructor (for test injection), -the caller retains ownership of the `HttpClient` and the client does not dispose -the injected instance. +##### Key Methods -##### Dependencies +**GitHubGraphQLClient (public constructor)**: Creates a new client owned by this instance. -| Dependency | Package | Purpose | -| -------------------------- | ------------------------------------------ | ---------------------------------------- | -| `GraphQLHttpClient` | `GraphQL.Client.Http` | Sends GraphQL queries over HTTPS | -| `SystemTextJsonSerializer` | `GraphQL.Client.Serializer.SystemTextJson` | Serializes/deserializes GraphQL payloads | +- *Parameters*: `string token` — GitHub authentication token; `string? graphqlEndpoint` — + optional GraphQL endpoint URL; defaults to `https://api.github.com/graphql`. +- *Postconditions*: The instance owns its `HttpClient` and `GraphQLHttpClient` and must be + disposed by the caller. -##### Key Methods +**GitHubGraphQLClient (internal constructor)**: Creates a new client using an injected +`HttpClient`; intended for test scenarios. + +- *Parameters*: `HttpClient httpClient` — pre-configured HTTP client; `string? graphqlEndpoint` — + optional GraphQL endpoint URL. +- *Postconditions*: The caller retains ownership of `httpClient`; this instance does not dispose + it. + +**GetCommitsAsync**: Returns all commit SHAs reachable from a branch within an optional date range. + +- *Parameters*: `string owner`, `string repo`, `string branch` — repository coordinates; optional + date filters. +- *Returns*: `Task>` — list of commit SHAs; empty list on error. + +**GetReleasesAsync**: Returns all release tag names for the repository. + +- *Parameters*: `string owner`, `string repo`. +- *Returns*: `Task>` — list of release tag names; empty list on error. + +**GetAllTagsAsync**: Returns all tag nodes for the repository. + +- *Parameters*: `string owner`, `string repo`. +- *Returns*: `Task>` — list of tag nodes with name and target commit SHA; empty list + on error. -The client provides methods for retrieving the repository data needed to build a -`BuildInformation` record: +**GetPullRequestsAsync**: Returns all pull request nodes for the repository, including description +bodies. + +- *Parameters*: `string owner`, `string repo`. +- *Returns*: `Task>` — list of pull request nodes including `Body`; empty + list on error. + +**GetAllIssuesAsync**: Returns all issue nodes for the repository across all states, including +description bodies. + +- *Parameters*: `string owner`, `string repo`. +- *Returns*: `Task>` — list of issue nodes including `Body`; empty list on error. + +**FindIssueIdsLinkedToPullRequestAsync**: Finds issue numbers linked to a specific pull request +via GitHub's closing-issues cross-reference. + +- *Parameters*: `string owner`, `string repo`, `int pullRequestNumber`. +- *Returns*: `Task>` — list of linked issue numbers; empty list on error. + +**Dispose**: Releases resources owned by this instance. + +- *Postconditions*: If `_ownsGraphQLClient` is true, disposes the `GraphQLHttpClient` (and the + underlying `HttpClient`). + +##### Error Handling + +All API methods catch exceptions from the underlying `GraphQLHttpClient` and return empty lists +rather than propagating them. This allows `GitHubRepoConnector` to continue with partial data +when the GitHub API is transiently unavailable. Because exceptions are silently swallowed, runtime +failures such as network errors, authentication failures, and malformed responses are not directly +observable by the caller; an unexpectedly empty result set is the only visible symptom. + +##### Dependencies -- `GetCommitsAsync` for commit SHAs in a range -- `GetReleasesAsync` for release tag names -- `GetAllTagsAsync` for tag nodes -- `GetPullRequestsAsync` for pull request data, including description bodies -- `GetAllIssuesAsync` for issue data, including description bodies -- `FindIssueIdsLinkedToPullRequestAsync` for cross-link lookups +- **GraphQLHttpClient** — from the `GraphQL.Client.Http` NuGet package; sends GraphQL queries over + HTTPS. +- **SystemTextJsonSerializer** — from the `GraphQL.Client.Serializer.SystemTextJson` NuGet + package; serializes and deserializes GraphQL payloads. +- **GitHubGraphQLTypes** — provides the record types used as deserialization targets. -##### Interactions +##### Callers -- `GitHubRepoConnector` creates and calls `GitHubGraphQLClient`. -- `GitHubGraphQLTypes` provide the request and response record types used for - serialization and deserialization. -- The GitHub GraphQL endpoint provides the remote repository data queried by the - client. +- **GitHubRepoConnector** — creates and calls `GitHubGraphQLClient` for all GraphQL API + communication. diff --git a/docs/design/build-mark/repo-connectors/github/github-graphql-types.md b/docs/design/build-mark/repo-connectors/github/github-graphql-types.md index 26fea4f..7c29612 100644 --- a/docs/design/build-mark/repo-connectors/github/github-graphql-types.md +++ b/docs/design/build-mark/repo-connectors/github/github-graphql-types.md @@ -2,43 +2,88 @@ ##### Purpose -`GitHubGraphQLTypes` is the collection of internal record types used by the -GitHub subsystem to represent GraphQL request and response payloads. These types -allow `GitHubGraphQLClient` to deserialize GitHub API responses into strongly -typed objects that `GitHubRepoConnector` can process safely and predictably. +`GitHubGraphQLTypes` is the collection of internal C# record types used by the GitHub subsystem +to represent GraphQL request and response payloads. These types allow `GitHubGraphQLClient` to +deserialize GitHub API responses into strongly typed objects that `GitHubRepoConnector` can process +safely and predictably. -##### Responsibilities +##### Data Model -- Represent tag, release, issue, pull request, and commit response nodes -- Carry pagination cursors and connection metadata -- Preserve issue and pull request description body fields for item-controls - parsing +**PageInfo.HasNextPage**: `bool` — Indicates whether additional pages are available in a paginated +connection. -##### Data Model +**PageInfo.EndCursor**: `string?` — Cursor value to supply in the next page request. + +**CommitNode.Oid**: `string?` — Git object ID (SHA) of the commit; used to match commits in the +target range. + +**TagNode.Name**: `string?` — Tag name (e.g. `v1.0.0`). + +**TagNode.Target**: `TagTargetData?` — Target object for the tag, carrying the commit SHA. + +**TagTargetData.Oid**: `string?` — Commit SHA the tag points to. + +**ReleaseNode.TagName**: `string?` — Tag name associated with the GitHub release. + +**PullRequestNode.Number**: `int?` — Pull request number. + +**PullRequestNode.Title**: `string?` — Pull request title. + +**PullRequestNode.Url**: `string?` — HTML URL of the pull request. + +**PullRequestNode.Merged**: `bool` — Whether the pull request has been merged. + +**PullRequestNode.MergeCommit**: `PullRequestMergeCommit?` — Merge commit reference; `null` when +unmerged. + +**PullRequestNode.HeadRefOid**: `string?` — Commit SHA of the pull request head; used to identify +commit ranges for unmerged pull requests. -The following record types are defined for GitHub GraphQL request and response serialization: +**PullRequestNode.Labels**: `PullRequestLabelsConnection?` — Labels assigned to the pull request; +used for type normalization. -- **Tag and release nodes**: types representing GitHub tag and release response objects, - including tag names and associated commit SHAs -- **Issue and pull request nodes**: `IssueNode` and `PullRequestNode` records carrying - number, title, URL, state, label connections, and description body fields -- **Commit nodes**: records carrying commit SHAs from GraphQL commit range queries -- **Pagination types**: `PageInfo`, connection, and edge wrapper types carrying `endCursor` - and `hasNextPage` fields for cursor-based pagination across all paginated queries +**PullRequestNode.Body**: `string?` — Pull request description body; passed to +`ItemControlsParser.Parse`. + +**PullRequestMergeCommit.Oid**: `string?` — Commit SHA of the merge commit. + +**PullRequestLabel.Name**: `string?` — Label name (e.g. `bug`, `feature`). + +**IssueNode.Number**: `int?` — Issue number. + +**IssueNode.Title**: `string?` — Issue title. + +**IssueNode.Url**: `string?` — HTML URL of the issue. + +**IssueNode.State**: `string?` — Issue state (`OPEN` or `CLOSED`). + +**IssueNode.Labels**: `IssueLabelsConnection?` — Labels assigned to the issue; used for type +normalization. + +**IssueNode.Body**: `string?` — Issue description body; passed to `ItemControlsParser.Parse`. + +**IssueLabel.Name**: `string?` — Label name. + +**LinkedIssueReference.Number**: `int?` — Issue number of a linked closing issue reference. ##### Key Methods -N/A — `GitHubGraphQLTypes` is a collection of record type definitions with no methods -beyond C# record-generated members. +N/A — `GitHubGraphQLTypes` is a collection of immutable C# record types used purely for GraphQL +deserialization. No methods beyond C#-generated record members are defined. ##### Error Handling -N/A — These are immutable record types used purely for JSON deserialization. No methods -detect or propagate errors. +N/A — These are immutable record types used purely for deserialization. No methods detect or +propagate errors. + +##### Dependencies + +- **GraphQL.Client.Serializer.SystemTextJson** — runtime library used by `GitHubGraphQLClient` to + deserialize these records from GraphQL HTTP responses. -##### Interactions +##### Callers -- `GitHubGraphQLClient` uses these records as serialization and deserialization - targets for GraphQL HTTP traffic. -- `GitHubRepoConnector` consumes the deserialized node data returned by +- **GitHubGraphQLClient** — uses these records as deserialization targets for GraphQL HTTP + responses. +- **GitHubRepoConnector** — consumes `PullRequestNode` and `IssueNode` data returned by `GitHubGraphQLClient`. diff --git a/docs/design/build-mark/repo-connectors/github/github-repo-connector.md b/docs/design/build-mark/repo-connectors/github/github-repo-connector.md index f14861d..35ecc88 100644 --- a/docs/design/build-mark/repo-connectors/github/github-repo-connector.md +++ b/docs/design/build-mark/repo-connectors/github/github-repo-connector.md @@ -2,172 +2,81 @@ ##### Purpose -`GitHubRepoConnector` is the production unit in the RepoConnectors/GitHub -subsystem. It implements `RepoConnectorBase` and uses `GitHubGraphQLClient` to -query the GitHub GraphQL API for issues, pull requests, version tags, and commits. +`GitHubRepoConnector` is the production connector in the GitHub subsystem. It implements +`RepoConnectorBase` and queries the GitHub GraphQL API via `GitHubGraphQLClient` to fetch issues, +pull requests, version tags, and commits needed to construct a `BuildInformation` record. -The unit reads the repository URL and current commit hash from Git, resolves the -GitHub token from environment variables, and fetches all data needed to construct -a `BuildInformation` record. +The unit reads the repository URL and current commit hash from Git, resolves the GitHub token from +environment variables or the `gh` CLI, and applies item-controls overrides from `buildmark` blocks +embedded in issue and pull request description bodies before assembling the result. ##### Data Model -###### Authentication +**_config**: `GitHubConnectorConfig?` — Optional configuration supplying owner, repository name, +GraphQL base URL, and token variable overrides. Received from `RepoConnectorFactory` at +construction time. -The connector resolves the GitHub token in two modes depending on whether `GitHubConnectorConfig.TokenVariable` is set. +Authentication is resolved in two modes. In custom variable mode (when `_config.TokenVariable` is +set), the named environment variable is read exclusively; missing or empty values throw +`InvalidOperationException`. In default mode, the following sources are tried in order: (1) +`GH_TOKEN` environment variable; (2) `GITHUB_TOKEN` environment variable; (3) output of `gh auth +token`. If no token is found, `InvalidOperationException` is thrown. -**Custom variable mode** (when `TokenVariable` is set): +GitHub labels are mapped to normalized `ItemInfo.Type` values: `bug` and `defect` map to `"bug"`; +`feature` and `enhancement` map to `"feature"`; `dependencies`, `renovate`, and `dependabot` map +to `"dependencies"`; `internal` and `chore` map to `"internal"`; `documentation`, `performance`, +and `security` are preserved as the label name; unlabeled items default to `"other"`. -The connector reads the named environment variable exclusively and does not fall back -to well-known names or the gh CLI: - -1. If the variable is not set (null), the connector throws `InvalidOperationException` with - a message identifying the missing variable. -2. If the variable is set but empty, the connector throws `InvalidOperationException` with a - message identifying the empty variable. -3. Otherwise the token value is used directly. - -**Default mode** (when `TokenVariable` is not set): - -1. `GH_TOKEN` environment variable -2. `GITHUB_TOKEN` environment variable -3. Output of `gh auth token` command - -If no token is found, the connector throws `InvalidOperationException`. - -###### Label Mapping - -GitHub issue and pull request labels are mapped to normalized types: - -| GitHub Labels | Normalized Type | -|--------------------------------------------|------------------| -| `bug`, `defect` | `"bug"` | -| `feature`, `enhancement` | `"feature"` | -| `dependencies`, `renovate`, `dependabot` | `"dependencies"` | -| `internal`, `chore` | `"internal"` | -| `documentation`, `performance`, `security` | label name | - -Items labelled as `"bug"` are placed in the `Bugs` list; all others go to `Changes`. - -When routing rules are configured via `.buildmark.yaml`, the label-derived categorization -is overridden by `RepoConnectorBase.ApplyRules`, which delegates to `ItemRouter` to -distribute all collected items into the configured report sections instead. - -###### GraphQL Response Types - -The `GitHubGraphQLClient` returns `PullRequestNode` and `IssueNode` records that -must include the `body` field so the connector can pass description text to -`ItemControlsParser`: - -**`PullRequestNode`** (updated to include `Body`): - -```csharp -internal record PullRequestNode( - int? Number, - string? Title, - string? Url, - bool Merged, - PullRequestMergeCommit? MergeCommit, - string? HeadRefOid, - PullRequestLabelsConnection? Labels, - string? Body); -``` - -**`IssueNode`** (updated to include `Body`): - -```csharp -internal record IssueNode( - int? Number, - string? Title, - string? Url, - string? State, - IssueLabelsConnection? Labels, - string? Body); -``` - -Both `GetPullRequestsAsync` and `GetAllIssuesAsync` must include `body` in their -GraphQL field selections. +##### Key Methods -###### Item Controls Override +**GetBuildInformationAsync**: Main entry point; fetches all data required to assemble a +`BuildInformation` record. + +- *Parameters*: `VersionTag? version` — optional target version; when omitted, the most recent + GitHub Release whose tag matches the current commit hash is used. +- *Returns*: `Task` — fully populated build information record. +- *Preconditions*: A resolvable GitHub token must be available in the environment. +- *Postconditions*: Returns a `BuildInformation` record; throws `InvalidOperationException` on + authentication or version resolution failure. + +Steps: (1) get repository URL, branch, and current commit hash from Git via `RunCommandAsync` +(inherited from `RepoConnectorBase`); (2) determine owner and repository name from `_config` or +by parsing the remote URL; (3) resolve the GitHub authentication token; (4) create a +`GitHubGraphQLClient` with the resolved token, using `_config.BaseUrl` as the GraphQL endpoint +when set (supports GitHub Enterprise Server); (5) fetch tags, releases, commits, pull requests +(with `body`), and issues (with `body`) via GraphQL; (6) determine the target version — if a +`version` argument is supplied, use it directly; otherwise use the most recent release whose tag +matches the current commit hash (throws `InvalidOperationException` when no match is found); (7) +determine the baseline version using `FindBaselineForRelease` or `FindBaselineForPreRelease` +(both inherited from `RepoConnectorBase`); (8) collect changes from pull requests merged in the +commit range, calling `ItemControlsParser.Parse` on each `body` and applying overrides; (9) +collect known issues from all issues (`states: [OPEN, CLOSED]`), applying item-controls overrides; +for each candidate bug, include it when `AffectedVersions.Contains(targetVersion)` if declared, +or only when the issue is open otherwise (covers LTS back-port gaps for closed bugs with declared +affected versions); (10) if routing rules are configured, call `ApplyRules` to populate +`BuildInformation.RoutedSections`; otherwise use legacy `Changes`, `Bugs`, and `KnownIssues` +lists; (11) generate the changelog URL; (12) return the assembled `BuildInformation`. -After the label-derived type is determined, the connector calls -`ItemControlsParser.Parse(body)` on the description body of each issue and pull -request. If the parser returns a non-null `ItemControlsInfo`, the following -overrides are applied: +##### Error Handling -1. **`visibility: internal`** - The item is excluded from all report sections, - regardless of its labels or type. -2. **`visibility: public`** - The item is included in the report even if its - label-derived type is `"other"`. -3. **`type: bug`** - The item is placed in the `Bugs` list regardless of labels. -4. **`type: feature`** - The item is placed in the `Changes` list regardless of - labels. -5. **`affected-versions`** - The parsed `VersionIntervalSet` is stored on the - `ItemInfo.AffectedVersions` property. +`GetBuildInformationAsync` throws `InvalidOperationException` when no GitHub token can be resolved, +when no release matches the current commit hash and no version is specified explicitly, or when a +git command fails. These exceptions propagate to `Program.ProcessBuildNotes`, which catches them, +writes an error message via `context.WriteError`, and returns early without generating a report. -When no `buildmark` block is present, the existing label-based rules apply -unchanged. +##### Dependencies -##### Key Methods +- **RepoConnectorBase** — base class providing `Configure`, `HasRules`, `ApplyRules`, + `FindVersionIndex`, `FindBaselineForPreRelease`, `FindBaselineForRelease`, and `RunCommandAsync`. +- **GitHubGraphQLClient** — executes GraphQL queries against the GitHub API. +- **GitHubConnectorConfig** — supplies owner, repository, base URL, and token variable overrides. +- **ItemControlsParser** — parses `buildmark` blocks from issue and pull request description + bodies. +- **ProcessRunner** — used via `RunCommandAsync` to run Git commands. +- **BuildInformation** — the output record assembled and returned by this unit. +- **ItemInfo** — the normalized item representation stored in `BuildInformation`. -###### `GetBuildInformationAsync(Version? version) → BuildInformation` - -Main entry point. Performs the following steps: - -1. Get repository metadata (URL, branch, current commit hash) from Git. -2. Determine the owner and repository name - from `GitHubConnectorConfig.Owner` - and `GitHubConnectorConfig.Repo` if provided, otherwise parsed from the Git - remote URL. -3. Resolve the GitHub authentication token (see Authentication above). -4. Create a `GitHubGraphQLClient` with the resolved token. If - `GitHubConnectorConfig.BaseUrl` is set, use that URL as the GraphQL endpoint - instead of the default `https://api.github.com/graphql` (supports GitHub - Enterprise). -5. Fetch all tags, commits, releases, issues (with body), and pull requests (with - body) via GraphQL. -6. If a version is provided explicitly, use it directly with the current commit - hash as the target. Otherwise, determine the target version from GitHub - Releases: use the most recent release whose tag matches the current commit - hash. Throws `InvalidOperationException` if no release matches. -7. Determine the baseline version from GitHub Releases: find the highest release - version below the target (for full releases) or the most recent release with - a different commit hash (for pre-releases). Returns `null` baseline if no - prior release exists. -8. Get all commits between the baseline and target. -9. Collect changes and bugs from pull requests merged in the commit range, - applying item controls overrides from description bodies. -10. Collect known issues from **all** issues (open and closed) by querying GitHub - with `states: [OPEN, CLOSED]` and applying item controls overrides from - description bodies. For each candidate bug: - - If `AffectedVersions` is declared, the bug is a known issue if and only if - `AffectedVersions.Contains(toVersion)` is true, regardless of open/closed - state. This covers closed bugs that were fixed in a later release but were - never back-ported to older branches (LTS back-port gap). - - If no `AffectedVersions` is declared, only open bugs are included. -11. Sort all lists chronologically. -12. If routing rules are configured, call `ApplyRules` (inherited from - `RepoConnectorBase`) to route all collected items into the configured report - sections and populate `BuildInformation.RoutedSections`. If no rules are - configured, items remain in the legacy `Changes`, `Bugs`, and `KnownIssues` - lists. -13. Generate the full changelog URL from the baseline and target tags. -14. Return the assembled `BuildInformation` record. - -##### Error Handling +##### Callers -`GetBuildInformationAsync` throws `InvalidOperationException` when no GitHub token can be -resolved, when no release matches the current commit hash and no version is specified -explicitly, or when a git command fails. These exceptions propagate to -`Program.ProcessBuildNotes`, which catches them, writes an error message via -`context.WriteError`, and returns early without generating a report. - -##### Interactions - -- `GitHubConnectorConfig` is received from `RepoConnectorFactory` and overrides - the owner, repository, and URL. -- `GitHubGraphQLClient` executes GraphQL queries against the GitHub API. -- `ProcessRunner` runs Git commands to get repository metadata. -- `ItemRouter` routes assembled items into report sections. -- `ItemControlsParser` parses buildmark blocks from issue and pull request - description bodies. -- `BuildInformation` is the output record assembled from fetched data. +- **RepoConnectorFactory** — creates `GitHubRepoConnector` when the environment indicates GitHub + or as the default fallback. diff --git a/docs/design/build-mark/repo-connectors/item-controls-info.md b/docs/design/build-mark/repo-connectors/item-controls-info.md index 77a9b32..a7430da 100644 --- a/docs/design/build-mark/repo-connectors/item-controls-info.md +++ b/docs/design/build-mark/repo-connectors/item-controls-info.md @@ -2,42 +2,43 @@ #### Purpose -`ItemControlsInfo` is the data record used by the RepoConnectors subsystem to -carry the controls extracted from a `buildmark` block. It stores the optional -visibility override, type override, and affected-version interval data that -`GitHubRepoConnector` applies while constructing `ItemInfo` records. +`ItemControlsInfo` is an immutable data record used by the RepoConnectors subsystem to carry the +controls extracted from a `buildmark` fenced code block. It stores the optional visibility +override, type override, and affected-version interval set that connectors apply while constructing +`ItemInfo` records. #### Data Model -```csharp -public record ItemControlsInfo( - string? Visibility, - string? Type, - VersionIntervalSet? AffectedVersions); -``` +**Visibility**: `string?` — Optional visibility override; accepted values are `"public"` and +`"internal"`. A value of `"internal"` causes the item to be excluded from all report sections; +`"public"` forces inclusion regardless of label-derived type. -- `Visibility` (`string?`) stores the optional visibility override (`public` or - `internal`). -- `Type` (`string?`) stores the optional type override (`bug` or `feature`). -- `AffectedVersions` (`VersionIntervalSet?`) stores the optional - affected-version interval set. +**Type**: `string?` — Optional type override; accepted values are `"bug"` and `"feature"`. Replaces +the label- or work-item-type-derived category when present. + +**AffectedVersions**: `VersionIntervalSet?` — Optional parsed interval set representing the version +range in which a known issue applies. When present, the item is included as a known issue if and +only if the target version falls within the set. #### Key Methods -N/A — `ItemControlsInfo` is an immutable data record with no methods beyond those -auto-generated by C#. +N/A — `ItemControlsInfo` is an immutable C# `record` type. No methods beyond those auto-generated +by the C# record feature are defined. #### Error Handling N/A — This is an immutable data record with no methods that detect or propagate errors. -#### Interactions +#### Dependencies + +- **VersionIntervalSet** — carries the parsed interval representation for the `AffectedVersions` + field. + +#### Callers -- `ItemControlsParser` creates an `ItemControlsInfo` instance when a `buildmark` - block contains one or more recognized keys. -- `GitHubRepoConnector` consumes the parsed values to override item visibility, - item type, and affected-version metadata. -- `WorkItemMapper` (used by `AzureDevOpsRepoConnector`) consumes the parsed values - to override item visibility, item type, and affected-version metadata. -- `VersionIntervalSet` carries the parsed interval representation for the - `affected-versions` field. +- **ItemControlsParser** — creates an `ItemControlsInfo` instance when a `buildmark` block + contains one or more recognized keys. +- **GitHubRepoConnector** — consumes the parsed values to override item visibility, type, and + affected-version metadata. +- **WorkItemMapper** — consumes the parsed values (merged with Azure DevOps custom fields) to + override item visibility, type, and affected-version metadata for work items. diff --git a/docs/design/build-mark/repo-connectors/item-controls-parser.md b/docs/design/build-mark/repo-connectors/item-controls-parser.md index a1760e0..77e2905 100644 --- a/docs/design/build-mark/repo-connectors/item-controls-parser.md +++ b/docs/design/build-mark/repo-connectors/item-controls-parser.md @@ -1,84 +1,66 @@ -### ItemControlsParser and ItemControlsInfo +### ItemControlsParser #### Purpose -`ItemControlsParser` is a static utility class that extracts a `buildmark` -fenced code block from an issue or pull request description and parses its -key-value fields into an `ItemControlsInfo` record. If no block is found, the -method returns `null` so that callers can apply default label-based rules. +`ItemControlsParser` is a static utility class that extracts a `buildmark` fenced code block from +an issue, pull request, or work item description and parses its key-value fields into an +`ItemControlsInfo` record. If no block is found, or no recognized keys are present, the method +returns `null` so callers can apply default label- or type-based rules. -`ItemControlsInfo` is the immutable data record produced by the parser. It holds -up to three optional fields: `Visibility`, `Type`, and `AffectedVersions`. +The parser first strips HTML comment delimiters (``) from the description, which allows +the `buildmark` block to be hidden from the GitHub rendered view while remaining detectable. It +then scans for a fenced code block whose language identifier is exactly `buildmark` +(case-insensitive), with a fence of three or more back-tick characters. Inside the block, each +non-empty line is treated as a `key: value` pair; the key is compared case-insensitively and the +value is compared case-sensitively. Unknown keys and unrecognized values are silently ignored. -#### Block Detection +Recognized keys and accepted values: -The parser locates a `buildmark` block using the following rules: - -1. Strip all HTML comment wrappers (``), which allows the block to be - hidden from the GitHub rendered view. -2. Scan the resulting text for a fenced code block whose language identifier is - exactly `buildmark` (case-insensitive). -3. The fence delimiter is three or more back-tick characters followed immediately - by `buildmark`. -4. The closing fence is the same number of back-tick characters on a line by - itself. -5. If no such block is found, `Parse` returns `null`. - -#### Key-Value Parsing - -Each non-empty line inside the block is treated as a `key: value` pair: - -- The key is the text before the first `:`, trimmed of whitespace. -- The value is the text after the first `:`, trimmed of whitespace. -- Lines that do not contain `:` are ignored. -- Unknown keys are silently ignored. -- Key matching is **case-insensitive** - keys are normalized to lowercase before - comparison. -- Value matching is **case-sensitive** - only the exact values listed below are - recognized; other values are silently ignored. - -Recognized keys: - -| Key | Accepted Values | Effect on `ItemControlsInfo` | -|----------------------|----------------------------------|------------------------------| -| `visibility` | `public`, `internal` | Sets `Visibility` | -| `type` | `bug`, `feature` | Sets `Type` | -| `affected-versions` | Interval expression (see below) | Sets `AffectedVersions` | - -Unrecognized values for a known key are silently ignored (the field remains -`null`). +| Key | Accepted values | Effect | +|---------------------|----------------------|-------------------------------------------| +| `visibility` | `public`, `internal` | Sets `ItemControlsInfo.Visibility` | +| `type` | `bug`, `feature` | Sets `ItemControlsInfo.Type` | +| `affected-versions` | Interval expression | Sets `ItemControlsInfo.AffectedVersions` | #### Data Model -See `item-controls-info.md` for the `ItemControlsInfo` data model definition. +N/A — `ItemControlsParser` is a static utility class with no instance state. #### Key Methods -##### `ItemControlsParser.Parse(string? description) → ItemControlsInfo?` +**Parse**: Parses item controls from a description string and returns an `ItemControlsInfo` record +or `null`. + +- *Parameters*: `string? description` — the issue, pull request, or work item description text to + parse. +- *Returns*: `ItemControlsInfo?` — a populated record when at least one recognized key is found; + `null` when the description is empty, no `buildmark` block is present, or no recognized keys are + found. +- *Preconditions*: None; null or empty input is handled gracefully. +- *Postconditions*: The returned record contains only recognized and valid values; all invalid + input is silently discarded. + +The algorithm: (1) return `null` if `description` is null or empty; (2) strip HTML comment +delimiters using a compiled regex; (3) scan lines for an opening fence of three or more back-ticks +followed by `buildmark` (case-insensitive); (4) return `null` if no such fence is found; (5) read +lines until the matching closing fence (same back-tick count on a line by itself); (6) parse each +line as `key: value` by splitting on the first colon, normalizing the key to lowercase; (7) build +and return an `ItemControlsInfo` from recognized keys, or `null` if none were recognized. -Entry point for the parser. Steps: +#### Error Handling -1. Return `null` if `description` is null or empty. -2. Strip HTML comment wrappers (``) from the description while - preserving the enclosed content. -3. Locate the `buildmark` code fence using the rules above. -4. Return `null` if no fence is found. -5. Split the block body into lines. -6. Parse each line as a key-value pair. -7. Build and return an `ItemControlsInfo` from the recognized keys, or `null` if no - recognized keys were found. +`Parse` returns `null` rather than throwing for any of: null or empty input, a missing `buildmark` +code block, unrecognized key-value pairs, or unrecognized values for known keys. No exceptions +propagate to callers; all invalid or unrecognized content is silently discarded. -#### Error Handling +#### Dependencies -`Parse` returns `null` rather than throwing for any of: null or empty input, missing -`buildmark` code block, unrecognized key-value pairs, or unrecognized values. No exceptions -propagate to callers; invalid or unrecognized content is silently discarded. +- **ItemControlsInfo** — the record type that `Parse` instantiates and returns. +- **VersionIntervalSet** — constructed by the parser when the `affected-versions` key is present + and its value parses to a non-empty interval set. -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|-----------------------|---------------------------------------------------------------------------------| -| `GitHubRepoConnector` | Calls `Parse` on each issue and PR description body | -| `WorkItemMapper` | Calls `Parse` on each work item description body (`AzureDevOpsRepoConnector`) | -| `VersionIntervalSet` | Created by the parser when `affected-versions` key is present | -| `ItemControlsInfo` | The record returned by `Parse` | +- **GitHubRepoConnector** — calls `Parse` on the `body` of each pull request and issue. +- **WorkItemMapper** — calls `Parse` on the `System.Description` field of each Azure DevOps work + item. diff --git a/docs/design/build-mark/repo-connectors/item-router.md b/docs/design/build-mark/repo-connectors/item-router.md index 5b53eea..c4f28c9 100644 --- a/docs/design/build-mark/repo-connectors/item-router.md +++ b/docs/design/build-mark/repo-connectors/item-router.md @@ -2,13 +2,16 @@ #### Purpose -`ItemRouter` is a shared static utility in the RepoConnectors subsystem that routes -a list of `ItemInfo` objects into report sections. It applies a list of `RuleConfig` -entries to determine which section each item belongs to, avoiding duplication of -routing logic across multiple connector implementations. +`ItemRouter` is a static utility class that routes a list of `ItemInfo` objects into report +sections by applying a list of `RuleConfig` entries in order. It centralizes routing logic so that +all connectors — GitHub, Azure DevOps, and Mock — share a single implementation rather than each +maintaining their own. -All connectors (GitHub, Azure DevOps, Mock) call `ItemRouter` rather than -each implementing their own routing. +Rules are evaluated in declaration order; the first matching rule wins. Items that do not match any +rule are placed in the default section, which is the first entry in the `sections` list, or +`"changes"` if the list is empty. A route value of `"suppressed"` (case-insensitive) causes an +item to be omitted from all sections. Sections not declared in `sections` are created dynamically +when a rule routes an item to an unknown section ID. #### Data Model @@ -16,49 +19,39 @@ N/A — `ItemRouter` is a static utility class with no instance state. #### Key Methods -##### `Route(items, rules, sections) → Dictionary>` - -Takes a list of `ItemInfo` objects, a list of `RuleConfig` entries, and a list of -`SectionConfig` entries, and returns a dictionary mapping each section ID to the -items assigned to that section. - -- `items` (`IReadOnlyList`) - items to be distributed into sections -- `rules` (`IReadOnlyList`) - routing rules that map item attributes to - sections -- `sections` (`IReadOnlyList`) - ordered list of report sections - -###### Algorithm - -Rules are evaluated in order; the first matching rule wins. Items that do not match -any rule are placed in the **default section**, which is the first entry in the -`sections` list, or `"changes"` if the list is empty. - -A route value of `"suppressed"` (case-insensitive) causes the item to be omitted -entirely from all sections. - -Sections not present in the configured `sections` list are created dynamically -when a rule routes an item to an unknown section ID. This allows rules to introduce -ad-hoc sections without requiring them to be pre-declared. - -###### Rule matching - -- A `null` `Match` block is a **catch-all** - the rule matches every item. -- A non-null `Match` block may specify `Label` and/or `WorkItemType` filter lists. - Both lists are matched case-insensitively against the item's `Type` field. - All non-empty filter lists must match for the rule to apply. +**Route**: Routes a list of `ItemInfo` objects into section buckets using the configured rules and +returns a dictionary keyed by section ID. + +- *Parameters*: `IReadOnlyList items` — the items to distribute; `IReadOnlyList + rules` — routing rules evaluated in order; `IReadOnlyList sections` — the ordered + set of configured report sections. +- *Returns*: `Dictionary>` — maps each section ID to the items assigned to + it; pre-populated for all configured section IDs, with dynamic entries for any rule-introduced + section IDs not in `sections`. +- *Preconditions*: All arguments must be non-null; duplicate IDs in `sections` will cause an + `ArgumentException` during dictionary initialization. +- *Postconditions*: Every item in `items` has been routed to exactly one section or suppressed; the + returned dictionary contains all configured section IDs plus any dynamically created ones. + +Rule matching: a `null` `Match` block is a catch-all that matches every item. A non-null `Match` +block may specify `Label` and/or `WorkItemType` filter lists; both are matched +case-insensitively against the item's `Type` field, and all non-empty filter lists must match for +the rule to apply. #### Error Handling No explicit error handling is performed. Callers are responsible for passing valid, non-null -arguments. Duplicate section IDs in the `sections` list will cause an `ArgumentException` from -the internal dictionary initialization. Null inputs will result in a `NullReferenceException` -propagating to the caller. +arguments. Duplicate section IDs in `sections` result in an `ArgumentException` from the internal +dictionary initialization. Null inputs result in a `NullReferenceException` propagating to the +caller. + +#### Dependencies + +- **ItemInfo** — provides the input items to be routed; defined in the BuildNotes subsystem. +- **RuleConfig** — provides routing rules; defined in the Configuration subsystem. +- **SectionConfig** — provides section definitions; defined in the Configuration subsystem. -#### Interactions +#### Callers -- `ItemInfo` provides the input items to be routed from the BuildNotes - subsystem. -- `RuleConfig` provides routing rules from the Configuration subsystem. -- `SectionConfig` provides section definitions from the Configuration subsystem. -- `RepoConnectorBase.ApplyRules` calls `ItemRouter.Route` to assign items to report sections. -- `GitHubRepoConnector`, `AzureDevOpsRepoConnector`, and `MockRepoConnector` call `ApplyRules` when rules are configured. +- **RepoConnectorBase** — calls `ItemRouter.Route` from within `ApplyRules` to distribute items + into sections before assembling the ordered section list. diff --git a/docs/design/build-mark/repo-connectors/mock.md b/docs/design/build-mark/repo-connectors/mock.md index 0b3b8d2..83da8c1 100644 --- a/docs/design/build-mark/repo-connectors/mock.md +++ b/docs/design/build-mark/repo-connectors/mock.md @@ -1,45 +1,52 @@ -### Mock Subsystem +### Mock #### Overview -The Mock subsystem groups the in-memory connector used by the built-in -`--validate` self-test. It sits within the RepoConnectors subsystem. +The Mock subsystem groups the in-memory connector used by the built-in `--validate` self-test. It +sits within the RepoConnectors subsystem and contains a single unit, `MockRepoConnector`. -`MockRepoConnector` lives in production code - not in the test project - because -the `--validate` flag must work in any deployment without requiring a separate test -assembly or external tooling. +`MockRepoConnector` lives in production code — not in the test project — because the `--validate` +flag must work in any deployment without requiring a separate test assembly or external tooling. -#### Units +The subsystem contains the following unit: -| Unit | File | Responsibility | -|----------------------|---------------------------------------------|----------------------------------------------| -| `MockRepoConnector` | `RepoConnectors/Mock/MockRepoConnector.cs` | In-memory connector for self-validation | +- `MockRepoConnector` — in-memory implementation of `IRepoConnector`; returns a deterministic + `BuildInformation` record from hard-coded dictionaries without making any network or filesystem + calls. #### Interfaces -The Mock subsystem exposes `MockRepoConnector`, which implements `IRepoConnector`. +**MockRepoConnector**: The in-memory `IRepoConnector` implementation used for self-validation. -| Member | Kind | Description | -| --- | --- | --- | -| `MockRepoConnector()` | Constructor | Create the connector with hard-coded in-memory data | -| `GetBuildInformationAsync(version)` | Method | Return a deterministic `BuildInformation` record from in-memory data | +- *Type*: In-process .NET public API. +- *Role*: Provider — exposed to the `Validation` unit in the SelfTest subsystem. +- *Contract*: Default constructor `MockRepoConnector()` requires no arguments; inherits + `Configure(rules, sections)` from `RepoConnectorBase`; `GetBuildInformationAsync(VersionTag? + version)` returns a deterministic `BuildInformation` from hard-coded in-memory data. +- *Constraints*: Does not call any external processes or network endpoints; throws + `InvalidOperationException` when no version tags exist in the hard-coded data and no version + argument is provided, or when the current commit hash does not match any tag and no version + argument is provided. #### Design -The Mock subsystem contains a single unit, so there is no inter-unit -collaboration to describe. `MockRepoConnector` overrides -`GetBuildInformationAsync` entirely with an in-memory implementation that -mirrors the production connector logic but operates on hard-coded dictionaries -instead of live API responses. The `RunCommandAsync` method inherited from -`RepoConnectorBase` is not called, as the mock does not execute any shell -commands. When routing rules have been configured via `Configure`, the connector -calls `ApplyRules` (inherited from `RepoConnectorBase`) to populate -`BuildInformation.RoutedSections`. - -#### Interactions - -| Unit / Subsystem | Role | -|---------------------|-------------------------------------------------------------------| -| `IRepoConnector` | Interface implemented by `MockRepoConnector` | -| `RepoConnectorBase` | Base class providing `FindVersionIndex` and command delegation | -| `Validation` | Instantiates `MockRepoConnector` directly for self-tests | +The Mock subsystem contains a single unit, so there is no inter-unit collaboration to describe. +`MockRepoConnector` overrides `GetBuildInformationAsync` entirely with an in-memory implementation +that mirrors the production connector logic but operates on hard-coded dictionaries instead of live +API responses: + +1. Build the list of `VersionTag` entries from `_tagHashes`. +2. Determine the target version tag using `FindVersionIndex` (inherited from `RepoConnectorBase`) + or the supplied `version` argument. +3. Determine the baseline version tag (highest tag below the target for full releases; most recent + tag with a different commit hash for pre-releases) using `FindBaselineForRelease` or + `FindBaselineForPreRelease` (both inherited from `RepoConnectorBase`). +4. Collect changes from `_pullRequestIssues` whose linked issues fall in the commit range between + baseline and target. +5. Collect known issues from `_issueTitles`: if an issue has an entry in + `_issueAffectedVersions`, include it only when `AffectedVersions.Contains(targetVersion)`; + otherwise include it only if it appears in `_openIssues`. +6. If routing rules are configured via `Configure`, call `ApplyRules` (inherited from + `RepoConnectorBase`) to produce `BuildInformation.RoutedSections`; otherwise use the legacy + `Changes`, `Bugs`, and `KnownIssues` categorization. +7. Return the assembled `BuildInformation` record. diff --git a/docs/design/build-mark/repo-connectors/mock/mock-repo-connector.md b/docs/design/build-mark/repo-connectors/mock/mock-repo-connector.md index fcf7a8f..d30e94e 100644 --- a/docs/design/build-mark/repo-connectors/mock/mock-repo-connector.md +++ b/docs/design/build-mark/repo-connectors/mock/mock-repo-connector.md @@ -2,65 +2,76 @@ ##### Purpose -`MockRepoConnector` is an in-memory implementation of `IRepoConnector` used for -self-validation and unit testing. It returns a fixed, deterministic dataset -without making any network or filesystem calls. +`MockRepoConnector` is an in-memory implementation of `IRepoConnector` used for self-validation +via the `--validate` flag and for unit testing. It returns a fixed, deterministic dataset without +making any network or filesystem calls. -`MockRepoConnector` lives in production code - not in the test project - because -the `--validate` flag must work in any deployment without requiring a separate test -assembly or external tooling. +`MockRepoConnector` lives in production code — not in the test project — because the `--validate` +flag must work in any deployment without requiring a separate test assembly or external tooling. ##### Data Model -The connector holds hard-coded mappings used to build the `BuildInformation` response: +**_issueTitles**: `Dictionary` — Maps issue ID to issue title for the hard-coded +in-memory dataset. -| Field | Type | Description | -|--------------------------|-------------------------------------------|----------------------------------------------| -| `_issueTitles` | `Dictionary` | Issue ID -> title | -| `_issueTypes` | `Dictionary` | Issue ID -> type (bug/feature/documentation) | -| `_pullRequestIssues` | `Dictionary>` | PR ID -> linked issue IDs | -| `_tagHashes` | `Dictionary` | Tag name -> commit hash | -| `_openIssues` | `List` | IDs of issues that remain open | -| `_issueAffectedVersions` | `Dictionary` | Issue ID -> declared affected-versions range | +**_issueTypes**: `Dictionary` — Maps issue ID to normalized type (e.g. `"bug"`, +`"feature"`, `"documentation"`). -##### Key Methods +**_pullRequestIssues**: `Dictionary>` — Maps pull request ID to the list of +linked issue IDs. -###### `GetBuildInformationAsync(version?) → BuildInformation` +**_tagHashes**: `Dictionary` — Maps tag name to commit hash; provides the version +history for the mock repository. -Resolves tag history and the current commit hash from the internal dictionaries, -determines the target and baseline versions, collects changes and known issues, -and returns a fully populated `BuildInformation` record. The logic mirrors the -production GitHubRepoConnector flow but operates entirely on in-memory data. +**_openIssues**: `List` — IDs of issues that remain open; used when no `AffectedVersions` +is declared to determine known-issue eligibility. -When collecting known issues, **all** issues (open and closed) are considered: +**_issueAffectedVersions**: `Dictionary` — Maps issue ID to its +declared affected-version interval set; overrides open/closed status for known-issue determination +when present. -- If `AffectedVersions` is non-null, the bug is included if and only if - `AffectedVersions.Contains(targetVersion)` is true, regardless of open/closed - state (models a closed bug never back-ported to an older branch). -- If `AffectedVersions` is null, only open bugs are included. +##### Key Methods -When routing rules have been configured via `Configure`, `GetBuildInformationAsync` -collects all items and passes them to `ApplyRules` (inherited from `RepoConnectorBase`) -to produce the `RoutedSections` list. If no rules are configured, the legacy -categorization into `Changes` and `Bugs` is used. +**GetBuildInformationAsync**: Resolves tag history and version information from internal +dictionaries, collects changes and known issues, and returns a fully populated `BuildInformation` +record. + +- *Parameters*: `VersionTag? version` — optional target version; when omitted, the tag matching + the hard-coded current commit hash is used. +- *Returns*: `Task` — deterministic build information record. +- *Preconditions*: None for the happy path; the internal dataset covers a representative set of + versions, issues, and pull requests. +- *Postconditions*: Returns a non-null `BuildInformation`; throws `InvalidOperationException` when + version resolution fails. + +Steps: (1) build the `VersionTag` list from `_tagHashes`; (2) determine the target version using +`FindVersionIndex` (inherited from `RepoConnectorBase`) or the supplied `version` argument; (3) +determine the baseline version using `FindBaselineForRelease` or `FindBaselineForPreRelease` +(inherited); (4) collect changes from `_pullRequestIssues` entries whose linked issues fall in the +commit range between baseline and target; (5) collect known issues: for each issue in +`_issueTitles` of type `"bug"`, include it when `_issueAffectedVersions` contains the target +version or (if no `AffectedVersions` entry exists) when the issue appears in `_openIssues`; (6) if +routing rules are configured via `Configure`, call `ApplyRules` (inherited) to populate +`BuildInformation.RoutedSections`; otherwise use the legacy `Changes`, `Bugs`, and `KnownIssues` +categorization; (7) return the assembled `BuildInformation`. ##### Error Handling -`GetBuildInformationAsync` throws `InvalidOperationException` in the following scenarios: +`GetBuildInformationAsync` throws `InvalidOperationException` in two scenarios: (1) when no +version tags exist in `_tagHashes` and no version argument is provided; (2) when the hard-coded +current commit hash does not match any tag and no version argument is provided. These conditions +mirror the equivalent error paths in the production connectors, making the mock suitable for +testing error-handling code paths as well as the happy path. -1. **No version tags exist in data and no version argument provided** - throws with message: - `"No tags found in repository and no version specified. Please provide a version parameter."` -2. **Current commit does not match any tag and no version argument provided** - throws with message: - `"Target version not specified and current commit does not match any tag. Please provide a version parameter."` +##### Dependencies -These conditions mirror the equivalent error paths in the production `GitHubRepoConnector` -and `AzureDevOpsRepoConnector`, making the mock suitable for testing error-handling code -paths as well as the happy path. +- **RepoConnectorBase** — base class providing `Configure`, `HasRules`, `ApplyRules`, + `FindVersionIndex`, `FindBaselineForPreRelease`, and `FindBaselineForRelease`. +- **VersionIntervalSet** — held in `_issueAffectedVersions`; used for known-issue determination. +- **BuildInformation** — the output record assembled and returned by this unit. +- **ItemInfo** — the normalized item representation stored in `BuildInformation`. -##### Interactions +##### Callers -| Unit / Subsystem | Role | -|--------------------------|-----------------------------------------------------------------------------------| -| `RepoConnectorBase` | Base class providing `FindVersionIndex` and command delegation | -| `Configure` (inherited) | Called by `Validation.RunRulesRouting` to test rules-based routing | -| `Validation` | Instantiates `MockRepoConnector` directly for self-tests | +- **Validation** — instantiates `MockRepoConnector` directly and calls `Configure` and + `GetBuildInformationAsync` as part of the `--validate` self-test. diff --git a/docs/design/build-mark/repo-connectors/repo-connector-base.md b/docs/design/build-mark/repo-connectors/repo-connector-base.md index 3fb610b..8094ca4 100644 --- a/docs/design/build-mark/repo-connectors/repo-connector-base.md +++ b/docs/design/build-mark/repo-connectors/repo-connector-base.md @@ -1,102 +1,132 @@ -### IRepoConnector and RepoConnectorBase +### RepoConnectorBase #### Purpose -`IRepoConnector` defines the contract that all repository connectors must satisfy. -`RepoConnectorBase` is an abstract class implementing `IRepoConnector` and providing -shared utilities used by concrete connectors. +`RepoConnectorBase` is an abstract class that implements `IRepoConnector` and provides shared +utilities used by all concrete connector implementations. It stores routing rules and section +definitions supplied via `Configure`, exposes `ApplyRules` to route items through `ItemRouter`, +provides `FindVersionIndex`, `FindBaselineForPreRelease`, and `FindBaselineForRelease` for version +resolution, and exposes `RunCommandAsync` for delegating shell commands to `ProcessRunner`. + +`IRepoConnector` defines the single public method contract: `GetBuildInformationAsync(VersionTag? +version)` returning `Task`. `RepoConnectorBase` declares this method `abstract` +so that each concrete connector supplies its own implementation while inheriting all shared +behavior. #### Data Model -`IRepoConnector` is a pure interface with no instance state. `RepoConnectorBase` stores -the routing rules and section definitions supplied via `Configure(rules, sections)`; these -are held as internal fields accessible to subclasses via `HasRules` and `ApplyRules`. +**_rules**: `IReadOnlyList` — Routing rules stored by `Configure`; defaults to an +empty list when `Configure` has not been called. + +**_sections**: `IReadOnlyList` — Section definitions stored by `Configure`; defaults +to an empty list when `Configure` has not been called. #### Key Methods -- `Configure(rules, sections)` — Stores routing rules and section definitions on the - connector instance; called by `Program.ProcessBuildNotes` before the first - `GetBuildInformationAsync` call -- `HasRules` — Internal property returning `true` when at least one rule has been - stored via `Configure` -- `ApplyRules(allItems)` — Protected method routing items via `ItemRouter.Route`, - then assembling an ordered list of `(SectionId, SectionTitle, Items)` tuples - following configured section order -- `FindVersionIndex(versions, targetVersion)` — Protected static method finding the - index of `targetVersion` in a `VersionTag` list using semantic `VersionComparable` - equality; returns `-1` if not found -- `RunCommandAsync(command, args)` — Protected virtual method delegating shell commands - to `ProcessRunner.RunAsync`; `virtual` so test subclasses can override without - spawning real processes - -#### Interface - -`IRepoConnector` exposes a single method: - -| Member | Kind | Description | -|-------------------------------------|--------|----------------------------------| -| `GetBuildInformationAsync(version)` | Method | Fetch complete build information | - -#### Base Class - -`RepoConnectorBase` provides: - -| Member | Kind | Description | -|------------------------------------------|-------------------|-------------------------------------------------------| -| `Configure(rules, sections)` | Public method | Stores routing rules and section definitions | -| `HasRules` | Internal bool | True when at least one rule has been configured | -| `ApplyRules(allItems)` | Protected method | Routes items into sections using configured rules | -| `RunCommandAsync(command, args)` | Protected virtual | Delegates shell commands to ProcessRunner | -| `FindVersionIndex(versions, target)` | Protected static | Locates version using semantic equality | - -##### `Configure(rules, sections)` - -Stores the routing rules and section definitions on the connector instance. Called -by `Program.ProcessBuildNotes` after the connector is created, passing `Rules` and +**Configure**: Stores routing rules and section definitions on the connector instance. + +- *Parameters*: `IReadOnlyList rules` — routing rules to apply when distributing + items; `IReadOnlyList sections` — section definitions that determine output + structure. +- *Returns*: `void`. +- *Preconditions*: None; may be called at any point before `GetBuildInformationAsync`. +- *Postconditions*: `_rules` and `_sections` are updated; subsequent calls to `ApplyRules` use the + newly stored values. + +Called by `Program.ProcessBuildNotes` after the connector is created, passing `Rules` and `Sections` from the loaded `.buildmark.yaml` configuration. -##### `HasRules` +**HasRules**: Internal boolean property that returns `true` when at least one rule has been stored +via `Configure`. -Internal boolean property that returns `true` when at least one rule has been -stored via `Configure`. Concrete connectors use this in `GetBuildInformationAsync` -to decide whether to call `ApplyRules` or use legacy categorization. +- *Returns*: `bool` — `true` when `_rules.Count > 0`. -##### `ApplyRules(allItems)` +Used by concrete connectors in `GetBuildInformationAsync` to decide whether to call `ApplyRules` +or use legacy categorization. -Routes the provided items using `ItemRouter.Route`, then assembles an ordered list +**ApplyRules**: Routes the provided items using `ItemRouter.Route`, then assembles an ordered list of `(SectionId, SectionTitle, Items)` tuples following the configured section order. -Any items routed to section IDs not in the configured section list are appended at -the end using the section ID as the display title. -##### `FindVersionIndex(versions, targetVersion)` +- *Parameters*: `IEnumerable allItems` — all items collected by the connector. +- *Returns*: `IReadOnlyList<(string SectionId, string SectionTitle, IReadOnlyList + Items)>` — sections in configured order, with any extra rule-introduced sections appended. +- *Preconditions*: `Configure` should have been called with at least one rule. +- *Postconditions*: All items have been routed; the returned list preserves the configured section + order. -Protected static method that finds the index of a `targetVersion` within a list of -`VersionTag` instances using **semantic VersionComparable equality**. This design -ensures that version tags with different prefixes but identical semantic versions -are considered equal: +Any items routed to section IDs not in the configured `sections` list are appended at the end +using the section ID as the display title. -- `"v1.2.3"` matches `"VER1.2.3"` and `"Release-1.2.3"` -- Comparison uses `versions[i].Semantic.Comparable.Equals(targetVersion.Semantic.Comparable)` -- This prevents version matching failures across different repository tag conventions +**FindVersionIndex**: Protected static method that finds the index of a target version within a +list of `VersionTag` instances using semantic `VersionComparable` equality. -Returns the zero-based index if found, or -1 if no semantically equivalent version exists. +- *Parameters*: `List versions` — the version list to search; + `VersionTag targetVersion` — the version to find. +- *Returns*: `int` — zero-based index when found; `-1` when no semantically equivalent version + exists. +- *Preconditions*: Neither argument may be null. +- *Postconditions*: Returns `-1` rather than throwing when no match is found. -The `RunCommandAsync` method accepts a command and a `params string[]` arguments -array, and is `virtual` so that test subclasses can override it with mock -implementations that return fixed strings without spawning real processes. +Comparison uses `versions[i].Semantic.Comparable.Equals(targetVersion.Semantic.Comparable)`, so +tags with different prefixes but identical semantic versions are considered equal (e.g. `"v1.2.3"` +matches `"VER1.2.3"`). -#### Error Handling +**FindBaselineForPreRelease**: Internal static method that finds the most recent preceding version +with a different commit hash than the target, skipping entries that share the same commit +(which would produce an empty changelog). + +- *Parameters*: `List precedingVersions` — version-commit tags that precede the + target, ordered oldest first; `string targetCommitHash` — commit hash of the target version. +- *Returns*: `VersionCommitTag?` — the most recent preceding entry with a different commit hash, + or `null` if none exists. -`RunCommandAsync` propagates `InvalidOperationException` from `ProcessRunner.RunAsync` -when a shell command fails. `FindVersionIndex` returns `-1` rather than throwing when no -matching version is found. Error handling for `GetBuildInformationAsync` is delegated to -concrete implementations. +**FindBaselineForRelease**: Internal static method that finds the most recent preceding +non-pre-release version, skipping any pre-release entries. -#### Interactions +- *Parameters*: `List precedingVersions` — version-commit tags that precede the + target, ordered oldest first. +- *Returns*: `VersionCommitTag?` — the most recent preceding non-pre-release entry, or `null` if + none exists. + +**RunCommandAsync**: Protected virtual method that delegates shell commands to +`ProcessRunner.RunAsync`. + +- *Parameters*: `string command` — the executable to run; `params string[] arguments` — arguments + passed to the process. +- *Returns*: `Task` — standard output of the command. +- *Preconditions*: The command must be available in the system PATH. +- *Postconditions*: Throws `InvalidOperationException` if the process exits with a non-zero code + or produces no output. + +Declared `virtual` so that test subclasses can override it without spawning real processes. + +#### Error Handling -- `ProcessRunner` is used by `RunCommandAsync` to execute shell commands in the - Utilities subsystem. -- `GitHubRepoConnector` is a concrete implementation that inherits this base. -- `AzureDevOpsRepoConnector` is a concrete implementation that inherits this base. -- `MockRepoConnector` is a test implementation that overrides - `GetBuildInformationAsync` with in-memory data. +`RunCommandAsync` propagates `InvalidOperationException` from `ProcessRunner.RunAsync` when a +shell command fails. `FindVersionIndex` returns `-1` rather than throwing when no matching version +is found. `FindBaselineForPreRelease` and `FindBaselineForRelease` return `null` rather than +throwing when no suitable baseline exists. Error handling for `GetBuildInformationAsync` is +delegated to concrete implementations. + +#### Dependencies + +- **IRepoConnector** — the interface that `RepoConnectorBase` implements; defines + `GetBuildInformationAsync`. +- **ProcessRunner** — used by `RunCommandAsync` to execute shell commands. +- **ItemRouter** — called by `ApplyRules` to route items into section buckets. +- **RuleConfig** — routing rules stored and applied by this unit. +- **SectionConfig** — section definitions stored and applied by this unit. +- **VersionTag** — used by `FindVersionIndex` for version list lookups. +- **VersionCommitTag** — used by `FindBaselineForPreRelease` and `FindBaselineForRelease` for + baseline selection. +- **ItemInfo** — the item type passed to `ApplyRules`. + +#### Callers + +- **GitHubRepoConnector** — concrete subclass that calls `Configure`, `HasRules`, `ApplyRules`, + `FindVersionIndex`, `FindBaselineForPreRelease`, `FindBaselineForRelease`, and `RunCommandAsync`. +- **AzureDevOpsRepoConnector** — concrete subclass with the same usage pattern. +- **MockRepoConnector** — concrete subclass that calls `Configure`, `HasRules`, `ApplyRules`, + `FindVersionIndex`, `FindBaselineForPreRelease`, and `FindBaselineForRelease`. +- **Program** — calls `Configure` via the `IRepoConnector` reference before invoking + `GetBuildInformationAsync`. diff --git a/docs/design/build-mark/repo-connectors/repo-connector-factory.md b/docs/design/build-mark/repo-connectors/repo-connector-factory.md index d7c70a7..e3badd3 100644 --- a/docs/design/build-mark/repo-connectors/repo-connector-factory.md +++ b/docs/design/build-mark/repo-connectors/repo-connector-factory.md @@ -2,76 +2,69 @@ #### Purpose -`RepoConnectorFactory` is a static factory class that creates the appropriate -`IRepoConnector` implementation based on the runtime environment. +`RepoConnectorFactory` is a static factory class that creates the appropriate `IRepoConnector` +implementation based on the runtime environment. It examines explicit configuration, environment +variables, and the git remote URL in a fixed priority order, then returns the matching connector so +that callers never need to know which platform is in use. #### Data Model -N/A — `RepoConnectorFactory` is a static factory class with no instance state. +N/A — `RepoConnectorFactory` is a static class with no instance state. #### Key Methods -##### `Create(ConnectorConfig? config) → IRepoConnector` - -The factory method accepts an optional `ConnectorConfig` from the -parsed `.buildmark.yaml` file and returns the appropriate -`IRepoConnector` implementation: - -- If `config?.Type` is `"azure-devops"`, returns a new `AzureDevOpsRepoConnector` - initialized with `config?.AzureDevOps`. - -When `config?.Type` is not `"azure-devops"` (including when `config` is `null` -or `Type` is `null`), the method auto-detects the environment using the -following signals, checked in order: - -1. The `TF_BUILD` environment variable is non-empty - indicates Azure DevOps - Pipelines; creates an `AzureDevOpsRepoConnector`. -2. The `GITHUB_ACTIONS` or `GITHUB_WORKSPACE` environment variable is - non-empty - creates a `GitHubRepoConnector`. -3. The git remote URL contains `dev.azure.com` or `visualstudio.com` - creates - an `AzureDevOpsRepoConnector`. -4. The git remote URL contains `github.com` - creates a `GitHubRepoConnector`. -5. None of the above matched - defaults to a `GitHubRepoConnector`. - -The git remote URL is obtained **once** using the sync-over-async pattern via -`ProcessRunner.TryRunAsync("git", "remote", "get-url", "origin").GetAwaiter().GetResult()`, -then forwarded to `CreateFromRemoteUrl`. If the git process is unavailable or returns -no output, `TryRunAsync` returns `null`; in that case `CreateFromRemoteUrl` falls -through to the default and returns a `GitHubRepoConnector`. -BuildMark is distributed as a .NET tool and is not intended for consumption as a -library by external callers, so this design reflects the tool-oriented execution -model rather than a guarantee that synchronization-context-related deadlocks are -impossible in every host. - -##### `CreateFromRemoteUrl(ConnectorConfig? config, string? remoteUrl) → IRepoConnector` *(internal)* - -An internal helper that selects a connector based on `remoteUrl` alone (skipping -environment-variable checks). It is exposed internally so that unit tests can -exercise the URL-based detection logic without requiring a real git process. - -- If `remoteUrl` contains `dev.azure.com` or `visualstudio.com` (case-insensitive), - returns a new `AzureDevOpsRepoConnector` initialized with `config?.AzureDevOps`. -- If `remoteUrl` contains `github.com` (case-insensitive), - returns a new `GitHubRepoConnector` initialized with `config?.GitHub`. -- If `remoteUrl` is `null` or does not match any known host, defaults to a - `GitHubRepoConnector` initialized with `config?.GitHub`. +**Create**: Creates a repository connector based on the current environment and optional +configuration. + +- *Parameters*: `ConnectorConfig? config` — optional connector configuration parsed from + `.buildmark.yaml`. +- *Returns*: `IRepoConnector` — the appropriate connector instance. +- *Preconditions*: None; null `config` is treated as unconfigured. +- *Postconditions*: Returns a non-null `IRepoConnector`; never throws. + +Selection order: (1) if `config.Type` equals `"azure-devops"`, return +`AzureDevOpsRepoConnector(config.AzureDevOps)`; (2) if `TF_BUILD` environment variable is +non-empty, return `AzureDevOpsRepoConnector(config?.AzureDevOps)`; (3) if `GITHUB_ACTIONS` or +`GITHUB_WORKSPACE` is non-empty, return `GitHubRepoConnector(config?.GitHub)`; (4) read the git +remote URL once via `ProcessRunner.TryRunAsync("git", "remote", "get-url", "origin")` using +sync-over-async (safe in a console application with no synchronization context); delegate to +`CreateFromRemoteUrl` with the result. If the git process is unavailable, `TryRunAsync` returns +`null` and `CreateFromRemoteUrl` defaults to `GitHubRepoConnector`. + +**CreateFromRemoteUrl**: Internal helper that selects a connector based on the git remote URL, +bypassing environment-variable checks. + +- *Parameters*: `ConnectorConfig? config` — optional configuration; `string? remoteUrl` — the git + remote URL, or `null` if unavailable. +- *Returns*: `IRepoConnector` — `AzureDevOpsRepoConnector` when `remoteUrl` contains + `dev.azure.com` or `visualstudio.com`; `GitHubRepoConnector` when `remoteUrl` contains + `github.com`; `GitHubRepoConnector` as the default when `remoteUrl` is null or unrecognized. +- *Preconditions*: None. +- *Postconditions*: Returns a non-null `IRepoConnector`. + +Exposed internally so that unit tests can exercise URL-based detection logic without requiring a +real git process. #### Error Handling `Create` never throws. If the git remote URL cannot be determined (e.g., git is unavailable), `ProcessRunner.TryRunAsync` returns `null` and the factory silently defaults to a -`GitHubRepoConnector`. Connector type detection errors are suppressed to avoid failing -tool startup on environment differences. - -#### Interactions - -| Unit / Subsystem | Role | -| ---------------------------- | ---------------------------------------------------------------------- | -| `IRepoConnector` | Return type of `Create` | -| `ConnectorConfig` | Optional envelope passed to `Create`; type discriminates result | -| `GitHubConnectorConfig` | Forwarded to `GitHubRepoConnector` as `config?.GitHub` | -| `AzureDevOpsConnectorConfig` | Forwarded to `AzureDevOpsRepoConnector` as `config?.AzureDevOps` | -| `GitHubRepoConnector` | The concrete connector returned for GitHub repositories | -| `AzureDevOpsRepoConnector` | The concrete connector returned for Azure DevOps repositories | -| `ProcessRunner` | Used via sync-over-async by `Create` to inspect git remote URL | -| `Program` | Calls `RepoConnectorFactory.Create(result.Config?.Connector)` | +`GitHubRepoConnector`. Connector type detection errors are suppressed to avoid failing tool startup +on environment differences. + +#### Dependencies + +- **IRepoConnector** — the return type of both factory methods. +- **ConnectorConfig** — optional envelope passed to `Create`; its `Type` field discriminates the + result. +- **GitHubConnectorConfig** — forwarded to `GitHubRepoConnector` as `config?.GitHub`. +- **AzureDevOpsConnectorConfig** — forwarded to `AzureDevOpsRepoConnector` as + `config?.AzureDevOps`. +- **GitHubRepoConnector** — returned for GitHub repositories and as the default fallback. +- **AzureDevOpsRepoConnector** — returned for Azure DevOps repositories. +- **ProcessRunner** — used via sync-over-async by `Create` to inspect the git remote URL. + +#### Callers + +- **Program** — calls `RepoConnectorFactory.Create(result.Config?.Connector)` to obtain the + connector before processing build notes. diff --git a/docs/design/build-mark/self-test.md b/docs/design/build-mark/self-test.md index a8e81d6..d98bfad 100644 --- a/docs/design/build-mark/self-test.md +++ b/docs/design/build-mark/self-test.md @@ -2,52 +2,45 @@ ### Overview -The SelfTest subsystem provides a self-validation capability for BuildMark. When the -user passes `--validate`, the subsystem exercises the core functionality of the tool -in the current environment, using a `MockRepoConnector` to avoid external API calls. +The SelfTest subsystem provides a self-validation capability for BuildMark. When the user passes `--validate`, +the subsystem exercises the core functionality of the tool using a `MockRepoConnector` to avoid external API +calls. It prints a header table showing the BuildMark version, machine name, OS, .NET runtime, and current +timestamp, then prints a pass/fail summary and optionally writes a TRX or JUnit XML results file. -The subsystem has no dependencies on the Cli subsystem beyond receiving a `Context` -as its input parameter. +The subsystem contains one unit: -### Units +- **`Validation`** (`SelfTest/Validation.cs`) — runs self-tests and writes results to a file -| Unit | File | Responsibility | -|--------------|--------------------------|----------------------------------------------| -| `Validation` | `SelfTest/Validation.cs` | Runs self-tests and writes results to a file | +The subsystem has no dependencies on the Cli subsystem beyond receiving a `Context` as its input parameter. ### Interfaces -`Validation` exposes one public method: +**`Validation.Run`**: Entry point for self-validation, consumed by `Program`. -| Member | Kind | Description | -|----------------|--------|------------------------------------------------------------| -| `Run(context)` | Method | Execute all self-tests and optionally write a results file | +- *Type*: In-process .NET static method +- *Role*: Provider — the SelfTest subsystem exposes this method for `Program`. +- *Contract*: `Run(Context context) → void`; executes all self-tests using `MockRepoConnector` for + deterministic data, prints a summary, and optionally writes TRX or JUnit XML results to + `context.ResultsFile`. +- *Constraints*: Sets `context.ExitCode` to 1 if any test fails. If `--results` is specified with an + unsupported extension, writes an error and returns without writing a file. ### Design -The SelfTest subsystem contains a single unit (`Validation`), so there is no -inter-unit collaboration to describe. `Validation.Run` executes each self-test -method in sequence using a `MockRepoConnector` for deterministic data, accumulates -`TestResult` records, and writes the results file in TRX or JUnit XML format at -the end of the run. The test methods are independent of each other and share no -mutable state; each creates its own `MockRepoConnector` instance. +The SelfTest subsystem contains a single unit (`Validation`), so there is no inter-unit collaboration to +describe. `Validation.Run` executes each self-test method in sequence using a `MockRepoConnector` for +deterministic data, accumulates `DemaConsulting.TestResults.TestResult` records, and writes the results +file at the end of the run. -### Interactions +The five self-tests each exercise a distinct aspect of the tool: -| Unit / Subsystem | Role | -|---------------------|-----------------------------------------------------------------------------| -| `Context` | Provides output methods and `ResultsFile` path | -| `MockRepoConnector` | Provides deterministic repository data for self-tests (RepoConnectors/Mock) | -| `BuildInformation` | Generated during tests to verify report content | +| Test Name | What It Verifies | +|--------------------------------------|-----------------------------------------------------------------------| +| `BuildMark_MarkdownReportGeneration` | Markdown report is correctly generated from mock data | +| `BuildMark_GitIntegration` | Git repository connector reads version tags and commits | +| `BuildMark_IssueTracking` | GitHub issue and pull request tracking works correctly | +| `BuildMark_KnownIssuesReporting` | Known issues are correctly included in the report when requested | +| `BuildMark_RulesRouting` | Rules-based item routing assigns items to the correct report sections | -### Validation Tests - -`Validation.Run` executes the following self-tests in order: - -| Test Name | What it verifies | -|------------------------------------------|------------------------------------------------------------------------| -| `BuildMark_MarkdownReportGeneration` | Markdown report is correctly generated from mock data | -| `BuildMark_GitIntegration` | Git repository connector reads version tags and commits | -| `BuildMark_IssueTracking` | GitHub issue and pull request tracking works correctly | -| `BuildMark_KnownIssuesReporting` | Known issues are correctly included in the report when requested | -| `BuildMark_RulesRouting` | Rules-based item routing assigns items to the correct report sections | +Each test method creates its own `MockRepoConnector` instance, builds a `BuildInformation` record, and +validates the output against expected content. Tests are independent and share no mutable state. diff --git a/docs/design/build-mark/self-test/validation.md b/docs/design/build-mark/self-test/validation.md index d8d4e86..7e2e192 100644 --- a/docs/design/build-mark/self-test/validation.md +++ b/docs/design/build-mark/self-test/validation.md @@ -2,73 +2,73 @@ #### Purpose -`Validation` is the sole unit in the SelfTest subsystem. It runs a fixed set of -self-tests that exercise the core functionality of BuildMark without requiring -network access or external tools beyond Git. Results are written to the console and, -optionally, to a TRX or JUnit XML results file. +`Validation` is the sole unit in the SelfTest subsystem. It runs a fixed set of self-tests that exercise +the core functionality of BuildMark without requiring network access or external tools beyond Git. Results +are written to the console and, optionally, to a TRX or JUnit XML results file. The unit is invoked by `Program.Run` when the `--validate` flag is set. #### Data Model -`Validation` has no persistent state. All data is local to the `Run` method and -its helpers. Test results are accumulated in a list of `TestResult` records that -are written to a file at the end of the run. +N/A — `Validation` is a static class with no instance state. All data is local to the `Run` method and +its helpers. Test results are accumulated in a `DemaConsulting.TestResults.TestResults` collection that +is written to file at the end of the run. #### Key Methods -##### `Run(Context context)` +**`Run`**: Entry point for self-validation. -Entry point for self-validation. It: +- *Parameters*: `Context context` — provides output methods, `ResultsFile` path, and the exit code sink. +- *Returns*: `void` +- *Preconditions*: `context` is non-null. +- *Postconditions*: All self-tests have run; summary printed; results file written if `context.ResultsFile` + is set; `context.ExitCode` is 1 if any test failed. -1. Prints a header showing the OS, .NET runtime, and current timestamp. -2. Executes each self-test method in sequence. -3. Prints a summary of passed and failed tests. -4. If `context.ResultsFile` is set, writes the results in TRX or JUnit XML format - (determined by the file extension `.trx` or `.xml`). -5. Writes any unsupported extension as an error. -6. Sets `context.ExitCode` to `1` if any test fails. +Prints a header showing the BuildMark version, machine name, OS, .NET runtime, and current timestamp. +Executes each self-test method in sequence. Prints a summary of passed and failed tests. If +`context.ResultsFile` is set, writes results in TRX (`.trx`) or JUnit XML (`.xml`) format. Sets +`context.ExitCode` to 1 if any test fails. -##### `RunMarkdownReportGeneration` +**`RunMarkdownReportGeneration`** (private): Creates a `MockRepoConnector` with representative data, calls +`Program.Run` with `--build-version 2.0.0` and `--report`, and verifies the output file contains expected +version and content markers (`# Build Report`, `## Version Information`, `v2.0.0`, `mno345pqr678`). -Creates a `MockRepoConnector` with representative data, generates a -`BuildInformation` record, calls `ToMarkdown`, writes the output to a temporary -file, and verifies the file contains expected version and content markers. +**`RunGitIntegration`** (private): Uses `MockRepoConnector` to verify that version, commit hash, and +previous version information appear in the console log (`Build Version: v2.0.0`, +`Commit Hash: mno345pqr678`, `Previous Version: ver-1.1.0`). -##### `RunGitIntegration` +**`RunIssueTracking`** (private): Uses `MockRepoConnector` to verify that `Changes:` and `Bugs Fixed:` +lines appear in the console log. -Uses `MockRepoConnector` to verify that the tool correctly extracts and displays -version, commit hash, and previous version information from repository data. -Validates the output against expected patterns. +**`RunKnownIssuesReporting`** (private): Uses `MockRepoConnector` with `--include-known-issues` to verify +that `Known Issues: 2` appears in the log and `## Known Issues` appears in the report file. -##### `RunIssueTracking` - -Uses `MockRepoConnector` to verify that issues and pull requests are categorized -and collected correctly into the `Changes` and `Bugs` lists of `BuildInformation`. - -##### `RunKnownIssuesReporting` - -Uses `MockRepoConnector` to verify that known issues are included in the markdown -report when the `--include-known-issues` flag is set. - -##### `RunRulesRouting` - -Creates a `MockRepoConnector` configured with routing rules that direct items labelled -`bug` to a `bugs` section and all other items to a `features` section. Generates a -`BuildInformation` record, calls `ToMarkdown`, writes the output to a temporary file, -and verifies the file contains both `## Features` and `## Bugs` section headings. +**`RunRulesRouting`** (private): Creates a `MockRepoConnector` configured with routing rules (`bug` label +→ `bugs` section; all others → `features` section). Verifies that the report file contains `## Features` +and `## Bugs` section headings. #### Error Handling -If `--results` is provided with an unsupported file extension (i.e., neither `.trx` nor -`.xml`), `Validation.Run` writes an error message via `context.WriteError` and returns -without writing a file. No exception is propagated to the caller. - -#### Interactions - -- `Context` provides output methods, `ResultsFile`, and the exit code sink. -- `MockRepoConnector` supplies deterministic data for all tests in the - `RepoConnectors/Mock` subsystem. -- `BuildInformation` is the test target validated against expected content. -- `TemporaryDirectory` (Utilities subsystem) provides temporary directory management - for test artifact isolation in `RunMarkdownReportGeneration` and `RunRulesRouting`. +If `--results` is provided with an unsupported file extension (not `.trx` or `.xml`), `Validation.Run` +writes an error message via `context.WriteError` and returns without writing a file. No exception is +propagated to the caller. Individual test exceptions are caught within the shared test-execution helper, +marked as failures, and reported via `context.WriteError`. + +#### Dependencies + +- **`Context`** — provides output methods, `ResultsFile` path, and the exit code sink (Cli subsystem) +- **`MockRepoConnector`** — supplies deterministic repository data for all tests + (RepoConnectors/Mock subsystem) +- **`BuildInformation`** — returned by the mock connector; validated against expected content + (BuildNotes subsystem) +- **`Program`** — `Run` is called within each test to exercise the full program execution path +- **`TemporaryDirectory`** — provides temporary directory management for test artifact isolation + (Utilities subsystem) +- **`DemaConsulting.TestResults`** — provides `TestResults`, `TestResult`, `TrxSerializer`, and + `JUnitSerializer` for results file output +- **`RuleConfig`, `RuleMatchConfig`, `SectionConfig`** — used in `RunRulesRouting` to configure routing + rules (Configuration subsystem) + +#### Callers + +- **`Program`** — calls `Validation.Run(context)` when the `--validate` flag is set diff --git a/docs/design/build-mark/utilities.md b/docs/design/build-mark/utilities.md index 81c26eb..944ec28 100644 --- a/docs/design/build-mark/utilities.md +++ b/docs/design/build-mark/utilities.md @@ -2,77 +2,77 @@ ### Overview -The Utilities subsystem provides the shared helper classes used across the -BuildMark system: +The Utilities subsystem provides the shared helper classes used across the BuildMark system. It +encapsulates safe path combination, external process execution, and disposable temporary directory +management so that the rest of the system can delegate these cross-cutting concerns to a single, +well-tested location. -- `PathHelpers` for safe path combination with traversal prevention -- `ProcessRunner` for executing external shell commands -- `TemporaryDirectory` for disposable temporary directory management +Version parsing, comparison, tag handling, and interval logic are implemented in the separate Version +subsystem. -Version parsing, comparison, tag handling, and interval logic are implemented in -the separate `Version` subsystem. +The subsystem contains three units: -### Units - -| Unit | File | Responsibility | -|----------------------|------------------------------------|-----------------------------------| -| `PathHelpers` | `Utilities/PathHelpers.cs` | Safe path combination | -| `ProcessRunner` | `Utilities/ProcessRunner.cs` | External process execution | -| `TemporaryDirectory` | `Utilities/TemporaryDirectory.cs` | Disposable temporary directory | +- **`PathHelpers`** (`Utilities/PathHelpers.cs`) — safe path combination with traversal prevention +- **`ProcessRunner`** (`Utilities/ProcessRunner.cs`) — async wrapper for executing external shell commands +- **`TemporaryDirectory`** (`Utilities/TemporaryDirectory.cs`) — disposable temporary directory management ### Interfaces -`PathHelpers` exposes the following static method: - -| Member | Kind | Description | -|-----------------------------------|--------|-------------------------------------------------| -| `SafePathCombine(base, relative)` | Method | Safely combine a base path with a relative path | +**`PathHelpers.SafePathCombine`**: Safely combines a base path with a relative path, consumed by +`TemporaryDirectory` and any unit that writes to user-supplied paths. -`ProcessRunner` exposes the following static methods: +- *Type*: In-process .NET static method +- *Role*: Provider — exposes safe path combination to other units +- *Contract*: `SafePathCombine(string basePath, string relativePath) → string`; returns the combined path + if the result stays within the base directory. +- *Constraints*: Throws `ArgumentNullException` for null inputs; throws `ArgumentException` when the + combined path escapes the base directory. -| Member | Kind | Description | -|-----------------------------------------|--------|---------------------------------------------------------| -| `RunAsync(command, params arguments)` | Method | Run a process and return stdout; throws on failure | -| `TryRunAsync(command, params arguments)`| Method | Run a process and return stdout, or null on any failure | +**`ProcessRunner.RunAsync`**: Runs an external process and returns its stdout, consumed by +`RepoConnectorBase` and any unit that needs to execute CLI commands. -`TemporaryDirectory` exposes the following members: +- *Type*: In-process .NET static async method +- *Role*: Provider — exposes process execution to connector units +- *Contract*: `RunAsync(string command, params string[] arguments) → Task`; captures stdout and + returns the trimmed output string. +- *Constraints*: Throws `InvalidOperationException` on non-zero exit code or missing command. -| Member | Kind | Description | -|--------------------------------|-------------|--------------------------------------------------------------| -| `TemporaryDirectory()` | Constructor | Creates a uniquely-named directory under `CurrentDirectory` | -| `DirectoryPath` | Property | Absolute path to the temporary directory on disk | -| `GetFilePath(relativePath)` | Method | Resolve a relative path, creating intermediate directories | -| `Dispose()` | Method | Delete the directory and all contents; suppress I/O errors | - -### Design +**`ProcessRunner.TryRunAsync`**: Runs an external process and returns its stdout or null on any failure. -The Utilities subsystem contains three units. `PathHelpers` and `ProcessRunner` are -stateless; `TemporaryDirectory` is instance-based and manages directory lifetime: +- *Type*: In-process .NET static async method +- *Role*: Provider — exposes fault-tolerant process execution +- *Contract*: `TryRunAsync(string command, params string[] arguments) → Task`; returns stdout on + success or `null` on any failure. +- *Constraints*: Never throws; all exceptions are caught and `null` is returned. -- `PathHelpers.SafePathCombine` is a pure function that combines a base path and - a relative path, normalizes both to absolute form, and rejects the result if the - combined path escapes the base directory. It is consumed by any unit that needs - to write output files to user-supplied paths safely. +**`TemporaryDirectory`**: Creates a disposable temporary directory, consumed by `Validation` and any unit +that needs isolated scratch space. -- `ProcessRunner.RunAsync` and `TryRunAsync` are async wrappers over - `System.Diagnostics.Process` that capture stdout and return it as a trimmed - string. On Windows, commands are routed through `cmd /c` to handle `.cmd` - and `.bat` scripts; on other platforms they are invoked directly. All connector - and factory code that needs to run Git, `gh`, or `az` CLI commands delegates - to `ProcessRunner` via `RepoConnectorBase.RunCommandAsync`. +- *Type*: In-process .NET instance class implementing `IDisposable` +- *Role*: Provider — exposes temporary directory lifecycle management +- *Contract*: Constructor creates the directory; `GetFilePath(string relativePath)` returns a validated + path within it; `Dispose()` deletes the directory and all contents. +- *Constraints*: `GetFilePath` throws `ArgumentException` if `relativePath` escapes the directory + boundary. `Dispose` suppresses `IOException` and `UnauthorizedAccessException`. -- `TemporaryDirectory` creates a uniquely-named directory under - `Environment.CurrentDirectory` on construction and deletes it recursively on - disposal. `GetFilePath` delegates path validation to `PathHelpers.SafePathCombine` - before creating any missing intermediate directories, ensuring all paths remain - within the temporary directory. - -### Interactions - -`PathHelpers` and `ProcessRunner` have no dependencies on other BuildMark -subsystems. `TemporaryDirectory` depends on `PathHelpers.SafePathCombine` for -path validation in `GetFilePath`. All three units are consumed by any subsystem -that needs safe path combination, external process execution, or temporary directory -management. +### Design -Version-specific consumers should use the separate `Version` subsystem. +The three units are independent of each other except that `TemporaryDirectory` depends on +`PathHelpers.SafePathCombine` for path validation in `GetFilePath`. + +`PathHelpers.SafePathCombine` is a pure function that normalizes both the base path and the candidate path +to absolute form with `Path.GetFullPath`, then computes `Path.GetRelativePath(absoluteBase, +absoluteCombined)` and rejects the input if the result escapes the base directory. Using `GetRelativePath` +for the containment check handles root paths, platform case-sensitivity, and directory-separator +normalization natively. + +`ProcessRunner.RunAsync` and `TryRunAsync` are async wrappers over `System.Diagnostics.Process`. On +Windows, non-empty commands are routed through `cmd /c` so that `.cmd` and `.bat` scripts (such as the +Azure CLI `az.cmd`) are resolved correctly. All connector and factory code that needs to run Git, `gh`, or +`az` CLI commands delegates to `ProcessRunner` via `RepoConnectorBase.RunCommandAsync`. + +`TemporaryDirectory` creates a uniquely-named directory under `Environment.CurrentDirectory` on +construction. Using `Environment.CurrentDirectory` avoids the macOS `/tmp` → `/private/tmp` symlink +mismatch that can cause path-containment checks to fail. `GetFilePath` delegates path validation to +`PathHelpers.SafePathCombine` before creating any missing intermediate directories, ensuring all paths +remain within the temporary directory. diff --git a/docs/design/build-mark/utilities/path-helpers.md b/docs/design/build-mark/utilities/path-helpers.md index c769eae..ea66510 100644 --- a/docs/design/build-mark/utilities/path-helpers.md +++ b/docs/design/build-mark/utilities/path-helpers.md @@ -1,12 +1,11 @@ -### PathHelpers Design +### PathHelpers #### Purpose -`PathHelpers` is a static utility class that provides a safe path-combination method. It -protects callers against path-traversal attacks by verifying the resolved combined path stays -within the base directory. Note that `Path.GetFullPath` normalizes `.`/`..` segments but does -not resolve symlinks or reparse points, so this check guards against string-level traversal -only. +`PathHelpers` is a static utility class that provides a safe path-combination method. It protects callers +against path-traversal attacks by verifying the resolved combined path stays within the base directory. +Note that `Path.GetFullPath` normalizes `.`/`..` segments but does not resolve symlinks or reparse points, +so this check guards against string-level traversal only. #### Data Model @@ -14,47 +13,36 @@ N/A — `PathHelpers` is a static utility class with no instance state. #### Key Methods -##### SafePathCombine Method - -```csharp -internal static string SafePathCombine(string basePath, string relativePath) -``` - -Combines `basePath` and `relativePath` safely, ensuring the resulting path remains within -the base directory. - -**Validation steps:** - -1. Reject null inputs via `ArgumentNullException.ThrowIfNull`. -2. Combine the paths with `Path.Combine` to produce the candidate path (preserving the - caller's relative/absolute style). -3. Resolve both `basePath` and the candidate to absolute form with `Path.GetFullPath`. -4. Compute `Path.GetRelativePath(absoluteBase, absoluteCombined)` and reject the input if - the result is exactly `".."`, starts with `".."` followed by `Path.DirectorySeparatorChar` - or `Path.AltDirectorySeparatorChar`, or is itself rooted (absolute), which would indicate - the combined path escapes the base directory. - -**Implementation rationale:** - -- **`Path.GetRelativePath` for containment check**: Using `GetRelativePath` to verify - containment handles root paths (e.g. `/`, `C:\`), platform case-sensitivity, and - directory-separator normalization natively. The containment test should treat `..` as an - escaping segment only when it is the entire relative result or is followed by a directory - separator, avoiding false positives for valid in-base names such as `..data`. -- **Post-combine canonical-path check**: Resolving paths after combining handles all traversal - patterns - `../`, embedded `/../`, absolute-path overrides, and platform edge cases - - without fragile pre-combine string inspection of `relativePath`. -- **ArgumentException on invalid input**: Callers receive a specific `ArgumentException` - identifying `relativePath` as the problematic parameter, making debugging straightforward. -- **No logging or error accumulation**: `SafePathCombine` is a pure utility method that throws - on invalid input; it does not interact with the `Context` or any output mechanism. +**`SafePathCombine`**: Combines `basePath` and `relativePath` safely, ensuring the resulting path remains +within the base directory. + +- *Parameters*: `string basePath` — the base directory to resolve within; `string relativePath` — the + path component to combine. +- *Returns*: `string` — the combined path if it remains within the base directory. +- *Preconditions*: Both arguments must be non-null; `relativePath` must not navigate above the base + directory. +- *Postconditions*: The returned path is contained within `basePath`. + +Combines the paths with `Path.Combine`, resolves both `basePath` and the candidate to absolute form with +`Path.GetFullPath`, then computes `Path.GetRelativePath(absoluteBase, absoluteCombined)` and rejects the +input if the result is exactly `".."`, starts with `".."` followed by a directory-separator character, or +is itself rooted (absolute). Using `GetRelativePath` for the containment check handles root paths, +platform case-sensitivity, and directory-separator normalization natively. The containment test treats +`..` as an escaping segment only when it is the entire relative result or is followed by a directory +separator, avoiding false positives for valid in-base names such as `..data`. #### Error Handling -`SafePathCombine` throws `ArgumentNullException` when either argument is `null` and -`ArgumentException` (identifying `relativePath` as the problematic parameter) when the -resolved combined path escapes the base directory. No other exceptions are thrown. +`SafePathCombine` throws `ArgumentNullException` when either argument is `null` and `ArgumentException` +(identifying `relativePath` as the problematic parameter) when the resolved combined path escapes the base +directory. `Path.GetFullPath` may additionally propagate `NotSupportedException` or `PathTooLongException` +for malformed paths. + +#### Dependencies + +N/A — `PathHelpers` has no dependencies on other BuildMark units or subsystems. -#### Interactions +#### Callers -`PathHelpers` has no dependencies on other BuildMark units or subsystems. +- **`TemporaryDirectory`** — calls `SafePathCombine` in the constructor and in `GetFilePath` to validate + all paths within the temporary directory boundary diff --git a/docs/design/build-mark/utilities/process-runner.md b/docs/design/build-mark/utilities/process-runner.md index 0cc42c1..6b2edcd 100644 --- a/docs/design/build-mark/utilities/process-runner.md +++ b/docs/design/build-mark/utilities/process-runner.md @@ -2,10 +2,10 @@ #### Purpose -`ProcessRunner` is a static helper class in the Utilities subsystem that executes -external shell commands and captures their standard output. It provides two public -methods: `RunAsync`, which throws on failure, and `TryRunAsync`, which returns -`null` on failure. +`ProcessRunner` is a static helper class in the Utilities subsystem that executes external shell commands +and captures their standard output. It provides two public methods: `RunAsync`, which throws on failure, +and `TryRunAsync`, which returns `null` on failure. A private helper `CreateStartInfo` encapsulates +platform-specific process configuration. #### Data Model @@ -13,51 +13,53 @@ N/A — `ProcessRunner` is a static utility class with no instance state. #### Key Methods -##### `RunAsync(command, params arguments) → string` +**`RunAsync`**: Starts the specified process, captures stdout and stderr asynchronously, waits for exit, +and returns the trimmed stdout string. -Starts the specified process, captures stdout and stderr asynchronously, waits for -exit, and returns the trimmed stdout string. Throws `InvalidOperationException` if -the process exits with a non-zero exit code or if the command is not found (wraps -`Win32Exception` into `InvalidOperationException` with a descriptive message). +- *Parameters*: `string command` — the executable or script name; `params string[] arguments` — arguments + added individually to `ProcessStartInfo.ArgumentList` for correct quoting. +- *Returns*: `Task` — the trimmed stdout string on success. +- *Preconditions*: `command` is a valid executable name or path. +- *Postconditions*: Returns trimmed stdout if the process exits with code zero. -The `arguments` parameter is a `params string[]` array. Each argument is added to -the `ProcessStartInfo.ArgumentList` collection so that the Process class handles -argument quoting correctly, rather than concatenating into a single string. +Throws `InvalidOperationException` if the process exits with a non-zero exit code or if the command is +not found (wraps `Win32Exception` into `InvalidOperationException` with a descriptive message). -##### `TryRunAsync(command, params arguments) → string?` +**`TryRunAsync`**: Executes the process and returns the stdout string if the exit code is zero, or `null` +if the process fails or throws any exception. -Executes the process and returns the stdout string if the exit code is zero, or -`null` if the process fails or throws any exception. This method never propagates -exceptions to its callers. +- *Parameters*: `string command` — the executable or script name; `params string[] arguments` — arguments + added individually to `ProcessStartInfo.ArgumentList`. +- *Returns*: `Task` — trimmed stdout on success, or `null` on any failure. +- *Preconditions*: None — any command string is accepted. +- *Postconditions*: Never throws; all exceptions are caught internally. -The `arguments` parameter is a `params string[]` array, matching the signature of -`RunAsync`. +**`CreateStartInfo`** (private): Creates a `ProcessStartInfo` for the given command. -##### `CreateStartInfo(command, arguments) → ProcessStartInfo` +- *Parameters*: `string command` — the executable or script name; `string[] arguments` — the arguments + array. +- *Returns*: `ProcessStartInfo` — configured with redirected stdout and stderr, no shell execution. -Private helper method that creates a `ProcessStartInfo` for the given command. +On Windows, non-empty commands are routed through `cmd /c` so that `.cmd` and `.bat` scripts (such as the +Azure CLI `az.cmd`) are resolved correctly by the Windows command interpreter. The command and all +arguments are added to `ProcessStartInfo.ArgumentList` for correct quoting. On non-Windows platforms, the +command is invoked directly without a shell wrapper. Empty or whitespace-only commands are not routed +through `cmd /c`, preserving the exception behavior for invalid commands. -On Windows, non-empty commands are routed through `cmd /c` so that `.cmd` and -`.bat` scripts (such as the Azure CLI `az.cmd`) are resolved correctly by the -Windows command interpreter. The command and all arguments are added to -`ProcessStartInfo.ArgumentList` for correct quoting. On non-Windows platforms, -the command is invoked directly without a shell wrapper. +#### Error Handling -Empty or whitespace-only commands are not routed through `cmd /c`, preserving the -exception behavior for invalid commands. +`RunAsync` throws `InvalidOperationException` when the process exits with a non-zero exit code or when +the command is not found (wrapping `Win32Exception` with a descriptive message). `TryRunAsync` catches all +exceptions and returns `null` on any failure, never propagating exceptions to callers. -#### Error Handling +#### Dependencies -`RunAsync` throws `InvalidOperationException` when the process exits with a non-zero exit -code or when the command is not found (wrapping `Win32Exception` with a descriptive message). -`TryRunAsync` catches all exceptions and returns `null` on any failure, never propagating -exceptions to callers. +N/A — `ProcessRunner` depends only on the .NET BCL (`System.Diagnostics.Process`, +`System.Runtime.InteropServices.RuntimeInformation`, `System.ComponentModel.Win32Exception`). -#### Interactions +#### Callers -| Unit / Subsystem | Role | -|-------------------------------|------------------------------------------------------------------------| -| `RepoConnectorBase` | Delegates `RunCommandAsync` to `ProcessRunner.RunAsync` | -| `RepoConnectorFactory` | Uses `TryRunAsync` to inspect the git remote URL | -| `GitHubRepoConnector` | Calls `RunCommandAsync` (via base) for git and gh CLI commands | -| `AzureDevOpsRepoConnector` | Calls `RunCommandAsync` (via base) for git and az CLI commands | +- **`RepoConnectorBase`** — delegates `RunCommandAsync` to `ProcessRunner.RunAsync` +- **`RepoConnectorFactory`** — uses `TryRunAsync` to inspect the git remote URL +- **`GitHubRepoConnector`** — calls `RunCommandAsync` (via base) for git and gh CLI commands +- **`AzureDevOpsRepoConnector`** — calls `RunCommandAsync` (via base) for git and az CLI commands diff --git a/docs/design/build-mark/utilities/temporary-directory.md b/docs/design/build-mark/utilities/temporary-directory.md index 3509a99..275aba3 100644 --- a/docs/design/build-mark/utilities/temporary-directory.md +++ b/docs/design/build-mark/utilities/temporary-directory.md @@ -1,75 +1,71 @@ -### TemporaryDirectory Design +### TemporaryDirectory #### Purpose -`TemporaryDirectory` is an `internal sealed` class implementing `IDisposable` that -creates a uniquely-named directory under `Environment.CurrentDirectory` on construction -and deletes it recursively on disposal. Using `Environment.CurrentDirectory` as the base -avoids the macOS `/tmp` → `/private/tmp` symlink mismatch that can cause path-containment -checks to fail when the real path and the requested path differ. +`TemporaryDirectory` is an `internal sealed` class implementing `IDisposable` that creates a +uniquely-named directory under `Environment.CurrentDirectory` on construction and deletes it recursively +on disposal. Using `Environment.CurrentDirectory` as the base avoids the macOS `/tmp` → `/private/tmp` +symlink mismatch that can cause path-containment checks to fail when the real path and the requested path +differ. #### Data Model -`TemporaryDirectory` is instance-based and owns a single directory for its lifetime: - -| Property | Type | Description | -| --------------- | -------- | ------------------------------------------------------- | -| `DirectoryPath` | `string` | Absolute path to the temporary directory on disk | +**`DirectoryPath`**: `string` — Absolute path to the temporary directory on disk. Set in the constructor +and immutable for the lifetime of the instance. #### Key Methods -##### Constructor - -```csharp -internal TemporaryDirectory() -``` - -Generates a unique name by combining a fixed prefix with a GUID string, creates the -directory under `Environment.CurrentDirectory`, and stores the resulting path in -`DirectoryPath`. Throws `InvalidOperationException` wrapping the original exception if -directory creation fails due to an I/O error. +**`TemporaryDirectory`** (constructor): Generates a unique name by combining a fixed prefix with a GUID +string, creates the directory under `Environment.CurrentDirectory`, and stores the resulting path in +`DirectoryPath`. -##### GetFilePath Method +- *Parameters*: None. +- *Returns*: A new `TemporaryDirectory` instance. +- *Preconditions*: `Environment.CurrentDirectory` must be accessible. +- *Postconditions*: `DirectoryPath` is set to the path of the newly created directory. -```csharp -internal string GetFilePath(string relativePath) -``` +Uses `PathHelpers.SafePathCombine` to build the path, then calls `Directory.CreateDirectory`. Throws +`InvalidOperationException` wrapping the original exception if directory creation fails due to an +`IOException`, `UnauthorizedAccessException`, or `ArgumentException`. -Returns the absolute path to a file inside the temporary directory identified by +**`GetFilePath`**: Returns the absolute path to a file inside the temporary directory identified by `relativePath`. -**Steps:** +- *Parameters*: `string relativePath` — a relative path (file name or subdirectory/file) within the + temporary directory; must not be `null`. +- *Returns*: `string` — the combined absolute path within the temporary directory. +- *Preconditions*: `relativePath` is non-null and does not navigate above the temporary directory. +- *Postconditions*: All intermediate directories between `DirectoryPath` and the resolved path exist. -1. Delegates to `PathHelpers.SafePathCombine(DirectoryPath, relativePath)` to produce a - validated absolute path. `SafePathCombine` rejects traversal sequences (`..`) and - absolute-path overrides, throwing `ArgumentException` on invalid input. -2. Creates all intermediate directories between `DirectoryPath` and the resolved file path - using `Directory.CreateDirectory` so that callers can write the file immediately. -3. Returns the validated path string. +Delegates to `PathHelpers.SafePathCombine(DirectoryPath, relativePath)` to produce a validated absolute +path, then calls `Directory.CreateDirectory` on the parent directory so that callers can write the file +immediately. -##### Dispose Method +**`Dispose`**: Deletes the temporary directory and all its contents. -```csharp -public void Dispose() -``` +- *Parameters*: None. +- *Returns*: `void` +- *Preconditions*: None — may be called even if the directory has already been deleted. +- *Postconditions*: The directory is deleted if it existed; cleanup errors are suppressed. -Deletes the temporary directory and all its contents by calling -`Directory.Delete(DirectoryPath, recursive: true)`. Both `IOException` and -`UnauthorizedAccessException` are caught and silently discarded so that callers in -`using` statements are not disrupted when the directory has already been removed or -when a file lock prevents deletion. +Calls `Directory.Delete(DirectoryPath, recursive: true)`. Both `IOException` and +`UnauthorizedAccessException` are caught and silently discarded so that callers in `using` statements are +not disrupted when the directory has already been removed or when a file lock prevents deletion. #### Error Handling -| Situation | Behavior | -| ------------------------------------------ | -------------------------------------------------- | -| Directory creation fails (I/O error) | Throws `InvalidOperationException` (wraps original)| -| Traversal or absolute path in GetFilePath | Throws `ArgumentException` (from `SafePathCombine`)| -| Directory already deleted before Dispose | Silently suppressed | -| File lock prevents deletion in Dispose | Silently suppressed | +Constructor throws `InvalidOperationException` (wrapping the original exception) if directory creation +fails due to an `IOException`, `UnauthorizedAccessException`, or `ArgumentException`. `GetFilePath` +propagates `ArgumentException` from `PathHelpers.SafePathCombine` when `relativePath` would escape the +temporary directory boundary. `Dispose` silently suppresses `IOException`, `UnauthorizedAccessException`, +and `DirectoryNotFoundException`; cleanup failures are non-fatal. + +#### Dependencies + +- **`PathHelpers`** — `SafePathCombine` is called by the constructor and `GetFilePath` to validate and + resolve all paths within the temporary directory boundary (Utilities subsystem) -#### Interactions +#### Callers -- `PathHelpers.SafePathCombine` (Utilities subsystem) is called by `GetFilePath` to - validate and resolve the caller-supplied relative path before creating intermediate - directories. +- **`Validation`** — creates a `TemporaryDirectory` instance per test run to isolate log and report files + (SelfTest subsystem) diff --git a/docs/design/build-mark/version.md b/docs/design/build-mark/version.md index 31967f4..02874e3 100644 --- a/docs/design/build-mark/version.md +++ b/docs/design/build-mark/version.md @@ -1,135 +1,82 @@ -## Version Subsystem Design +## Version Subsystem ### Overview -The Version subsystem provides comprehensive semantic version processing capabilities for BuildMark. -It encapsulates all version-related functionality including parsing, comparison, validation, and version -range operations, ensuring consistent semantic versioning behavior across all BuildMark components. +The Version subsystem provides semantic version processing for BuildMark. It handles all +version-related operations: parsing raw repository tag strings into structured semantic +versions, comparing versions numerically, evaluating version range expressions, and +associating parsed versions with their Git commit hashes for build boundary determination. -### Architecture +The subsystem boundary covers version representation and operations only — it does not +interact with Git or remote APIs directly. All raw tag strings flow in from repository +connector implementations. -The Version subsystem is composed of six units: +The subsystem contains six units: -- `VersionComparable` (Unit) - core semantic version comparison and ordering engine -- `VersionSemantic` (Unit) - semantic version parsing and validation -- `VersionTag` (Unit) - repository version tag processing and extraction -- `VersionInterval` (Unit) - version range representation and operations -- `VersionIntervalSet` (Unit) - ordered collection of version intervals for range queries -- `VersionCommitTag` (Unit) - version-to-commit association for build information - -### Version Type Hierarchy - -```text -VersionTag (raw repository tag) - ↓ (extraction) -VersionSemantic (parsed semantic version) - ↓ (normalization) -VersionComparable (optimized comparison) - ↓ (range operations) -VersionInterval / VersionIntervalSet (version ranges) - ↓ (build association) -VersionCommitTag (version + commit hash) -``` - -### Design Principles - -#### Semantic Versioning Compliance - -All version processing substantially adheres to Semantic Versioning 2.0.0 (). -Pre-release identifiers are compared case-insensitively rather than using the ASCII -case-sensitive sort defined by SemVer 2.0.0. - -#### Performance Optimization - -Version comparison operations are optimized for high-frequency usage in repository processing -through construction-time parsing and cached segment arrays. - -#### Type Safety - -Each version type serves a specific purpose with clear boundaries: - -- **VersionTag**: Raw string from repository -- **VersionSemantic**: Validated SemVer structure -- **VersionComparable**: Optimized for comparison operations -- **VersionInterval**: Range queries and filtering -- **VersionCommitTag**: Build metadata association +- **VersionComparable** — core integer-based semantic version comparison engine +- **VersionSemantic** — full semantic version with optional build metadata +- **VersionTag** — repository tag parsing and normalization +- **VersionInterval** — single version interval model and parser +- **VersionIntervalSet** — ordered set of version intervals for range queries +- **VersionCommitTag** — version tag paired with a Git commit hash ### Interfaces -The Version subsystem exposes all six unit types as public records or classes. -The primary interface consumed by other subsystems is: - -| Member | Kind | Description | -| --- | --- | --- | -| `VersionTag.Create(tag)` | Static method | Parse a repository tag; throws on invalid input | -| `VersionTag.TryCreate(tag)` | Static method | Parse a repository tag; returns `null` on invalid input | -| `VersionIntervalSet.Parse(text)` | Static method | Parse a comma-separated set of version intervals | -| `VersionIntervalSet.Contains(version)` | Method | Test whether a version falls in any interval in the set | -| `VersionComparable.Create(version)` | Static method | Parse semantic version for comparison; throws on invalid input | -| `VersionComparable.TryCreate(version)` | Static method | Parse a semantic version; returns `null` on invalid input | - -### External Interfaces - -| Interface | Direction | Protocol / Format | -|------------------|------------|-------------------------------------------| -| Repository Tags | Input | String tags from GitHub/Git repositories | -| Version Parsing | Processing | SemVer 2.0.0 compliant parsing | -| Version Compare | Processing | IComparable standard interface | -| Build Info | Output | VersionCommitTag records for build notes | - -### Integration Points - -#### Repository Connectors - -Version subsystem processes raw repository tags from GitHub and other sources, -extracting semantic versions for build boundary determination. - -#### Build Notes - -Provides VersionCommitTag associations that link semantic versions to specific commit hashes for build information generation. - -#### Configuration - -Supports version range specifications in configuration files through VersionInterval processing. - -### Error Handling - -Version processing provides two parsing patterns: - -- `TryCreate()` factory methods return null for invalid input, enabling safe parsing without exceptions -- `Create()` factory methods throw `ArgumentException` for invalid input, enabling fail-fast behavior -- Malformed version ranges are rejected during parsing -- Version comparison operations are guaranteed to be consistent and transitive +**Version Processing API**: Public factory methods and record types exposed to the rest of +BuildMark for tag parsing and version range evaluation. + +- *Type*: In-process .NET public API. +- *Role*: Provider (other subsystems consume this). +- *Contract*: `VersionTag.Create(tag)` and `VersionTag.TryCreate(tag)` parse a repository + tag string; `VersionComparable.Create(version)` and `VersionComparable.TryCreate(version)` + parse a bare semantic version string; `VersionIntervalSet.Parse(text)` parses a + comma-separated bracket-bound range expression; `VersionIntervalSet.Contains(version)` tests + whether a version falls within any interval in the set. +- *Constraints*: `Create` factory methods throw `ArgumentException` on invalid input; all + `TryCreate` and `Parse` methods return `null` or an empty set rather than throwing. + +**Repository Tag Consumer**: Accepts raw tag strings from repo connector implementations. + +- *Type*: In-process .NET call. +- *Role*: Consumer (this subsystem consumes strings provided by RepoConnectors). +- *Contract*: String tag values forwarded to `VersionTag.TryCreate` or `VersionTag.Create`. + The parser accepts tags with arbitrary alphabetic or path-separator prefixes preceding a + `major.minor.patch` triple. +- *Constraints*: Null or whitespace inputs return `null` from `TryCreate`; tags with no + recognizable `major.minor.patch` triple also return `null`. + +**Version Range Consumer**: Accepts interval expression strings from `ItemControlsParser`. + +- *Type*: In-process .NET call. +- *Role*: Consumer (this subsystem consumes range strings provided by ItemControlsParser). +- *Contract*: Comma-separated bracket-bound interval strings such as `(,1.0.1],[1.1.0,1.2.0)` + are parsed via `VersionIntervalSet.Parse`. +- *Constraints*: Malformed interval tokens are silently discarded; the returned set contains + only the successfully parsed intervals. ### Design -The units in the Version subsystem form a directed processing hierarchy. Raw -repository tag strings flow in from connectors and pass through `VersionTag`, -which strips tag prefixes and extracts a `VersionSemantic`. `VersionSemantic` -wraps a `VersionComparable` that exposes numeric major/minor/patch fields and -pre-release segments for sorting. `VersionCommitTag` pairs a `VersionTag` with -its Git commit hash so that `BuildInformation` can record the exact commit at -each version boundary. - -Version range expressions flow in from `ItemControlsParser` as text and are -parsed by `VersionIntervalSet.Parse`, which delegates to `VersionInterval.Parse` -for each token. `VersionInterval.Contains` tests a candidate version using -`VersionComparable.TryCreate` for the bound comparisons. - -No unit in the subsystem holds mutable state; all types are records or -effectively immutable classes instantiated via `Create`/`TryCreate` factory -methods. - -### Performance Characteristics - -#### Version Comparison - -- **Construction**: O(n) where n is pre-release identifier count -- **Comparison**: O(min(a,b)) where a,b are pre-release segment counts -- **Memory**: Constant per-version overhead for parsed segments - -#### Version Range Operations - -- **Interval Creation**: O(1) for single ranges -- **Set Operations**: O(n) where n is interval count -- **Contains Checks**: O(n) because the current implementation performs a linear scan +Raw repository tags enter the subsystem as strings from repo connector implementations. +`VersionTag.TryCreate` applies a source-generated regex pattern that accepts an optional +alphabetic or path prefix, extracts the `major.minor.patch` triple, and captures optional +pre-release and build-metadata segments. The numbers and pre-release string are packaged +into a `VersionComparable` record; the `VersionComparable` and optional metadata string are +packaged into a `VersionSemantic` record; and the original tag string and the `VersionSemantic` +are packaged into the returned `VersionTag` record. + +`VersionComparable` splits the pre-release string at construction time into a cached +`PreReleaseSegment[]` array, avoiding repeated string parsing on every comparison. `CompareTo` +compares major/minor/patch numerically, then falls back to the pre-release segment array for +pre-release ordering per SemVer 2.0.0 (with case-insensitive text segment comparison by +design). Comparison operator overloads (`<`, `<=`, `>`, `>=`) delegate to `CompareTo`. + +Version range expressions enter via `VersionIntervalSet.Parse`, which walks the expression +character by character, tracking bracket depth to distinguish commas that separate intervals +from commas inside a single interval's bounds. Each extracted token is forwarded to +`VersionInterval.Parse`, which reads the opening and closing bracket characters to determine +inclusivity and splits the interior text on the first comma to obtain lower and upper bound +strings. `VersionInterval.Contains` calls `VersionComparable.TryCreate` on each bound string +at evaluation time and applies the inclusivity flags. + +`VersionCommitTag` is a plain record pairing a `VersionTag` with a Git commit hash. It carries +no logic; repo connectors construct it and `BuildInformation` consumes it. diff --git a/docs/design/build-mark/version/version-commit-tag.md b/docs/design/build-mark/version/version-commit-tag.md index 7c4f32b..3d5a29c 100644 --- a/docs/design/build-mark/version/version-commit-tag.md +++ b/docs/design/build-mark/version/version-commit-tag.md @@ -2,35 +2,32 @@ #### Purpose -`VersionCommitTag` is a record in the Version subsystem that pairs a parsed -`VersionTag` value with the Git commit hash at which that tag was created. It is -used to identify the baseline and current version boundaries when assembling a +`VersionCommitTag` pairs a parsed `VersionTag` with the Git commit hash at which that tag +was created. It identifies the baseline and current version boundaries when assembling a `BuildInformation` record. #### Data Model -```csharp -public record VersionCommitTag( - VersionTag VersionTag, - string CommitHash); -``` +**VersionTag**: `VersionTag` — Parsed version information for this tag, including the +original repository tag string and the extracted semantic version. -| Property | Type | Description | -|--------------|--------------|------------------------------------------------| -| `VersionTag` | `VersionTag` | Parsed version information for this tag | -| `CommitHash` | `string` | Git commit hash at the point this tag was made | +**CommitHash**: `string` — Git commit hash at the point this tag was created. #### Key Methods -N/A — `VersionCommitTag` is an immutable data record with no methods beyond those auto-generated by C#. +N/A — `VersionCommitTag` is an immutable data record with no methods beyond those +auto-generated by C#. #### Error Handling -N/A — `VersionCommitTag` is an immutable data record with no methods that detect or propagate errors. +N/A — `VersionCommitTag` is an immutable data record; construction passes `VersionTag` and +`string` directly without validation. -#### Interactions +#### Dependencies -- `VersionTag` supplies the parsed tag and semantic version details. -- `BuildInformation` uses `VersionCommitTag` for `BaselineVersionTag` and - `CurrentVersionTag`. -- `RepoConnectors` construct `VersionCommitTag` records from repository data. +- **VersionTag** — supplies the parsed tag and semantic version carried by this record. + +#### Callers + +- **BuildInformation** +- **RepoConnectorBase** (and its subclasses in the GitHub, AzureDevOps, and Mock subsystems) diff --git a/docs/design/build-mark/version/version-comparable.md b/docs/design/build-mark/version/version-comparable.md index f952496..221dfbb 100644 --- a/docs/design/build-mark/version/version-comparable.md +++ b/docs/design/build-mark/version/version-comparable.md @@ -1,121 +1,83 @@ -### Version Comparable +### VersionComparable #### Purpose -The `VersionComparable` class provides core semantic version comparison functionality. -It handles versions in the format `major.minor.patch[-pre-release]` and implements -proper semantic version ordering rules with optimized performance for pre-release comparison. +`VersionComparable` represents the comparable portion of a semantic version — +`major.minor.patch[-pre-release]`. It parses version strings using a source-generated regex, +caches pre-release segments at construction time for efficient repeated comparisons, and +implements `IComparable` with numeric major/minor/patch ordering and +SemVer-compliant pre-release precedence rules. Non-numeric pre-release segments are compared +case-insensitively, which differs from the ASCII case-sensitive sort defined by SemVer 2.0.0. #### Data Model -| Property | Type | Description | -| -------- | ---- | ----------- | -| Major | int | Major version number | -| Minor | int | Minor version number | -| Patch | int | Patch version number | -| Numbers | string | Core version numbers as string (major.minor.patch) | -| PreRelease | string? | Pre-release identifier (null for release versions) | -| IsPreRelease | bool | Whether this is a pre-release version | -| CompareVersion | string | Normalized comparison string (major.minor.patch[-pre-release]) | +**Major**: `int` — Major version number parsed from the version string. -#### Key Methods - -- `Create(string version)` — Parses a `major.minor.patch[-pre-release]` string; - throws `ArgumentException` on invalid input -- `TryCreate(string version)` — Parses a version string; returns `null` on invalid - input instead of throwing -- `CompareTo(VersionComparable other)` — Implements `IComparable` - using numeric major/minor/patch comparison followed by SemVer pre-release ordering - -`Create` and `TryCreate` use a source-generated `Regex` pattern to validate and parse the -input. Pre-release segments are split at construction time by `ParsePreReleaseSegments` into a -cached `PreReleaseSegment[]` array so that repeated comparisons (`CompareTo`) avoid -re-parsing the pre-release string. Operator overloads (`<`, `<=`, `>`, `>=`) delegate to -`CompareTo`. - -#### Performance Optimization - -##### Pre-Release Parsing - -The class implements optimized pre-release comparison through: - -- **PreReleaseSegment Structure**: Internal record struct representing parsed pre-release segments -- **Construction-Time Parsing**: Pre-release strings are parsed once during object construction -- **Efficient Comparison**: Comparisons use pre-parsed segments instead of repeated string operations - -##### Implementation Details +**Minor**: `int` — Minor version number parsed from the version string. -| Component | Description | -| --------- | ----------- | -| `PreReleaseSegment` | Internal struct storing either numeric or text segment values | -| `ParsePreReleaseSegments` | Static method parsing pre-release strings into segment arrays | -| `ComparePreReleaseSegments` | Optimized comparison using pre-parsed segment arrays | +**Patch**: `int` — Patch version number parsed from the version string. -This optimization eliminates repeated string splitting and parsing during comparison operations, -providing significant performance benefits for sorting and version range operations. +**PreRelease**: `string?` — Pre-release identifier (e.g., `rc.4`, `alpha.1`), or `null` +for release versions. -#### Interface +**Numbers**: `string` — Derived property; returns `major.minor.patch` as a formatted string. -The class implements `IComparable` providing analytical comparison: +**IsPreRelease**: `bool` — Derived property; `true` when `PreRelease` is non-null and +non-empty. -- Numeric comparison of version numbers (1.2.3 < 1.11.2) -- Release versions > pre-release versions for same numbers -- SemVer-compliant pre-release ordering with numeric precedence +**CompareVersion**: `string` — Derived property; returns `major.minor.patch` for release +versions and `major.minor.patch-pre-release` for pre-release versions. -##### Pre-Release Comparison Rules - -Pre-release versions follow SemVer specification: - -1. Numeric identifiers are compared numerically (5 < 10) -2. Non-numeric identifiers are compared lexicographically (case-insensitive by design; - note the SemVer specification uses case-sensitive ASCII sort order) -3. Numeric identifiers have lower precedence than non-numeric -4. Shorter pre-release lists have lower precedence than longer ones - -#### Comparison Operators - -Standard comparison operators are overloaded: - -- `<`, `<=`, `>`, `>=` delegate to `CompareTo` -- Natural ordering for use in collections and sorting +#### Key Methods -#### Factory Methods +**Create**: Parses a `major.minor.patch[-pre-release]` string and returns a +`VersionComparable`; throws `ArgumentException` when the input does not match the expected +format. -- `Create(string version)` - Creates instance, throws on invalid input -- `TryCreate(string version)` - Returns null for invalid input +- *Parameters*: `string versionString` — the version string to parse. +- *Returns*: `VersionComparable` — the parsed version. +- *Preconditions*: Input is a non-null, non-whitespace string. +- *Postconditions*: Returns a valid `VersionComparable`; throws `ArgumentException` on + invalid input. -#### Example +**TryCreate**: Parses a `major.minor.patch[-pre-release]` string; returns `null` on invalid +input instead of throwing. -```csharp -var v1 = VersionComparable.Create("1.2.3"); -var v2 = VersionComparable.Create("1.2.3-beta"); -var v3 = VersionComparable.Create("1.11.0"); -var v4 = VersionComparable.Create("1.2.3-alpha.5"); -var v5 = VersionComparable.Create("1.2.3-alpha.10"); +- *Parameters*: `string versionString` — the version string to parse. +- *Returns*: `VersionComparable?` — the parsed version, or `null` if the input is invalid. +- *Preconditions*: None — null and whitespace inputs return `null`. +- *Postconditions*: Returns a valid `VersionComparable` or `null`; never throws. -// v4 < v5 < v2 < v1 < v3 (numeric pre-release comparison, pre-release < release) -``` +Both methods apply the source-generated regex pattern +`^(?\d+\.\d+\.\d+)(?:-(?[a-zA-Z0-9.-]+))?$` to validate and extract +version components. -#### Regex Pattern +**CompareTo**: Implements `IComparable`; compares two versions using +numeric major/minor/patch fields, then SemVer pre-release ordering using the pre-parsed +`PreReleaseSegment[]` cache. -The class uses a generated regex pattern for parsing: +- *Parameters*: `VersionComparable? other` — the version to compare against. +- *Returns*: `int` — negative if this instance is less, zero if equal, positive if greater. +- *Preconditions*: None — a `null` argument is treated as less than any non-null value. +- *Postconditions*: Returns a consistent, transitive ordering; never throws. -```regex -^(?\d+\.\d+\.\d+)(?:-(?[a-zA-Z0-9.-]+))?$ -``` +Comparison operator overloads (`<`, `<=`, `>`, `>=`) delegate to `CompareTo`. -This pattern matches: +#### Error Handling -- Required: major.minor.patch numbers -- Optional: hyphen followed by pre-release identifier +`Create` throws `ArgumentException` when the input string does not match the +`major.minor.patch[-pre-release]` format. `TryCreate` returns `null` instead of throwing. +Once a valid instance is constructed, `CompareTo` and the operator overloads never fail. -#### Error Handling +#### Dependencies -`Create(string version)` throws `ArgumentException` when the input string does not match -the expected `major.minor.patch[-pre-release]` format. `TryCreate(string version)` returns -`null` instead of throwing, allowing callers to test validity without exception handling. -Comparison operations on a valid instance never fail. +N/A — `VersionComparable` has no dependencies on other BuildMark units; it relies only on +.NET BCL types (`System.Text.RegularExpressions`, `System`). -#### Interactions +#### Callers -Consumed by `VersionSemantic`, `VersionInterval`, and `VersionIntervalSet` for range evaluation. +- **VersionSemantic** — wraps a `VersionComparable` as its `Comparable` property. +- **VersionTag** — accesses `Comparable` via `Semantic.Comparable` for equality and ordering. +- **VersionInterval** — calls `VersionComparable.TryCreate` on bound strings during `Contains` + evaluation. +- **VersionIntervalSet** — accepts a `VersionComparable` overload in `Contains`. diff --git a/docs/design/build-mark/version/version-interval-set.md b/docs/design/build-mark/version/version-interval-set.md index 7263719..84dbcdf 100644 --- a/docs/design/build-mark/version/version-interval-set.md +++ b/docs/design/build-mark/version/version-interval-set.md @@ -3,49 +3,74 @@ #### Purpose `VersionIntervalSet` is an ordered, immutable collection of one or more `VersionInterval` -instances. It is parsed from the `affected-versions` field of a `buildmark` block and tests -whether a version falls inside any contained interval. The full parsing algorithm and detailed -method descriptions are documented together with `VersionInterval` in -_VersionInterval and VersionIntervalSet Design_. +instances parsed from a comma-separated bracket-bound range expression such as the +`affected-versions` field of a `buildmark` block. It tests whether a candidate version falls +within any contained interval. #### Data Model -```csharp -public record VersionIntervalSet( - IReadOnlyList Intervals); -``` - -| Property | Type | Description | -|-------------|----------------------------------|----------------------------------| -| `Intervals` | `IReadOnlyList` | Ordered list of parsed intervals | +**Intervals**: `IReadOnlyList` — Ordered list of parsed version intervals. +Only intervals that successfully parsed from the input expression are included; malformed +tokens are discarded silently. #### Key Methods -- `Parse(string text)` — Parses a comma-separated list of interval expressions into a - `VersionIntervalSet`; discards unrecognized tokens silently -- `Contains(string version)` — Tests whether a semantic version string falls within - any interval in the set; returns `false` for invalid version strings -- `Contains(VersionComparable version)` — Tests whether a `VersionComparable` instance - falls within any interval in the set -- `Contains(VersionTag version)` — Convenience overload delegating to - `Contains(VersionComparable)` using `version.Semantic.Comparable` +**Parse**: Parses a comma-separated list of bracket-bound interval expressions and returns a +`VersionIntervalSet`. + +- *Parameters*: `string text` — the range expression to parse (e.g., + `(,1.0.1],[1.1.0,1.2.0)`). +- *Returns*: `VersionIntervalSet` — a set containing the successfully parsed intervals. +- *Preconditions*: None. +- *Postconditions*: Never throws; unrecognized tokens are silently discarded. + +The algorithm walks the string character by character, incrementing a depth counter on `[` +or `(` and decrementing it on `]` or `)`. A complete token is extracted each time the depth +returns to zero; the token is forwarded to `VersionInterval.Parse` and appended to the list +if valid. + +**Contains(string)**: Tests whether a semantic version string falls within any interval in +the set. + +- *Parameters*: `string version` — the candidate semantic version string. +- *Returns*: `bool` — `true` if any interval contains the version; `false` if no interval + matches or the version string is invalid. +- *Preconditions*: None. +- *Postconditions*: Never throws. -See _VersionInterval and VersionIntervalSet Design_ for the full algorithmic descriptions of -each method. +**Contains(VersionComparable)**: Tests whether a `VersionComparable` instance falls within +any interval in the set. + +- *Parameters*: `VersionComparable version` — the candidate version. +- *Returns*: `bool` — `true` if any interval contains the version. +- *Preconditions*: `version` is non-null. +- *Postconditions*: Never throws. + +**Contains(VersionTag)**: Convenience overload; delegates to `Contains(VersionComparable)` +using `version.Semantic.Comparable`. + +- *Parameters*: `VersionTag version` — the candidate version tag. +- *Returns*: `bool` — `true` if any interval contains the version. +- *Preconditions*: `version` is non-null. +- *Postconditions*: Never throws. #### Error Handling -`Parse` silently discards interval tokens that do not conform to the expected bracket-bound -format, returning a set containing only the valid intervals. `Contains(string version)` returns -`false` when the candidate version string is not a valid semantic version, rather than +`Parse` never throws; it silently discards interval tokens that do not conform to the +bracket-bound format, returning a set containing only the valid intervals. `Contains(string)` +returns `false` when the candidate version string is not a valid semantic version, rather than propagating a parse error. -#### Interactions +#### Dependencies + +- **VersionInterval** — each element of `Intervals`; `Contains` overloads delegate to + `VersionInterval.Contains`. +- **VersionComparable** — accepted by the `Contains(VersionComparable)` overload and used + indirectly by each `VersionInterval` during bound evaluation. +- **VersionTag** — accepted by the `Contains(VersionTag)` convenience overload. + +#### Callers -| Unit / Subsystem | Role | -|----------------------|--------------------------------------------------------------------------| -| `VersionInterval` | Each element of `Intervals`; `Contains` overloads delegate to it | -| `VersionComparable` | Used by `Contains(VersionComparable)` for ordered semantic comparison | -| `VersionTag` | Accepted by the `Contains(VersionTag)` convenience overload | -| `ItemControlsParser` | Creates `VersionIntervalSet` from the `affected-versions` field value | -| `ItemControlsInfo` | Holds the `VersionIntervalSet` for the `affected-versions` field | +- **ItemControlsParser** — calls `VersionIntervalSet.Parse` to create the set from the + `affected-versions` field value. +- **ItemControlsInfo** — stores the `VersionIntervalSet` for the `affected-versions` field. diff --git a/docs/design/build-mark/version/version-interval.md b/docs/design/build-mark/version/version-interval.md index b061b47..26b94e6 100644 --- a/docs/design/build-mark/version/version-interval.md +++ b/docs/design/build-mark/version/version-interval.md @@ -1,170 +1,80 @@ -### VersionInterval and VersionIntervalSet +### VersionInterval #### Purpose -`VersionInterval` represents a single mathematical version interval using -inclusive or exclusive bounds, where either bound may be omitted to indicate -an unbounded range. It supports both parsing interval expressions and testing -whether a specific version falls inside the interval. `VersionIntervalSet` is -an ordered, immutable collection of one or more `VersionInterval` instances -parsed from the `affected-versions` field of a `buildmark` block, and can test -whether a version falls inside any contained interval. +`VersionInterval` represents a single mathematical version interval with optional inclusive +or exclusive lower and upper bounds. Either bound may be omitted to indicate an unbounded +range. It parses interval expressions in standard bracket notation (e.g., `[1.1.0,1.2.0)`, +`(,1.0.1]`) and tests whether a given version falls within the interval. -#### Interval Notation +#### Data Model -The interval format follows standard mathematical notation: +**LowerBound**: `string?` — Lower boundary version string; `null` means the interval is +unbounded below. -| Symbol | Meaning | -|--------|----------------------------| -| `[` | Inclusive lower bound | -| `(` | Exclusive lower bound | -| `]` | Inclusive upper bound | -| `)` | Exclusive upper bound | +**LowerInclusive**: `bool` — `true` when the lower bound is inclusive (`[`); `false` when +exclusive (`(`). -An empty lower bound (e.g., `(,1.0.1]`) means no minimum version. An empty -upper bound (e.g., `[3.0.0,)`) means no maximum version. +**UpperBound**: `string?` — Upper boundary version string; `null` means the interval is +unbounded above. -Multiple intervals are separated by `,` **between** ranges. The parser -distinguishes a separating comma from the commas that appear **inside** an -interval (between the bounds) by tracking bracket depth. - -#### Data Model - VersionInterval - -```csharp -public record VersionInterval( - string? LowerBound, - bool LowerInclusive, - string? UpperBound, - bool UpperInclusive); -``` - -| Property | Type | Description | -|------------------|-----------|------------------------------------------------| -| `LowerBound` | `string?` | Lower version string, or `null` if unbounded | -| `LowerInclusive` | `bool` | `true` if the lower bound is inclusive (`[`) | -| `UpperBound` | `string?` | Upper version string, or `null` if unbounded | -| `UpperInclusive` | `bool` | `true` if the upper bound is inclusive (`]`) | - -#### Data Model - VersionIntervalSet - -```csharp -public record VersionIntervalSet( - IReadOnlyList Intervals); -``` - -| Property | Type | Description | -|-------------|-----------------------------------|-----------------------------------| -| `Intervals` | `IReadOnlyList` | Ordered list of parsed intervals | +**UpperInclusive**: `bool` — `true` when the upper bound is inclusive (`]`); `false` when +exclusive (`)`). #### Key Methods -##### `VersionInterval.Parse(string text) → VersionInterval?` - -Parses a single interval token such as `(,1.0.1]` or `[1.1.0,1.2.0)`: - -1. Verify the first character is `[` or `(` and the last character is `]` or `)`. -2. Extract the opening bracket to determine `LowerInclusive`. -3. Extract the closing bracket to determine `UpperInclusive`. -4. Split the interior text on the first `,` to obtain the lower and upper bound - strings. -5. Treat an empty string for either bound as `null` (unbounded). -6. Return `null` if the input does not match the expected pattern. - -##### `VersionIntervalSet.Parse(string text) → VersionIntervalSet` - -Parses a comma-separated list of intervals: - -1. Walk the string character by character, tracking the current bracket depth - (incremented on `[` or `(`, decremented on `]` or `)`). -2. Split on `,` only when bracket depth is zero (these commas separate intervals, - not bounds within an interval). -3. Call `VersionInterval.Parse` on each token. -4. Discard tokens that do not parse successfully. -5. Return a `VersionIntervalSet` wrapping the resulting list. +**Parse**: Parses a single interval token such as `(,1.0.1]` or `[1.1.0,1.2.0)` and returns +a `VersionInterval`; returns `null` for malformed input. -##### `VersionInterval.Contains(string version) → bool` +- *Parameters*: `string? text` — the interval expression to parse. +- *Returns*: `VersionInterval?` — the parsed interval, or `null` if the input is not a valid + bracket-bound interval expression. +- *Preconditions*: None — null, whitespace, and non-bracket-bounded strings return `null`. +- *Postconditions*: Returns a valid `VersionInterval` with inclusivity and bound strings set, + or `null`. -Tests whether a semantic version string falls within the interval: +The algorithm verifies the first character is `[` or `(` and the last is `]` or `)`, +determines inclusivity from those characters, then splits the interior on the first `,` to +obtain lower and upper bound strings. An empty bound string is treated as `null` (unbounded). -1. Parse the candidate version string using `VersionComparable.TryCreate`. -2. Return `false` if the version string is not a valid semantic version. -3. Compare the candidate version against `LowerBound` when present using `VersionComparable.TryCreate`. -4. Reject the version when it is less than the lower bound. -5. Reject the version when it is equal to the lower bound and `LowerInclusive` - is `false`. -6. Compare the candidate version against `UpperBound` when present using `VersionComparable.TryCreate`. -7. Reject the version when it is greater than the upper bound. -8. Reject the version when it is equal to the upper bound and `UpperInclusive` - is `false`. -9. Return `true` otherwise. +**Contains(string)**: Tests whether a semantic version string falls within the interval. -##### `VersionInterval.Contains(VersionComparable version) → bool` +- *Parameters*: `string version` — the candidate semantic version string. +- *Returns*: `bool` — `true` if the version is within the interval; `false` if the version is + outside the interval or is not a valid semantic version. +- *Preconditions*: None. +- *Postconditions*: Returns `false` for invalid version strings rather than throwing. -Tests whether a `VersionComparable` instance falls within the interval: +**Contains(VersionComparable)**: Tests whether a `VersionComparable` instance falls within +the interval. -1. Compare the candidate version against `LowerBound` when present using `VersionComparable.TryCreate`. -2. Reject the version when it is less than the lower bound. -3. Reject the version when it is equal to the lower bound and `LowerInclusive` - is `false`. -4. Compare the candidate version against `UpperBound` when present using `VersionComparable.TryCreate`. -5. Reject the version when it is greater than the upper bound. -6. Reject the version when it is equal to the upper bound and `UpperInclusive` - is `false`. -7. Return `true` otherwise. +- *Parameters*: `VersionComparable version` — the candidate version. +- *Returns*: `bool` — `true` if the version is within the interval. +- *Preconditions*: `version` is non-null. +- *Postconditions*: Never throws. -##### `VersionInterval.Contains(VersionTag version) → bool` +**Contains(VersionTag)**: Convenience overload; delegates to `Contains(VersionComparable)` +using `version.Semantic.Comparable`. -Convenience overload for callers that already hold a parsed BuildMark -`VersionTag`. This overload delegates to `Contains(VersionComparable)` using -`version.Semantic.Comparable`. - -##### `VersionIntervalSet.Contains(string version) → bool` - -Tests whether a semantic version string falls within any interval in the set: - -1. Iterate through `Intervals` in order. -2. Call `VersionInterval.Contains(string)` on each interval. -3. Return `true` as soon as any interval contains the candidate version. -4. Return `false` when no interval matches. - -##### `VersionIntervalSet.Contains(VersionComparable version) → bool` - -Tests whether a `VersionComparable` instance falls within any interval in the set: - -1. Iterate through `Intervals` in order. -2. Call `VersionInterval.Contains(VersionComparable)` on each interval. -3. Return `true` as soon as any interval contains the candidate version. -4. Return `false` when no interval matches. - -##### `VersionIntervalSet.Contains(VersionTag version) → bool` - -Convenience overload for callers that already hold a parsed BuildMark -`VersionTag`. This overload delegates to `Contains(VersionComparable)` using -`version.Semantic.Comparable`. - -#### Parsing Examples - -| Input | Result | -|----------------------------|---------------------------------------------------| -| `(,1.0.1]` | One interval: up to and including `1.0.1` | -| `[1.1.0,1.2.0)` | One interval: `1.1.0` up to `1.2.0` (exclusive) | -| `(,1.0.1],[1.1.0,1.2.0)` | Two intervals | -| `[3.0.0,)` | One interval: `3.0.0` and later | +- *Parameters*: `VersionTag version` — the candidate version tag. +- *Returns*: `bool` — `true` if the version is within the interval. +- *Preconditions*: `version` is non-null. +- *Postconditions*: Never throws. #### Error Handling -`VersionInterval.Parse` returns `null` for malformed interval tokens rather than throwing. -`VersionIntervalSet.Parse` silently discards tokens that do not parse successfully, returning -a set containing only the valid intervals. `Contains(string version)` returns `false` if the -candidate version string is not a valid semantic version, rather than propagating a parse error. +`Parse` returns `null` for null, empty, whitespace, or bracket-malformed input rather than +throwing. `Contains(string)` returns `false` when the candidate version string cannot be +parsed by `VersionComparable.TryCreate`, rather than propagating a parse error. Once a valid +instance is constructed, `Contains(VersionComparable)` and `Contains(VersionTag)` never throw. + +#### Dependencies -#### Interactions +- **VersionComparable** — used by `Contains` overloads to parse bound strings and compare + versions. +- **VersionTag** — accepted by the `Contains(VersionTag)` convenience overload. -`VersionInterval` and `VersionIntervalSet` are general-purpose utility types. -They are created by `ItemControlsParser`, stored on `ItemControlsInfo`, and may -consume BuildMark `VersionTag` instances through their `Contains(VersionTag)` -overloads. +#### Callers -The implementation uses `VersionComparable` for semantic version parsing and -analytical comparison, providing consistent numerical ordering (e.g., 1.2.3 < 1.11.2) -across the version handling system. +- **VersionIntervalSet** — holds a list of `VersionInterval` instances and delegates `Contains` + calls to each element. diff --git a/docs/design/build-mark/version/version-semantic.md b/docs/design/build-mark/version/version-semantic.md index f569e03..e7dfb9d 100644 --- a/docs/design/build-mark/version/version-semantic.md +++ b/docs/design/build-mark/version/version-semantic.md @@ -1,78 +1,75 @@ -### Version Semantic +### VersionSemantic #### Purpose -The `VersionSemantic` record type extends `VersionComparable` with semantic version metadata -support. As a C# `record`, it provides structural equality by default - two `VersionSemantic` -instances are equal when all their properties compare equal. It provides the full semantic -version structure including build metadata while preserving comparison functionality. +`VersionSemantic` is a record that extends version comparison with optional build metadata +support. It wraps a `VersionComparable` and stores the `+metadata` component of a full +semantic version string. Build metadata is preserved for display but excluded from all +ordering comparisons, as specified by SemVer 2.0.0. #### Data Model -| Property | Type | Description | -| -------- | ---- | ----------- | -| Comparable | VersionComparable | Core comparison logic and version components | -| Metadata | string? | Build metadata (+metadata), or `null` when absent | -| FullVersion | string | Complete version string (major.minor.patch\[-pre-release\]\[+metadata\]) | +**Comparable**: `VersionComparable` — Core comparable portion of the version +(`major.minor.patch[-pre-release]`); used for all ordering operations. -#### Key Methods +**Metadata**: `string?` — Build metadata string (the portion after `+`), or `null` when no +metadata is present. -- `Create(string version)` — Parses a full semantic version string including optional - `+metadata`; throws `ArgumentException` on invalid input -- `TryCreate(string version)` — Parses a full semantic version string; returns `null` - on invalid input instead of throwing +**FullVersion**: `string` — Derived property; returns `major.minor.patch[-pre-release]` when +there is no metadata, or `major.minor.patch[-pre-release]+metadata` when metadata is present. -Both methods split the input on `+` (using `Split('+', 2)`) to separate the core version from -optional build metadata, then delegate the core version part to `VersionComparable.TryCreate`. -An empty metadata segment is normalized to `null`. Comparison operations delegate entirely to -the wrapped `Comparable` instance; build metadata does not affect ordering per the SemVer -specification. +**Major**: `int` — Delegated from `Comparable.Major`. -#### Delegated Properties +**Minor**: `int` — Delegated from `Comparable.Minor`. -For convenience, the following properties delegate to the `Comparable` instance: +**Patch**: `int` — Delegated from `Comparable.Patch`. -- `Major`, `Minor`, `Patch` - Version number components -- `Numbers` - Core semantic numbers (major.minor.patch) -- `PreRelease` - Pre-release identifier (`null` when no pre-release) -- `IsPreRelease` - Whether this is a pre-release version -- `CompareVersion` - Comparison string (excludes metadata) +**Numbers**: `string` — Delegated from `Comparable.Numbers`; returns `major.minor.patch`. -#### Comparison +**PreRelease**: `string` — Delegated from `Comparable.PreRelease`; returns empty string when +no pre-release is present. -Comparison operations are performed on the `Comparable` instance, following -semantic version rules where build metadata does not affect precedence. +**IsPreRelease**: `bool` — Delegated from `Comparable.IsPreRelease`. -#### Factory Methods +**CompareVersion**: `string` — Delegated from `Comparable.CompareVersion`; build metadata is +excluded from this string per SemVer 2.0.0. -- `Create(string version)` - Creates instance, throws on invalid input -- `TryCreate(string version)` - Returns null for invalid input +#### Key Methods -##### TryCreate Parsing Algorithm +**Create**: Parses a full semantic version string (including optional `+metadata`) and returns +a `VersionSemantic`; throws `ArgumentException` on invalid input. -1. Return `null` if the input is null or whitespace. -2. Split on `+` using `Split('+', 2)` to separate the version string from optional build metadata. -3. Normalize empty metadata to `null` (metadata is `null`, not an empty string, when absent). -4. Delegate the version part to `VersionComparable.TryCreate`; return `null` if it returns `null`. -5. Return a new `VersionSemantic(comparable, metadata)`. +- *Parameters*: `string versionString` — the version string to parse. +- *Returns*: `VersionSemantic` — the parsed version. +- *Preconditions*: Input is a non-null, non-whitespace string containing a valid + `major.minor.patch` triple. +- *Postconditions*: Returns a valid `VersionSemantic`; throws `ArgumentException` on invalid + input. -#### Example +**TryCreate**: Parses a full semantic version string; returns `null` on invalid input instead +of throwing. -```csharp -var version = VersionSemantic.Create("1.2.3-beta.1+build.123"); -// version.Major = 1 -// version.Comparable.Major = 1 -// version.Metadata = "build.123" -// version.FullVersion = "1.2.3-beta.1+build.123" -// version.CompareVersion = "1.2.3-beta.1" -``` +- *Parameters*: `string versionString` — the version string to parse. +- *Returns*: `VersionSemantic?` — the parsed version, or `null` if the input is invalid. +- *Preconditions*: None — null and whitespace inputs return `null`. +- *Postconditions*: Returns a valid `VersionSemantic` or `null`; never throws. + +Both methods split the input on `+` (using `Split('+', 2)`) to separate the core version from +optional build metadata. The core version part is forwarded to `VersionComparable.TryCreate`; +an empty or absent metadata segment is normalized to `null`. #### Error Handling -`Create(string version)` throws `ArgumentException` for invalid input. `TryCreate(string version)` -returns `null` instead of throwing. Once constructed, property access and comparison operations -cannot fail. +`Create` throws `ArgumentException` when the input string does not match the semantic version +format. `TryCreate` returns `null` instead of throwing. Once a valid instance is constructed, +property access and delegation to `Comparable` cannot fail. + +#### Dependencies + +- **VersionComparable** — wrapped as the `Comparable` property; provides all ordering and + comparison operations. -#### Interactions +#### Callers -Consumed by `VersionTag` for version extraction from Git tag strings. +- **VersionTag** — creates a `VersionSemantic` during tag parsing and stores it as the + `Semantic` property. diff --git a/docs/design/build-mark/version/version-tag.md b/docs/design/build-mark/version/version-tag.md index e9336bf..72b0e82 100644 --- a/docs/design/build-mark/version/version-tag.md +++ b/docs/design/build-mark/version/version-tag.md @@ -1,110 +1,89 @@ -### Version Tag +### VersionTag #### Purpose -The `VersionTag` class parses repository tags to extract semantic version information. -It handles various tag formats and prefixes while providing access to both the -original tag and parsed semantic version. **Critically, VersionTag instances are -compared based on their semantic version content (VersionComparable), not their -tag strings, enabling version equality across different tag formats.** +`VersionTag` parses a raw repository tag string and extracts the embedded semantic version. +It preserves the original tag string for display and logging while providing structured +version access through a `VersionSemantic` property. Equality between `VersionTag` instances +is based on the semantic version content (`Semantic.Comparable`), not on the raw tag string, +so tags with different prefixes but identical semantic versions compare as equal. #### Data Model -| Property | Type | Description | -|----------|-----------------|------------------------------| -| Tag | string | Original repository tag | -| Semantic | VersionSemantic | Parsed semantic version info | +**Tag**: `string` — Original repository tag string exactly as it appears in the repository. -#### Key Methods - -- `Create(string tag)` — Parses a repository tag string and extracts the embedded - semantic version; throws `ArgumentException` when no recognizable semantic version - can be found -- `TryCreate(string tag)` — Parses a repository tag string; returns `null` when no - semantic version can be extracted instead of throwing -- `ToString()` — Returns the original `Tag` string verbatim, preserving the repository - tag format for display and logging - -The parsing algorithm strips known prefix patterns (e.g., `v`, `ver`, `release/`) and then -attempts `VersionSemantic.TryCreate` on the remainder. Equality between `VersionTag` -instances is based on `Semantic.Comparable` rather than the raw `Tag` string, so tags with -different prefixes but identical semantic versions compare as equal. - -#### Delegated Properties +**Semantic**: `VersionSemantic` — Parsed semantic version extracted from the tag. -For convenience, the following properties delegate to the `Semantic.Comparable` instance: +**FullVersion**: `string` — Delegated from `Semantic.FullVersion`; the extracted semantic +version without the tag prefix. -- `Major`, `Minor`, `Patch` - Version number components -- `PreRelease` - Pre-release identifier -- `CompareVersion` - Comparison string -- `Numbers` - Version numbers only (major.minor.patch) +**Major**: `int` — Delegated from `Semantic.Major`. -Additional delegated properties from `Semantic`: +**Minor**: `int` — Delegated from `Semantic.Minor`. -- `Metadata` - Build metadata -- `FullVersion` - Complete semantic version string +**Patch**: `int` — Delegated from `Semantic.Patch`. -#### Tag Format Support +**Numbers**: `string` — Delegated from `Semantic.Numbers`; returns `major.minor.patch`. -The parser supports various repository tag formats: +**PreRelease**: `string` — Delegated from `Semantic.PreRelease`; returns empty string when no +pre-release is present. -- Simple: `1.2.3`, `v1.2.3`, `ver1.2.3` -- Complex prefixes: `Release_1.2.3`, `MyApp-v1.2.3` -- Path-separator prefixes: `release/1.2.3`, `builds/release/1.2.3` -- Pre-release: `1.2.3-beta`, `1.2.3.rc.1` (dot becomes hyphen) -- Metadata: `1.2.3+build.123` +**CompareVersion**: `string` — Delegated from `Semantic.CompareVersion`. -#### Version Equality +**Metadata**: `string` — Delegated from `Semantic.Metadata`; returns empty string when no +build metadata is present. -**Important Design Principle**: VersionTag instances with different tag strings but -identical semantic versions are considered equal. This enables repository connectors -to correctly identify versions regardless of tagging conventions: +**IsPreRelease**: `bool` — Delegated from `Semantic.IsPreRelease`. -- `"v1.2.3"` equals `"VER1.2.3"` equals `"Release-1.2.3"` equals `"release/1.2.3"` -- Equality is determined by `Semantic.Comparable.Equals()` -- FindVersionIndex in RepoConnectorBase uses this semantic comparison +#### Key Methods -This design prevents version matching failures when repositories use different -tag naming conventions but identical semantic versions. +**Create**: Parses a repository tag string and returns a `VersionTag`; throws +`ArgumentException` when no recognizable semantic version can be extracted. -#### Factory Methods +- *Parameters*: `string tag` — the repository tag string to parse. +- *Returns*: `VersionTag` — the parsed tag with its embedded semantic version. +- *Preconditions*: Input contains a `major.minor.patch` triple, optionally preceded by an + alphabetic or path-separator prefix. +- *Postconditions*: Returns a valid `VersionTag`; throws `ArgumentException` on invalid input. -- `Create(string tag)` - Creates instance, throws on invalid tag -- `TryCreate(string tag)` - Returns null for invalid tag +**TryCreate**: Parses a repository tag string; returns `null` when no semantic version can be +extracted, instead of throwing. -#### Display / ToString +- *Parameters*: `string tag` — the repository tag string to parse. +- *Returns*: `VersionTag?` — the parsed tag, or `null` if no semantic version can be + extracted. +- *Preconditions*: None — null and whitespace inputs return `null`. +- *Postconditions*: Returns a valid `VersionTag` or `null`; never throws. -The `ToString()` method is overridden to return the original `Tag` string verbatim. -This preserves the repository tag format for display and logging purposes while keeping semantic comparison -available through `Semantic.Comparable`: +Both methods apply a source-generated regex pattern that accepts an optional alphabetic or +path-separator prefix before the `major.minor.patch` triple, and captures optional pre-release +and build-metadata segments. The separator between the numbers and pre-release may be a hyphen +(`-`) or a dot (`.`). Equality between `VersionTag` instances is determined by +`Semantic.Comparable`, so `v1.2.3` and `release/1.2.3` are considered equal. -```csharp -var versionTag = VersionTag.Create("release/1.2.3-rc.1"); -Console.WriteLine(versionTag); // "release/1.2.3-rc.1" -Console.WriteLine(versionTag.FullVersion); // "1.2.3-rc.1" -``` +**ToString**: Returns the original `Tag` string verbatim. -#### Example +- *Parameters*: None. +- *Returns*: `string` — the original repository tag string. +- *Preconditions*: None. +- *Postconditions*: Never throws; always returns the `Tag` value set at construction. -```csharp -var versionTag = VersionTag.Create("MyApp-v1.2.3-beta.1+build.123"); -// versionTag.Tag = "MyApp-v1.2.3-beta.1+build.123" -// versionTag.Numbers = "1.2.3" -// versionTag.FullVersion = "1.2.3-beta.1+build.123" -// versionTag.CompareVersion = "1.2.3-beta.1" +#### Error Handling -// Version equality example -var tag1 = VersionTag.Create("v1.2.3"); -var tag2 = VersionTag.Create("VER1.2.3"); -// tag1.Semantic.Comparable.Equals(tag2.Semantic.Comparable) == true -``` +`Create` throws `ArgumentException` when the tag string does not contain a recognizable +`major.minor.patch` triple. `TryCreate` returns `null` instead of throwing. Once constructed, +property access and `ToString` cannot fail. -#### Error Handling +#### Dependencies -`Create(string tag)` throws `ArgumentException` when the tag cannot be parsed into a -recognizable semantic version format. `TryCreate(string tag)` returns `null` instead of -throwing. Once constructed, property access and `ToString()` cannot fail. +- **VersionSemantic** — stores the parsed semantic version as the `Semantic` property. +- **VersionComparable** — accessed indirectly through `Semantic.Comparable` for equality and + ordering. -#### Interactions +#### Callers -Consumed by `VersionCommitTag`, RepoConnectors (for tag parsing), and `Program` (for filtering). +- **VersionCommitTag** — holds a `VersionTag` as its `VersionTag` property. +- **RepoConnectorBase** — uses `VersionTag` instances to locate version boundaries (e.g., + `FindVersionIndex`). +- **ItemControlsParser** — filters items by version using `VersionTag` values. +- **Program** — uses `VersionTag` when filtering build notes by version range. diff --git a/docs/design/introduction.md b/docs/design/introduction.md index 44c7dda..5cf7edd 100644 --- a/docs/design/introduction.md +++ b/docs/design/introduction.md @@ -1,28 +1,36 @@ # Introduction -This document provides the detailed design for BuildMark, a .NET command-line tool -that generates markdown build notes from Git repository metadata, including GitHub -and Azure DevOps repositories. +This document provides the detailed design for BuildMark — a .NET command-line tool that +generates markdown build notes from Git repository metadata, including GitHub and Azure DevOps +repositories. It covers local software items (systems, subsystems, and units) and the OTS +software items they consume. ## Purpose -The purpose of this document is to describe the internal design of each software unit -that comprises BuildMark. It captures data models, algorithms, key methods, and -inter-unit interactions at a level of detail sufficient for formal code review, -compliance verification, and future maintenance. The document does not restate -requirements; it explains how they are realized. +The purpose of this document is to define the design for each software item in BuildMark — +full architectural and detailed design for local items (systems, subsystems, and units), and +integration and usage design for OTS software items. A reviewer should be able to understand +how each item satisfies its requirements without reading source code. The document does not +restate requirements; it explains how they are realized. ## Scope -This document covers the detailed design of the BuildMark system, including all -subsystems and units identified in the software structure below. Each unit has -its own detailed design chapter within this document. +This document covers the following software items: + +Local items: + +- **BuildMark**: system, subsystem, and unit design for all local components. + +OTS items: + +- **YamlDotNet**: integration and usage design. The following topics are out of scope: - External library internals - Build pipeline configuration - Deployment and packaging +- Test projects ## Software Structure @@ -153,19 +161,15 @@ Each local software item has corresponding artifacts in parallel directory trees - Source: `src/DemaConsulting.BuildMark/.../{Item}.cs` - Tests: `test/DemaConsulting.BuildMark.Tests/.../{Item}Tests.cs` -Review-sets: defined in `.reviewmark.yaml` - -## Document Conventions +OTS items have integration and usage design documentation parallel to system folders: -Throughout this document: +- Requirements: `docs/reqstream/ots/{ots-name}.yaml` +- Design: `docs/design/ots/{ots-name}.md` +- Verification: `docs/verification/ots/{ots-name}.md` -- Class names, method names, property names, and file names appear in `monospace` font. -- The word **shall** denotes a design constraint that the implementation must satisfy. -- Section headings within each unit chapter follow a consistent structure: overview, data model, - methods/algorithms, and interactions with other units. -- Text tables are used in preference to diagrams, which may not render in all PDF viewers. +Review-sets: defined in `.reviewmark.yaml` ## References -- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) — compiled user guide and documentation -- See the BuildMark repository at . +- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) — compiled user + guide and documentation diff --git a/docs/design/title.txt b/docs/design/title.txt index d9ce920..dcab311 100644 --- a/docs/design/title.txt +++ b/docs/design/title.txt @@ -1,8 +1,8 @@ --- title: BuildMark Software Design Document -subtitle: A .NET CLI Tool for Generating Build Notes from GitHub +subtitle: Markdown Build Notes Generation Tool author: DEMA Consulting -description: Detailed design document for the BuildMark tool +description: Software Design Document for BuildMark lang: en-US keywords: - BuildMark diff --git a/docs/reqstream/build-mark.yaml b/docs/reqstream/build-mark.yaml index cfa51a6..9a11f54 100644 --- a/docs/reqstream/build-mark.yaml +++ b/docs/reqstream/build-mark.yaml @@ -1,6 +1,7 @@ --- +# BuildMark system-level requirements sections: - - title: BuildMark System Requirements + - title: BuildMark Requirements sections: - title: Command-Line Interface requirements: diff --git a/docs/reqstream/build-mark/build-notes.yaml b/docs/reqstream/build-mark/build-notes.yaml index 38a6761..ff1a618 100644 --- a/docs/reqstream/build-mark/build-notes.yaml +++ b/docs/reqstream/build-mark/build-notes.yaml @@ -1,30 +1,24 @@ --- -# BuildNotes Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark BuildNotes subsystem -# - The BuildNotes subsystem spans BuildInformation.cs, ItemInfo.cs, -# and WebLink.cs -# - Subsystem requirements describe the shared report data model and markdown -# rendering behavior used by Program and repository connectors - +# BuildMark BuildNotes subsystem requirements sections: - - title: BuildNotes Subsystem Requirements - requirements: - - id: BuildMark-BuildNotes-ReportModel - title: >- - The BuildNotes subsystem shall provide the report data model and - markdown rendering behavior for generated build notes. - justification: | - BuildMark separates report assembly from repository retrieval so that - connectors can populate a common in-memory model and Program can render - the final markdown output consistently. - tests: - - BuildNotes_ReportModel_GeneratesCorrectMarkdown - - BuildNotes_ReportModel_IncludesKnownIssues - - BuildNotes_ReportModel_IncludesFullChangelog - children: - - BuildMark-BuildInformation-Markdown - - BuildMark-BuildInformation-RoutedSections - - BuildMark-ItemInfo-Record - - BuildMark-WebLink-Record + - title: BuildMark Requirements + sections: + - title: BuildNotes Requirements + requirements: + - id: BuildMark-BuildNotes-ReportModel + title: >- + The BuildNotes subsystem shall provide the report data model and + markdown rendering behavior for generated build notes. + justification: | + BuildMark separates report assembly from repository retrieval so that + connectors can populate a common in-memory model and Program can render + the final markdown output consistently. + tests: + - BuildNotes_ReportModel_GeneratesCorrectMarkdown + - BuildNotes_ReportModel_IncludesKnownIssues + - BuildNotes_ReportModel_IncludesFullChangelog + children: + - BuildMark-BuildInformation-Markdown + - BuildMark-BuildInformation-RoutedSections + - BuildMark-ItemInfo-Record + - BuildMark-WebLink-Record diff --git a/docs/reqstream/build-mark/build-notes/build-information.yaml b/docs/reqstream/build-mark/build-notes/build-information.yaml index 5e0c697..24846af 100644 --- a/docs/reqstream/build-mark/build-notes/build-information.yaml +++ b/docs/reqstream/build-mark/build-notes/build-information.yaml @@ -1,45 +1,44 @@ --- -# Software Unit Requirements for the BuildInformation Class -# -# BuildInformation is the top-level BuildNotes record that holds the current and -# baseline version tags, categorized items, known issues, and the optional full -# changelog link for one report instance. - +# BuildMark BuildInformation unit requirements sections: - - title: BuildInformation Unit Requirements - requirements: - - id: BuildMark-BuildInformation-Markdown - title: >- - The BuildInformation class shall render the collected build data as a - structured markdown report. - justification: | - Report generation is the primary outcome of BuildMark. The BuildNotes - model must render version information, categorized items, optional known - issues, and the optional full changelog link in a predictable format. - tests: - - BuildInformation_ToMarkdown_GeneratesCorrectMarkdownWithDefaults - - BuildInformation_ToMarkdown_IncludesKnownIssuesWhenRequested - - BuildInformation_ToMarkdown_RespectsCustomHeadingDepth - - BuildInformation_ToMarkdown_IncludesIssueLinks - - BuildInformation_ToMarkdown_IncludesFullChangelogWhenLinkPresent - - BuildInformation_ToMarkdown_ExcludesFullChangelogWhenNoBaseline - - BuildInformation_ToMarkdown_UsesBulletLists - - BuildInformation_ToMarkdown_DisplaysNAForEmptyChanges - - BuildInformation_ToMarkdown_DisplaysNAForEmptyBugs - - BuildInformation_ToMarkdown_HandlesFirstReleaseWithNA + - title: BuildMark Requirements + sections: + - title: BuildNotes Requirements + sections: + - title: BuildInformation Requirements + requirements: + - id: BuildMark-BuildInformation-Markdown + title: >- + The BuildInformation class shall render the collected build data as a + structured markdown report. + justification: | + Report generation is the primary outcome of BuildMark. The BuildNotes + model must render version information, categorized items, optional known + issues, and the optional full changelog link in a predictable format. + tests: + - BuildInformation_ToMarkdown_GeneratesCorrectMarkdownWithDefaults + - BuildInformation_ToMarkdown_IncludesKnownIssuesWhenRequested + - BuildInformation_ToMarkdown_RespectsCustomHeadingDepth + - BuildInformation_ToMarkdown_IncludesIssueLinks + - BuildInformation_ToMarkdown_IncludesFullChangelogWhenLinkPresent + - BuildInformation_ToMarkdown_ExcludesFullChangelogWhenNoBaseline + - BuildInformation_ToMarkdown_UsesBulletLists + - BuildInformation_ToMarkdown_DisplaysNAForEmptyChanges + - BuildInformation_ToMarkdown_DisplaysNAForEmptyBugs + - BuildInformation_ToMarkdown_HandlesFirstReleaseWithNA - - id: BuildMark-BuildInformation-RoutedSections - title: >- - The BuildInformation class shall render custom report sections from - RoutedSections when routing rules are configured. - justification: | - When connector routing rules are active, items are distributed into - custom sections rather than the default Changes/Bugs/KnownIssues - categorization. ToMarkdown must render those custom sections when - RoutedSections is populated, and fall back to the default sections - when it is null or empty. - tests: - - BuildInformation_ToMarkdown_WithRoutedSections_RendersCustomSections - - BuildInformation_ToMarkdown_WithoutRoutedSections_RendersDefaultSections - - BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssues_RendersKnownIssuesSection - - BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssuesFlagFalse_DoesNotRenderKnownIssuesSection + - id: BuildMark-BuildInformation-RoutedSections + title: >- + The BuildInformation class shall render custom report sections from + RoutedSections when routing rules are configured. + justification: | + When connector routing rules are active, items are distributed into + custom sections rather than the default Changes/Bugs/KnownIssues + categorization. ToMarkdown must render those custom sections when + RoutedSections is populated, and fall back to the default sections + when it is null or empty. + tests: + - BuildInformation_ToMarkdown_WithRoutedSections_RendersCustomSections + - BuildInformation_ToMarkdown_WithoutRoutedSections_RendersDefaultSections + - BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssues_RendersKnownIssuesSection + - BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssuesFlagFalse_DoesNotRenderKnownIssuesSection diff --git a/docs/reqstream/build-mark/build-notes/item-info.yaml b/docs/reqstream/build-mark/build-notes/item-info.yaml index 296fad4..e39c64c 100644 --- a/docs/reqstream/build-mark/build-notes/item-info.yaml +++ b/docs/reqstream/build-mark/build-notes/item-info.yaml @@ -1,21 +1,20 @@ --- -# Software Unit Requirements for the ItemInfo Class -# -# ItemInfo represents one issue or pull request entry in a generated build-note -# report, including its display identity, classification, sort index, and -# optional affected-version interval data. - +# BuildMark ItemInfo unit requirements sections: - - title: ItemInfo Unit Requirements - requirements: - - id: BuildMark-ItemInfo-Record - title: >- - The ItemInfo record shall carry the identifier, title, link, type, - ordering index, and optional affected-version data for one report item. - justification: | - Connectors and downstream report generation need a stable data shape for - individual changes, bug fixes, and known issues so that items can be - sorted, classified, filtered, and rendered consistently. - tests: - - BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex - - BuildInformation_ToMarkdown_UsesBulletLists + - title: BuildMark Requirements + sections: + - title: BuildNotes Requirements + sections: + - title: ItemInfo Requirements + requirements: + - id: BuildMark-ItemInfo-Record + title: >- + The ItemInfo record shall carry the identifier, title, link, type, + ordering index, and optional affected-version data for one report item. + justification: | + Connectors and downstream report generation need a stable data shape for + individual changes, bug fixes, and known issues so that items can be + sorted, classified, filtered, and rendered consistently. + tests: + - BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex + - BuildInformation_ToMarkdown_UsesBulletLists diff --git a/docs/reqstream/build-mark/build-notes/web-link.yaml b/docs/reqstream/build-mark/build-notes/web-link.yaml index 40e1eda..4bbe3d7 100644 --- a/docs/reqstream/build-mark/build-notes/web-link.yaml +++ b/docs/reqstream/build-mark/build-notes/web-link.yaml @@ -1,19 +1,19 @@ --- -# Software Unit Requirements for the WebLink Class -# -# WebLink stores hyperlink text and target URL for report elements such as the -# optional full changelog link. - +# BuildMark WebLink unit requirements sections: - - title: WebLink Unit Requirements - requirements: - - id: BuildMark-WebLink-Record - title: >- - The WebLink record shall store display text and a target URL for a - hyperlink included in the generated report. - justification: | - BuildInformation needs a lightweight value object for optional links such - as the full changelog entry so the rendered markdown can present a stable - label and destination. - tests: - - WebLink_Constructor_StoresTextAndUrl + - title: BuildMark Requirements + sections: + - title: BuildNotes Requirements + sections: + - title: WebLink Requirements + requirements: + - id: BuildMark-WebLink-Record + title: >- + The WebLink record shall store display text and a target URL for a + hyperlink included in the generated report. + justification: | + BuildInformation needs a lightweight value object for optional links such + as the full changelog entry so the rendered markdown can present a stable + label and destination. + tests: + - WebLink_Constructor_StoresTextAndUrl diff --git a/docs/reqstream/build-mark/cli.yaml b/docs/reqstream/build-mark/cli.yaml index d7e58a3..5261ef6 100644 --- a/docs/reqstream/build-mark/cli.yaml +++ b/docs/reqstream/build-mark/cli.yaml @@ -1,180 +1,176 @@ --- -# Cli Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark Cli subsystem -# - The Cli subsystem spans Context.cs (command-line argument parsing and I/O) -# - Subsystem requirements describe the externally visible command-line interface behavior - +# BuildMark Cli subsystem requirements sections: - - title: Cli Subsystem Requirements - requirements: - - id: BuildMark-Cli-Context - title: The Cli subsystem shall parse command-line arguments and manage program I/O state for the tool. - justification: | - Provides a standardized approach to command-line argument parsing and output - handling across all DEMA Consulting DotNet Tools. All parsed flags and output - channels must be accessible through a single, consistent entry point so that - the rest of the tool can read user intent without re-parsing. - tests: - - Cli_Context_EmptyArguments_CreatesValidContext - - Cli_VersionFlag_SetsProperty - - Cli_SilentFlag_SetsProperty - - Cli_LogFlag_CreatesLogFile - - Cli_InvalidArgument_ThrowsException - children: - - BuildMark-Context-ArgumentParsing - - BuildMark-Context-InvalidArgs - - BuildMark-Context-Output - - BuildMark-Context-Silent - - BuildMark-Context-ErrorOutput - - BuildMark-Context-ExitCode + - title: BuildMark Requirements + sections: + - title: Cli Requirements + requirements: + - id: BuildMark-Cli-Context + title: The Cli subsystem shall parse command-line arguments and manage program I/O state for the tool. + justification: | + Provides a standardized approach to command-line argument parsing and output + handling across all DEMA Consulting DotNet Tools. All parsed flags and output + channels must be accessible through a single, consistent entry point so that + the rest of the tool can read user intent without re-parsing. + tests: + - Cli_Context_EmptyArguments_CreatesValidContext + - Cli_VersionFlag_SetsProperty + - Cli_SilentFlag_SetsProperty + - Cli_LogFlag_CreatesLogFile + - Cli_InvalidArgument_ThrowsException + children: + - BuildMark-Context-ArgumentParsing + - BuildMark-Context-InvalidArgs + - BuildMark-Context-Output + - BuildMark-Context-Silent + - BuildMark-Context-ErrorOutput + - BuildMark-Context-ExitCode - - id: BuildMark-Cli-Version - title: The Cli subsystem shall support -v and --version flags to signal version display. - justification: | - Users need to quickly identify the version of the tool they are using for - troubleshooting and compatibility verification. - tests: - - Cli_VersionFlag_SetsProperty - - Cli_VersionShortFlag_SetsProperty - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-Version + title: The Cli subsystem shall support -v and --version flags to signal version display. + justification: | + Users need to quickly identify the version of the tool they are using for + troubleshooting and compatibility verification. + tests: + - Cli_VersionFlag_SetsProperty + - Cli_VersionShortFlag_SetsProperty + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-Help - title: The Cli subsystem shall support -?, -h, and --help flags to signal help display. - justification: | - Users need access to command-line usage documentation without requiring - external resources. - tests: - - Cli_HelpFlag_SetsProperty - - Cli_HelpShortFlags_SetProperty - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-Help + title: The Cli subsystem shall support -?, -h, and --help flags to signal help display. + justification: | + Users need access to command-line usage documentation without requiring + external resources. + tests: + - Cli_HelpFlag_SetsProperty + - Cli_HelpShortFlags_SetProperty + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-Silent - title: The Cli subsystem shall support --silent flag to suppress console output. - justification: | - Enables automated scripts and CI/CD pipelines to run the tool without - cluttering output logs when only the exit code is needed. - tests: - - Cli_SilentFlag_SetsProperty - - Cli_SilentFlag_SuppressesConsoleOutput - children: - - BuildMark-Context-Silent + - id: BuildMark-Cli-Silent + title: The Cli subsystem shall support --silent flag to suppress console output. + justification: | + Enables automated scripts and CI/CD pipelines to run the tool without + cluttering output logs when only the exit code is needed. + tests: + - Cli_SilentFlag_SetsProperty + - Cli_SilentFlag_SuppressesConsoleOutput + children: + - BuildMark-Context-Silent - - id: BuildMark-Cli-BuildVersion - title: The Cli subsystem shall support --build-version flag to specify the build version. - justification: | - Allows users to override or supplement version information from source control, - enabling flexible version management strategies and supporting scenarios where - version numbers are determined externally. - tests: - - Cli_BuildVersionFlag_SetsProperty - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-BuildVersion + title: The Cli subsystem shall support --build-version flag to specify the build version. + justification: | + Allows users to override or supplement version information from source control, + enabling flexible version management strategies and supporting scenarios where + version numbers are determined externally. + tests: + - Cli_BuildVersionFlag_SetsProperty + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-ReportFile - title: The Cli subsystem shall support --report flag to specify the report output file path. - justification: | - Enables users to direct build notes output to a specific file, supporting - flexible integration into CI/CD pipelines and documentation workflows. - tests: - - Cli_ReportFlags_SetProperties - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-ReportFile + title: The Cli subsystem shall support --report flag to specify the report output file path. + justification: | + Enables users to direct build notes output to a specific file, supporting + flexible integration into CI/CD pipelines and documentation workflows. + tests: + - Cli_ReportFlags_SetProperties + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-Depth - title: The Cli subsystem shall support --depth flag to configure the markdown heading depth. - justification: | - Allows users to embed the generated report at any heading level within a larger - markdown document, ensuring proper document hierarchy in compound documents. - tests: - - Cli_ReportFlags_SetProperties - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-Depth + title: The Cli subsystem shall support --depth flag to configure the markdown heading depth. + justification: | + Allows users to embed the generated report at any heading level within a larger + markdown document, ensuring proper document hierarchy in compound documents. + tests: + - Cli_ReportFlags_SetProperties + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-IncludeKnownIssues - title: The Cli subsystem shall support --include-known-issues flag to include known issues in the report. - justification: | - Provides users control over whether known issues are included in generated build - notes, enabling comprehensive release documentation when needed. - tests: - - Cli_ReportFlags_SetProperties - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-IncludeKnownIssues + title: The Cli subsystem shall support --include-known-issues flag to include known issues in the report. + justification: | + Provides users control over whether known issues are included in generated build + notes, enabling comprehensive release documentation when needed. + tests: + - Cli_ReportFlags_SetProperties + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-Log - title: The Cli subsystem shall support --log flag to write output to a log file. - justification: | - Provides persistent logging for debugging and audit trails. Log files enable - post-run inspection of tool output without requiring console capture. - tests: - - Cli_LogFlag_CreatesLogFile - children: - - BuildMark-Context-Output + - id: BuildMark-Cli-Log + title: The Cli subsystem shall support --log flag to write output to a log file. + justification: | + Provides persistent logging for debugging and audit trails. Log files enable + post-run inspection of tool output without requiring console capture. + tests: + - Cli_LogFlag_CreatesLogFile + children: + - BuildMark-Context-Output - - id: BuildMark-Cli-Validate - title: The Cli subsystem shall support --validate flag to signal self-validation. - justification: | - Provides a built-in mechanism to verify the tool is functioning correctly - in the deployment environment. - tests: - - Cli_ValidateFlag_SetsProperty - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-Validate + title: The Cli subsystem shall support --validate flag to signal self-validation. + justification: | + Provides a built-in mechanism to verify the tool is functioning correctly + in the deployment environment. + tests: + - Cli_ValidateFlag_SetsProperty + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-Lint - title: The Cli subsystem shall support --lint flag to signal configuration linting. - justification: | - Allows users to validate the .buildmark.yaml configuration file without running - a full build, providing early feedback on configuration errors. - tests: - - Cli_LintFlag_SetsProperty - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-Lint + title: The Cli subsystem shall support --lint flag to signal configuration linting. + justification: | + Allows users to validate the .buildmark.yaml configuration file without running + a full build, providing early feedback on configuration errors. + tests: + - Cli_LintFlag_SetsProperty + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-Results - title: >- - The Cli subsystem shall support --results (and --result alias) flag to - specify a test results output file. - justification: | - Enables integration with CI/CD systems that expect standard test result formats - (TRX or JUnit XML). - tests: - - Cli_ResultsFlag_SetsProperty - - Cli_ResultFlag_SetsProperty - children: - - BuildMark-Context-ArgumentParsing + - id: BuildMark-Cli-Results + title: >- + The Cli subsystem shall support --results (and --result alias) flag to + specify a test results output file. + justification: | + Enables integration with CI/CD systems that expect standard test result formats + (TRX or JUnit XML). + tests: + - Cli_ResultsFlag_SetsProperty + - Cli_ResultFlag_SetsProperty + children: + - BuildMark-Context-ArgumentParsing - - id: BuildMark-Cli-ErrorOutput - title: The Cli subsystem 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. - tests: - - Cli_ErrorOutput_WritesToStderr - children: - - BuildMark-Context-ErrorOutput + - id: BuildMark-Cli-ErrorOutput + title: The Cli subsystem 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. + tests: + - Cli_ErrorOutput_WritesToStderr + children: + - BuildMark-Context-ErrorOutput - - id: BuildMark-Cli-InvalidArgs - title: The Cli subsystem 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 in automated workflows. - tests: - - Cli_InvalidArgument_ThrowsException - - Cli_MissingArgumentValue_ThrowsException - children: - - BuildMark-Context-InvalidArgs + - id: BuildMark-Cli-InvalidArgs + title: The Cli subsystem 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 in automated workflows. + tests: + - Cli_InvalidArgument_ThrowsException + - Cli_MissingArgumentValue_ThrowsException + children: + - BuildMark-Context-InvalidArgs - - id: BuildMark-Cli-ExitCode - title: The Cli subsystem shall return appropriate exit codes. - justification: | - Standard exit codes enable build automation systems and scripts to detect success - or failure conditions programmatically. - tests: - - Cli_ExitCode_DefaultsToZero - - Cli_WriteError_SetsExitCodeToOne - children: - - BuildMark-Context-ExitCode + - id: BuildMark-Cli-ExitCode + title: The Cli subsystem shall return appropriate exit codes. + justification: | + Standard exit codes enable build automation systems and scripts to detect success + or failure conditions programmatically. + tests: + - Cli_ExitCode_DefaultsToZero + - Cli_WriteError_SetsExitCodeToOne + children: + - BuildMark-Context-ExitCode diff --git a/docs/reqstream/build-mark/cli/context.yaml b/docs/reqstream/build-mark/cli/context.yaml index 8d4af99..22b79f0 100644 --- a/docs/reqstream/build-mark/cli/context.yaml +++ b/docs/reqstream/build-mark/cli/context.yaml @@ -1,94 +1,93 @@ --- -# Software Unit Requirements for the Context Class -# -# The Context class handles command-line argument parsing and program output. -# It is the primary interface between the user's command-line invocation and -# the tool's internal logic. - +# BuildMark Context unit requirements sections: - - title: Context Unit Requirements - requirements: - - id: BuildMark-Context-ArgumentParsing - title: The Context class shall parse command-line arguments into structured properties. - justification: | - Provides a standardized approach to command-line argument parsing across all - DEMA Consulting DotNet Tools. Each recognized flag or value is stored as a - typed property so that the rest of the tool can read intent without re-parsing. - tests: - - Context_Create_EmptyArguments_CreatesValidContext - - Context_Create_LongVersionFlag_SetsVersionProperty - - Context_Create_ShortVersionFlag_SetsVersionProperty - - Context_Create_LongHelpFlag_SetsHelpProperty - - Context_Create_ShortHelpFlag_SetsHelpProperty - - Context_Create_QuestionMarkHelpFlag_SetsHelpProperty - - Context_Create_SilentFlag_SetsSilentProperty - - Context_Create_ValidateFlag_SetsValidateProperty - - Context_Create_LintFlag_SetsLintProperty - - Context_Create_BuildVersionArgument_SetsBuildVersionProperty - - Context_Create_ReportArgument_SetsReportFileProperty - - Context_Create_DepthArgument_SetsDepthProperty - - Context_Create_LegacyReportDepthArgument_SetsDepthProperty - - Context_Create_IncludeKnownIssuesFlag_SetsIncludeKnownIssuesProperty - - Context_Create_ResultsArgument_SetsResultsFileProperty - - Context_Create_ResultArgument_SetsResultsFileProperty - - Context_Create_LogArgument_CreatesLogFile - - Context_Create_MultipleArguments_SetsAllPropertiesCorrectly + - title: BuildMark Requirements + sections: + - title: Cli Requirements + sections: + - title: Context Requirements + requirements: + - id: BuildMark-Context-ArgumentParsing + title: The Context class shall parse command-line arguments into structured properties. + justification: | + Provides a standardized approach to command-line argument parsing across all + DEMA Consulting DotNet Tools. Each recognized flag or value is stored as a + typed property so that the rest of the tool can read intent without re-parsing. + tests: + - Context_Create_EmptyArguments_CreatesValidContext + - Context_Create_LongVersionFlag_SetsVersionProperty + - Context_Create_ShortVersionFlag_SetsVersionProperty + - Context_Create_LongHelpFlag_SetsHelpProperty + - Context_Create_ShortHelpFlag_SetsHelpProperty + - Context_Create_QuestionMarkHelpFlag_SetsHelpProperty + - Context_Create_SilentFlag_SetsSilentProperty + - Context_Create_ValidateFlag_SetsValidateProperty + - Context_Create_LintFlag_SetsLintProperty + - Context_Create_BuildVersionArgument_SetsBuildVersionProperty + - Context_Create_ReportArgument_SetsReportFileProperty + - Context_Create_DepthArgument_SetsDepthProperty + - Context_Create_LegacyReportDepthArgument_SetsDepthProperty + - Context_Create_IncludeKnownIssuesFlag_SetsIncludeKnownIssuesProperty + - Context_Create_ResultsArgument_SetsResultsFileProperty + - Context_Create_ResultArgument_SetsResultsFileProperty + - Context_Create_LogArgument_CreatesLogFile + - Context_Create_MultipleArguments_SetsAllPropertiesCorrectly - - id: BuildMark-Context-InvalidArgs - title: The Context class 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. - tests: - - Context_Create_UnsupportedArgument_ThrowsArgumentException - - Context_Create_BuildVersionWithoutValue_ThrowsArgumentException - - Context_Create_ReportWithoutValue_ThrowsArgumentException - - Context_Create_DepthWithoutValue_ThrowsArgumentException - - Context_Create_DepthWithNonIntegerValue_ThrowsArgumentException - - Context_Create_DepthWithZeroValue_ThrowsArgumentException - - Context_Create_DepthWithNegativeValue_ThrowsArgumentException - - Context_Create_DepthExceedingMaximum_ThrowsArgumentOutOfRangeException - - Context_Create_ResultsWithoutValue_ThrowsArgumentException - - Context_Create_ResultWithoutValue_ThrowsArgumentException - - Context_Create_LogWithoutValue_ThrowsArgumentException - - Context_Create_InvalidLogFilePath_ThrowsInvalidOperationException + - id: BuildMark-Context-InvalidArgs + title: The Context class 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. + tests: + - Context_Create_UnsupportedArgument_ThrowsArgumentException + - Context_Create_BuildVersionWithoutValue_ThrowsArgumentException + - Context_Create_ReportWithoutValue_ThrowsArgumentException + - Context_Create_DepthWithoutValue_ThrowsArgumentException + - Context_Create_DepthWithNonIntegerValue_ThrowsArgumentException + - Context_Create_DepthWithZeroValue_ThrowsArgumentException + - Context_Create_DepthWithNegativeValue_ThrowsArgumentException + - Context_Create_DepthExceedingMaximum_ThrowsArgumentOutOfRangeException + - Context_Create_ResultsWithoutValue_ThrowsArgumentException + - Context_Create_ResultWithoutValue_ThrowsArgumentException + - Context_Create_LogWithoutValue_ThrowsArgumentException + - Context_Create_InvalidLogFilePath_ThrowsInvalidOperationException - - id: BuildMark-Context-Output - title: The Context class shall write output to the console and optionally to a log file. - justification: | - Provides persistent logging for debugging and audit trails, while also - allowing console output to be suppressed in automated environments. - tests: - - Context_WriteLine_NotSilent_WritesToConsole - - Context_WriteLine_Silent_DoesNotWriteToConsole - - Context_WriteLine_WithLogFile_WritesToLogFile - - Context_WriteError_WithLogFile_WritesToLogFile - - Context_Dispose_ClosesLogFileProperly + - id: BuildMark-Context-Output + title: The Context class shall write output to the console and optionally to a log file. + justification: | + Provides persistent logging for debugging and audit trails, while also + allowing console output to be suppressed in automated environments. + tests: + - Context_WriteLine_NotSilent_WritesToConsole + - Context_WriteLine_Silent_DoesNotWriteToConsole + - Context_WriteLine_WithLogFile_WritesToLogFile + - Context_WriteError_WithLogFile_WritesToLogFile + - Context_Dispose_ClosesLogFileProperly - - id: BuildMark-Context-Silent - title: The Context class shall suppress console output when the silent flag is set. - justification: | - Enables automated scripts and CI/CD pipelines to run the tool without - cluttering output logs. - tests: - - Context_Create_SilentFlag_SetsSilentProperty - - Context_WriteLine_Silent_DoesNotWriteToConsole - - Context_WriteError_Silent_DoesNotWriteToConsole + - id: BuildMark-Context-Silent + title: The Context class shall suppress console output when the silent flag is set. + justification: | + Enables automated scripts and CI/CD pipelines to run the tool without + cluttering output logs. + tests: + - Context_Create_SilentFlag_SetsSilentProperty + - Context_WriteLine_Silent_DoesNotWriteToConsole + - Context_WriteError_Silent_DoesNotWriteToConsole - - id: BuildMark-Context-ErrorOutput - title: The Context class 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. - tests: - - Context_WriteError_NotSilent_WritesToConsole - - Context_WriteError_SetsExitCodeToOne + - id: BuildMark-Context-ErrorOutput + title: The Context class 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. + tests: + - Context_WriteError_NotSilent_WritesToConsole + - Context_WriteError_SetsExitCodeToOne - - id: BuildMark-Context-ExitCode - title: The Context class shall track errors and expose a non-zero exit code when errors have occurred. - justification: | - Callers (scripts, CI/CD pipelines) must be able to detect failure conditions - programmatically via the process exit code. - tests: - - Context_ExitCode_NoErrors_RemainsZero - - Context_WriteError_SetsExitCodeToOne + - id: BuildMark-Context-ExitCode + title: The Context class shall track errors and expose a non-zero exit code when errors have occurred. + justification: | + Callers (scripts, CI/CD pipelines) must be able to detect failure conditions + programmatically via the process exit code. + tests: + - Context_ExitCode_NoErrors_RemainsZero + - Context_WriteError_SetsExitCodeToOne diff --git a/docs/reqstream/build-mark/configuration.yaml b/docs/reqstream/build-mark/configuration.yaml index db36434..d5465ff 100644 --- a/docs/reqstream/build-mark/configuration.yaml +++ b/docs/reqstream/build-mark/configuration.yaml @@ -1,229 +1,223 @@ --- -# Configuration Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark Configuration subsystem -# - The Configuration subsystem spans BuildMarkConfig.cs, BuildMarkConfigReader.cs, -# ConfigurationLoadResult.cs, ConfigurationIssue.cs, ConnectorConfig.cs, -# GitHubConnectorConfig.cs, AzureDevOpsConnectorConfig.cs, SectionConfig.cs, -# and RuleConfig.cs -# - Subsystem requirements describe the externally visible configuration behavior +# Configuration subsystem requirements sections: - - title: Configuration Subsystem Requirements - requirements: - - id: BuildMark-Configuration-Read - title: >- - The Configuration subsystem shall read the optional .buildmark.yaml file and - return a ConfigurationLoadResult. - justification: | - The subsystem must always return a result object regardless of whether the - file is present or malformed, so that callers can inspect issues without - special-casing null returns. - tests: - - Configuration_ReadAsync_ValidFile_ReturnsConfiguration - - Configuration_ReadAsync_MissingFile_ReturnsEmptyResult - - Configuration_ReadAsync_MalformedFile_ReportsError - children: - - BuildMark-ConfigReader-ReadAsync - - BuildMark-ConfigReader-MissingFile - - BuildMark-ConfigReader-MalformedFile - - - id: BuildMark-Configuration-Issues - title: >- - The Configuration subsystem shall surface parse errors and validation warnings - through ConfigurationLoadResult with location, severity, and description. - justification: | - Providing structured issue reports with file path, line number, severity, and - description allows the tool to give precise, actionable feedback when a - configuration file contains errors. - tests: - - Configuration_Issues_ErrorIssue_SetsExitCode - - Configuration_Issues_WarningIssue_DoesNotSetExitCode - - Configuration_Issues_ValidationError_ReportsAccurateLine - children: - - BuildMark-ConfigLoadResult-ReportTo - - - id: BuildMark-Configuration-ConnectorConfig - title: The Configuration subsystem shall deserialize the connector envelope and connector-specific settings. - justification: | - The ConnectorConfig envelope carries a type discriminator and per-connector - settings objects (GitHubConnectorConfig, AzureDevOpsConnectorConfig). Correct - deserialization ensures the factory receives the right settings for the - selected connector. - tests: - - Configuration_ConnectorConfig_ValidFile_ParsesConnectorSettings - - Configuration_ConnectorConfig_ValidFile_ParsesAzureDevOpsSettings - children: - - BuildMark-GitHubConnectorConfig-Properties - - BuildMark-AzureDevOpsConnectorConfig-Properties - - - title: BuildMarkConfigReader Unit Requirements - requirements: - - id: BuildMark-ConfigReader-ReadAsync - title: >- - BuildMarkConfigReader shall always return a configuration load result regardless - of whether the file is present or contains parse errors. - justification: | - Callers must always receive a result object rather than null or an exception - so that subsequent steps (issue reporting, connector creation) are uniform - regardless of file presence or parse errors. - tests: - - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - - - id: BuildMark-ConfigReader-MissingFile - title: >- - BuildMarkConfigReader shall return an empty configuration result when - the .buildmark.yaml file is absent. - justification: | - An absent configuration file is the normal case for repositories that have - not yet adopted .buildmark.yaml. The tool must continue working with defaults. - tests: - - BuildMarkConfigReader_ReadAsync_MissingFile_ReturnsEmptyResult - - - id: BuildMark-ConfigReader-MalformedFile - title: >- - BuildMarkConfigReader shall return an error result with actionable messages - when the configuration file cannot be parsed. - justification: | - A malformed configuration file should produce actionable error messages rather - than a silent failure or an unhandled exception. - tests: - - BuildMarkConfigReader_ReadAsync_MalformedFile_ReturnsErrorIssue - - - title: ConfigurationLoadResult Unit Requirements - requirements: - - id: BuildMark-ConfigLoadResult-ReportTo - title: >- - ConfigurationLoadResult shall report all configuration issues to the user - and signal an error exit code when any issue has error severity. - justification: | - Centralizing issue reporting in the result object ensures consistent - formatting and exit-code behavior across both the --lint path and the - normal build path. - tests: - - ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode - - - title: GitHubConnectorConfig Unit Requirements - requirements: - - id: BuildMark-GitHubConnectorConfig-Properties - title: >- - GitHubConnectorConfig shall expose Owner, Repo, and BaseUrl properties that - override the corresponding auto-detected values in GitHubRepoConnector. - justification: | - Teams using GitHub Enterprise or repositories where auto-detection is unreliable - need a way to specify the owner, repository name, and API base URL explicitly - in the configuration file. - tests: - - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - - - id: BuildMark-GitHubConnectorConfig-TokenVariable - title: >- - GitHubConnectorConfig shall expose a TokenVariable property that specifies the - name of the environment variable holding the GitHub access token. - justification: | - Teams that store their GitHub access token in a non-standard environment variable - need a way to tell the connector which variable to read. When TokenVariable is set, - the connector must use only that variable and must not fall back to well-known names - or the gh CLI, so that the operator retains full control over credential sourcing. - tests: - - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable - - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException - - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException - - - title: AzureDevOpsConnectorConfig Unit Requirements - requirements: - - id: BuildMark-AzureDevOpsConnectorConfig-Properties - title: >- - AzureDevOpsConnectorConfig shall expose OrganizationUrl, Organization, Project, and - Repository properties that override the corresponding auto-detected - values in AzureDevOpsRepoConnector. - justification: | - Teams using Azure DevOps where auto-detection from the Git remote URL is - unreliable need a way to specify the organization URL, optional organization - name, project, and repository name explicitly in the configuration file. - tests: - - BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration - - - id: BuildMark-AzureDevOpsConnectorConfig-TokenVariable - title: >- - AzureDevOpsConnectorConfig shall expose a TokenVariable property that specifies - the name of the environment variable holding the Azure DevOps access token. - justification: | - Teams that store their Azure DevOps access token in a non-standard environment - variable need a way to tell the connector which variable to read. When TokenVariable - is set, the connector must use only that variable and must not fall back to well-known - names or the az CLI, so that the operator retains full control over credential sourcing. - tests: - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException - - - title: ReportConfig Unit Requirements - requirements: - - id: BuildMark-ReportConfig-Properties - title: >- - ReportConfig shall expose File, Depth, and IncludeKnownIssues properties - that override the corresponding default report output settings. - justification: | - Teams that want to control the report output file path, heading depth, or - inclusion of known issues need a way to specify these settings explicitly - in the configuration file via the report: key. - tests: - - BuildMarkConfigReader_ReadAsync_ValidReportSection_ReturnsParsedReportConfig - - BuildMarkConfigReader_ReadAsync_InvalidReportDepth_ReturnsErrorIssue - - - title: ConnectorConfig Unit Requirements - requirements: - - id: BuildMark-ConnectorConfig-Properties - title: >- - ConnectorConfig shall expose Type, GitHub, and AzureDevOps properties - that select and configure the active repository connector. - justification: | - The ConnectorConfig envelope carries a type discriminator and per-connector - settings so the factory can instantiate and configure the correct connector - without inspecting multiple top-level keys. - tests: - - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - - BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration - - - title: ConfigurationIssue Unit Requirements - requirements: - - id: BuildMark-ConfigurationIssue-Record - title: >- - ConfigurationIssue shall record the file path, line number, severity, - and description of a single configuration parse or validation problem. - justification: | - Structured issue records allow the tool to report precise, actionable - feedback about configuration problems without losing location context - when multiple issues are present in the same file. - tests: - - ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode - - ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode - - ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber - - - title: SectionConfig Unit Requirements - requirements: - - id: BuildMark-SectionConfig-Properties - title: >- - SectionConfig shall expose Id and Title properties that define one - named report section for item routing. - justification: | - Report sections must have a stable machine-readable identifier (Id) for - routing rules to reference and a human-readable display title for the - generated markdown output. - tests: - - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection - - - title: RuleConfig Unit Requirements - requirements: - - id: BuildMark-RuleConfig-Properties - title: >- - RuleConfig shall expose Match and Route properties that define one - item-routing rule for the ItemRouter. - justification: | - Routing rules must specify match conditions (label or work-item type) - and a destination section identifier so that ItemRouter can correctly - categorize items without embedding routing logic in connector code. - tests: - - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection + - title: BuildMark Requirements + sections: + - title: Configuration Requirements + requirements: + - id: BuildMark-Configuration-Read + title: >- + The Configuration subsystem shall read the optional .buildmark.yaml file and + return a ConfigurationLoadResult. + justification: | + The subsystem must always return a result object regardless of whether the + file is present or malformed, so that callers can inspect issues without + special-casing null returns. + tests: + - Configuration_ReadAsync_ValidFile_ReturnsConfiguration + - Configuration_ReadAsync_MissingFile_ReturnsEmptyResult + - Configuration_ReadAsync_MalformedFile_ReportsError + children: + - BuildMark-ConfigReader-ReadAsync + - BuildMark-ConfigReader-MissingFile + - BuildMark-ConfigReader-MalformedFile + + - id: BuildMark-Configuration-Issues + title: >- + The Configuration subsystem shall surface parse errors and validation warnings + through ConfigurationLoadResult with location, severity, and description. + justification: | + Providing structured issue reports with file path, line number, severity, and + description allows the tool to give precise, actionable feedback when a + configuration file contains errors. + tests: + - Configuration_Issues_ErrorIssue_SetsExitCode + - Configuration_Issues_WarningIssue_DoesNotSetExitCode + - Configuration_Issues_ValidationError_ReportsAccurateLine + children: + - BuildMark-ConfigLoadResult-ReportTo + + - id: BuildMark-Configuration-ConnectorConfig + title: The Configuration subsystem shall deserialize the connector envelope and connector-specific settings. + justification: | + The ConnectorConfig envelope carries a type discriminator and per-connector + settings objects (GitHubConnectorConfig, AzureDevOpsConnectorConfig). Correct + deserialization ensures the factory receives the right settings for the + selected connector. + tests: + - Configuration_ConnectorConfig_ValidFile_ParsesConnectorSettings + - Configuration_ConnectorConfig_ValidFile_ParsesAzureDevOpsSettings + children: + - BuildMark-GitHubConnectorConfig-Properties + - BuildMark-AzureDevOpsConnectorConfig-Properties + sections: + - title: BuildMarkConfigReader Requirements + requirements: + - id: BuildMark-ConfigReader-ReadAsync + title: >- + BuildMarkConfigReader shall always return a configuration load result regardless + of whether the file is present or contains parse errors. + justification: | + Callers must always receive a result object rather than null or an exception + so that subsequent steps (issue reporting, connector creation) are uniform + regardless of file presence or parse errors. + tests: + - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration + + - id: BuildMark-ConfigReader-MissingFile + title: >- + BuildMarkConfigReader shall return an empty configuration result when + the .buildmark.yaml file is absent. + justification: | + An absent configuration file is the normal case for repositories that have + not yet adopted .buildmark.yaml. The tool must continue working with defaults. + tests: + - BuildMarkConfigReader_ReadAsync_MissingFile_ReturnsEmptyResult + + - id: BuildMark-ConfigReader-MalformedFile + title: >- + BuildMarkConfigReader shall return an error result with actionable messages + when the configuration file cannot be parsed. + justification: | + A malformed configuration file should produce actionable error messages rather + than a silent failure or an unhandled exception. + tests: + - BuildMarkConfigReader_ReadAsync_MalformedFile_ReturnsErrorIssue + + - title: ConfigurationLoadResult Requirements + requirements: + - id: BuildMark-ConfigLoadResult-ReportTo + title: >- + ConfigurationLoadResult shall report all configuration issues to the user + and signal an error exit code when any issue has error severity. + justification: | + Centralizing issue reporting in the result object ensures consistent + formatting and exit-code behavior across both the --lint path and the + normal build path. + tests: + - ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode + + - title: GitHubConnectorConfig Requirements + requirements: + - id: BuildMark-GitHubConnectorConfig-Properties + title: >- + GitHubConnectorConfig shall expose Owner, Repo, and BaseUrl properties that + override the corresponding auto-detected values in GitHubRepoConnector. + justification: | + Teams using GitHub Enterprise or repositories where auto-detection is unreliable + need a way to specify the owner, repository name, and API base URL explicitly + in the configuration file. + tests: + - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration + + - id: BuildMark-GitHubConnectorConfig-TokenVariable + title: >- + GitHubConnectorConfig shall expose a TokenVariable property that specifies the + name of the environment variable holding the GitHub access token. + justification: | + Teams that store their GitHub access token in a non-standard environment variable + need a way to tell the connector which variable to read. When TokenVariable is set, + the connector must use only that variable and must not fall back to well-known names + or the gh CLI, so that the operator retains full control over credential sourcing. + tests: + - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable + - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException + - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException + + - title: AzureDevOpsConnectorConfig Requirements + requirements: + - id: BuildMark-AzureDevOpsConnectorConfig-Properties + title: >- + AzureDevOpsConnectorConfig shall expose OrganizationUrl, Organization, Project, and + Repository properties that override the corresponding auto-detected + values in AzureDevOpsRepoConnector. + justification: | + Teams using Azure DevOps where auto-detection from the Git remote URL is + unreliable need a way to specify the organization URL, optional organization + name, project, and repository name explicitly in the configuration file. + tests: + - BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration + + - id: BuildMark-AzureDevOpsConnectorConfig-TokenVariable + title: >- + AzureDevOpsConnectorConfig shall expose a TokenVariable property that specifies + the name of the environment variable holding the Azure DevOps access token. + justification: | + Teams that store their Azure DevOps access token in a non-standard environment + variable need a way to tell the connector which variable to read. When TokenVariable + is set, the connector must use only that variable and must not fall back to well-known + names or the az CLI, so that the operator retains full control over credential sourcing. + tests: + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException + + - title: ReportConfig Requirements + requirements: + - id: BuildMark-ReportConfig-Properties + title: >- + ReportConfig shall expose File, Depth, and IncludeKnownIssues properties + that override the corresponding default report output settings. + justification: | + Teams that want to control the report output file path, heading depth, or + inclusion of known issues need a way to specify these settings explicitly + in the configuration file via the report: key. + tests: + - BuildMarkConfigReader_ReadAsync_ValidReportSection_ReturnsParsedReportConfig + - BuildMarkConfigReader_ReadAsync_InvalidReportDepth_ReturnsErrorIssue + + - title: ConnectorConfig Requirements + requirements: + - id: BuildMark-ConnectorConfig-Properties + title: >- + ConnectorConfig shall expose Type, GitHub, and AzureDevOps properties + that select and configure the active repository connector. + justification: | + The ConnectorConfig envelope carries a type discriminator and per-connector + settings so the factory can instantiate and configure the correct connector + without inspecting multiple top-level keys. + tests: + - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration + - BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration + + - title: ConfigurationIssue Requirements + requirements: + - id: BuildMark-ConfigurationIssue-Record + title: >- + ConfigurationIssue shall record the file path, line number, severity, + and description of a single configuration parse or validation problem. + justification: | + Structured issue records allow the tool to report precise, actionable + feedback about configuration problems without losing location context + when multiple issues are present in the same file. + tests: + - ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode + - ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode + - ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber + + - title: SectionConfig Requirements + requirements: + - id: BuildMark-SectionConfig-Properties + title: >- + SectionConfig shall expose Id and Title properties that define one + named report section for item routing. + justification: | + Report sections must have a stable machine-readable identifier (Id) for + routing rules to reference and a human-readable display title for the + generated markdown output. + tests: + - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection + + - title: RuleConfig Requirements + requirements: + - id: BuildMark-RuleConfig-Properties + title: >- + RuleConfig shall expose Match and Route properties that define one + item-routing rule for the ItemRouter. + justification: | + Routing rules must specify match conditions (label or work-item type) + and a destination section identifier so that ItemRouter can correctly + categorize items without embedding routing logic in connector code. + tests: + - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection diff --git a/docs/reqstream/build-mark/platform-requirements.yaml b/docs/reqstream/build-mark/platform-requirements.yaml index b921f84..662ec47 100644 --- a/docs/reqstream/build-mark/platform-requirements.yaml +++ b/docs/reqstream/build-mark/platform-requirements.yaml @@ -1,96 +1,99 @@ --- +# BuildMark platform requirements sections: - - title: Platform Support - requirements: - - id: BuildMark-Plt-Windows - title: The tool shall run on Windows operating systems. - justification: | - Windows support is essential for .NET developers working in Windows-centric - environments, including enterprise settings and teams using Visual Studio. This - ensures BuildMark serves the full spectrum of .NET development scenarios. - # Test source pattern "windows@" ensures these tests ran on Windows. - # This filtering is necessary to prove Windows OS functionality. - tests: - - windows@BuildMark_VersionFlag_OutputsVersion - - windows@BuildMark_HelpFlag_OutputsUsageInformation - - windows@BuildMark_ReportParameter_IsAccepted - - windows@BuildMark_MarkdownReportGeneration - - windows@BuildMark_GitIntegration - - windows@BuildMark_IssueTracking - - windows@BuildMark_KnownIssuesReporting + - title: BuildMark Requirements + sections: + - title: Platform Support + requirements: + - id: BuildMark-Plt-Windows + title: The tool shall run on Windows operating systems. + justification: | + Windows support is essential for .NET developers working in Windows-centric + environments, including enterprise settings and teams using Visual Studio. This + ensures BuildMark serves the full spectrum of .NET development scenarios. + # Test source pattern "windows@" ensures these tests ran on Windows. + # This filtering is necessary to prove Windows OS functionality. + tests: + - windows@BuildMark_VersionFlag_OutputsVersion + - windows@BuildMark_HelpFlag_OutputsUsageInformation + - windows@BuildMark_ReportParameter_IsAccepted + - windows@BuildMark_MarkdownReportGeneration + - windows@BuildMark_GitIntegration + - windows@BuildMark_IssueTracking + - windows@BuildMark_KnownIssuesReporting - - id: BuildMark-Plt-Linux - title: The tool shall run on Linux operating systems. - justification: | - Linux support is critical for modern DevOps practices and cloud-native development - where Linux-based CI/CD systems and containerized environments dominate. This - ensures BuildMark works seamlessly in contemporary .NET deployment scenarios. - # Test source pattern "ubuntu@" ensures these tests ran on Linux. - # This filtering is necessary to prove Linux OS functionality. - tests: - - ubuntu@BuildMark_VersionFlag_OutputsVersion - - ubuntu@BuildMark_HelpFlag_OutputsUsageInformation - - ubuntu@BuildMark_ReportParameter_IsAccepted - - ubuntu@BuildMark_MarkdownReportGeneration - - ubuntu@BuildMark_GitIntegration - - ubuntu@BuildMark_IssueTracking - - ubuntu@BuildMark_KnownIssuesReporting + - id: BuildMark-Plt-Linux + title: The tool shall run on Linux operating systems. + justification: | + Linux support is critical for modern DevOps practices and cloud-native development + where Linux-based CI/CD systems and containerized environments dominate. This + ensures BuildMark works seamlessly in contemporary .NET deployment scenarios. + # Test source pattern "ubuntu@" ensures these tests ran on Linux. + # This filtering is necessary to prove Linux OS functionality. + tests: + - ubuntu@BuildMark_VersionFlag_OutputsVersion + - ubuntu@BuildMark_HelpFlag_OutputsUsageInformation + - ubuntu@BuildMark_ReportParameter_IsAccepted + - ubuntu@BuildMark_MarkdownReportGeneration + - ubuntu@BuildMark_GitIntegration + - ubuntu@BuildMark_IssueTracking + - ubuntu@BuildMark_KnownIssuesReporting - - id: BuildMark-Plt-MacOS - title: The tool shall run on macOS operating systems. - justification: | - macOS support is essential for developers working on Apple platforms. This ensures - BuildMark serves the full spectrum of .NET development scenarios including macOS-based - CI/CD agents and developer workstations. - # Test source pattern "macos@" ensures these tests ran on macOS. - # This filtering is necessary to prove macOS functionality. - tests: - - macos@BuildMark_VersionFlag_OutputsVersion - - macos@BuildMark_HelpFlag_OutputsUsageInformation - - macos@BuildMark_ReportParameter_IsAccepted - - macos@BuildMark_MarkdownReportGeneration - - macos@BuildMark_GitIntegration - - macos@BuildMark_IssueTracking - - macos@BuildMark_KnownIssuesReporting + - id: BuildMark-Plt-MacOS + title: The tool shall run on macOS operating systems. + justification: | + macOS support is essential for developers working on Apple platforms. This ensures + BuildMark serves the full spectrum of .NET development scenarios including macOS-based + CI/CD agents and developer workstations. + # Test source pattern "macos@" ensures these tests ran on macOS. + # This filtering is necessary to prove macOS functionality. + tests: + - macos@BuildMark_VersionFlag_OutputsVersion + - macos@BuildMark_HelpFlag_OutputsUsageInformation + - macos@BuildMark_ReportParameter_IsAccepted + - macos@BuildMark_MarkdownReportGeneration + - macos@BuildMark_GitIntegration + - macos@BuildMark_IssueTracking + - macos@BuildMark_KnownIssuesReporting - - id: BuildMark-Plt-Net8 - title: The tool shall support .NET 8.0 runtime. - justification: | - .NET 8.0 is a Long-Term Support (LTS) release with support through November 2026. - Supporting this version ensures BuildMark remains usable for organizations following - Microsoft's LTS support lifecycle and requiring stability guarantees. - # Test source pattern "dotnet8.x@" ensures these tests ran on .NET 8.0. - # This filtering is necessary to prove .NET 8.0 runtime support. - tests: - - dotnet8.x@BuildMark_MarkdownReportGeneration - - dotnet8.x@BuildMark_GitIntegration - - dotnet8.x@BuildMark_IssueTracking - - dotnet8.x@BuildMark_KnownIssuesReporting + - id: BuildMark-Plt-Net8 + title: The tool shall support .NET 8.0 runtime. + justification: | + .NET 8.0 is a Long-Term Support (LTS) release with support through November 2026. + Supporting this version ensures BuildMark remains usable for organizations following + Microsoft's LTS support lifecycle and requiring stability guarantees. + # Test source pattern "dotnet8.x@" ensures these tests ran on .NET 8.0. + # This filtering is necessary to prove .NET 8.0 runtime support. + tests: + - dotnet8.x@BuildMark_MarkdownReportGeneration + - dotnet8.x@BuildMark_GitIntegration + - dotnet8.x@BuildMark_IssueTracking + - dotnet8.x@BuildMark_KnownIssuesReporting - - id: BuildMark-Plt-Net9 - title: The tool shall support .NET 9.0 runtime. - justification: | - .NET 9.0 is a Standard Term Support (STS) release with support through May 2026. - Supporting this version provides users access to the latest .NET features and - performance improvements for teams who prefer newer releases. - # Test source pattern "dotnet9.x@" ensures these tests ran on .NET 9.0. - # This filtering is necessary to prove .NET 9.0 runtime support. - tests: - - dotnet9.x@BuildMark_MarkdownReportGeneration - - dotnet9.x@BuildMark_GitIntegration - - dotnet9.x@BuildMark_IssueTracking - - dotnet9.x@BuildMark_KnownIssuesReporting + - id: BuildMark-Plt-Net9 + title: The tool shall support .NET 9.0 runtime. + justification: | + .NET 9.0 is a Standard Term Support (STS) release with support through May 2026. + Supporting this version provides users access to the latest .NET features and + performance improvements for teams who prefer newer releases. + # Test source pattern "dotnet9.x@" ensures these tests ran on .NET 9.0. + # This filtering is necessary to prove .NET 9.0 runtime support. + tests: + - dotnet9.x@BuildMark_MarkdownReportGeneration + - dotnet9.x@BuildMark_GitIntegration + - dotnet9.x@BuildMark_IssueTracking + - dotnet9.x@BuildMark_KnownIssuesReporting - - id: BuildMark-Plt-Net10 - title: The tool shall support .NET 10.0 runtime. - justification: | - .NET 10.0 is the next Long-Term Support (LTS) release planned for November 2025. - Early support ensures BuildMark remains current as users transition to this new - LTS version and provides forward compatibility guarantees. - # Test source pattern "dotnet10.x@" ensures these tests ran on .NET 10.0. - # This filtering is necessary to prove .NET 10.0 runtime support. - tests: - - dotnet10.x@BuildMark_MarkdownReportGeneration - - dotnet10.x@BuildMark_GitIntegration - - dotnet10.x@BuildMark_IssueTracking - - dotnet10.x@BuildMark_KnownIssuesReporting + - id: BuildMark-Plt-Net10 + title: The tool shall support .NET 10.0 runtime. + justification: | + .NET 10.0 is the next Long-Term Support (LTS) release planned for November 2025. + Early support ensures BuildMark remains current as users transition to this new + LTS version and provides forward compatibility guarantees. + # Test source pattern "dotnet10.x@" ensures these tests ran on .NET 10.0. + # This filtering is necessary to prove .NET 10.0 runtime support. + tests: + - dotnet10.x@BuildMark_MarkdownReportGeneration + - dotnet10.x@BuildMark_GitIntegration + - dotnet10.x@BuildMark_IssueTracking + - dotnet10.x@BuildMark_KnownIssuesReporting diff --git a/docs/reqstream/build-mark/program.yaml b/docs/reqstream/build-mark/program.yaml index e7a59b1..125d1db 100644 --- a/docs/reqstream/build-mark/program.yaml +++ b/docs/reqstream/build-mark/program.yaml @@ -1,126 +1,123 @@ --- -# Software Unit Requirements for the Program Class -# -# The Program class is the main entry point for BuildMark. It creates a Context -# from command-line arguments, dispatches to the appropriate logic based on the -# flags (version, help, validate, report), and returns the exit code. - +# BuildMark Program unit requirements sections: - - title: Program Unit Requirements - requirements: - - id: BuildMark-Program-Version - title: The Program class shall support -v and --version flags to display version information. - justification: | - Users need to quickly identify the version of the tool they are using for - troubleshooting and compatibility verification. - tests: - - Program_Run_VersionFlag_OutputsVersionToConsole - - Program_Version_ReturnsValidVersion + - title: BuildMark Requirements + sections: + - title: Program Requirements + requirements: + - id: BuildMark-Program-Version + title: The Program class shall support -v and --version flags to display version information. + justification: | + Users need to quickly identify the version of the tool they are using for + troubleshooting and compatibility verification. + tests: + - Program_Run_VersionFlag_OutputsVersionToConsole + - Program_Version_ReturnsValidVersion - - id: BuildMark-Program-Help - title: The Program class shall support -?, -h, and --help flags to display usage information. - justification: | - Users need access to command-line usage documentation without requiring - external resources. - tests: - - Program_Run_HelpFlag_OutputsHelpMessage - - Program_Run_QuestionMarkFlag_OutputsHelpMessage - - Program_Run_LongHelpFlag_OutputsHelpMessage + - id: BuildMark-Program-Help + title: The Program class shall support -?, -h, and --help flags to display usage information. + justification: | + Users need access to command-line usage documentation without requiring + external resources. + tests: + - Program_Run_HelpFlag_OutputsHelpMessage + - Program_Run_QuestionMarkFlag_OutputsHelpMessage + - Program_Run_LongHelpFlag_OutputsHelpMessage - - id: BuildMark-Program-Validate - title: The Program class shall support --validate flag to invoke the self-validation framework. - justification: | - Provides a built-in mechanism to verify the tool is functioning correctly - in the deployment environment. - tests: - - Program_Run_ValidateFlag_OutputsValidationMessage + - id: BuildMark-Program-Validate + title: The Program class shall support --validate flag to invoke the self-validation framework. + justification: | + Provides a built-in mechanism to verify the tool is functioning correctly + in the deployment environment. + tests: + - Program_Run_ValidateFlag_OutputsValidationMessage - - id: BuildMark-Program-Lint - title: The Program class shall support a --lint flag to validate the .buildmark.yaml configuration file. - justification: | - Operators need a quick way to verify that the configuration file is well-formed - without running a full build. The --lint flag reads and validates .buildmark.yaml, - reports any issues to the user, and exits without generating a report. - tests: - - Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero + - id: BuildMark-Program-Lint + title: The Program class shall support a --lint flag to validate the .buildmark.yaml configuration file. + justification: | + Operators need a quick way to verify that the configuration file is well-formed + without running a full build. The --lint flag reads and validates .buildmark.yaml, + reports any issues to the user, and exits without generating a report. + tests: + - Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero - - id: BuildMark-Program-Report - title: The Program class shall generate build notes markdown reports when --report is specified. - justification: | - Report generation is the primary purpose of the BuildMark tool. The Program - class orchestrates the repository connector, gathering of build information, - and generation of the output markdown report. - tests: - - Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues + - id: BuildMark-Program-Report + title: The Program class shall generate build notes markdown reports when --report is specified. + justification: | + Report generation is the primary purpose of the BuildMark tool. The Program + class orchestrates the repository connector, gathering of build information, + and generation of the output markdown report. + tests: + - Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues - - id: BuildMark-Program-Silent - title: The Program class shall support --silent flag to suppress console output during execution. - justification: | - Silent mode enables automated build pipelines to invoke BuildMark without - cluttering their output logs when only the exit code or report file is needed. - tests: - - Program_Run_WithSilentFlag_SuppressesOutput + - id: BuildMark-Program-Silent + title: The Program class shall support --silent flag to suppress console output during execution. + justification: | + Silent mode enables automated build pipelines to invoke BuildMark without + cluttering their output logs when only the exit code or report file is needed. + tests: + - Program_Run_WithSilentFlag_SuppressesOutput - - id: BuildMark-Program-Log - title: The Program class shall support --log flag to write execution output to a log file. - justification: | - Log file support enables persistent capture of BuildMark output for audit trails - and post-build analysis in automated environments. - tests: - - Program_Run_WithLogFlag_WritesToLogFile + - id: BuildMark-Program-Log + title: The Program class shall support --log flag to write execution output to a log file. + justification: | + Log file support enables persistent capture of BuildMark output for audit trails + and post-build analysis in automated environments. + tests: + - Program_Run_WithLogFlag_WritesToLogFile - - id: BuildMark-Program-Results - title: The Program class shall support --results flag to write validation results to a test results file. - justification: | - Writing results to standard test result formats (TRX or JUnit XML) enables - integration with CI/CD platforms that process test result files. - tests: - - Program_Run_WithResultsFlag_WritesResultsFile + - id: BuildMark-Program-Results + title: The Program class shall support --results flag to write validation results to a test results file. + justification: | + Writing results to standard test result formats (TRX or JUnit XML) enables + integration with CI/CD platforms that process test result files. + tests: + - Program_Run_WithResultsFlag_WritesResultsFile - - id: BuildMark-Program-BuildVersion - title: The Program class shall support --build-version flag to specify the version for report generation. - justification: | - Specifying the build version allows users to override or supplement version information - from source control, enabling flexible version management strategies. - tests: - - Program_Run_WithBuildVersionFlag_AcceptsBuildVersion + - id: BuildMark-Program-BuildVersion + title: The Program class shall support --build-version flag to specify the version for report generation. + justification: | + Specifying the build version allows users to override or supplement version information + from source control, enabling flexible version management strategies. + tests: + - Program_Run_WithBuildVersionFlag_AcceptsBuildVersion - - id: BuildMark-Program-Depth - title: The Program class shall support --depth flag to configure the markdown heading depth of the report. - justification: | - Configurable heading depth allows BuildMark reports to be embedded at any level - within a larger document without disrupting the document hierarchy. - tests: - - Program_Run_WithDepthFlag_SetsHeadingDepth + - id: BuildMark-Program-Depth + title: The Program class shall support --depth flag to configure the markdown heading depth of the report. + justification: | + Configurable heading depth allows BuildMark reports to be embedded at any level + within a larger document without disrupting the document hierarchy. + tests: + - Program_Run_WithDepthFlag_SetsHeadingDepth - - id: BuildMark-Program-IncludeKnownIssues - title: >- - The Program class shall support --include-known-issues flag to include known - issues in the generated build notes report. - justification: | - Known-issue disclosure in release notes promotes transparency and helps users - avoid known pitfalls. The flag enables this optional section without affecting - the default report output. - tests: - - Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues + - id: BuildMark-Program-IncludeKnownIssues + title: >- + The Program class shall support --include-known-issues flag to include known + issues in the generated build notes report. + justification: | + Known-issue disclosure in release notes promotes transparency and helps users + avoid known pitfalls. The flag enables this optional section without affecting + the default report output. + tests: + - Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues - - id: BuildMark-Program-ErrorHandling-InvalidBuildVersion - title: >- - The Program class shall report an error and set exit code 1 when an invalid - build version is provided. - justification: | - Clear error reporting on invalid version inputs allows users and CI/CD pipelines - to detect and diagnose problems quickly without inspecting logs for root causes. - tests: - - Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode + - id: BuildMark-Program-ErrorHandling-InvalidBuildVersion + title: >- + The Program class shall report an error and set exit code 1 when an invalid + build version is provided. + justification: | + Clear error reporting on invalid version inputs allows users and CI/CD pipelines + to detect and diagnose problems quickly without inspecting logs for root causes. + tests: + - Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode - - id: BuildMark-Program-ErrorHandling-ConnectorFailure - title: >- - The Program class shall report an error and set exit code 1 when the repository - connector fails during data retrieval. - justification: | - Clear error reporting on connector failures allows users and CI/CD pipelines to - detect and diagnose integration problems quickly without inspecting logs for root - causes. - tests: - - Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode + - id: BuildMark-Program-ErrorHandling-ConnectorFailure + title: >- + The Program class shall report an error and set exit code 1 when the repository + connector fails during data retrieval. + justification: | + Clear error reporting on connector failures allows users and CI/CD pipelines to + detect and diagnose integration problems quickly without inspecting logs for root + causes. + tests: + - Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode diff --git a/docs/reqstream/build-mark/repo-connectors.yaml b/docs/reqstream/build-mark/repo-connectors.yaml index 71dd49f..88fb0b0 100644 --- a/docs/reqstream/build-mark/repo-connectors.yaml +++ b/docs/reqstream/build-mark/repo-connectors.yaml @@ -1,147 +1,142 @@ --- -# RepoConnectors Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark RepoConnectors subsystem -# - The RepoConnectors subsystem provides the common interface, base class, factory, -# item router, and item-controls parsing used by all connector implementations -# - Concrete connectors live in the GitHub and Mock subsystems beneath this one -# - Subsystem requirements describe the externally visible repository connector behavior +# RepoConnectors subsystem requirements sections: - - title: RepoConnectors Subsystem Requirements - requirements: - - id: BuildMark-RepoConnectors-ConnectorInterface - title: >- - The RepoConnectors subsystem shall provide a common interface for all repository connectors. - justification: | - A shared interface ensures that all connector implementations are interchangeable, - enabling the factory and program to work with any connector implementation - without depending on concrete types. - tests: - - RepoConnectors_ConnectorBase_MockConnector_ImplementsInterface - - RepoConnectors_ConnectorBase_GitHubConnector_ImplementsInterface - children: - - BuildMark-RepoConnectorBase-Interface - - BuildMark-RepoConnectorBase-RulesRouting - - BuildMark-RepoConnectorBase-FindVersionIndex + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + requirements: + - id: BuildMark-RepoConnectors-ConnectorInterface + title: >- + The RepoConnectors subsystem shall provide a common interface for all repository connectors. + justification: | + A shared interface ensures that all connector implementations are interchangeable, + enabling the factory and program to work with any connector implementation + without depending on concrete types. + tests: + - RepoConnectors_ConnectorBase_MockConnector_ImplementsInterface + - RepoConnectors_ConnectorBase_GitHubConnector_ImplementsInterface + children: + - BuildMark-RepoConnectorBase-Interface + - BuildMark-RepoConnectorBase-RulesRouting + - BuildMark-RepoConnectorBase-FindVersionIndex - - id: BuildMark-RepoConnectors-ProcessRunner - title: >- - The RepoConnectors subsystem shall provide a process execution utility for running shell commands. - justification: | - Repository connectors rely on shell commands (git, gh CLI) to retrieve repository - information. A shared process-runner utility centralizes subprocess management, - ensuring consistent command execution and output handling across all connector - implementations. - tests: - - RepoConnectors_ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput - - RepoConnectors_ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull - - RepoConnectors_ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull - - RepoConnectors_ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput - - RepoConnectors_ProcessRunner_RunAsync_WithFailingCommand_ThrowsException - children: - - BuildMark-RepoConnectorBase-CommandExecution + - id: BuildMark-RepoConnectors-ProcessRunner + title: >- + The RepoConnectors subsystem shall provide a process execution utility for running shell commands. + justification: | + Repository connectors rely on shell commands (git, gh CLI) to retrieve repository + information. A shared process-runner utility centralizes subprocess management, + ensuring consistent command execution and output handling across all connector + implementations. + tests: + - RepoConnectors_ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput + - RepoConnectors_ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull + - RepoConnectors_ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull + - RepoConnectors_ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput + - RepoConnectors_ProcessRunner_RunAsync_WithFailingCommand_ThrowsException + children: + - BuildMark-RepoConnectorBase-CommandExecution - - id: BuildMark-RepoConnectors-Factory - title: The RepoConnectors subsystem shall provide a factory for creating the appropriate repository connector. - justification: | - A factory simplifies connector creation and encapsulates the logic for selecting - the correct connector implementation, enabling future extensibility with additional - repository connector types. - tests: - - RepoConnectors_Factory_Create_ReturnsConnector - - RepoConnectors_Factory_Create_ReturnsGitHubConnectorForThisRepo - children: - - BuildMark-RepoConnectorFactory-Create - - BuildMark-RepoConnectorFactory-ConnectorConfig - - BuildMark-RepoConnectorFactory-AzureDevOpsDetection + - id: BuildMark-RepoConnectors-Factory + title: The RepoConnectors subsystem shall provide a factory for creating the appropriate repository connector. + justification: | + A factory simplifies connector creation and encapsulates the logic for selecting + the correct connector implementation, enabling future extensibility with additional + repository connector types. + tests: + - RepoConnectors_Factory_Create_ReturnsConnector + - RepoConnectors_Factory_Create_ReturnsGitHubConnectorForThisRepo + children: + - BuildMark-RepoConnectorFactory-Create + - BuildMark-RepoConnectorFactory-ConnectorConfig + - BuildMark-RepoConnectorFactory-AzureDevOpsDetection - - id: BuildMark-RepoConnectors-ItemRouter - title: >- - The RepoConnectors subsystem shall provide a shared item-routing utility - for assigning items to report sections. - justification: | - All connector implementations must route items (issues and pull requests) into - the correct report sections according to the configured section and rule definitions. - Centralizing this logic in a shared unit ensures consistent routing behavior - across the GitHub connector and any future connectors such as Azure DevOps. - tests: - - RepoConnectors_ItemRouter_MatchingRule_RoutesToSection - - RepoConnectors_ItemRouter_SuppressedRoute_OmitsItem - children: - - BuildMark-ItemRouter-Route + - id: BuildMark-RepoConnectors-ItemRouter + title: >- + The RepoConnectors subsystem shall provide a shared item-routing utility + for assigning items to report sections. + justification: | + All connector implementations must route items (issues and pull requests) into + the correct report sections according to the configured section and rule definitions. + Centralizing this logic in a shared unit ensures consistent routing behavior + across the GitHub connector and any future connectors such as Azure DevOps. + tests: + - RepoConnectors_ItemRouter_MatchingRule_RoutesToSection + - RepoConnectors_ItemRouter_SuppressedRoute_OmitsItem + children: + - BuildMark-ItemRouter-Route - - id: BuildMark-RepoConnectors-ItemControls - title: >- - The RepoConnectors subsystem shall parse a buildmark code block from a repository item - description and expose the extracted controls as a structured record. - justification: | - Connector implementations need to extract optional visibility, type, and - affected-version overrides from issue and pull request description bodies. - Centralizing this parsing logic within the RepoConnectors subsystem ensures - it is reusable by all connector implementations without duplication. - tests: - - RepoConnectors_ItemControls_VisibilityPublic_ReturnsPublicVisibility - - RepoConnectors_ItemControls_VisibilityInternal_ReturnsInternalVisibility - - RepoConnectors_ItemControls_TypeBug_ReturnsBugType - - RepoConnectors_ItemControls_TypeFeature_ReturnsFeatureType - - RepoConnectors_ItemControls_AffectedVersions_ReturnsIntervalSet - - RepoConnectors_ItemControls_HiddenBlock_ReturnsControls - - RepoConnectors_ItemControls_NoBlock_ReturnsNull - children: - - BuildMark-ItemControlsInfo-Record - - BuildMark-ItemControlsParser-Parse - - BuildMark-ItemControlsParser-HiddenBlock + - id: BuildMark-RepoConnectors-ItemControls + title: >- + The RepoConnectors subsystem shall parse a buildmark code block from a repository item + description and expose the extracted controls as a structured record. + justification: | + Connector implementations need to extract optional visibility, type, and + affected-version overrides from issue and pull request description bodies. + Centralizing this parsing logic within the RepoConnectors subsystem ensures + it is reusable by all connector implementations without duplication. + tests: + - RepoConnectors_ItemControls_VisibilityPublic_ReturnsPublicVisibility + - RepoConnectors_ItemControls_VisibilityInternal_ReturnsInternalVisibility + - RepoConnectors_ItemControls_TypeBug_ReturnsBugType + - RepoConnectors_ItemControls_TypeFeature_ReturnsFeatureType + - RepoConnectors_ItemControls_AffectedVersions_ReturnsIntervalSet + - RepoConnectors_ItemControls_HiddenBlock_ReturnsControls + - RepoConnectors_ItemControls_NoBlock_ReturnsNull + children: + - BuildMark-ItemControlsInfo-Record + - BuildMark-ItemControlsParser-Parse + - BuildMark-ItemControlsParser-HiddenBlock - - id: BuildMark-RepoConnectors-GitHub - title: >- - The RepoConnectors subsystem shall provide a GitHub repository connector - subsystem. - justification: | - Generating build notes from GitHub repositories requires a dedicated subsystem - that can authenticate to the GitHub API, retrieve commits, releases, tags, pull - requests, and issues, and assemble them into structured build information. - tests: - - RepoConnectors_GitHubConnector_ImplementsInterface_ReturnsTrue - - RepoConnectors_GitHubConnector_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation - - RepoConnectors_GitHubConnector_GetBuildInformation_WithMultipleVersions_SelectsCorrectBaseline - - RepoConnectors_GitHubConnector_GetBuildInformation_WithPullRequests_GathersChanges - - RepoConnectors_GitHubConnector_GetBuildInformation_WithOpenIssues_IdentifiesKnownIssues - - RepoConnectors_GitHubConnector_GetBuildInformation_ReleaseVersion_SkipsPreReleases - children: - - BuildMark-GitHub-SubSystem + - id: BuildMark-RepoConnectors-GitHub + title: >- + The RepoConnectors subsystem shall provide a GitHub repository connector + subsystem. + justification: | + Generating build notes from GitHub repositories requires a dedicated subsystem + that can authenticate to the GitHub API, retrieve commits, releases, tags, pull + requests, and issues, and assemble them into structured build information. + tests: + - RepoConnectors_GitHubConnector_ImplementsInterface_ReturnsTrue + - RepoConnectors_GitHubConnector_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation + - RepoConnectors_GitHubConnector_GetBuildInformation_WithMultipleVersions_SelectsCorrectBaseline + - RepoConnectors_GitHubConnector_GetBuildInformation_WithPullRequests_GathersChanges + - RepoConnectors_GitHubConnector_GetBuildInformation_WithOpenIssues_IdentifiesKnownIssues + - RepoConnectors_GitHubConnector_GetBuildInformation_ReleaseVersion_SkipsPreReleases + children: + - BuildMark-GitHub-SubSystem - - id: BuildMark-RepoConnectors-Mock - title: >- - The RepoConnectors subsystem shall provide a mock connector subsystem - for self-test and development. - justification: | - A mock connector subsystem enables the built-in --validate self-test and unit - testing of build information processing logic without requiring an actual - repository connection, ensuring tests are fast, deterministic, and independent - of external services. - tests: - - RepoConnectors_MockConnector_Constructor_CreatesInstance - - RepoConnectors_MockConnector_ImplementsInterface_ReturnsTrue - - RepoConnectors_MockConnector_GetBuildInformation_ReturnsExpectedVersion - - RepoConnectors_MockConnector_GetBuildInformation_ReturnsCompleteInformation - children: - - BuildMark-Mock-SubSystem + - id: BuildMark-RepoConnectors-Mock + title: >- + The RepoConnectors subsystem shall provide a mock connector subsystem + for self-test and development. + justification: | + A mock connector subsystem enables the built-in --validate self-test and unit + testing of build information processing logic without requiring an actual + repository connection, ensuring tests are fast, deterministic, and independent + of external services. + tests: + - RepoConnectors_MockConnector_Constructor_CreatesInstance + - RepoConnectors_MockConnector_ImplementsInterface_ReturnsTrue + - RepoConnectors_MockConnector_GetBuildInformation_ReturnsExpectedVersion + - RepoConnectors_MockConnector_GetBuildInformation_ReturnsCompleteInformation + children: + - BuildMark-Mock-SubSystem - - id: BuildMark-RepoConnectors-AzureDevOps - title: >- - The RepoConnectors subsystem shall provide an Azure DevOps repository connector - subsystem. - justification: | - Generating build notes from Azure DevOps repositories requires a dedicated subsystem - that can authenticate to the Azure DevOps REST API, retrieve commits, tags, pull - requests, and work items, and assemble them into structured build information. - tests: - - RepoConnectors_AzureDevOps_ImplementsInterface_ReturnsTrue - - RepoConnectors_AzureDevOps_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation - - RepoConnectors_AzureDevOps_GetBuildInformation_WithPullRequests_GathersChanges - - RepoConnectors_AzureDevOps_GetBuildInformation_WithOpenWorkItems_IdentifiesKnownIssues - - RepoConnectors_AzureDevOps_GetBuildInformation_ReleaseVersion_SkipsPreReleases - children: - - BuildMark-AzureDevOps-SubSystem + - id: BuildMark-RepoConnectors-AzureDevOps + title: >- + The RepoConnectors subsystem shall provide an Azure DevOps repository connector + subsystem. + justification: | + Generating build notes from Azure DevOps repositories requires a dedicated subsystem + that can authenticate to the Azure DevOps REST API, retrieve commits, tags, pull + requests, and work items, and assemble them into structured build information. + tests: + - RepoConnectors_AzureDevOps_ImplementsInterface_ReturnsTrue + - RepoConnectors_AzureDevOps_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation + - RepoConnectors_AzureDevOps_GetBuildInformation_WithPullRequests_GathersChanges + - RepoConnectors_AzureDevOps_GetBuildInformation_WithOpenWorkItems_IdentifiesKnownIssues + - RepoConnectors_AzureDevOps_GetBuildInformation_ReleaseVersion_SkipsPreReleases + children: + - BuildMark-AzureDevOps-SubSystem diff --git a/docs/reqstream/build-mark/repo-connectors/azure-devops.yaml b/docs/reqstream/build-mark/repo-connectors/azure-devops.yaml index 3b6c14a..2a02b90 100644 --- a/docs/reqstream/build-mark/repo-connectors/azure-devops.yaml +++ b/docs/reqstream/build-mark/repo-connectors/azure-devops.yaml @@ -1,38 +1,35 @@ --- -# AzureDevOps Sub-Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark AzureDevOps sub-subsystem -# - The AzureDevOps sub-subsystem provides the production connector used when -# the repository host is Azure DevOps (cloud or on-premises) -# - Sub-subsystem requirements describe the externally visible contract -# satisfied by the units beneath this sub-subsystem +# AzureDevOps subsystem requirements sections: - - title: AzureDevOps Sub-Subsystem Requirements - requirements: - - id: BuildMark-AzureDevOps-SubSystem - title: >- - The AzureDevOps sub-subsystem shall implement the IRepoConnector interface - for Azure DevOps repositories. - justification: | - Generating build notes from Azure DevOps repositories requires a dedicated sub-subsystem - that can authenticate to the Azure DevOps REST API, retrieve commits, tags, pull - requests, and work items, apply item-controls overrides from buildmark blocks and - custom fields, and assemble them into structured build information. - tests: - - AzureDevOps_IRepoConnector_ConnectorInstance_ImplementsInterface - - AzureDevOps_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation - - AzureDevOps_GetBuildInformation_WithPullRequests_GathersChanges - - AzureDevOps_GetBuildInformation_WithOpenWorkItems_IdentifiesKnownIssues - - AzureDevOps_GetBuildInformation_ReleaseVersion_SkipsPreReleases - children: - - BuildMark-AzureDevOps-UrlParsing - - BuildMark-AzureDevOps-ConnectorConfig - - BuildMark-AzureDevOps-BuildInformation - - BuildMark-AzureDevOps-ItemControls - - BuildMark-AzureDevOps-CustomFields - - BuildMark-AzureDevOps-Rules - - BuildMark-AzureDevOps-RestClient - - BuildMark-AzureDevOps-WorkItemMapper - - BuildMark-AzureDevOps-TokenVariable + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: AzureDevOps Requirements + requirements: + - id: BuildMark-AzureDevOps-SubSystem + title: >- + The AzureDevOps sub-subsystem shall implement the IRepoConnector interface + for Azure DevOps repositories. + justification: | + Generating build notes from Azure DevOps repositories requires a dedicated sub-subsystem + that can authenticate to the Azure DevOps REST API, retrieve commits, tags, pull + requests, and work items, apply item-controls overrides from buildmark blocks and + custom fields, and assemble them into structured build information. + tests: + - AzureDevOps_IRepoConnector_ConnectorInstance_ImplementsInterface + - AzureDevOps_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation + - AzureDevOps_GetBuildInformation_WithPullRequests_GathersChanges + - AzureDevOps_GetBuildInformation_WithOpenWorkItems_IdentifiesKnownIssues + - AzureDevOps_GetBuildInformation_ReleaseVersion_SkipsPreReleases + children: + - BuildMark-AzureDevOps-UrlParsing + - BuildMark-AzureDevOps-ConnectorConfig + - BuildMark-AzureDevOps-BuildInformation + - BuildMark-AzureDevOps-ItemControls + - BuildMark-AzureDevOps-CustomFields + - BuildMark-AzureDevOps-Rules + - BuildMark-AzureDevOps-RestClient + - BuildMark-AzureDevOps-WorkItemMapper + - BuildMark-AzureDevOps-TokenVariable diff --git a/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.yaml b/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.yaml index 8f4a9d6..0e8bfdc 100644 --- a/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.yaml +++ b/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.yaml @@ -1,106 +1,104 @@ --- -# Software Unit Requirements for the AzureDevOpsRepoConnector Class -# -# The AzureDevOpsRepoConnector class connects to Azure DevOps using the REST API -# to retrieve commits, tags, pull requests, and work items, assembling them into -# structured BuildInformation for report generation. -# -# NOTE: REST client requirements have been extracted to azure-devops-rest-client.yaml. -# NOTE: Work item mapper and custom fields requirements have been extracted to -# work-item-mapper.yaml. +# AzureDevOpsRepoConnector unit requirements sections: - - title: AzureDevOps Unit Requirements - requirements: - - id: BuildMark-AzureDevOps-UrlParsing - title: >- - The AzureDevOpsRepoConnector class shall parse organization URL, project, and repository - from Azure DevOps Services and on-premises Azure DevOps Server git remote URLs. - justification: | - The connector must support both cloud Azure DevOps Services (dev.azure.com, - visualstudio.com) and on-premises Azure DevOps Server instances. A unified URL - parser using the _git path segment anchor handles all HTTPS URL formats, while - SSH URLs use the git@ssh.dev.azure.com:v3 format. - tests: - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_DevAzureComHttps_ReturnsCorrectComponents - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_DevAzureComWithGitSuffix_StripsGitSuffix - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_VisualStudioComHttps_ReturnsCorrectComponents - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_SshUrl_ReturnsCorrectComponents - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_OnPremServer_ReturnsCorrectComponents - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_OnPremWithPort_ReturnsCorrectComponents - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_OnPremWithGitSuffix_StripsGitSuffix - - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_UnsupportedFormat_ThrowsArgumentException + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: AzureDevOps Requirements + sections: + - title: AzureDevOpsRepoConnector Requirements + requirements: + - id: BuildMark-AzureDevOps-UrlParsing + title: >- + The AzureDevOpsRepoConnector class shall parse organization URL, project, and repository + from Azure DevOps Services and on-premises Azure DevOps Server git remote URLs. + justification: | + The connector must support both cloud Azure DevOps Services (dev.azure.com, + visualstudio.com) and on-premises Azure DevOps Server instances. A unified URL + parser using the _git path segment anchor handles all HTTPS URL formats, while + SSH URLs use the git@ssh.dev.azure.com:v3 format. + tests: + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_DevAzureComHttps_ReturnsCorrectComponents + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_DevAzureComWithGitSuffix_StripsGitSuffix + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_VisualStudioComHttps_ReturnsCorrectComponents + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_SshUrl_ReturnsCorrectComponents + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_OnPremServer_ReturnsCorrectComponents + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_OnPremWithPort_ReturnsCorrectComponents + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_OnPremWithGitSuffix_StripsGitSuffix + - AzureDevOpsRepoConnector_ParseAzureDevOpsUrl_UnsupportedFormat_ThrowsArgumentException - - id: BuildMark-AzureDevOps-ConnectorConfig - title: >- - The AzureDevOpsRepoConnector class shall accept an optional AzureDevOpsConnectorConfig - to override the organization URL, project, and repository name. - justification: | - When a .buildmark.yaml file provides Azure DevOps connector settings, the connector - must use the configured organization URL, project, and repository name instead of - auto-detecting them from the Git remote URL. - tests: - - AzureDevOpsRepoConnector_Constructor_WithConfig_StoresConfigurationOverrides + - id: BuildMark-AzureDevOps-ConnectorConfig + title: >- + The AzureDevOpsRepoConnector class shall accept an optional AzureDevOpsConnectorConfig + to override the organization URL, project, and repository name. + justification: | + When a .buildmark.yaml file provides Azure DevOps connector settings, the connector + must use the configured organization URL, project, and repository name instead of + auto-detecting them from the Git remote URL. + tests: + - AzureDevOpsRepoConnector_Constructor_WithConfig_StoresConfigurationOverrides - - id: BuildMark-AzureDevOps-BuildInformation - title: The AzureDevOpsRepoConnector class shall retrieve build information from an Azure DevOps repository. - justification: | - The primary purpose of the AzureDevOpsRepoConnector is to assemble BuildInformation - from Azure DevOps repository data using the REST API, correctly identifying the current - version tag, the baseline (previous) version tag, and the changes between them. + - id: BuildMark-AzureDevOps-BuildInformation + title: The AzureDevOpsRepoConnector class shall retrieve build information from an Azure DevOps repository. + justification: | + The primary purpose of the AzureDevOpsRepoConnector is to assemble BuildInformation + from Azure DevOps repository data using the REST API, correctly identifying the current + version tag, the baseline (previous) version tag, and the changes between them. - Known-issues collection queries all bugs regardless of state. When affected-versions - is declared the item state is ignored; only the version range check determines - inclusion. This handles the LTS back-port gap scenario where a bug is resolved after - being fixed in a newer release but was never back-ported to an older branch. - tests: - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithMockedData_ReturnsValidBuildInformation - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithMultipleVersions_SelectsCorrectPreviousVersion - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithPullRequests_GathersChangesCorrectly - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithOpenWorkItems_IdentifiesKnownIssues - - AzureDevOpsRepoConnector_GetBuildInformationAsync_ReleaseVersion_SkipsAllPreReleases - - AzureDevOpsRepoConnector_ImplementsInterface_ReturnsTrue - - AzureDevOpsRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions - - AzureDevOpsRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue + Known-issues collection queries all bugs regardless of state. When affected-versions + is declared the item state is ignored; only the version range check determines + inclusion. This handles the LTS back-port gap scenario where a bug is resolved after + being fixed in a newer release but was never back-ported to an older branch. + tests: + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithMockedData_ReturnsValidBuildInformation + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithMultipleVersions_SelectsCorrectPreviousVersion + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithPullRequests_GathersChangesCorrectly + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithOpenWorkItems_IdentifiesKnownIssues + - AzureDevOpsRepoConnector_GetBuildInformationAsync_ReleaseVersion_SkipsAllPreReleases + - AzureDevOpsRepoConnector_ImplementsInterface_ReturnsTrue + - AzureDevOpsRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions + - AzureDevOpsRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue - - id: BuildMark-AzureDevOps-ItemControls - title: >- - The AzureDevOpsRepoConnector class shall apply item controls extracted from work item - description bodies to override visibility, type, and affected-version metadata. - justification: | - The Azure DevOps connector must translate raw Azure DevOps data into the BuildInformation - model. Applying item controls at this layer ensures that visibility and type overrides from - buildmark code blocks in work item descriptions are consistently enforced. - tests: - - AzureDevOpsRepoConnector_GetBuildInformationAsync_VisibilityInternal_ExcludesItem - - AzureDevOpsRepoConnector_GetBuildInformationAsync_VisibilityPublic_IncludesItem - - AzureDevOpsRepoConnector_GetBuildInformationAsync_TypeBugOverride_ClassifiesAsBug - - AzureDevOpsRepoConnector_GetBuildInformationAsync_TypeFeatureOverride_ClassifiesAsFeature + - id: BuildMark-AzureDevOps-ItemControls + title: >- + The AzureDevOpsRepoConnector class shall apply item controls extracted from work item + description bodies to override visibility, type, and affected-version metadata. + justification: | + The Azure DevOps connector must translate raw Azure DevOps data into the BuildInformation + model. Applying item controls at this layer ensures that visibility and type overrides from + buildmark code blocks in work item descriptions are consistently enforced. + tests: + - AzureDevOpsRepoConnector_GetBuildInformationAsync_VisibilityInternal_ExcludesItem + - AzureDevOpsRepoConnector_GetBuildInformationAsync_VisibilityPublic_IncludesItem + - AzureDevOpsRepoConnector_GetBuildInformationAsync_TypeBugOverride_ClassifiesAsBug + - AzureDevOpsRepoConnector_GetBuildInformationAsync_TypeFeatureOverride_ClassifiesAsFeature - - id: BuildMark-AzureDevOps-Rules - title: >- - The AzureDevOpsRepoConnector class shall apply configured routing rules and sections - to distribute assembled items into the appropriate report sections. - justification: | - When a .buildmark.yaml file provides routing rules and section definitions, - the connector must delegate to RepoConnectorBase.ApplyRules so that items are - distributed according to the operator-supplied rules, supporting work-item-type - matching for Azure DevOps work items. - tests: - - AzureDevOpsRepoConnector_Configure_WithRules_HasRulesReturnsTrue - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithConfiguredRules_PopulatesRoutedSections + - id: BuildMark-AzureDevOps-Rules + title: >- + The AzureDevOpsRepoConnector class shall apply configured routing rules and sections + to distribute assembled items into the appropriate report sections. + justification: | + When a .buildmark.yaml file provides routing rules and section definitions, + the connector must delegate to RepoConnectorBase.ApplyRules so that items are + distributed according to the operator-supplied rules, supporting work-item-type + matching for Azure DevOps work items. + tests: + - AzureDevOpsRepoConnector_Configure_WithRules_HasRulesReturnsTrue + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithConfiguredRules_PopulatesRoutedSections - - id: BuildMark-AzureDevOps-TokenVariable - title: >- - The AzureDevOpsRepoConnector class shall use only the configured token variable when - TokenVariable is set, and shall throw InvalidOperationException when the variable - is absent or empty. - justification: | - When an operator explicitly names a token variable in the configuration, the - connector must not silently fall back to other credential sources. Strict - enforcement ensures that misconfigured environments produce clear error messages - rather than accidentally using a different token with unexpected permissions. - tests: - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException + - id: BuildMark-AzureDevOps-TokenVariable + title: >- + The AzureDevOpsRepoConnector class shall use only the configured token variable when + TokenVariable is set, and shall throw InvalidOperationException when the variable + is absent or empty. + justification: | + When an operator explicitly names a token variable in the configuration, the + connector must not silently fall back to other credential sources. Strict + enforcement ensures that misconfigured environments produce clear error messages + rather than accidentally using a different token with unexpected permissions. + tests: + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException + - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException diff --git a/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.yaml b/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.yaml index 2ba73b5..76f45ae 100644 --- a/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.yaml +++ b/docs/reqstream/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.yaml @@ -1,77 +1,80 @@ --- -# Software Unit Requirements for the AzureDevOpsRestClient Class -# -# AzureDevOpsRestClient handles paginated HTTPS communication with the Azure -# DevOps REST API endpoint. It supports both cloud (dev.azure.com) and -# on-premises Azure DevOps Server instances. +# AzureDevOpsRestClient unit requirements sections: - - title: AzureDevOpsRestClient Unit Requirements - requirements: - - id: BuildMark-AzureDevOps-RestClient - title: >- - The AzureDevOpsRestClient shall retrieve repository data using the Azure DevOps - REST API, including support for paginated responses. - justification: | - The Azure DevOps REST API returns large result sets in pages. The client must - transparently follow pagination to retrieve complete repository data so that - build information reflects the full history. Authentication and response - parsing must be handled reliably to support consistent data retrieval. - tests: - - AzureDevOpsRestClient_GetRepositoryAsync_ValidResponse_ReturnsRepository - - AzureDevOpsRestClient_GetCommitsAsync_ValidResponse_ReturnsCommits - - AzureDevOpsRestClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests - - AzureDevOpsRestClient_GetPullRequestWorkItemsAsync_ValidResponse_ReturnsWorkItemRefs - - AzureDevOpsRestClient_GetWorkItemsAsync_ValidResponse_ReturnsWorkItems - - AzureDevOpsRestClient_QueryWorkItemsAsync_ValidWiql_ReturnsWorkItemIds - - AzureDevOpsRestClient_GetPullRequestWorkItemsAsync_StringValuedIds_DeserializesCorrectly - - AzureDevOpsRestClient_QueryWorkItemsAsync_StringValuedIds_DeserializesCorrectly - children: - - BuildMark-AzureDevOps-GetRepository - - BuildMark-AzureDevOps-GetCommits - - BuildMark-AzureDevOps-GetTags - - BuildMark-AzureDevOps-GetPullRequests - - BuildMark-AzureDevOps-GetWorkItems + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: AzureDevOps Requirements + sections: + - title: AzureDevOpsRestClient Requirements + requirements: + - id: BuildMark-AzureDevOps-RestClient + title: >- + The AzureDevOpsRestClient shall retrieve repository data using the Azure DevOps + REST API, including support for paginated responses. + justification: | + The Azure DevOps REST API returns large result sets in pages. The client must + transparently follow pagination to retrieve complete repository data so that + build information reflects the full history. Authentication and response + parsing must be handled reliably to support consistent data retrieval. + tests: + - AzureDevOpsRestClient_GetRepositoryAsync_ValidResponse_ReturnsRepository + - AzureDevOpsRestClient_GetCommitsAsync_ValidResponse_ReturnsCommits + - AzureDevOpsRestClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests + - AzureDevOpsRestClient_GetPullRequestWorkItemsAsync_ValidResponse_ReturnsWorkItemRefs + - AzureDevOpsRestClient_GetWorkItemsAsync_ValidResponse_ReturnsWorkItems + - AzureDevOpsRestClient_QueryWorkItemsAsync_ValidWiql_ReturnsWorkItemIds + - AzureDevOpsRestClient_GetPullRequestWorkItemsAsync_StringValuedIds_DeserializesCorrectly + - AzureDevOpsRestClient_QueryWorkItemsAsync_StringValuedIds_DeserializesCorrectly + children: + - BuildMark-AzureDevOps-GetRepository + - BuildMark-AzureDevOps-GetCommits + - BuildMark-AzureDevOps-GetTags + - BuildMark-AzureDevOps-GetPullRequests + - BuildMark-AzureDevOps-GetWorkItems - - id: BuildMark-AzureDevOps-GetRepository - title: The AzureDevOpsRestClient shall retrieve repository details from the Azure DevOps API. - justification: | - Repository detail retrieval provides the repository identity needed for subsequent - API calls and for generating accurate hyperlinks in build notes. - tests: - - AzureDevOpsRestClient_GetRepositoryAsync_ValidResponse_ReturnsRepository + - id: BuildMark-AzureDevOps-GetRepository + title: The AzureDevOpsRestClient shall retrieve repository details from the Azure DevOps API. + justification: | + Repository detail retrieval provides the repository identity needed for subsequent + API calls and for generating accurate hyperlinks in build notes. + tests: + - AzureDevOpsRestClient_GetRepositoryAsync_ValidResponse_ReturnsRepository - - id: BuildMark-AzureDevOps-GetCommits - title: The AzureDevOpsRestClient shall retrieve commits from the Azure DevOps API with pagination support. - justification: | - Commit retrieval is required to determine the set of changes between version tags. - Pagination ensures complete history is retrieved regardless of repository size. - tests: - - AzureDevOpsRestClient_GetCommitsAsync_ValidResponse_ReturnsCommits + - id: BuildMark-AzureDevOps-GetCommits + title: The AzureDevOpsRestClient shall retrieve commits from the Azure DevOps API with pagination support. + justification: | + Commit retrieval is required to determine the set of changes between version tags. + Pagination ensures complete history is retrieved regardless of repository size. + tests: + - AzureDevOpsRestClient_GetCommitsAsync_ValidResponse_ReturnsCommits - - id: BuildMark-AzureDevOps-GetTags - title: The AzureDevOpsRestClient shall retrieve tags from the Azure DevOps API. - justification: | - Tag retrieval is required to identify version boundaries for build note generation. - All tags must be fetched to correctly determine previous version baselines. - tests: - - AzureDevOpsRestClient_GetTagsAsync_ValidResponse_ReturnsTags + - id: BuildMark-AzureDevOps-GetTags + title: The AzureDevOpsRestClient shall retrieve tags from the Azure DevOps API. + justification: | + Tag retrieval is required to identify version boundaries for build note generation. + All tags must be fetched to correctly determine previous version baselines. + tests: + - AzureDevOpsRestClient_GetTagsAsync_ValidResponse_ReturnsTags - - id: BuildMark-AzureDevOps-GetPullRequests - title: The AzureDevOpsRestClient shall retrieve pull requests from the Azure DevOps API with pagination support. - justification: | - Pull request retrieval provides the change entries for build notes. Pagination - ensures all pull requests in the version range are included. - tests: - - AzureDevOpsRestClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests - - AzureDevOpsRestClient_GetPullRequestWorkItemsAsync_StringValuedIds_DeserializesCorrectly + - id: BuildMark-AzureDevOps-GetPullRequests + title: The AzureDevOpsRestClient shall retrieve pull requests from the Azure DevOps API with pagination + support. + justification: | + Pull request retrieval provides the change entries for build notes. Pagination + ensures all pull requests in the version range are included. + tests: + - AzureDevOpsRestClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests + - AzureDevOpsRestClient_GetPullRequestWorkItemsAsync_StringValuedIds_DeserializesCorrectly - - id: BuildMark-AzureDevOps-GetWorkItems - title: The AzureDevOpsRestClient shall retrieve work items from the Azure DevOps API with pagination support. - justification: | - Work item retrieval provides the issue and bug entries for build notes. Pagination - and WIQL query support ensure complete work item coverage. - tests: - - AzureDevOpsRestClient_GetWorkItemsAsync_ValidResponse_ReturnsWorkItems - - AzureDevOpsRestClient_QueryWorkItemsAsync_ValidWiql_ReturnsWorkItemIds - - AzureDevOpsRestClient_QueryWorkItemsAsync_StringValuedIds_DeserializesCorrectly + - id: BuildMark-AzureDevOps-GetWorkItems + title: The AzureDevOpsRestClient shall retrieve work items from the Azure DevOps API with pagination support. + justification: | + Work item retrieval provides the issue and bug entries for build notes. Pagination + and WIQL query support ensure complete work item coverage. + tests: + - AzureDevOpsRestClient_GetWorkItemsAsync_ValidResponse_ReturnsWorkItems + - AzureDevOpsRestClient_QueryWorkItemsAsync_ValidWiql_ReturnsWorkItemIds + - AzureDevOpsRestClient_QueryWorkItemsAsync_StringValuedIds_DeserializesCorrectly diff --git a/docs/reqstream/build-mark/repo-connectors/azure-devops/work-item-mapper.yaml b/docs/reqstream/build-mark/repo-connectors/azure-devops/work-item-mapper.yaml index fcf947a..e0aeb8c 100644 --- a/docs/reqstream/build-mark/repo-connectors/azure-devops/work-item-mapper.yaml +++ b/docs/reqstream/build-mark/repo-connectors/azure-devops/work-item-mapper.yaml @@ -1,57 +1,59 @@ --- -# Software Unit Requirements for the WorkItemMapper Class -# -# WorkItemMapper maps Azure DevOps work items to ItemInfo objects, applying -# type normalization, state-based filtering, and custom field extraction for -# visibility and affected-versions controls. +# WorkItemMapper unit requirements sections: - - title: WorkItemMapper Unit Requirements - requirements: - - id: BuildMark-AzureDevOps-WorkItemMapper - title: >- - The WorkItemMapper class shall map Azure DevOps work items to ItemInfo objects, - applying type normalization and state-based filtering. - justification: | - Azure DevOps work items use platform-specific type names and state values that must - be normalized to the BuildMark ItemInfo model. The mapper centralizes this translation - logic to ensure consistent type classification and state filtering across all connector - operations. - tests: - - WorkItemMapper_MapWorkItemToItemInfo_BugType_ReturnsBugItem - - WorkItemMapper_MapWorkItemToItemInfo_UserStoryType_ReturnsFeatureItem - - WorkItemMapper_MapWorkItemToItemInfo_EpicType_ReturnsFeatureItem - - WorkItemMapper_MapWorkItemToItemInfo_TaskType_ReturnsTaskItem - - WorkItemMapper_IsWorkItemResolved_ResolvedState_ReturnsTrue - - WorkItemMapper_IsWorkItemResolved_ActiveState_ReturnsFalse - - WorkItemMapper_GetWorkItemTypeForRuleMatching_ReturnsWorkItemTypeName - children: - - BuildMark-AzureDevOps-SuppressRemovedWorkItems + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: AzureDevOps Requirements + sections: + - title: WorkItemMapper Requirements + requirements: + - id: BuildMark-AzureDevOps-WorkItemMapper + title: >- + The WorkItemMapper class shall map Azure DevOps work items to ItemInfo objects, + applying type normalization and state-based filtering. + justification: | + Azure DevOps work items use platform-specific type names and state values that must + be normalized to the BuildMark ItemInfo model. The mapper centralizes this translation + logic to ensure consistent type classification and state filtering across all connector + operations. + tests: + - WorkItemMapper_MapWorkItemToItemInfo_BugType_ReturnsBugItem + - WorkItemMapper_MapWorkItemToItemInfo_UserStoryType_ReturnsFeatureItem + - WorkItemMapper_MapWorkItemToItemInfo_EpicType_ReturnsFeatureItem + - WorkItemMapper_MapWorkItemToItemInfo_TaskType_ReturnsTaskItem + - WorkItemMapper_IsWorkItemResolved_ResolvedState_ReturnsTrue + - WorkItemMapper_IsWorkItemResolved_ActiveState_ReturnsFalse + - WorkItemMapper_GetWorkItemTypeForRuleMatching_ReturnsWorkItemTypeName + children: + - BuildMark-AzureDevOps-SuppressRemovedWorkItems - - id: BuildMark-AzureDevOps-SuppressRemovedWorkItems - title: >- - The WorkItemMapper class shall suppress work items in the Removed state from all - sections of build notes. - justification: | - Azure DevOps work items in the Removed state represent items that were explicitly - abandoned or cancelled. Surfacing these items in build notes is misleading — they - imply work was delivered (in changes) or an open bug exists (in known issues) when - the team has decided the item no longer exists. Suppressing Removed items in - MapWorkItemToItemInfo with an early-exit null return covers both the changes and - known-issues code paths with a single check. - tests: - - WorkItemMapper_MapWorkItemToItemInfo_RemovedState_ReturnsNull + - id: BuildMark-AzureDevOps-SuppressRemovedWorkItems + title: >- + The WorkItemMapper class shall suppress work items in the Removed state from all + sections of build notes. + justification: | + Azure DevOps work items in the Removed state represent items that were explicitly + abandoned or cancelled. Surfacing these items in build notes is misleading — they + imply work was delivered (in changes) or an open bug exists (in known issues) when + the team has decided the item no longer exists. Suppressing Removed items in + MapWorkItemToItemInfo with an early-exit null return covers both the changes and + known-issues code paths with a single check. + tests: + - WorkItemMapper_MapWorkItemToItemInfo_RemovedState_ReturnsNull - - id: BuildMark-AzureDevOps-CustomFields - title: >- - The WorkItemMapper class shall read Custom.Visibility and Custom.AffectedVersions - custom fields from Azure DevOps work items to control item visibility and version ranges. - justification: | - Azure DevOps work items support native custom fields for visibility and version range - metadata. These fields provide a more natural Azure DevOps-native alternative to - buildmark code blocks for teams that prefer not to embed YAML in descriptions. - Custom fields take precedence over buildmark blocks when both are present. - tests: - - WorkItemMapper_ExtractItemControls_CustomVisibilityField_ReturnsMappedControls - - WorkItemMapper_ExtractItemControls_CustomAffectedVersionsField_ReturnsMappedVersionSet - - WorkItemMapper_ExtractItemControls_CustomFieldsTakePrecedenceOverBuildmarkBlock + - id: BuildMark-AzureDevOps-CustomFields + title: >- + The WorkItemMapper class shall read Custom.Visibility and Custom.AffectedVersions + custom fields from Azure DevOps work items to control item visibility and version ranges. + justification: | + Azure DevOps work items support native custom fields for visibility and version range + metadata. These fields provide a more natural Azure DevOps-native alternative to + buildmark code blocks for teams that prefer not to embed YAML in descriptions. + Custom fields take precedence over buildmark blocks when both are present. + tests: + - WorkItemMapper_ExtractItemControls_CustomVisibilityField_ReturnsMappedControls + - WorkItemMapper_ExtractItemControls_CustomAffectedVersionsField_ReturnsMappedVersionSet + - WorkItemMapper_ExtractItemControls_CustomFieldsTakePrecedenceOverBuildmarkBlock diff --git a/docs/reqstream/build-mark/repo-connectors/github.yaml b/docs/reqstream/build-mark/repo-connectors/github.yaml index 9bbfa3e..139df65 100644 --- a/docs/reqstream/build-mark/repo-connectors/github.yaml +++ b/docs/reqstream/build-mark/repo-connectors/github.yaml @@ -1,37 +1,34 @@ --- -# GitHub Sub-Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark GitHub sub-subsystem -# - The GitHub sub-subsystem provides the production connector used when -# the repository host is GitHub or GitHub Enterprise -# - Sub-subsystem requirements describe the externally visible contract -# satisfied by the units beneath this sub-subsystem +# GitHub subsystem requirements sections: - - title: GitHub Sub-Subsystem Requirements - requirements: - - id: BuildMark-GitHub-SubSystem - title: >- - The GitHub sub-subsystem shall implement the IRepoConnector interface - for GitHub repositories. - justification: | - Generating build notes from GitHub repositories requires a dedicated sub-subsystem - that can authenticate to the GitHub API, retrieve commits, releases, tags, pull - requests, and issues, apply item-controls overrides, and assemble them into - structured build information. - tests: - - GitHub_ImplementsInterface_ReturnsTrue - - GitHub_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation - - GitHub_GetBuildInformation_WithMultipleVersions_SelectsCorrectBaseline - - GitHub_GetBuildInformation_WithPullRequests_GathersChanges - - GitHub_GetBuildInformation_WithOpenIssues_IdentifiesKnownIssues - - GitHub_GetBuildInformation_ReleaseVersion_SkipsPreReleases - children: - - BuildMark-GitHub-ConnectorConfig - - BuildMark-GitHub-BuildInformation - - BuildMark-GitHub-ItemControls - - BuildMark-GitHub-DescriptionBody - - BuildMark-GitHub-GraphQLClient - - BuildMark-GitHub-Rules - - BuildMark-GitHub-TokenVariable + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: GitHub Requirements + requirements: + - id: BuildMark-GitHub-SubSystem + title: >- + The GitHub sub-subsystem shall implement the IRepoConnector interface + for GitHub repositories. + justification: | + Generating build notes from GitHub repositories requires a dedicated sub-subsystem + that can authenticate to the GitHub API, retrieve commits, releases, tags, pull + requests, and issues, apply item-controls overrides, and assemble them into + structured build information. + tests: + - GitHub_ImplementsInterface_ReturnsTrue + - GitHub_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation + - GitHub_GetBuildInformation_WithMultipleVersions_SelectsCorrectBaseline + - GitHub_GetBuildInformation_WithPullRequests_GathersChanges + - GitHub_GetBuildInformation_WithOpenIssues_IdentifiesKnownIssues + - GitHub_GetBuildInformation_ReleaseVersion_SkipsPreReleases + children: + - BuildMark-GitHub-ConnectorConfig + - BuildMark-GitHub-BuildInformation + - BuildMark-GitHub-ItemControls + - BuildMark-GitHub-DescriptionBody + - BuildMark-GitHub-GraphQLClient + - BuildMark-GitHub-Rules + - BuildMark-GitHub-TokenVariable diff --git a/docs/reqstream/build-mark/repo-connectors/github/github-graphql-client.yaml b/docs/reqstream/build-mark/repo-connectors/github/github-graphql-client.yaml index 70632ab..d147342 100644 --- a/docs/reqstream/build-mark/repo-connectors/github/github-graphql-client.yaml +++ b/docs/reqstream/build-mark/repo-connectors/github/github-graphql-client.yaml @@ -1,130 +1,132 @@ --- -# Software Unit Requirements for the GitHubGraphQLClient Class and DescriptionBody -# -# GitHubGraphQLClient handles paginated HTTPS communication with the GitHub -# GraphQL endpoint. DescriptionBody requirements specify that pull request and -# issue description bodies are retrieved and made available for item controls -# parsing. +# GitHubGraphQLClient unit requirements sections: - - title: GitHubGraphQLClient Unit Requirements - requirements: - - id: BuildMark-GitHub-GraphQLClient - title: >- - The GitHubGraphQLClient shall retrieve repository data using the GitHub GraphQL API, - including support for paginated responses. - justification: | - The GitHub API returns large result sets in pages. The client must transparently - follow pagination cursors to retrieve all commits, releases, tags, pull requests, - issues, and linked issue IDs so that build information reflects the complete - repository history rather than only the first page of results. + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: GitHub Requirements + sections: + - title: GitHubGraphQLClient Requirements + requirements: + - id: BuildMark-GitHub-GraphQLClient + title: >- + The GitHubGraphQLClient shall retrieve repository data using the GitHub GraphQL API, + including support for paginated responses. + justification: | + The GitHub API returns large result sets in pages. The client must transparently + follow pagination cursors to retrieve all commits, releases, tags, pull requests, + issues, and linked issue IDs so that build information reflects the complete + repository history rather than only the first page of results. - This requirement serves as a parent summary requirement. Its children - (BuildMark-GitHub-GetCommits, BuildMark-GitHub-GetReleases, BuildMark-GitHub-GetTags, - BuildMark-GitHub-GetPullRequests, BuildMark-GitHub-GetIssues, and - BuildMark-GitHub-ErrorHandling) each cover one specific aspect of the client's - observable behavior and carry the detailed test mappings. - tests: - - GitHubGraphQLClient_GetCommitsAsync_ValidResponse_ReturnsCommitShas - - GitHubGraphQLClient_GetCommitsAsync_WithPagination_ReturnsAllCommits - - GitHubGraphQLClient_GetReleasesAsync_ValidResponse_ReturnsReleaseTagNames - - GitHubGraphQLClient_GetReleasesAsync_WithPagination_ReturnsAllReleases - - GitHubGraphQLClient_GetAllTagsAsync_ValidResponse_ReturnsTagNodes - - GitHubGraphQLClient_GetAllTagsAsync_WithPagination_ReturnsAllTags - - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests - - GitHubGraphQLClient_GetPullRequestsAsync_WithPagination_ReturnsAllPullRequests - - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssues - - GitHubGraphQLClient_GetAllIssuesAsync_WithPagination_ReturnsAllIssues - - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_ValidResponse_ReturnsIssueIds - - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_WithPagination_ReturnsAllIssues - children: - - BuildMark-GitHub-GetCommits - - BuildMark-GitHub-GetReleases - - BuildMark-GitHub-GetTags - - BuildMark-GitHub-GetPullRequests - - BuildMark-GitHub-GetIssues - - BuildMark-GitHub-ErrorHandling + This requirement serves as a parent summary requirement. Its children + (BuildMark-GitHub-GetCommits, BuildMark-GitHub-GetReleases, BuildMark-GitHub-GetTags, + BuildMark-GitHub-GetPullRequests, BuildMark-GitHub-GetIssues, and + BuildMark-GitHub-ErrorHandling) each cover one specific aspect of the client's + observable behavior and carry the detailed test mappings. + tests: + - GitHubGraphQLClient_GetCommitsAsync_ValidResponse_ReturnsCommitShas + - GitHubGraphQLClient_GetCommitsAsync_WithPagination_ReturnsAllCommits + - GitHubGraphQLClient_GetReleasesAsync_ValidResponse_ReturnsReleaseTagNames + - GitHubGraphQLClient_GetReleasesAsync_WithPagination_ReturnsAllReleases + - GitHubGraphQLClient_GetAllTagsAsync_ValidResponse_ReturnsTagNodes + - GitHubGraphQLClient_GetAllTagsAsync_WithPagination_ReturnsAllTags + - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests + - GitHubGraphQLClient_GetPullRequestsAsync_WithPagination_ReturnsAllPullRequests + - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssues + - GitHubGraphQLClient_GetAllIssuesAsync_WithPagination_ReturnsAllIssues + - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_ValidResponse_ReturnsIssueIds + - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_WithPagination_ReturnsAllIssues + children: + - BuildMark-GitHub-GetCommits + - BuildMark-GitHub-GetReleases + - BuildMark-GitHub-GetTags + - BuildMark-GitHub-GetPullRequests + - BuildMark-GitHub-GetIssues + - BuildMark-GitHub-ErrorHandling - - id: BuildMark-GitHub-DescriptionBody - title: >- - The GitHubRepoConnector shall make the full description text of pull - requests and issues available for item controls parsing. - justification: | - ItemControlsParser requires the complete description text of each pull request - and issue to locate and extract a buildmark code block. The description text - must be retrieved as part of the repository data query so that item controls - can be applied to each item. - tests: - - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequestsWithBody - - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssuesWithBody + - id: BuildMark-GitHub-DescriptionBody + title: >- + The GitHubRepoConnector shall make the full description text of pull + requests and issues available for item controls parsing. + justification: | + ItemControlsParser requires the complete description text of each pull request + and issue to locate and extract a buildmark code block. The description text + must be retrieved as part of the repository data query so that item controls + can be applied to each item. + tests: + - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequestsWithBody + - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssuesWithBody - - id: BuildMark-GitHub-GetCommits - title: The GitHubGraphQLClient shall retrieve commits from the GitHub repository with pagination support. - justification: | - Commit retrieval is required to determine the set of changes between version tags. - Pagination ensures complete history is retrieved regardless of repository size. - tests: - - GitHubGraphQLClient_GetCommitsAsync_ValidResponse_ReturnsCommitShas - - GitHubGraphQLClient_GetCommitsAsync_WithPagination_ReturnsAllCommits + - id: BuildMark-GitHub-GetCommits + title: The GitHubGraphQLClient shall retrieve commits from the GitHub repository with pagination support. + justification: | + Commit retrieval is required to determine the set of changes between version tags. + Pagination ensures complete history is retrieved regardless of repository size. + tests: + - GitHubGraphQLClient_GetCommitsAsync_ValidResponse_ReturnsCommitShas + - GitHubGraphQLClient_GetCommitsAsync_WithPagination_ReturnsAllCommits - - id: BuildMark-GitHub-GetReleases - title: The GitHubGraphQLClient shall retrieve releases from the GitHub repository with pagination support. - justification: | - Release retrieval provides known-issues data based on published releases. - Pagination ensures all releases are fetched for complete known-issue analysis. - tests: - - GitHubGraphQLClient_GetReleasesAsync_ValidResponse_ReturnsReleaseTagNames - - GitHubGraphQLClient_GetReleasesAsync_WithPagination_ReturnsAllReleases + - id: BuildMark-GitHub-GetReleases + title: The GitHubGraphQLClient shall retrieve releases from the GitHub repository with pagination support. + justification: | + Release retrieval provides known-issues data based on published releases. + Pagination ensures all releases are fetched for complete known-issue analysis. + tests: + - GitHubGraphQLClient_GetReleasesAsync_ValidResponse_ReturnsReleaseTagNames + - GitHubGraphQLClient_GetReleasesAsync_WithPagination_ReturnsAllReleases - - id: BuildMark-GitHub-GetTags - title: The GitHubGraphQLClient shall retrieve all tags from the GitHub repository with pagination support. - justification: | - Tag retrieval is required to identify version boundaries for build note generation. - All tags must be fetched to correctly determine previous version baselines. - tests: - - GitHubGraphQLClient_GetAllTagsAsync_ValidResponse_ReturnsTagNodes - - GitHubGraphQLClient_GetAllTagsAsync_WithPagination_ReturnsAllTags + - id: BuildMark-GitHub-GetTags + title: The GitHubGraphQLClient shall retrieve all tags from the GitHub repository with pagination support. + justification: | + Tag retrieval is required to identify version boundaries for build note generation. + All tags must be fetched to correctly determine previous version baselines. + tests: + - GitHubGraphQLClient_GetAllTagsAsync_ValidResponse_ReturnsTagNodes + - GitHubGraphQLClient_GetAllTagsAsync_WithPagination_ReturnsAllTags - - id: BuildMark-GitHub-GetPullRequests - title: The GitHubGraphQLClient shall retrieve pull requests from the GitHub repository with pagination support. - justification: | - Pull request retrieval provides the change entries for build notes. Pagination - ensures all pull requests in the version range are included. - tests: - - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests - - GitHubGraphQLClient_GetPullRequestsAsync_WithPagination_ReturnsAllPullRequests - - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequestsWithBody + - id: BuildMark-GitHub-GetPullRequests + title: The GitHubGraphQLClient shall retrieve pull requests from the GitHub repository with pagination + support. + justification: | + Pull request retrieval provides the change entries for build notes. Pagination + ensures all pull requests in the version range are included. + tests: + - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequests + - GitHubGraphQLClient_GetPullRequestsAsync_WithPagination_ReturnsAllPullRequests + - GitHubGraphQLClient_GetPullRequestsAsync_ValidResponse_ReturnsPullRequestsWithBody - - id: BuildMark-GitHub-GetIssues - title: The GitHubGraphQLClient shall retrieve issues from the GitHub repository with pagination support. - justification: | - Issue retrieval provides bug fix entries and known-issue data. Pagination - ensures all issues associated with the version range are included. - tests: - - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssues - - GitHubGraphQLClient_GetAllIssuesAsync_WithPagination_ReturnsAllIssues - - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssuesWithBody - - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_ValidResponse_ReturnsIssueIds - - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_WithPagination_ReturnsAllIssues + - id: BuildMark-GitHub-GetIssues + title: The GitHubGraphQLClient shall retrieve issues from the GitHub repository with pagination support. + justification: | + Issue retrieval provides bug fix entries and known-issue data. Pagination + ensures all issues associated with the version range are included. + tests: + - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssues + - GitHubGraphQLClient_GetAllIssuesAsync_WithPagination_ReturnsAllIssues + - GitHubGraphQLClient_GetAllIssuesAsync_ValidResponse_ReturnsIssuesWithBody + - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_ValidResponse_ReturnsIssueIds + - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_WithPagination_ReturnsAllIssues - - id: BuildMark-GitHub-ErrorHandling - title: >- - The GitHubGraphQLClient shall return an empty list rather than propagating - exceptions when a GitHub API query fails. - justification: | - Transient network failures, HTTP error responses, and malformed JSON payloads - must not crash the build-notes pipeline. Returning an empty list on any query - failure allows the connector to produce a partial result or a meaningful error - message rather than an unhandled exception. - tests: - - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_HttpError_ReturnsEmptyList - - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_InvalidJson_ReturnsEmptyList - - GitHubGraphQLClient_GetAllIssuesAsync_Exception_ReturnsEmptyList - - GitHubGraphQLClient_GetAllTagsAsync_HttpError_ReturnsEmptyList - - GitHubGraphQLClient_GetAllTagsAsync_InvalidJson_ReturnsEmptyList - - GitHubGraphQLClient_GetCommitsAsync_HttpError_ReturnsEmptyList - - GitHubGraphQLClient_GetCommitsAsync_InvalidJson_ReturnsEmptyList - - GitHubGraphQLClient_GetPullRequestsAsync_HttpError_ReturnsEmptyList - - GitHubGraphQLClient_GetPullRequestsAsync_InvalidJson_ReturnsEmptyList - - GitHubGraphQLClient_GetReleasesAsync_HttpError_ReturnsEmptyList - - GitHubGraphQLClient_GetReleasesAsync_InvalidJson_ReturnsEmptyList + - id: BuildMark-GitHub-ErrorHandling + title: >- + The GitHubGraphQLClient shall return an empty list rather than propagating + exceptions when a GitHub API query fails. + justification: | + Transient network failures, HTTP error responses, and malformed JSON payloads + must not crash the build-notes pipeline. Returning an empty list on any query + failure allows the connector to produce a partial result or a meaningful error + message rather than an unhandled exception. + tests: + - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_HttpError_ReturnsEmptyList + - GitHubGraphQLClient_FindIssueIdsLinkedToPullRequestAsync_InvalidJson_ReturnsEmptyList + - GitHubGraphQLClient_GetAllIssuesAsync_Exception_ReturnsEmptyList + - GitHubGraphQLClient_GetAllTagsAsync_HttpError_ReturnsEmptyList + - GitHubGraphQLClient_GetAllTagsAsync_InvalidJson_ReturnsEmptyList + - GitHubGraphQLClient_GetCommitsAsync_HttpError_ReturnsEmptyList + - GitHubGraphQLClient_GetCommitsAsync_InvalidJson_ReturnsEmptyList + - GitHubGraphQLClient_GetPullRequestsAsync_HttpError_ReturnsEmptyList + - GitHubGraphQLClient_GetPullRequestsAsync_InvalidJson_ReturnsEmptyList + - GitHubGraphQLClient_GetReleasesAsync_HttpError_ReturnsEmptyList + - GitHubGraphQLClient_GetReleasesAsync_InvalidJson_ReturnsEmptyList diff --git a/docs/reqstream/build-mark/repo-connectors/github/github-repo-connector.yaml b/docs/reqstream/build-mark/repo-connectors/github/github-repo-connector.yaml index 19637f1..9ee0e57 100644 --- a/docs/reqstream/build-mark/repo-connectors/github/github-repo-connector.yaml +++ b/docs/reqstream/build-mark/repo-connectors/github/github-repo-connector.yaml @@ -1,98 +1,97 @@ --- -# Software Unit Requirements for the GitHubRepoConnector Class -# -# The GitHubRepoConnector class connects to GitHub using the GraphQL API to -# retrieve commits, releases, tags, pull requests, and issues, assembling them -# into structured BuildInformation for report generation. -# -# NOTE: GraphQL client and description body requirements have been extracted to -# github-graphql-client.yaml. +# GitHubRepoConnector unit requirements sections: - - title: GitHubRepoConnector Unit Requirements - requirements: - - id: BuildMark-GitHub-ConnectorConfig - title: >- - The GitHubRepoConnector class shall accept an optional GitHubConnectorConfig to - override the repository owner, name, and API base URL. - justification: | - When a .buildmark.yaml file provides GitHub connector settings, the connector - must use the configured owner, repo, and optional GitHub Enterprise base URL - instead of auto-detecting them from the Git remote URL. CLI arguments remain - as a fallback when the config values are absent. - tests: - - GitHubRepoConnector_Constructor_WithConfig_StoresConfigurationOverrides + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: GitHub Requirements + sections: + - title: GitHubRepoConnector Requirements + requirements: + - id: BuildMark-GitHub-ConnectorConfig + title: >- + The GitHubRepoConnector class shall accept an optional GitHubConnectorConfig to + override the repository owner, name, and API base URL. + justification: | + When a .buildmark.yaml file provides GitHub connector settings, the connector + must use the configured owner, repo, and optional GitHub Enterprise base URL + instead of auto-detecting them from the Git remote URL. CLI arguments remain + as a fallback when the config values are absent. + tests: + - GitHubRepoConnector_Constructor_WithConfig_StoresConfigurationOverrides - - id: BuildMark-GitHub-BuildInformation - title: The GitHubRepoConnector class shall retrieve build information from a GitHub repository. - justification: | - The primary purpose of the GitHubRepoConnector is to assemble BuildInformation - from GitHub repository data. It must correctly identify the current version tag, - the baseline (previous) version tag, and the changes between them, correctly - handling pre-release tags and version selection edge cases. + - id: BuildMark-GitHub-BuildInformation + title: The GitHubRepoConnector class shall retrieve build information from a GitHub repository. + justification: | + The primary purpose of the GitHubRepoConnector is to assemble BuildInformation + from GitHub repository data. It must correctly identify the current version tag, + the baseline (previous) version tag, and the changes between them, correctly + handling pre-release tags and version selection edge cases. - Known-issues collection considers all issues (open and closed). When - affected-versions is declared the issue state is ignored; only the version range - check determines inclusion. This handles the LTS back-port gap scenario where a - bug is closed after being fixed in a newer release but was never back-ported. - tests: - - GitHubRepoConnector_GetBuildInformationAsync_WithMockedData_ReturnsValidBuildInformation - - GitHubRepoConnector_GetBuildInformationAsync_WithMultipleVersions_SelectsCorrectPreviousVersionAndGeneratesChangelogLink - - GitHubRepoConnector_GetBuildInformationAsync_WithPullRequests_GathersChangesCorrectly - - GitHubRepoConnector_GetBuildInformationAsync_WithOpenIssues_IdentifiesKnownIssues - - GitHubRepoConnector_GetBuildInformationAsync_ReleaseVersion_SkipsAllPreReleases - - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseWithSameCommitHash_SkipsToNextDifferentHash - - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHistory_UsesLatestDifferentHash - - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPreviousSameHash_ReturnsNullBaseline - - GitHubRepoConnector_GetBuildInformationAsync_WithDuplicateMergeCommitSha_DoesNotThrow - - GitHubRepoConnector_ImplementsInterface_ReturnsTrue - - GitHubRepoConnector_GetBuildInformationAsync_PrWithSubstringMatchLabel_NotClassifiedAsBug - - GitHubRepoConnector_GetBuildInformationAsync_IssueWithSubstringMatchLabel_NotClassifiedAsKnownIssue - - GitHubRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions - - GitHubRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue + Known-issues collection considers all issues (open and closed). When + affected-versions is declared the issue state is ignored; only the version range + check determines inclusion. This handles the LTS back-port gap scenario where a + bug is closed after being fixed in a newer release but was never back-ported. + tests: + - GitHubRepoConnector_GetBuildInformationAsync_WithMockedData_ReturnsValidBuildInformation + - GitHubRepoConnector_GetBuildInformationAsync_WithMultipleVersions_SelectsCorrectPreviousVersionAndGeneratesChangelogLink + - GitHubRepoConnector_GetBuildInformationAsync_WithPullRequests_GathersChangesCorrectly + - GitHubRepoConnector_GetBuildInformationAsync_WithOpenIssues_IdentifiesKnownIssues + - GitHubRepoConnector_GetBuildInformationAsync_ReleaseVersion_SkipsAllPreReleases + - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseWithSameCommitHash_SkipsToNextDifferentHash + - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHistory_UsesLatestDifferentHash + - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPreviousSameHash_ReturnsNullBaseline + - GitHubRepoConnector_GetBuildInformationAsync_WithDuplicateMergeCommitSha_DoesNotThrow + - GitHubRepoConnector_ImplementsInterface_ReturnsTrue + - GitHubRepoConnector_GetBuildInformationAsync_PrWithSubstringMatchLabel_NotClassifiedAsBug + - GitHubRepoConnector_GetBuildInformationAsync_IssueWithSubstringMatchLabel_NotClassifiedAsKnownIssue + - GitHubRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions + - GitHubRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue - - id: BuildMark-GitHub-ItemControls - title: >- - The GitHubRepoConnector class shall apply item controls extracted from issue - and pull request description bodies to override visibility, type, and - affected-version metadata. - justification: | - The GitHub connector is responsible for translating raw GitHub data into the - BuildInformation model. Applying item controls at this layer ensures that - visibility and type overrides are consistently enforced regardless of labels, - and that affected-version data is captured and stored on each ItemInfo for - downstream use. - tests: - - GitHubRepoConnector_GetBuildInformationAsync_VisibilityInternal_ExcludesItem - - GitHubRepoConnector_GetBuildInformationAsync_VisibilityPublic_IncludesItem - - GitHubRepoConnector_GetBuildInformationAsync_TypeBugOverride_ClassifiesAsBug - - GitHubRepoConnector_GetBuildInformationAsync_TypeFeatureOverride_ClassifiesAsFeature + - id: BuildMark-GitHub-ItemControls + title: >- + The GitHubRepoConnector class shall apply item controls extracted from issue + and pull request description bodies to override visibility, type, and + affected-version metadata. + justification: | + The GitHub connector is responsible for translating raw GitHub data into the + BuildInformation model. Applying item controls at this layer ensures that + visibility and type overrides are consistently enforced regardless of labels, + and that affected-version data is captured and stored on each ItemInfo for + downstream use. + tests: + - GitHubRepoConnector_GetBuildInformationAsync_VisibilityInternal_ExcludesItem + - GitHubRepoConnector_GetBuildInformationAsync_VisibilityPublic_IncludesItem + - GitHubRepoConnector_GetBuildInformationAsync_TypeBugOverride_ClassifiesAsBug + - GitHubRepoConnector_GetBuildInformationAsync_TypeFeatureOverride_ClassifiesAsFeature - - id: BuildMark-GitHub-Rules - title: >- - The GitHubRepoConnector class shall apply configured routing rules and sections - to distribute assembled items into the appropriate report sections. - justification: | - When a .buildmark.yaml file provides routing rules and section definitions, - the connector must delegate to RepoConnectorBase.ApplyRules so that items are - distributed according to the operator-supplied rules rather than the default - label-derived categorization. This allows teams to customize which items - appear in which sections of the generated build notes. - tests: - - GitHubRepoConnector_Configure_WithRules_HasRulesReturnsTrue - - GitHubRepoConnector_GetBuildInformationAsync_WithConfiguredRules_PopulatesRoutedSections + - id: BuildMark-GitHub-Rules + title: >- + The GitHubRepoConnector class shall apply configured routing rules and sections + to distribute assembled items into the appropriate report sections. + justification: | + When a .buildmark.yaml file provides routing rules and section definitions, + the connector must delegate to RepoConnectorBase.ApplyRules so that items are + distributed according to the operator-supplied rules rather than the default + label-derived categorization. This allows teams to customize which items + appear in which sections of the generated build notes. + tests: + - GitHubRepoConnector_Configure_WithRules_HasRulesReturnsTrue + - GitHubRepoConnector_GetBuildInformationAsync_WithConfiguredRules_PopulatesRoutedSections - - id: BuildMark-GitHub-TokenVariable - title: >- - The GitHubRepoConnector class shall use only the configured token variable when - TokenVariable is set, and shall throw InvalidOperationException when the variable - is absent or empty. - justification: | - When an operator explicitly names a token variable in the configuration, the - connector must not silently fall back to other credential sources. Strict - enforcement ensures that misconfigured environments produce clear error messages - rather than accidentally using a different token with unexpected permissions. - tests: - - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable - - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException - - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException + - id: BuildMark-GitHub-TokenVariable + title: >- + The GitHubRepoConnector class shall use only the configured token variable when + TokenVariable is set, and shall throw InvalidOperationException when the variable + is absent or empty. + justification: | + When an operator explicitly names a token variable in the configuration, the + connector must not silently fall back to other credential sources. Strict + enforcement ensures that misconfigured environments produce clear error messages + rather than accidentally using a different token with unexpected permissions. + tests: + - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable + - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException + - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException diff --git a/docs/reqstream/build-mark/repo-connectors/item-controls-parser.yaml b/docs/reqstream/build-mark/repo-connectors/item-controls-parser.yaml index 493c03e..04e2a06 100644 --- a/docs/reqstream/build-mark/repo-connectors/item-controls-parser.yaml +++ b/docs/reqstream/build-mark/repo-connectors/item-controls-parser.yaml @@ -1,58 +1,59 @@ --- -# Software Unit Requirements for the ItemControlsParser and ItemControlsInfo Classes -# -# ItemControlsParser is a static utility class that extracts a buildmark fenced -# code block from a description string and parses its key-value fields into an -# ItemControlsInfo record. -# ItemControlsInfo is the immutable data record that holds the parsed controls. +# ItemControlsParser and ItemControlsInfo unit requirements sections: - - title: ItemControlsParser Unit Requirements - requirements: - - id: BuildMark-ItemControlsInfo-Record - title: >- - The ItemControlsInfo record shall store the parsed visibility, type, - and affected-version values extracted from a buildmark block. - justification: | - Connectors need a single immutable value to carry all parsed overrides - from ItemControlsParser to downstream classification and reporting logic. - Storing the parsed values together keeps the parser output stable and - easy to consume. - tests: - - ItemControlsParser_Parse_WithVisibilityPublic_ReturnsPublicVisibility - - ItemControlsParser_Parse_WithTypeBug_ReturnsBugType - - ItemControlsParser_Parse_WithAffectedVersions_ReturnsIntervalSet + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: ItemControlsInfo Requirements + requirements: + - id: BuildMark-ItemControlsInfo-Record + title: >- + The ItemControlsInfo record shall store the parsed visibility, type, + and affected-version values extracted from a buildmark block. + justification: | + Connectors need a single immutable value to carry all parsed overrides + from ItemControlsParser to downstream classification and reporting logic. + Storing the parsed values together keeps the parser output stable and + easy to consume. + tests: + - ItemControlsParser_Parse_WithVisibilityPublic_ReturnsPublicVisibility + - ItemControlsParser_Parse_WithTypeBug_ReturnsBugType + - ItemControlsParser_Parse_WithAffectedVersions_ReturnsIntervalSet - - id: BuildMark-ItemControlsParser-Parse - title: >- - The ItemControlsParser class shall extract and parse a buildmark code block - from a description string, returning null when no block is present. - justification: | - Returning null for a missing block allows callers to apply default label-based - rules unchanged, preserving backward compatibility with issues and pull requests - that do not include a buildmark block. - tests: - - ItemControlsParser_Parse_WithVisibilityPublic_ReturnsPublicVisibility - - ItemControlsParser_Parse_WithVisibilityInternal_ReturnsInternalVisibility - - ItemControlsParser_Parse_WithTypeBug_ReturnsBugType - - ItemControlsParser_Parse_WithTypeFeature_ReturnsFeatureType - - ItemControlsParser_Parse_WithAffectedVersions_ReturnsIntervalSet - - ItemControlsParser_Parse_WithNoBlock_ReturnsNull - - ItemControlsParser_Parse_WithNullDescription_ReturnsNull - - ItemControlsParser_Parse_WithEmptyDescription_ReturnsNull - - ItemControlsParser_Parse_WithUnknownKey_IgnoresKey - - ItemControlsParser_Parse_WithUnrecognizedVisibilityValue_IgnoresValue - - ItemControlsParser_Parse_WithUnrecognizedTypeValue_IgnoresValue - - ItemControlsParser_Parse_WithUnrecognizedAffectedVersionsValue_IgnoresValue + - title: ItemControlsParser Requirements + requirements: + - id: BuildMark-ItemControlsParser-Parse + title: >- + The ItemControlsParser class shall extract and parse a buildmark code block + from a description string, returning null when no block is present. + justification: | + Returning null for a missing block allows callers to apply default label-based + rules unchanged, preserving backward compatibility with issues and pull requests + that do not include a buildmark block. + tests: + - ItemControlsParser_Parse_WithVisibilityPublic_ReturnsPublicVisibility + - ItemControlsParser_Parse_WithVisibilityInternal_ReturnsInternalVisibility + - ItemControlsParser_Parse_WithTypeBug_ReturnsBugType + - ItemControlsParser_Parse_WithTypeFeature_ReturnsFeatureType + - ItemControlsParser_Parse_WithAffectedVersions_ReturnsIntervalSet + - ItemControlsParser_Parse_WithNoBlock_ReturnsNull + - ItemControlsParser_Parse_WithNullDescription_ReturnsNull + - ItemControlsParser_Parse_WithEmptyDescription_ReturnsNull + - ItemControlsParser_Parse_WithUnknownKey_IgnoresKey + - ItemControlsParser_Parse_WithUnrecognizedVisibilityValue_IgnoresValue + - ItemControlsParser_Parse_WithUnrecognizedTypeValue_IgnoresValue + - ItemControlsParser_Parse_WithUnrecognizedAffectedVersionsValue_IgnoresValue - - id: BuildMark-ItemControlsParser-HiddenBlock - title: >- - The ItemControlsParser class shall recognize a buildmark code block that is - wrapped in an HTML comment. - justification: | - Some teams prefer clean issue descriptions without visible metadata blocks. - The parser must strip HTML comment wrappers before scanning for the code fence - so that hidden blocks are treated identically to visible ones. - tests: - - ItemControlsParser_Parse_WithHiddenBlock_ReturnsControls - - ItemControlsParser_Parse_WithHiddenBlockVisibilityInternal_ReturnsInternalVisibility + - id: BuildMark-ItemControlsParser-HiddenBlock + title: >- + The ItemControlsParser class shall recognize a buildmark code block that is + wrapped in an HTML comment. + justification: | + Some teams prefer clean issue descriptions without visible metadata blocks. + The parser must strip HTML comment wrappers before scanning for the code fence + so that hidden blocks are treated identically to visible ones. + tests: + - ItemControlsParser_Parse_WithHiddenBlock_ReturnsControls + - ItemControlsParser_Parse_WithHiddenBlockVisibilityInternal_ReturnsInternalVisibility diff --git a/docs/reqstream/build-mark/repo-connectors/item-router.yaml b/docs/reqstream/build-mark/repo-connectors/item-router.yaml index 3fa380a..cde83b5 100644 --- a/docs/reqstream/build-mark/repo-connectors/item-router.yaml +++ b/docs/reqstream/build-mark/repo-connectors/item-router.yaml @@ -1,26 +1,27 @@ --- -# Software Unit Requirements for the ItemRouter Class -# -# ItemRouter distributes ItemInfo records into configured report sections using -# section definitions and routing rules supplied by the active connector. +# ItemRouter unit requirements sections: - - title: ItemRouter Unit Requirements - requirements: - - id: BuildMark-ItemRouter-Route - title: >- - The ItemRouter class shall assign items to report sections according to - the configured rules and sections. - justification: | - Centralizing routing logic ensures all connectors classify and group - items consistently when generating build notes, without duplicating the - same rule-processing behavior in multiple connector implementations. - tests: - - ItemRouter_Route_MatchingRuleRoutesItemToConfiguredSection - - ItemRouter_Route_SuppressedRouteOmitsMatchingItem - - ItemRouter_Route_WithNullMatchBlock_MatchesAllItems - - ItemRouter_Route_WithWorkItemTypeMatch_RoutesMatchingItem - - ItemRouter_Route_WithNoMatchingRule_RoutesToDefaultSection - - ItemRouter_Route_ItemNotInConfiguredSections_CreatesNewSection - - ItemRouter_Route_WithCaseInsensitiveLabelMatch_RoutesItem - - ItemRouter_Route_WithCaseInsensitiveSuppressedRoute_OmitsMatchingItem + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: ItemRouter Requirements + requirements: + - id: BuildMark-ItemRouter-Route + title: >- + The ItemRouter class shall assign items to report sections according to + the configured rules and sections. + justification: | + Centralizing routing logic ensures all connectors classify and group + items consistently when generating build notes, without duplicating the + same rule-processing behavior in multiple connector implementations. + tests: + - ItemRouter_Route_MatchingRuleRoutesItemToConfiguredSection + - ItemRouter_Route_SuppressedRouteOmitsMatchingItem + - ItemRouter_Route_WithNullMatchBlock_MatchesAllItems + - ItemRouter_Route_WithWorkItemTypeMatch_RoutesMatchingItem + - ItemRouter_Route_WithNoMatchingRule_RoutesToDefaultSection + - ItemRouter_Route_ItemNotInConfiguredSections_CreatesNewSection + - ItemRouter_Route_WithCaseInsensitiveLabelMatch_RoutesItem + - ItemRouter_Route_WithCaseInsensitiveSuppressedRoute_OmitsMatchingItem diff --git a/docs/reqstream/build-mark/repo-connectors/mock.yaml b/docs/reqstream/build-mark/repo-connectors/mock.yaml index 14d99e2..f36e230 100644 --- a/docs/reqstream/build-mark/repo-connectors/mock.yaml +++ b/docs/reqstream/build-mark/repo-connectors/mock.yaml @@ -1,28 +1,25 @@ --- -# Mock Sub-Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark Mock sub-subsystem -# - The Mock sub-subsystem provides a deterministic in-memory connector used -# by the built-in --validate self-test and development unit tests -# - Sub-subsystem requirements describe the externally visible contract -# satisfied by the units beneath this sub-subsystem +# Mock subsystem requirements sections: - - title: Mock Sub-Subsystem Requirements - requirements: - - id: BuildMark-Mock-SubSystem - title: >- - The Mock sub-subsystem shall provide a deterministic repository connector - for self-test and development. - justification: | - A deterministic mock connector enables the built-in --validate self-test and - unit testing of build information processing logic without requiring an actual - repository connection, ensuring tests are fast, repeatable, and independent - of external services. - tests: - - Mock_ImplementsInterface_ReturnsTrue - - Mock_GetBuildInformation_ReturnsExpectedVersion - - Mock_GetBuildInformation_ReturnsCompleteInformation - children: - - BuildMark-MockRepoConnector-Deterministic + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: Mock Requirements + requirements: + - id: BuildMark-Mock-SubSystem + title: >- + The Mock sub-subsystem shall provide a deterministic repository connector + for self-test and development. + justification: | + A deterministic mock connector enables the built-in --validate self-test and + unit testing of build information processing logic without requiring an actual + repository connection, ensuring tests are fast, repeatable, and independent + of external services. + tests: + - Mock_ImplementsInterface_ReturnsTrue + - Mock_GetBuildInformation_ReturnsExpectedVersion + - Mock_GetBuildInformation_ReturnsCompleteInformation + children: + - BuildMark-MockRepoConnector-Deterministic diff --git a/docs/reqstream/build-mark/repo-connectors/mock/mock-repo-connector.yaml b/docs/reqstream/build-mark/repo-connectors/mock/mock-repo-connector.yaml index 1a81945..d465e1a 100644 --- a/docs/reqstream/build-mark/repo-connectors/mock/mock-repo-connector.yaml +++ b/docs/reqstream/build-mark/repo-connectors/mock/mock-repo-connector.yaml @@ -1,34 +1,36 @@ --- -# Software Unit Requirements for the MockRepoConnector Class -# -# MockRepoConnector is an in-memory repository connector used for -# deterministic testing. It provides fixed build information covering -# multiple versions, change types, and known issues. +# MockRepoConnector unit requirements sections: - - title: MockRepoConnector Unit Requirements - requirements: - - id: BuildMark-MockRepoConnector-Deterministic - title: The MockRepoConnector class shall return deterministic build information for testing. - justification: | - Tests that exercise the report generation and self-validation logic must run - without external dependencies. The MockRepoConnector provides a fixed, - predictable dataset so tests can assert exact outcomes. + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: Mock Requirements + sections: + - title: MockRepoConnector Requirements + requirements: + - id: BuildMark-MockRepoConnector-Deterministic + title: The MockRepoConnector class shall return deterministic build information for testing. + justification: | + Tests that exercise the report generation and self-validation logic must run + without external dependencies. The MockRepoConnector provides a fixed, + predictable dataset so tests can assert exact outcomes. - The dataset includes a closed bug (issue 7) that carries an affected-versions - range, allowing tests to verify that the known-issues collection applies the - correct two-tier rule: version-range check for bugs with affected-versions, and - open/closed status fallback for bugs without. - tests: - - MockRepoConnector_Constructor_CreatesInstance - - MockRepoConnector_ImplementsInterface - - MockRepoConnector_GetBuildInformationAsync_ReturnsExpectedVersion - - MockRepoConnector_GetBuildInformationAsync_ReturnsCompleteInformation - - MockRepoConnector_GetBuildInformationAsync_WithValidVersionFromTags_ReturnsCorrectBaseline - - MockRepoConnector_GetBuildInformationAsync_CategorizesChangesCorrectly - - MockRepoConnector_Configure_StoresRulesAndSections - - MockRepoConnector_GetBuildInformationAsync_WithRules_ReturnsRoutedSections - - MockRepoConnector_GetBuildInformationAsync_WithoutRules_ReturnsNullRoutedSections - - MockRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions - - MockRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue - - MockRepoConnector_GetBuildInformationAsync_WithRulesAndKnownIssues_KnownIssuesNotInRoutedSections + The dataset includes a closed bug (issue 7) that carries an affected-versions + range, allowing tests to verify that the known-issues collection applies the + correct two-tier rule: version-range check for bugs with affected-versions, and + open/closed status fallback for bugs without. + tests: + - MockRepoConnector_Constructor_CreatesInstance + - MockRepoConnector_ImplementsInterface + - MockRepoConnector_GetBuildInformationAsync_ReturnsExpectedVersion + - MockRepoConnector_GetBuildInformationAsync_ReturnsCompleteInformation + - MockRepoConnector_GetBuildInformationAsync_WithValidVersionFromTags_ReturnsCorrectBaseline + - MockRepoConnector_GetBuildInformationAsync_CategorizesChangesCorrectly + - MockRepoConnector_Configure_StoresRulesAndSections + - MockRepoConnector_GetBuildInformationAsync_WithRules_ReturnsRoutedSections + - MockRepoConnector_GetBuildInformationAsync_WithoutRules_ReturnsNullRoutedSections + - MockRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions + - MockRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue + - MockRepoConnector_GetBuildInformationAsync_WithRulesAndKnownIssues_KnownIssuesNotInRoutedSections diff --git a/docs/reqstream/build-mark/repo-connectors/repo-connector-base.yaml b/docs/reqstream/build-mark/repo-connectors/repo-connector-base.yaml index 5177df3..9bc6ae0 100644 --- a/docs/reqstream/build-mark/repo-connectors/repo-connector-base.yaml +++ b/docs/reqstream/build-mark/repo-connectors/repo-connector-base.yaml @@ -1,108 +1,108 @@ --- -# Software Unit Requirements for the IRepoConnector Interface and RepoConnectorBase Class -# -# IRepoConnector defines the contract for all repository connectors. -# RepoConnectorBase provides a common base implementation including process -# execution delegation and version-list search utilities. +# RepoConnectorBase unit requirements sections: - - title: RepoConnectorBase Unit Requirements - requirements: - - id: BuildMark-RepoConnectorBase-Interface - title: >- - Repository connectors shall be interchangeable, allowing the factory and - program to use any connector implementation without depending on concrete types. - justification: | - A common interface ensures that all repository connectors are interchangeable, - enabling the factory and program to work with any connector implementation - without depending on concrete types. - tests: - - MockRepoConnector_ImplementsInterface - - GitHubRepoConnector_ImplementsInterface_ReturnsTrue + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: RepoConnectorBase Requirements + requirements: + - id: BuildMark-RepoConnectorBase-Interface + title: >- + Repository connectors shall be interchangeable, allowing the factory and + program to use any connector implementation without depending on concrete types. + justification: | + A common interface ensures that all repository connectors are interchangeable, + enabling the factory and program to work with any connector implementation + without depending on concrete types. + tests: + - MockRepoConnector_ImplementsInterface + - GitHubRepoConnector_ImplementsInterface_ReturnsTrue - - id: BuildMark-RepoConnectorBase-CommandExecution - title: >- - Repository connectors shall execute shell commands and return their output - to retrieve repository information. - justification: | - Repository connectors run git and CLI commands to retrieve repository - information such as version tags, commit hashes, and remote URLs. The base - class centralizes process execution so that all connector implementations - consistently invoke commands and propagate their output without duplicating - subprocess-management logic. - tests: - - GitHubRepoConnector_GetBuildInformationAsync_WithMockedData_ReturnsValidBuildInformation - - GitHubRepoConnector_GetBuildInformationAsync_WithMultipleVersions_SelectsCorrectPreviousVersionAndGeneratesChangelogLink + - id: BuildMark-RepoConnectorBase-CommandExecution + title: >- + Repository connectors shall execute shell commands and return their output + to retrieve repository information. + justification: | + Repository connectors run git and CLI commands to retrieve repository + information such as version tags, commit hashes, and remote URLs. The base + class centralizes process execution so that all connector implementations + consistently invoke commands and propagate their output without duplicating + subprocess-management logic. + tests: + - GitHubRepoConnector_GetBuildInformationAsync_WithMockedData_ReturnsValidBuildInformation + - GitHubRepoConnector_GetBuildInformationAsync_WithMultipleVersions_SelectsCorrectPreviousVersionAndGeneratesChangelogLink - - id: BuildMark-RepoConnectorBase-RulesRouting - title: >- - The RepoConnectorBase class shall accept routing rules and section definitions - and apply them to distribute items into the appropriate report sections. - justification: | - Centralizing routing configuration and application in the base class ensures - that all connectors honour the same rules and section definitions supplied by - the program configuration, without duplicating routing logic in every concrete - connector. - tests: - - RepoConnectorBase_Configure_StoresRulesAndSections_HasRulesReturnsTrue - - RepoConnectorBase_Configure_EmptyRules_HasRulesReturnsFalse - - RepoConnectorBase_ApplyRules_RoutesItemsToConfiguredSections - - MockRepoConnector_Configure_StoresRulesAndSections - - MockRepoConnector_GetBuildInformationAsync_WithRules_ReturnsRoutedSections - - MockRepoConnector_GetBuildInformationAsync_WithoutRules_ReturnsNullRoutedSections + - id: BuildMark-RepoConnectorBase-RulesRouting + title: >- + The RepoConnectorBase class shall accept routing rules and section definitions + and apply them to distribute items into the appropriate report sections. + justification: | + Centralizing routing configuration and application in the base class ensures + that all connectors honour the same rules and section definitions supplied by + the program configuration, without duplicating routing logic in every concrete + connector. + tests: + - RepoConnectorBase_Configure_StoresRulesAndSections_HasRulesReturnsTrue + - RepoConnectorBase_Configure_EmptyRules_HasRulesReturnsFalse + - RepoConnectorBase_ApplyRules_RoutesItemsToConfiguredSections + - MockRepoConnector_Configure_StoresRulesAndSections + - MockRepoConnector_GetBuildInformationAsync_WithRules_ReturnsRoutedSections + - MockRepoConnector_GetBuildInformationAsync_WithoutRules_ReturnsNullRoutedSections - - id: BuildMark-RepoConnectorBase-FindVersionIndex - title: >- - The RepoConnectorBase class shall locate a version tag within a list by - semantic equality, supporting repositories that use different tag string - formats for the same version. - justification: | - Matching version tags by semantic equality rather than raw tag string allows - connectors to handle different tagging conventions (e.g., 'v1.2.3', - 'VER1.2.3', 'Release-1.2.3') without failing to find a corresponding entry. - Centralizing this in the base class avoids duplication across connectors. - tests: - - RepoConnectorBase_FindVersionIndex_DifferentPrefixSameVersion_ReturnsCorrectIndex - - RepoConnectorBase_FindVersionIndex_VersionNotInList_ReturnsMinusOne + - id: BuildMark-RepoConnectorBase-FindVersionIndex + title: >- + The RepoConnectorBase class shall locate a version tag within a list by + semantic equality, supporting repositories that use different tag string + formats for the same version. + justification: | + Matching version tags by semantic equality rather than raw tag string allows + connectors to handle different tagging conventions (e.g., 'v1.2.3', + 'VER1.2.3', 'Release-1.2.3') without failing to find a corresponding entry. + Centralizing this in the base class avoids duplication across connectors. + tests: + - RepoConnectorBase_FindVersionIndex_DifferentPrefixSameVersion_ReturnsCorrectIndex + - RepoConnectorBase_FindVersionIndex_VersionNotInList_ReturnsMinusOne - - id: BuildMark-RepoConnectorBase-BaselinePreRelease - title: >- - For a pre-release target version, RepoConnectorBase shall select the most - recent preceding tag with a different commit hash as the baseline, skipping - tags that share the same commit hash to avoid generating empty changelogs. - justification: | - When multiple pre-release tags are created from the same commit (e.g., a tag - is renamed or recreated), using such a tag as the baseline would produce an - empty changelog because the commit range would be empty. By skipping tags with - the same commit hash, BuildMark always produces a meaningful changelog for - pre-release builds. - tests: - - RepoConnectorBase_FindBaselineForPreRelease_SameCommitSkipped_ReturnsPreviousDistinctCommit - - RepoConnectorBase_FindBaselineForPreRelease_AllSameCommit_ReturnsNull + - id: BuildMark-RepoConnectorBase-BaselinePreRelease + title: >- + For a pre-release target version, RepoConnectorBase shall select the most + recent preceding tag with a different commit hash as the baseline, skipping + tags that share the same commit hash to avoid generating empty changelogs. + justification: | + When multiple pre-release tags are created from the same commit (e.g., a tag + is renamed or recreated), using such a tag as the baseline would produce an + empty changelog because the commit range would be empty. By skipping tags with + the same commit hash, BuildMark always produces a meaningful changelog for + pre-release builds. + tests: + - RepoConnectorBase_FindBaselineForPreRelease_SameCommitSkipped_ReturnsPreviousDistinctCommit + - RepoConnectorBase_FindBaselineForPreRelease_AllSameCommit_ReturnsNull - - id: BuildMark-RepoConnectorBase-BaselineRelease - title: >- - For a release target version, RepoConnectorBase shall select the most recent - preceding release tag as the baseline, skipping all pre-release tags. - justification: | - Release notes should describe changes since the previous stable release, not - since the most recent pre-release candidate. Skipping pre-release tags when - selecting the baseline ensures that the generated changelog covers the complete - set of changes that went into the release. - tests: - - RepoConnectorBase_FindBaselineForRelease_SkipsPreReleaseTags_ReturnsPreviousReleaseTag - - RepoConnectorBase_FindBaselineForRelease_NoPreviousRelease_ReturnsNull + - id: BuildMark-RepoConnectorBase-BaselineRelease + title: >- + For a release target version, RepoConnectorBase shall select the most recent + preceding release tag as the baseline, skipping all pre-release tags. + justification: | + Release notes should describe changes since the previous stable release, not + since the most recent pre-release candidate. Skipping pre-release tags when + selecting the baseline ensures that the generated changelog covers the complete + set of changes that went into the release. + tests: + - RepoConnectorBase_FindBaselineForRelease_SkipsPreReleaseTags_ReturnsPreviousReleaseTag + - RepoConnectorBase_FindBaselineForRelease_NoPreviousRelease_ReturnsNull - - id: BuildMark-RepoConnectorBase-BaselineNoHistory - title: >- - When no qualifying baseline tag exists in the version history, - RepoConnectorBase shall return null to indicate that build notes should be - generated from the beginning of repository history. - justification: | - The first release in a repository has no predecessor tag, so there is no - meaningful baseline from which to compute a changelog. Returning null allows - the connector to generate build notes covering the complete repository history - up to the first release, rather than producing an error or an empty report. - tests: - - RepoConnectorBase_FindBaselineForRelease_NoPreviousVersion_ReturnsNull - - RepoConnectorBase_FindBaselineForPreRelease_NoPreviousVersion_ReturnsNull + - id: BuildMark-RepoConnectorBase-BaselineNoHistory + title: >- + When no qualifying baseline tag exists in the version history, + RepoConnectorBase shall return null to indicate that build notes should be + generated from the beginning of repository history. + justification: | + The first release in a repository has no predecessor tag, so there is no + meaningful baseline from which to compute a changelog. Returning null allows + the connector to generate build notes covering the complete repository history + up to the first release, rather than producing an error or an empty report. + tests: + - RepoConnectorBase_FindBaselineForRelease_NoPreviousVersion_ReturnsNull + - RepoConnectorBase_FindBaselineForPreRelease_NoPreviousVersion_ReturnsNull diff --git a/docs/reqstream/build-mark/repo-connectors/repo-connector-factory.yaml b/docs/reqstream/build-mark/repo-connectors/repo-connector-factory.yaml index 0a2134c..2950db2 100644 --- a/docs/reqstream/build-mark/repo-connectors/repo-connector-factory.yaml +++ b/docs/reqstream/build-mark/repo-connectors/repo-connector-factory.yaml @@ -1,51 +1,51 @@ --- -# Software Unit Requirements for the RepoConnectorFactory Class -# -# RepoConnectorFactory creates the appropriate IRepoConnector implementation -# based on the runtime environment (GitHub Actions environment variables and -# git remote URL inspection). +# RepoConnectorFactory unit requirements sections: - - title: RepoConnectorFactory Unit Requirements - requirements: - - id: BuildMark-RepoConnectorFactory-Create - title: >- - The RepoConnectorFactory class shall create the appropriate repository - connector based on environment variables and git remote URL inspection. - justification: | - The factory encapsulates connector selection logic, auto-detecting - the environment using GitHub Actions environment variables and git remote - URL inspection, so that the program does not need to contain environment - detection logic itself. - tests: - - RepoConnectorFactory_Create_ReturnsConnector - - RepoConnectorFactory_Create_ReturnsGitHubConnectorForThisRepo - - RepoConnectorFactory_Create_WithGitHubRemoteUrl_ReturnsGitHubConnector - - RepoConnectorFactory_Create_WithNullRemoteUrl_DefaultsToGitHubConnector + - title: BuildMark Requirements + sections: + - title: RepoConnectors Requirements + sections: + - title: RepoConnectorFactory Requirements + requirements: + - id: BuildMark-RepoConnectorFactory-Create + title: >- + The RepoConnectorFactory class shall create the appropriate repository + connector based on environment variables and git remote URL inspection. + justification: | + The factory encapsulates connector selection logic, auto-detecting + the environment using GitHub Actions environment variables and git remote + URL inspection, so that the program does not need to contain environment + detection logic itself. + tests: + - RepoConnectorFactory_Create_ReturnsConnector + - RepoConnectorFactory_Create_ReturnsGitHubConnectorForThisRepo + - RepoConnectorFactory_Create_WithGitHubRemoteUrl_ReturnsGitHubConnector + - RepoConnectorFactory_Create_WithNullRemoteUrl_DefaultsToGitHubConnector - - id: BuildMark-RepoConnectorFactory-ConnectorConfig - title: >- - The RepoConnectorFactory class shall accept an optional ConnectorConfig and forward - connector-specific settings to the created connector. - justification: | - The factory must pass GitHubConnectorConfig (when present) to GitHubRepoConnector - so that owner, repository, and base URL overrides from .buildmark.yaml take - effect. This pattern extends naturally to future connector types. - tests: - - RepoConnectorFactory_Create_WithConnectorConfig_ForwardsGitHubConfiguration + - id: BuildMark-RepoConnectorFactory-ConnectorConfig + title: >- + The RepoConnectorFactory class shall accept an optional ConnectorConfig and forward + connector-specific settings to the created connector. + justification: | + The factory must pass GitHubConnectorConfig (when present) to GitHubRepoConnector + so that owner, repository, and base URL overrides from .buildmark.yaml take + effect. This pattern extends naturally to future connector types. + tests: + - RepoConnectorFactory_Create_WithConnectorConfig_ForwardsGitHubConfiguration - - id: BuildMark-RepoConnectorFactory-AzureDevOpsDetection - title: >- - The RepoConnectorFactory class shall detect Azure DevOps environments and create an - AzureDevOpsRepoConnector when appropriate. - justification: | - The factory must auto-detect Azure DevOps Pipelines environments by checking the - TF_BUILD environment variable and git remote URLs containing dev.azure.com or - visualstudio.com. It must also support explicit configuration via ConnectorConfig - with type "azure-devops" and forward AzureDevOpsConnectorConfig to the created connector. - tests: - - RepoConnectorFactory_Create_WithAzureDevOpsType_CreatesAzureDevOpsConnector - - RepoConnectorFactory_Create_WithTfBuildEnv_ReturnsAzureDevOpsConnector - - RepoConnectorFactory_Create_WithAzureDevOpsRemoteUrl_ReturnsAzureDevOpsConnector - - RepoConnectorFactory_Create_WithVisualStudioRemoteUrl_ReturnsAzureDevOpsConnector - - RepoConnectorFactory_Create_WithAzureDevOpsConnectorConfig_ForwardsAzureDevOpsConfiguration + - id: BuildMark-RepoConnectorFactory-AzureDevOpsDetection + title: >- + The RepoConnectorFactory class shall detect Azure DevOps environments and create an + AzureDevOpsRepoConnector when appropriate. + justification: | + The factory must auto-detect Azure DevOps Pipelines environments by checking the + TF_BUILD environment variable and git remote URLs containing dev.azure.com or + visualstudio.com. It must also support explicit configuration via ConnectorConfig + with type "azure-devops" and forward AzureDevOpsConnectorConfig to the created connector. + tests: + - RepoConnectorFactory_Create_WithAzureDevOpsType_CreatesAzureDevOpsConnector + - RepoConnectorFactory_Create_WithTfBuildEnv_ReturnsAzureDevOpsConnector + - RepoConnectorFactory_Create_WithAzureDevOpsRemoteUrl_ReturnsAzureDevOpsConnector + - RepoConnectorFactory_Create_WithVisualStudioRemoteUrl_ReturnsAzureDevOpsConnector + - RepoConnectorFactory_Create_WithAzureDevOpsConnectorConfig_ForwardsAzureDevOpsConfiguration diff --git a/docs/reqstream/build-mark/self-test.yaml b/docs/reqstream/build-mark/self-test.yaml index 031f39f..73abb46 100644 --- a/docs/reqstream/build-mark/self-test.yaml +++ b/docs/reqstream/build-mark/self-test.yaml @@ -1,42 +1,37 @@ --- -# SelfTest Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark SelfTest subsystem -# - The SelfTest subsystem spans Validation.cs (self-validation test execution) -# - Subsystem requirements describe the self-validation mechanism for tool qualification -# in regulated environments - +# BuildMark SelfTest subsystem requirements sections: - - title: SelfTest Subsystem Requirements - requirements: - - id: BuildMark-SelfTest-Qualification - title: The tool shall provide a self-validation mechanism to qualify the tool in its deployment environment. - justification: | - In regulated environments, tool qualification evidence is required to demonstrate - that the tool functions correctly in its deployment environment before it is used - to generate compliance artifacts. The SelfTest subsystem provides a built-in - self-validation suite that exercises core behaviors and produces a pass/fail - summary, enabling quality assurance teams to obtain tool qualification evidence - without requiring a separate test harness. - tests: - - SelfTest_Validation_WithTrxFile_WritesResults - - SelfTest_Validation_WithXmlFile_WritesResults - - SelfTest_Qualification_WithoutResultsFile_Succeeds - children: - - BuildMark-Validation-Run + - title: BuildMark Requirements + sections: + - title: SelfTest Requirements + requirements: + - id: BuildMark-SelfTest-Qualification + title: The tool shall provide a self-validation mechanism to qualify the tool in its deployment environment. + justification: | + In regulated environments, tool qualification evidence is required to demonstrate + that the tool functions correctly in its deployment environment before it is used + to generate compliance artifacts. The SelfTest subsystem provides a built-in + self-validation suite that exercises core behaviors and produces a pass/fail + summary, enabling quality assurance teams to obtain tool qualification evidence + without requiring a separate test harness. + tests: + - SelfTest_Validation_WithTrxFile_WritesResults + - SelfTest_Validation_WithXmlFile_WritesResults + - SelfTest_Qualification_WithoutResultsFile_Succeeds + children: + - BuildMark-Validation-Run - - id: BuildMark-SelfTest-ResultsOutput - title: The tool shall write self-validation results to a standard test result file when --results is provided. - justification: | - CI/CD pipelines and requirements traceability tools (such as ReqStream) consume - test result files in standard formats. By supporting both TRX (MSTest) and JUnit - XML output, the SelfTest subsystem enables self-validation results to be fed - directly into pipeline tooling and traceability reports without additional - conversion steps, satisfying audit trail requirements. - tests: - - SelfTest_ResultsOutput_WithTrxFile_CreatesFile - - SelfTest_ResultsOutput_WithXmlFile_CreatesFile - children: - - BuildMark-Validation-TrxOutput - - BuildMark-Validation-JUnitOutput + - id: BuildMark-SelfTest-ResultsOutput + title: The tool shall write self-validation results to a standard test result file when --results is provided. + justification: | + CI/CD pipelines and requirements traceability tools (such as ReqStream) consume + test result files in standard formats. By supporting both TRX (VSTest) and JUnit + XML output, the SelfTest subsystem enables self-validation results to be fed + directly into pipeline tooling and traceability reports without additional + conversion steps, satisfying audit trail requirements. + tests: + - SelfTest_ResultsOutput_WithTrxFile_CreatesFile + - SelfTest_ResultsOutput_WithXmlFile_CreatesFile + children: + - BuildMark-Validation-TrxOutput + - BuildMark-Validation-JUnitOutput diff --git a/docs/reqstream/build-mark/self-test/validation.yaml b/docs/reqstream/build-mark/self-test/validation.yaml index ff2e494..2a2e3a2 100644 --- a/docs/reqstream/build-mark/self-test/validation.yaml +++ b/docs/reqstream/build-mark/self-test/validation.yaml @@ -1,41 +1,41 @@ --- -# Software Unit Requirements for the Validation Class -# -# The Validation class executes the BuildMark self-validation test suite and -# writes results to standard test result files (TRX or JUnit XML format). - +# BuildMark Validation unit requirements sections: - - title: Validation Unit Requirements - requirements: - - id: BuildMark-Validation-Run - title: The Validation class shall execute self-validation tests and produce a summary report. - justification: | - Regulated environments require tool qualification evidence that the tool functions - correctly in the specific deployment environment. The Validation class exercises - core BuildMark behaviors and produces a pass/fail summary to support tool - qualification activities. - tests: - - Validation_Run_WithTrxResultsFile_WritesTrxFile - - Validation_Run_WithXmlResultsFile_WritesJUnitFile - - Validation_Run_WithoutResultsFile_CompletesSuccessfully + - title: BuildMark Requirements + sections: + - title: SelfTest Requirements + sections: + - title: Validation Requirements + requirements: + - id: BuildMark-Validation-Run + title: The Validation class shall execute self-validation tests and produce a summary report. + justification: | + Regulated environments require tool qualification evidence that the tool functions + correctly in the specific deployment environment. The Validation class exercises + core BuildMark behaviors and produces a pass/fail summary to support tool + qualification activities. + tests: + - Validation_Run_WithTrxResultsFile_WritesTrxFile + - Validation_Run_WithXmlResultsFile_WritesJUnitFile + - Validation_Run_WithoutResultsFile_CompletesSuccessfully - - id: BuildMark-Validation-TrxOutput - title: The Validation class shall write TRX format test results when a .trx results file is specified. - justification: | - TRX format support enables integration with Microsoft test tooling, Visual - Studio Test Explorer, and Azure DevOps pipelines, providing native support - for .NET development environments. - tests: - - Validation_Run_WithTrxResultsFile_WritesTrxFile - - Validation_Run_WithUnsupportedResultsFileExtension_ShowsError - - Validation_Run_WithInvalidResultsFilePath_ShowsError + - id: BuildMark-Validation-TrxOutput + title: The Validation class shall write TRX format test results when a .trx results file is specified. + justification: | + TRX format support enables integration with Microsoft test tooling, Visual + Studio Test Explorer, and Azure DevOps pipelines, providing native support + for .NET development environments. + tests: + - Validation_Run_WithTrxResultsFile_WritesTrxFile + - Validation_Run_WithUnsupportedResultsFileExtension_ShowsError + - Validation_Run_WithInvalidResultsFilePath_ShowsError - - id: BuildMark-Validation-JUnitOutput - title: The Validation class shall write JUnit XML format test results when an .xml results file is specified. - justification: | - JUnit format is a widely-supported standard across many CI/CD platforms and - testing tools. Supporting this format ensures BuildMark can integrate with - diverse toolchains beyond the Microsoft ecosystem. - tests: - - Validation_Run_WithXmlResultsFile_WritesJUnitFile - - Validation_Run_WithUnsupportedResultsFileExtension_ShowsError + - id: BuildMark-Validation-JUnitOutput + title: The Validation class shall write JUnit XML format test results when an .xml results file is specified. + justification: | + JUnit format is a widely-supported standard across many CI/CD platforms and + testing tools. Supporting this format ensures BuildMark can integrate with + diverse toolchains beyond the Microsoft ecosystem. + tests: + - Validation_Run_WithXmlResultsFile_WritesJUnitFile + - Validation_Run_WithUnsupportedResultsFileExtension_ShowsError diff --git a/docs/reqstream/build-mark/utilities.yaml b/docs/reqstream/build-mark/utilities.yaml index 97ec629..fc6ddc4 100644 --- a/docs/reqstream/build-mark/utilities.yaml +++ b/docs/reqstream/build-mark/utilities.yaml @@ -1,55 +1,51 @@ --- -# Utilities Subsystem Requirements -# -# PURPOSE: -# - Define requirements for the BuildMark Utilities subsystem -# - The Utilities subsystem spans PathHelpers.cs, ProcessRunner.cs, and TemporaryDirectory.cs -# - Subsystem requirements describe the shared utility behavior available to all other subsystems - +# BuildMark Utilities subsystem requirements sections: - - title: Utilities Subsystem Requirements - requirements: - - id: BuildMark-Utilities-SafePaths - title: The Utilities subsystem shall provide safe file path manipulation that prevents path traversal. - justification: | - The Utilities subsystem provides shared path utilities consumed by other subsystems. - When constructing file paths from caller-supplied inputs, the subsystem must reject - path traversal sequences (such as '..') and absolute paths to prevent unintended - file system access. This requirement captures the subsystem-level safety guarantee - that all consumers of the Utilities subsystem can rely upon. - tests: - - Utilities_SafePaths_ValidPaths_CombinesCorrectly - - Utilities_SafePaths_TraversalPath_ThrowsException - - Utilities_SafePaths_AbsolutePath_ThrowsException - children: - - BuildMark-PathHelpers-SafeCombine + - title: BuildMark Requirements + sections: + - title: Utilities Requirements + requirements: + - id: BuildMark-Utilities-SafePaths + title: The Utilities subsystem shall provide safe file path manipulation that prevents path traversal. + justification: | + The Utilities subsystem provides shared path utilities consumed by other subsystems. + When constructing file paths from caller-supplied inputs, the subsystem must reject + path traversal sequences (such as '..') and absolute paths to prevent unintended + file system access. This requirement captures the subsystem-level safety guarantee + that all consumers of the Utilities subsystem can rely upon. + tests: + - Utilities_SafePaths_ValidPaths_CombinesCorrectly + - Utilities_SafePaths_TraversalPath_ThrowsException + - Utilities_SafePaths_AbsolutePath_ThrowsException + children: + - BuildMark-PathHelpers-SafeCombine - - id: BuildMark-Utilities-ProcessRunner - title: The Utilities subsystem shall provide a process execution utility for running external shell commands. - justification: | - Multiple subsystems need to execute shell commands (e.g., git, gh CLI) to retrieve - repository information and authentication tokens. Placing ProcessRunner in the shared - Utilities subsystem ensures a consistent, testable interface with proper error - handling, avoiding duplication across connector implementations. - tests: - - Utilities_ProcessRunner_ValidCommand_ReturnsOutput - - Utilities_ProcessRunner_InvalidCommand_ReturnsNull - - Utilities_ProcessRunner_FailingCommand_ThrowsException - children: - - BuildMark-ProcessRunner-RunAsync + - id: BuildMark-Utilities-ProcessRunner + title: The Utilities subsystem shall provide a process execution utility for running external shell commands. + justification: | + Multiple subsystems need to execute shell commands (e.g., git, gh CLI) to retrieve + repository information and authentication tokens. Placing ProcessRunner in the shared + Utilities subsystem ensures a consistent, testable interface with proper error + handling, avoiding duplication across connector implementations. + tests: + - Utilities_ProcessRunner_ValidCommand_ReturnsOutput + - Utilities_ProcessRunner_InvalidCommand_ReturnsNull + - Utilities_ProcessRunner_FailingCommand_ThrowsException + children: + - BuildMark-ProcessRunner-RunAsync - - id: BuildMark-Utilities-TemporaryDirectory - title: The Utilities subsystem shall provide a disposable temporary directory for isolating file-system artifacts. - justification: | - Multiple subsystems need a safe, isolated location to write temporary files during - self-test and integration operations. Placing TemporaryDirectory in the shared - Utilities subsystem ensures consistent creation, path-safety, and cleanup behavior - across all consumers, without each caller reimplementing ad-hoc temporary-file logic. - tests: - - TemporaryDirectory_Constructor_CreatesDirectory - - TemporaryDirectory_Dispose_DeletesDirectory - children: - - BuildMark-TemporaryDirectory-Creation - - BuildMark-TemporaryDirectory-FilePath - - BuildMark-TemporaryDirectory-Traversal - - BuildMark-TemporaryDirectory-Cleanup + - id: BuildMark-Utilities-TemporaryDirectory + title: The Utilities subsystem shall provide a disposable temporary directory for isolating file-system artifacts. + justification: | + Multiple subsystems need a safe, isolated location to write temporary files during + self-test and integration operations. Placing TemporaryDirectory in the shared + Utilities subsystem ensures consistent creation, path-safety, and cleanup behavior + across all consumers, without each caller reimplementing ad-hoc temporary-file logic. + tests: + - TemporaryDirectory_Constructor_CreatesDirectory + - TemporaryDirectory_Dispose_DeletesDirectory + children: + - BuildMark-TemporaryDirectory-Creation + - BuildMark-TemporaryDirectory-FilePath + - BuildMark-TemporaryDirectory-Traversal + - BuildMark-TemporaryDirectory-Cleanup diff --git a/docs/reqstream/build-mark/utilities/path-helpers.yaml b/docs/reqstream/build-mark/utilities/path-helpers.yaml index 4f459bd..6d01687 100644 --- a/docs/reqstream/build-mark/utilities/path-helpers.yaml +++ b/docs/reqstream/build-mark/utilities/path-helpers.yaml @@ -1,24 +1,23 @@ --- -# Software Unit Requirements for the PathHelpers Class -# -# The PathHelpers class provides safe path-combination utilities that protect -# against path-traversal attacks by rejecting relative paths containing ".." -# or absolute paths when a relative path is expected. - +# BuildMark PathHelpers unit requirements sections: - - title: PathHelpers Unit Requirements - requirements: - - id: BuildMark-PathHelpers-SafeCombine - title: The PathHelpers class shall combine paths safely, preventing path traversal. - justification: | - Prevents path-traversal vulnerabilities when constructing file paths from - user-supplied or external inputs. Paths containing ".." or rooted paths - must be rejected to ensure the combined path remains under the base directory. - tests: - - PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly - - PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException - - PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException - - PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException - - PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException - - PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException - - PathHelpers_SafePathCombine_PathStartingWithDots_CombinesCorrectly + - title: BuildMark Requirements + sections: + - title: Utilities Requirements + sections: + - title: PathHelpers Requirements + requirements: + - id: BuildMark-PathHelpers-SafeCombine + title: The PathHelpers class shall combine paths safely, preventing path traversal. + justification: | + Prevents path-traversal vulnerabilities when constructing file paths from + user-supplied or external inputs. Paths containing ".." or rooted paths + must be rejected to ensure the combined path remains under the base directory. + tests: + - PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly + - PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException + - PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException + - PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException + - PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException + - PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException + - PathHelpers_SafePathCombine_PathStartingWithDots_CombinesCorrectly diff --git a/docs/reqstream/build-mark/utilities/process-runner.yaml b/docs/reqstream/build-mark/utilities/process-runner.yaml index 4e5945f..0cc3ad0 100644 --- a/docs/reqstream/build-mark/utilities/process-runner.yaml +++ b/docs/reqstream/build-mark/utilities/process-runner.yaml @@ -1,25 +1,24 @@ --- -# Software Unit Requirements for the ProcessRunner Class -# -# ProcessRunner provides static helpers for running external processes -# (such as git and gh CLI) and capturing their output. It exposes both -# a throwing variant (RunAsync) and a non-throwing variant (TryRunAsync). - +# BuildMark ProcessRunner unit requirements sections: - - title: ProcessRunner Unit Requirements - requirements: - - id: BuildMark-ProcessRunner-RunAsync - title: The ProcessRunner class shall execute external commands and return their output. - justification: | - Repository connectors need to run git and gh CLI commands to discover the - repository URL, current branch, current commit hash, and authentication - tokens. A centralized process runner ensures consistent error handling and - output capture across all callers. - tests: - - ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput - - ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull - - ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull - - ProcessRunner_TryRunAsync_WithException_ReturnsNull - - ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput - - ProcessRunner_RunAsync_WithFailingCommand_ThrowsException - - ProcessRunner_RunAsync_WithNonexistentCommand_ThrowsDescriptiveException + - title: BuildMark Requirements + sections: + - title: Utilities Requirements + sections: + - title: ProcessRunner Requirements + requirements: + - id: BuildMark-ProcessRunner-RunAsync + title: The ProcessRunner class shall execute external commands and return their output. + justification: | + Repository connectors need to run git and gh CLI commands to discover the + repository URL, current branch, current commit hash, and authentication + tokens. A centralized process runner ensures consistent error handling and + output capture across all callers. + tests: + - ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput + - ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull + - ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull + - ProcessRunner_TryRunAsync_WithException_ReturnsNull + - ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput + - ProcessRunner_RunAsync_WithFailingCommand_ThrowsException + - ProcessRunner_RunAsync_WithNonexistentCommand_ThrowsDescriptiveException diff --git a/docs/reqstream/build-mark/utilities/temporary-directory.yaml b/docs/reqstream/build-mark/utilities/temporary-directory.yaml index c3e8ed6..ffc9b11 100644 --- a/docs/reqstream/build-mark/utilities/temporary-directory.yaml +++ b/docs/reqstream/build-mark/utilities/temporary-directory.yaml @@ -1,51 +1,50 @@ --- -# Software Unit Requirements for the TemporaryDirectory Class -# -# The TemporaryDirectory class provides a disposable temporary directory that -# creates an isolated file-system location under Environment.CurrentDirectory, -# offers safe path resolution via PathHelpers, and deletes all contents on disposal. - +# BuildMark TemporaryDirectory unit requirements sections: - - title: TemporaryDirectory Unit Requirements - requirements: - - id: BuildMark-TemporaryDirectory-Creation - title: The TemporaryDirectory class shall create a uniquely-named temporary directory on construction. - justification: | - Each instance must own a distinct directory so that concurrent or sequential - uses of TemporaryDirectory do not interfere with each other. Creating under - Environment.CurrentDirectory avoids the macOS /tmp → /private/tmp symlink - mismatch that can break path-containment checks. - tests: - - TemporaryDirectory_Constructor_CreatesDirectory - - TemporaryDirectory_Constructor_CreatesUniqueDirectories + - title: BuildMark Requirements + sections: + - title: Utilities Requirements + sections: + - title: TemporaryDirectory Requirements + requirements: + - id: BuildMark-TemporaryDirectory-Creation + title: The TemporaryDirectory class shall create a uniquely-named temporary directory on construction. + justification: | + Each instance must own a distinct directory so that concurrent or sequential + uses of TemporaryDirectory do not interfere with each other. Creating under + Environment.CurrentDirectory avoids the macOS /tmp → /private/tmp symlink + mismatch that can break path-containment checks. + tests: + - TemporaryDirectory_Constructor_CreatesDirectory + - TemporaryDirectory_Constructor_CreatesUniqueDirectories - - id: BuildMark-TemporaryDirectory-FilePath - title: The TemporaryDirectory class shall resolve relative paths and create intermediate directories via GetFilePath. - justification: | - Callers need a simple way to obtain a fully-qualified path for a file inside - the temporary directory without having to create parent directories themselves. - GetFilePath delegates path validation to PathHelpers.SafePathCombine and - creates any missing intermediate directories before returning the path. - tests: - - TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory - - TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories + - id: BuildMark-TemporaryDirectory-FilePath + title: The TemporaryDirectory class shall resolve relative paths and create intermediate directories via GetFilePath. + justification: | + Callers need a simple way to obtain a fully-qualified path for a file inside + the temporary directory without having to create parent directories themselves. + GetFilePath delegates path validation to PathHelpers.SafePathCombine and + creates any missing intermediate directories before returning the path. + tests: + - TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory + - TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories - - id: BuildMark-TemporaryDirectory-Traversal - title: The TemporaryDirectory class shall reject path-traversal attempts in GetFilePath. - justification: | - Path inputs supplied by callers must not be allowed to escape the temporary - directory. GetFilePath delegates to PathHelpers.SafePathCombine, which rejects - any relative path containing ".." segments or an absolute path override. - tests: - - TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException + - id: BuildMark-TemporaryDirectory-Traversal + title: The TemporaryDirectory class shall reject path-traversal attempts in GetFilePath. + justification: | + Path inputs supplied by callers must not be allowed to escape the temporary + directory. GetFilePath delegates to PathHelpers.SafePathCombine, which rejects + any relative path containing ".." segments or an absolute path override. + tests: + - TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException - - id: BuildMark-TemporaryDirectory-Cleanup - title: The TemporaryDirectory class shall delete the directory and all its contents on disposal. - justification: | - Temporary directories must not accumulate on disk across runs. Dispose must - remove the directory tree and suppress I/O errors (IOException, - UnauthorizedAccessException) so that callers in using-statements are not - disrupted even when the directory has already been deleted externally. - tests: - - TemporaryDirectory_Dispose_DeletesDirectory - - TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow + - id: BuildMark-TemporaryDirectory-Cleanup + title: The TemporaryDirectory class shall delete the directory and all its contents on disposal. + justification: | + Temporary directories must not accumulate on disk across runs. Dispose must + remove the directory tree and suppress I/O errors (IOException, + UnauthorizedAccessException) so that callers in using-statements are not + disrupted even when the directory has already been deleted externally. + tests: + - TemporaryDirectory_Dispose_DeletesDirectory + - TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow diff --git a/docs/reqstream/build-mark/version.yaml b/docs/reqstream/build-mark/version.yaml index 831a1ff..792eb6f 100644 --- a/docs/reqstream/build-mark/version.yaml +++ b/docs/reqstream/build-mark/version.yaml @@ -1,4 +1,5 @@ --- +# BuildMark Version subsystem requirements includes: - version/version-comparable.yaml - version/version-semantic.yaml @@ -8,47 +9,49 @@ includes: - version/version-commit-tag.yaml sections: - - title: Version Subsystem Requirements - requirements: - - id: BuildMark-Version-Subsystem - title: >- - Version subsystem shall provide semantic version processing capabilities - for BuildMark operations. - justification: | - The Version subsystem encapsulates all version-related functionality including - parsing, comparison, validation, and version range operations. This subsystem - ensures consistent semantic versioning behavior across all BuildMark components - and provides the foundation for repository version tag processing and build - information generation. - tests: - - Version_Subsystem_CreateAllVersionTypes_WorksCorrectly - - Version_Subsystem_TagToComparableIntegration_WorksCorrectly - children: - - BuildMark-VersionComparable-Comparison - - BuildMark-VersionComparable-PreReleaseComparison - - BuildMark-VersionComparable-Creation - - BuildMark-VersionSemantic-FullVersion - - BuildMark-VersionTag-Formats - - BuildMark-VersionTag-Equality - - BuildMark-VersionInterval-Parse - - BuildMark-VersionInterval-Contains - - BuildMark-VersionIntervalSet-Parse - - BuildMark-VersionIntervalSet-Contains - - BuildMark-VersionCommitTag-Record + - title: BuildMark Requirements + sections: + - title: Version Requirements + requirements: + - id: BuildMark-Version-Subsystem + title: >- + Version subsystem shall provide semantic version processing capabilities + for BuildMark operations. + justification: | + The Version subsystem encapsulates all version-related functionality including + parsing, comparison, validation, and version range operations. This subsystem + ensures consistent semantic versioning behavior across all BuildMark components + and provides the foundation for repository version tag processing and build + information generation. + tests: + - Version_Subsystem_CreateAllVersionTypes_WorksCorrectly + - Version_Subsystem_TagToComparableIntegration_WorksCorrectly + children: + - BuildMark-VersionComparable-Comparison + - BuildMark-VersionComparable-PreReleaseComparison + - BuildMark-VersionComparable-Creation + - BuildMark-VersionSemantic-FullVersion + - BuildMark-VersionTag-Formats + - BuildMark-VersionTag-Equality + - BuildMark-VersionInterval-Parse + - BuildMark-VersionInterval-Contains + - BuildMark-VersionIntervalSet-Parse + - BuildMark-VersionIntervalSet-Contains + - BuildMark-VersionCommitTag-Record - - id: BuildMark-Version-SemanticVersioning - title: >- - Version subsystem shall comply with Semantic Versioning 2.0.0 specification - for all version processing operations, except that text pre-release identifiers - are compared case-insensitively as documented in BuildMark-VersionComparable-PreReleaseComparison. - justification: | - Compliance with SemVer 2.0.0 ensures consistent and predictable version - comparison behavior that aligns with industry standards and developer - expectations. This is critical for proper dependency resolution and - version range operations. - tests: - - Version_Subsystem_SemanticVersioningCompliance_WorksCorrectly - children: - - BuildMark-VersionComparable-Comparison - - BuildMark-VersionComparable-PreReleaseComparison - - BuildMark-VersionSemantic-FullVersion + - id: BuildMark-Version-SemanticVersioning + title: >- + Version subsystem shall comply with Semantic Versioning 2.0.0 specification + for all version processing operations, except that text pre-release identifiers + are compared case-insensitively as documented in BuildMark-VersionComparable-PreReleaseComparison. + justification: | + Compliance with SemVer 2.0.0 ensures consistent and predictable version + comparison behavior that aligns with industry standards and developer + expectations. This is critical for proper dependency resolution and + version range operations. + tests: + - Version_Subsystem_SemanticVersioningCompliance_WorksCorrectly + children: + - BuildMark-VersionComparable-Comparison + - BuildMark-VersionComparable-PreReleaseComparison + - BuildMark-VersionSemantic-FullVersion diff --git a/docs/reqstream/build-mark/version/version-commit-tag.yaml b/docs/reqstream/build-mark/version/version-commit-tag.yaml index 4269cfc..6280619 100644 --- a/docs/reqstream/build-mark/version/version-commit-tag.yaml +++ b/docs/reqstream/build-mark/version/version-commit-tag.yaml @@ -1,19 +1,19 @@ --- -# Software Unit Requirements for the VersionCommitTag Class -# -# VersionCommitTag pairs a parsed BuildMark Version with the commit hash for the tag so -# BuildInformation can identify the baseline and current release boundaries. - +# BuildMark VersionCommitTag unit requirements sections: - - title: VersionCommitTag Unit Requirements - requirements: - - id: BuildMark-VersionCommitTag-Record - title: >- - The VersionCommitTag record shall store a parsed version together with the - commit hash associated with that version tag. - justification: | - BuildMark reports both the semantic version and the commit boundary for - the current and baseline release tags. The record keeps those values - paired so range calculations and report rendering stay consistent. - tests: - - VersionCommitTag_Constructor_ValidParameters_CreatesInstance + - title: BuildMark Requirements + sections: + - title: Version Requirements + sections: + - title: VersionCommitTag Requirements + requirements: + - id: BuildMark-VersionCommitTag-Record + title: >- + The VersionCommitTag record shall store a parsed version together with the + commit hash associated with that version tag. + justification: | + BuildMark reports both the semantic version and the commit boundary for + the current and baseline release tags. The record keeps those values + paired so range calculations and report rendering stay consistent. + tests: + - VersionCommitTag_Constructor_ValidParameters_CreatesInstance diff --git a/docs/reqstream/build-mark/version/version-comparable.yaml b/docs/reqstream/build-mark/version/version-comparable.yaml index dc330f1..c88ba43 100644 --- a/docs/reqstream/build-mark/version/version-comparable.yaml +++ b/docs/reqstream/build-mark/version/version-comparable.yaml @@ -1,60 +1,63 @@ --- -# Version Comparable Requirements - +# BuildMark VersionComparable unit requirements sections: - - title: VersionComparable Requirements - requirements: - - id: BuildMark-VersionComparable-Comparison - title: >- - VersionComparable shall provide analytical comparison of semantic - versions with integer comparison for major.minor.patch components. - justification: | - Proper version ordering requires analytical comparison (1.2.3 < 1.11.2) - rather than lexicographic comparison. Using integer comparison ensures - correct ordering regardless of the number of digits in version components. - tests: - - VersionComparable_CompareTo_SameMajorMinorPatch_ReturnsZero - - VersionComparable_CompareTo_DifferentMajor_ReturnsCorrectOrder - - VersionComparable_CompareTo_DifferentMinor_ReturnsCorrectOrder - - VersionComparable_CompareTo_DifferentPatch_ReturnsCorrectOrder - - VersionComparable_CompareTo_PreReleaseVsRelease_ReturnsCorrectOrder - - VersionComparable_CompareTo_PreReleaseVersions_ReturnsLexicographicOrder - - VersionComparable_Operators_LessThan_WorksCorrectly - - VersionComparable_Operators_GreaterThan_WorksCorrectly - - VersionComparable_Operators_LessThanOrEqual_WorksCorrectly - - VersionComparable_Operators_GreaterThanOrEqual_WorksCorrectly + - title: BuildMark Requirements + sections: + - title: Version Requirements + sections: + - title: VersionComparable Requirements + requirements: + - id: BuildMark-VersionComparable-Comparison + title: >- + VersionComparable shall provide analytical comparison of semantic + versions with integer comparison for major.minor.patch components. + justification: | + Proper version ordering requires analytical comparison (1.2.3 < 1.11.2) + rather than lexicographic comparison. Using integer comparison ensures + correct ordering regardless of the number of digits in version components. + tests: + - VersionComparable_CompareTo_SameMajorMinorPatch_ReturnsZero + - VersionComparable_CompareTo_DifferentMajor_ReturnsCorrectOrder + - VersionComparable_CompareTo_DifferentMinor_ReturnsCorrectOrder + - VersionComparable_CompareTo_DifferentPatch_ReturnsCorrectOrder + - VersionComparable_CompareTo_PreReleaseVsRelease_ReturnsCorrectOrder + - VersionComparable_CompareTo_PreReleaseVersions_ReturnsLexicographicOrder + - VersionComparable_Operators_LessThan_WorksCorrectly + - VersionComparable_Operators_GreaterThan_WorksCorrectly + - VersionComparable_Operators_LessThanOrEqual_WorksCorrectly + - VersionComparable_Operators_GreaterThanOrEqual_WorksCorrectly - - id: BuildMark-VersionComparable-PreReleaseComparison - title: >- - VersionComparable shall correctly order pre-release versions according - to Semantic Versioning specification, with the intentional deviation that - text identifiers are compared case-insensitively. - justification: | - Pre-release versions must be ordered correctly per SemVer specification - to ensure proper dependency resolution and version range operations. - This includes handling complex pre-release identifiers with mixed - numeric and text components. Text identifiers are compared - case-insensitively as a deliberate design choice; SemVer 2.0.0 - specifies case-sensitive ASCII sort order, but case-insensitive - comparison is more practical for typical repository tag naming - conventions. - tests: - - VersionComparable_CompareTo_PreReleaseNumeric_ComparesNumerically - - VersionComparable_CompareTo_PreReleaseSemVerRules_CorrectOrdering - - VersionComparable_CompareTo_NumericVsNonNumeric_NumericIsLess - - VersionComparable_CompareTo_ShorterPreRelease_IsLess - - VersionComparable_CompareTo_ComplexPreRelease_CorrectOrdering + - id: BuildMark-VersionComparable-PreReleaseComparison + title: >- + VersionComparable shall correctly order pre-release versions according + to Semantic Versioning specification, with the intentional deviation that + text identifiers are compared case-insensitively. + justification: | + Pre-release versions must be ordered correctly per SemVer specification + to ensure proper dependency resolution and version range operations. + This includes handling complex pre-release identifiers with mixed + numeric and text components. Text identifiers are compared + case-insensitively as a deliberate design choice; SemVer 2.0.0 + specifies case-sensitive ASCII sort order, but case-insensitive + comparison is more practical for typical repository tag naming + conventions. + tests: + - VersionComparable_CompareTo_PreReleaseNumeric_ComparesNumerically + - VersionComparable_CompareTo_PreReleaseSemVerRules_CorrectOrdering + - VersionComparable_CompareTo_NumericVsNonNumeric_NumericIsLess + - VersionComparable_CompareTo_ShorterPreRelease_IsLess + - VersionComparable_CompareTo_ComplexPreRelease_CorrectOrdering - - id: BuildMark-VersionComparable-Creation - title: >- - VersionComparable shall be constructible from a version string and shall - reject inputs that do not represent a valid semantic version. - justification: | - Callers must be able to create VersionComparable instances from repository tag - strings and user-supplied version values, and must receive a clear error or a - null result when the input is not a valid version, so that invalid version data - does not propagate silently through version comparisons. - tests: - - VersionComparable_Create_ValidVersion_ReturnsInstance - - VersionComparable_TryCreate_InvalidVersion_ReturnsNull - - VersionComparable_Create_InvalidVersion_ThrowsArgumentException + - id: BuildMark-VersionComparable-Creation + title: >- + VersionComparable shall be constructible from a version string and shall + reject inputs that do not represent a valid semantic version. + justification: | + Callers must be able to create VersionComparable instances from repository tag + strings and user-supplied version values, and must receive a clear error or a + null result when the input is not a valid version, so that invalid version data + does not propagate silently through version comparisons. + tests: + - VersionComparable_Create_ValidVersion_ReturnsInstance + - VersionComparable_TryCreate_InvalidVersion_ReturnsNull + - VersionComparable_Create_InvalidVersion_ThrowsArgumentException diff --git a/docs/reqstream/build-mark/version/version-interval-set.yaml b/docs/reqstream/build-mark/version/version-interval-set.yaml index aef824d..c20731b 100644 --- a/docs/reqstream/build-mark/version/version-interval-set.yaml +++ b/docs/reqstream/build-mark/version/version-interval-set.yaml @@ -1,39 +1,42 @@ --- -# Software Unit Requirements for the VersionIntervalSet Class - +# BuildMark VersionIntervalSet unit requirements sections: - - title: VersionIntervalSet Unit Requirements - requirements: - - id: BuildMark-VersionIntervalSet-Parse - title: >- - The VersionIntervalSet class shall parse a comma-separated string of interval - tokens into an ordered collection of VersionInterval instances. - justification: | - The comma that separates multiple intervals also appears inside individual - intervals (between lower and upper bounds). The parser must distinguish - between the two by tracking bracket depth, ensuring disjoint version ranges - can be expressed correctly in a single affected-versions field. - tests: - - VersionIntervalSet_Parse_SingleInterval_ReturnsOneInterval - - VersionIntervalSet_Parse_TwoIntervals_ReturnsTwoIntervals - - VersionIntervalSet_Parse_IntervalsWithInternalComma_ParsedCorrectly - - VersionIntervalSet_Parse_EmptyString_ReturnsEmptySet - - VersionIntervalSet_Parse_InvalidToken_DiscardedSilently + - title: BuildMark Requirements + sections: + - title: Version Requirements + sections: + - title: VersionIntervalSet Requirements + requirements: + - id: BuildMark-VersionIntervalSet-Parse + title: >- + The VersionIntervalSet class shall parse a comma-separated string of interval + tokens into an ordered collection of VersionInterval instances. + justification: | + The comma that separates multiple intervals also appears inside individual + intervals (between lower and upper bounds). The parser must distinguish + between the two by tracking bracket depth, ensuring disjoint version ranges + can be expressed correctly in a single affected-versions field. + tests: + - VersionIntervalSet_Parse_SingleInterval_ReturnsOneInterval + - VersionIntervalSet_Parse_TwoIntervals_ReturnsTwoIntervals + - VersionIntervalSet_Parse_IntervalsWithInternalComma_ParsedCorrectly + - VersionIntervalSet_Parse_EmptyString_ReturnsEmptySet + - VersionIntervalSet_Parse_InvalidToken_DiscardedSilently - - id: BuildMark-VersionIntervalSet-Contains - title: >- - The VersionIntervalSet class shall determine whether a candidate version falls - inside any interval in the set. - justification: | - Affected-version metadata can contain multiple disjoint ranges. The class must - allow callers to determine whether a version is covered by any one of those - ranges without re-implementing interval iteration logic, and must accept version - values in the forms used throughout the tool so callers are not forced to convert - before querying. - tests: - - VersionIntervalSet_Contains_StringInsideFirstInterval_ReturnsTrue - - VersionIntervalSet_Contains_StringInsideLaterInterval_ReturnsTrue - - VersionIntervalSet_Contains_StringOutsideAllIntervals_ReturnsFalse - - VersionIntervalSet_Contains_EmptySet_ReturnsFalse - - VersionIntervalSet_Contains_VersionTag_DelegatesToSemanticVersion - - VersionIntervalSet_Contains_VersionComparable_HandlesPreRelease + - id: BuildMark-VersionIntervalSet-Contains + title: >- + The VersionIntervalSet class shall determine whether a candidate version falls + inside any interval in the set. + justification: | + Affected-version metadata can contain multiple disjoint ranges. The class must + allow callers to determine whether a version is covered by any one of those + ranges without re-implementing interval iteration logic, and must accept version + values in the forms used throughout the tool so callers are not forced to convert + before querying. + tests: + - VersionIntervalSet_Contains_StringInsideFirstInterval_ReturnsTrue + - VersionIntervalSet_Contains_StringInsideLaterInterval_ReturnsTrue + - VersionIntervalSet_Contains_StringOutsideAllIntervals_ReturnsFalse + - VersionIntervalSet_Contains_EmptySet_ReturnsFalse + - VersionIntervalSet_Contains_VersionTag_DelegatesToSemanticVersion + - VersionIntervalSet_Contains_VersionComparable_HandlesPreRelease diff --git a/docs/reqstream/build-mark/version/version-interval.yaml b/docs/reqstream/build-mark/version/version-interval.yaml index 91ffe3f..d1f9319 100644 --- a/docs/reqstream/build-mark/version/version-interval.yaml +++ b/docs/reqstream/build-mark/version/version-interval.yaml @@ -1,47 +1,47 @@ --- -# Software Unit Requirements for the VersionInterval Class -# -# VersionInterval represents a single mathematical version interval with inclusive -# or exclusive bounds (either of which may be null for an unbounded range). - +# BuildMark VersionInterval unit requirements sections: - - title: VersionInterval Unit Requirements - requirements: - - id: BuildMark-VersionInterval-Parse - title: >- - The VersionInterval class shall parse a single interval token using standard - mathematical interval notation, tolerating unrecognized input without failing - the parse of the enclosing interval set. - justification: | - Tolerating malformed interval tokens allows the enclosing interval set to - silently discard them rather than failing the entire parse, making the feature - resilient to minor user errors in the buildmark block. - tests: - - VersionInterval_Parse_InclusiveLower_IsInclusive - - VersionInterval_Parse_ExclusiveLower_IsExclusive - - VersionInterval_Parse_InclusiveUpper_IsInclusive - - VersionInterval_Parse_ExclusiveUpper_IsExclusive - - VersionInterval_Parse_UnboundedLower_HasNullLowerBound - - VersionInterval_Parse_UnboundedUpper_HasNullUpperBound - - VersionInterval_Parse_BothBoundsPresent_ReturnsInterval - - VersionInterval_Parse_InvalidFormat_ReturnsNull + - title: BuildMark Requirements + sections: + - title: Version Requirements + sections: + - title: VersionInterval Requirements + requirements: + - id: BuildMark-VersionInterval-Parse + title: >- + The VersionInterval class shall parse a single interval token using standard + mathematical interval notation, tolerating unrecognized input without failing + the parse of the enclosing interval set. + justification: | + Tolerating malformed interval tokens allows the enclosing interval set to + silently discard them rather than failing the entire parse, making the feature + resilient to minor user errors in the buildmark block. + tests: + - VersionInterval_Parse_InclusiveLower_IsInclusive + - VersionInterval_Parse_ExclusiveLower_IsExclusive + - VersionInterval_Parse_InclusiveUpper_IsInclusive + - VersionInterval_Parse_ExclusiveUpper_IsExclusive + - VersionInterval_Parse_UnboundedLower_HasNullLowerBound + - VersionInterval_Parse_UnboundedUpper_HasNullUpperBound + - VersionInterval_Parse_BothBoundsPresent_ReturnsInterval + - VersionInterval_Parse_InvalidFormat_ReturnsNull - - id: BuildMark-VersionInterval-Contains - title: >- - The VersionInterval class shall determine whether a candidate version falls - inside the interval. - justification: | - Callers need to evaluate whether a release version is included by an - affected-version interval. The class must accept version values in the - forms used throughout the tool — raw strings, parsed comparable versions, - and repository tag objects — so that callers are not forced to convert - before querying. - tests: - - VersionInterval_Contains_StringEqualToInclusiveLower_ReturnsTrue - - VersionInterval_Contains_StringEqualToExclusiveLower_ReturnsFalse - - VersionInterval_Contains_StringEqualToInclusiveUpper_ReturnsTrue - - VersionInterval_Contains_StringEqualToExclusiveUpper_ReturnsFalse - - VersionInterval_Contains_StringInsideUnboundedInterval_ReturnsTrue - - VersionInterval_Contains_StringOutsideInterval_ReturnsFalse - - VersionInterval_Contains_Version_DelegatesToSemanticVersion - - VersionInterval_Contains_VersionComparable_HandlesPreRelease + - id: BuildMark-VersionInterval-Contains + title: >- + The VersionInterval class shall determine whether a candidate version falls + inside the interval. + justification: | + Callers need to evaluate whether a release version is included by an + affected-version interval. The class must accept version values in the + forms used throughout the tool — raw strings, parsed comparable versions, + and repository tag objects — so that callers are not forced to convert + before querying. + tests: + - VersionInterval_Contains_StringEqualToInclusiveLower_ReturnsTrue + - VersionInterval_Contains_StringEqualToExclusiveLower_ReturnsFalse + - VersionInterval_Contains_StringEqualToInclusiveUpper_ReturnsTrue + - VersionInterval_Contains_StringEqualToExclusiveUpper_ReturnsFalse + - VersionInterval_Contains_StringInsideUnboundedInterval_ReturnsTrue + - VersionInterval_Contains_StringOutsideInterval_ReturnsFalse + - VersionInterval_Contains_Version_DelegatesToSemanticVersion + - VersionInterval_Contains_VersionComparable_HandlesPreRelease diff --git a/docs/reqstream/build-mark/version/version-semantic.yaml b/docs/reqstream/build-mark/version/version-semantic.yaml index 8577216..bed46bb 100644 --- a/docs/reqstream/build-mark/version/version-semantic.yaml +++ b/docs/reqstream/build-mark/version/version-semantic.yaml @@ -1,23 +1,26 @@ --- -# Version Semantic Requirements - +# BuildMark VersionSemantic unit requirements sections: - - title: VersionSemantic Requirements - requirements: - - id: BuildMark-VersionSemantic-FullVersion - title: >- - VersionSemantic shall represent a complete semantic version including - optional build metadata, with version precedence based on the major, - minor, patch, and pre-release components. - justification: | - Semantic versioning includes build metadata (e.g., +build.123) that - does not affect version precedence. VersionSemantic must preserve the - full string representation while correctly ordering versions based only - on the numeric and pre-release components. - tests: - - VersionSemantic_Create_WithBuildMetadata_ReturnsInstance - - VersionSemantic_Create_WithoutBuildMetadata_ReturnsInstance - - VersionSemantic_Properties_DelegateToComparable_Correctly - - VersionSemantic_ToString_FormatsCompletely_WithAllComponents - - VersionSemantic_TryCreate_InvalidVersion_ReturnsNull - - VersionSemantic_PreRelease_ReturnsEmptyStringForRelease + - title: BuildMark Requirements + sections: + - title: Version Requirements + sections: + - title: VersionSemantic Requirements + requirements: + - id: BuildMark-VersionSemantic-FullVersion + title: >- + VersionSemantic shall represent a complete semantic version including + optional build metadata, with version precedence based on the major, + minor, patch, and pre-release components. + justification: | + Semantic versioning includes build metadata (e.g., +build.123) that + does not affect version precedence. VersionSemantic must preserve the + full string representation while correctly ordering versions based only + on the numeric and pre-release components. + tests: + - VersionSemantic_Create_WithBuildMetadata_ReturnsInstance + - VersionSemantic_Create_WithoutBuildMetadata_ReturnsInstance + - VersionSemantic_Properties_DelegateToComparable_Correctly + - VersionSemantic_ToString_FormatsCompletely_WithAllComponents + - VersionSemantic_TryCreate_InvalidVersion_ReturnsNull + - VersionSemantic_PreRelease_ReturnsEmptyStringForRelease diff --git a/docs/reqstream/build-mark/version/version-tag.yaml b/docs/reqstream/build-mark/version/version-tag.yaml index d605a35..f72b00f 100644 --- a/docs/reqstream/build-mark/version/version-tag.yaml +++ b/docs/reqstream/build-mark/version/version-tag.yaml @@ -1,34 +1,37 @@ --- -# Version Tag Requirements - +# BuildMark VersionTag unit requirements sections: - - title: VersionTag Requirements - requirements: - - id: BuildMark-VersionTag-Formats - title: >- - VersionTag shall parse repository tags in various formats and normalize - them to VersionComparable for consistent version handling. - justification: | - Repository tags come in many formats (v1.2.3, 1.2.3.rc.1, release-1.2.3). - VersionTag provides parsing and normalization while preserving the original - tag for display purposes. - tests: - - VersionTag_Create_StandardTag_ParsesCorrectly - - VersionTag_Create_PrefixedTag_ParsesCorrectly - - VersionTag_Create_DotSeparatedPreRelease_NormalizesToHyphen - - VersionTag_Create_ComplexTag_ExtractsVersionCorrectly - - VersionTag_TryCreate_InvalidTag_ReturnsNull - - VersionTag_Properties_ExposeOriginalAndParsed_Correctly - - VersionTag_ToString_ReturnsOriginalTag + - title: BuildMark Requirements + sections: + - title: Version Requirements + sections: + - title: VersionTag Requirements + requirements: + - id: BuildMark-VersionTag-Formats + title: >- + VersionTag shall parse repository tags in various formats and normalize + them to VersionComparable for consistent version handling. + justification: | + Repository tags come in many formats (v1.2.3, 1.2.3.rc.1, release-1.2.3). + VersionTag provides parsing and normalization while preserving the original + tag for display purposes. + tests: + - VersionTag_Create_StandardTag_ParsesCorrectly + - VersionTag_Create_PrefixedTag_ParsesCorrectly + - VersionTag_Create_DotSeparatedPreRelease_NormalizesToHyphen + - VersionTag_Create_ComplexTag_ExtractsVersionCorrectly + - VersionTag_TryCreate_InvalidTag_ReturnsNull + - VersionTag_Properties_ExposeOriginalAndParsed_Correctly + - VersionTag_ToString_ReturnsOriginalTag - - id: BuildMark-VersionTag-Equality - title: >- - Tags that represent the same semantic version but differ only in string - formatting shall compare as equal. - justification: | - Repository connectors must recognize that "v1.2.3", "VER1.2.3", and - "Release_1.2.3" represent the same release for version matching, - baseline determination, and range operations. String-based comparison - would incorrectly treat these as different versions. - tests: - - VersionComparable_Equals_DifferentPrefixesSameVersion_ReturnsTrue + - id: BuildMark-VersionTag-Equality + title: >- + Tags that represent the same semantic version but differ only in string + formatting shall compare as equal. + justification: | + Repository connectors must recognize that "v1.2.3", "VER1.2.3", and + "Release_1.2.3" represent the same release for version matching, + baseline determination, and range operations. String-based comparison + would incorrectly treat these as different versions. + tests: + - VersionComparable_Equals_DifferentPrefixesSameVersion_ReturnsTrue diff --git a/docs/requirements_doc/definition.yaml b/docs/requirements_doc/definition.yaml index 628b789..bc9c807 100644 --- a/docs/requirements_doc/definition.yaml +++ b/docs/requirements_doc/definition.yaml @@ -1,12 +1,10 @@ --- -resource-path: - - docs/requirements_doc - - docs/template +resource-path: [docs/requirements_doc, docs/template] input-files: - docs/requirements_doc/title.txt - docs/requirements_doc/introduction.md - - docs/requirements_doc/generated/requirements.md - - docs/requirements_doc/generated/justifications.md + - docs/requirements_doc/generated/requirements.md # Generated by ReqStream (requirements listing) + - docs/requirements_doc/generated/justifications.md # Generated by ReqStream (requirement justifications) template: template.html table-of-contents: true number-sections: true diff --git a/docs/requirements_doc/introduction.md b/docs/requirements_doc/introduction.md index 133e707..976f6fd 100644 --- a/docs/requirements_doc/introduction.md +++ b/docs/requirements_doc/introduction.md @@ -1,37 +1,17 @@ # Introduction -This document contains the requirements for the BuildMark project. +This document lists all requirements for BuildMark. ## Purpose -BuildMark is a .NET command-line tool that generates comprehensive markdown build notes reports from -Git repository history and issue-tracking systems. It analyzes commits, pull requests, and issues to -create human-readable build notes, making it easy to integrate release documentation into CI/CD -pipelines and documentation workflows. +To provide a complete, traceable record of all requirements for BuildMark, +including requirements at the system, subsystem, and unit levels, plus OTS and Shared Package requirements. ## Scope -This requirements document covers: - -- Command-line interface and options -- Git repository integration -- GitHub integration for issues and pull requests -- Azure DevOps integration for work items and pull requests -- Markdown report generation capabilities -- Validation and self-testing features -- Data models and repository connectors -- Platform support for Windows, Linux, and multiple .NET runtimes - -## Audience - -This document is intended for: - -- Software developers working on BuildMark -- Quality assurance teams validating requirements -- Project stakeholders reviewing project scope -- Users understanding the tool's capabilities +This document covers all requirements defined in `docs/reqstream/` for BuildMark. ## References -- [BuildMark Releases](https://github.com/demaconsulting/BuildMark/releases) — +- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) — compiled requirements, trace matrix, and quality reports diff --git a/docs/requirements_doc/title.txt b/docs/requirements_doc/title.txt index db6608c..4b3c7fd 100644 --- a/docs/requirements_doc/title.txt +++ b/docs/requirements_doc/title.txt @@ -1,13 +1,12 @@ --- -title: BuildMark Requirements -subtitle: Requirements Specification for the BuildMark Tool -author: DEMA Consulting -description: Requirements Specification for the BuildMark Tool +title: "BuildMark Requirements Document" +subtitle: "Markdown Build Notes Generation Tool" +author: "DEMA Consulting" +description: "Requirements Document for BuildMark" lang: en-US keywords: - - BuildMark - Requirements - - Specification + - BuildMark - .NET - YAML - Command-Line Tool diff --git a/docs/requirements_report/definition.yaml b/docs/requirements_report/definition.yaml index 9ee62a4..e8b5571 100644 --- a/docs/requirements_report/definition.yaml +++ b/docs/requirements_report/definition.yaml @@ -1,11 +1,9 @@ --- -resource-path: - - docs/requirements_report - - docs/template +resource-path: [docs/requirements_report, docs/template] input-files: - docs/requirements_report/title.txt - docs/requirements_report/introduction.md - - docs/requirements_report/generated/trace_matrix.md + - docs/requirements_report/generated/trace_matrix.md # Generated by ReqStream (requirements traceability matrix) template: template.html table-of-contents: true number-sections: true diff --git a/docs/requirements_report/introduction.md b/docs/requirements_report/introduction.md index e1e6cf3..8e6eadc 100644 --- a/docs/requirements_report/introduction.md +++ b/docs/requirements_report/introduction.md @@ -1,22 +1,22 @@ # Introduction -This document contains the requirements trace matrix for the BuildMark project. +This document provides the requirements Trace Matrix for BuildMark, +mapping each requirement to its corresponding test evidence. ## Purpose -The trace matrix links requirements to their corresponding test cases, ensuring complete -test coverage and traceability from requirements to implementation. +To demonstrate that every requirement is covered by at least one passing test, +providing compliance evidence for BuildMark. ## Scope -This document covers all requirements defined in `docs/reqstream/` for BuildMark and their -corresponding test evidence from unit, integration, and self-validation test runs. +This document covers all requirements in `docs/reqstream/` and their test evidence. ## Test Sources Requirements traceability in BuildMark uses two types of tests: -- **Unit and Integration Tests**: Standard MSTest tests that verify code functionality +- **Unit and Integration Tests**: Standard xUnit tests that verify code functionality - **Self-Validation Tests**: Built-in validation tests run via `buildmark --validate --results` To generate complete traceability reports, both test result files must be included: diff --git a/docs/requirements_report/title.txt b/docs/requirements_report/title.txt index 86f4d7b..5934bce 100644 --- a/docs/requirements_report/title.txt +++ b/docs/requirements_report/title.txt @@ -1,15 +1,17 @@ --- -title: BuildMark Trace Matrix -subtitle: Requirements Traceability Matrix for the BuildMark Tool -author: DEMA Consulting -description: Requirements Traceability Matrix for the BuildMark Tool +title: "BuildMark Trace Matrix" +subtitle: "Markdown Build Notes Generation Tool" +author: "DEMA Consulting" +description: "Trace Matrix for BuildMark" lang: en-US keywords: - - BuildMark - - Trace Matrix - - Traceability - Requirements - - Testing + - Trace Matrix + - BuildMark - .NET - Command-Line Tool + - Git + - GitHub + - Traceability + - Testing --- diff --git a/docs/user_guide/definition.yaml b/docs/user_guide/definition.yaml index fdb7792..46db3c8 100644 --- a/docs/user_guide/definition.yaml +++ b/docs/user_guide/definition.yaml @@ -1,11 +1,10 @@ --- -resource-path: - - docs/user_guide - - docs/template - +resource-path: [docs/user_guide, docs/template] input-files: - docs/user_guide/title.txt - docs/user_guide/introduction.md + - docs/user_guide/installation.md + - docs/user_guide/getting-started.md - docs/user_guide/configuration.md - docs/user_guide/cli-reference.md - docs/user_guide/item-controls.md diff --git a/docs/user_guide/getting-started.md b/docs/user_guide/getting-started.md new file mode 100644 index 0000000..cb55c9d --- /dev/null +++ b/docs/user_guide/getting-started.md @@ -0,0 +1,47 @@ +# Getting Started + +## Basic Usage + +The simplest usage requires a build version and an output report path: + +```bash +buildmark --build-version v1.2.3 --report build-notes.md +``` + +This command analyzes the Git repository in the current directory, finds the previous version tag, +and generates a markdown report with changes, bug fixes, and other release information. + +## Using a GitHub Token + +For private repositories or to avoid GitHub API rate limits, provide a GitHub token through an +environment variable: + +```bash +# Using GH_TOKEN +export GH_TOKEN= +buildmark --build-version v1.2.3 --report build-notes.md + +# Or using GITHUB_TOKEN +export GITHUB_TOKEN= +buildmark --build-version v1.2.3 --report build-notes.md +``` + +## Using an Azure DevOps Token + +For Azure DevOps repositories, provide a personal access token: + +```bash +export AZURE_DEVOPS_PAT=your-pat-token... +buildmark --build-version v1.2.3 --report build-notes.md +``` + +In Azure Pipelines, the pipeline service connection token is picked up automatically from +`SYSTEM_ACCESSTOKEN` when the pipeline is granted access. + +## Including Known Issues + +To include known issues in the generated report: + +```bash +buildmark --build-version v1.2.3 --report build-notes.md --include-known-issues +``` diff --git a/docs/user_guide/installation.md b/docs/user_guide/installation.md new file mode 100644 index 0000000..060f2af --- /dev/null +++ b/docs/user_guide/installation.md @@ -0,0 +1,57 @@ +# Installation + +## Prerequisites + +BuildMark requires a supported .NET SDK version: + +- .NET 8.0 +- .NET 9.0 +- .NET 10.0 + +Install the SDK from if it is not already available on the +build machine. + +## Global Installation + +Install BuildMark as a global .NET tool for system-wide access: + +```bash +dotnet tool install --global DemaConsulting.BuildMark +``` + +Verify the installation: + +```bash +buildmark --version +``` + +## Local Installation + +For team projects, install BuildMark as a local tool to keep the tool version aligned with the +repository: + +```bash +# Create tool manifest if it does not exist +dotnet new tool-manifest + +# Install the tool +dotnet tool install DemaConsulting.BuildMark +``` + +Run the locally installed tool: + +```bash +dotnet buildmark --version +``` + +## Update + +Update BuildMark to the latest version when needed: + +```bash +# Global installation +dotnet tool update --global DemaConsulting.BuildMark + +# Local installation +dotnet tool update DemaConsulting.BuildMark +``` diff --git a/docs/user_guide/introduction.md b/docs/user_guide/introduction.md index bbda349..6e0e26a 100644 --- a/docs/user_guide/introduction.md +++ b/docs/user_guide/introduction.md @@ -1,156 +1,43 @@ - - # Introduction -BuildMark is a .NET command-line tool that generates comprehensive markdown build notes reports from Git repository -history and issue-tracking systems. It analyzes commits, pull requests, and issues to create human-readable build -notes, making it easy to integrate release documentation into your CI/CD pipelines and documentation workflows. +This guide describes how to install, configure, and use BuildMark. ## Purpose -The purpose of this guide is to explain how to install, configure, and operate BuildMark to -generate markdown build notes from Git repository history and connected issue-tracking systems. +The purpose of this guide is to explain how to install, configure, and operate BuildMark to generate +markdown build notes from Git repository history and connected issue-tracking systems. + +BuildMark is a .NET command-line tool that analyzes commits, pull requests, and issues from GitHub +and Azure DevOps repositories to produce human-readable markdown build notes. It is designed for +integration into CI/CD pipelines and release documentation workflows. + +Key capabilities include: + +- **Git Integration** — analyzes repository history, tags, and branches +- **Issue Tracking** — extracts changes and bug fixes from GitHub and Azure DevOps +- **Configurable Routing** — routes items into custom report sections by label or work-item type +- **CI/CD Ready** — designed for automation in GitHub Actions and Azure Pipelines +- **Multi-Platform** — runs on Windows, Linux, and macOS with .NET 8, 9, and 10 +- **Self-Validation** — built-in qualification tests for use in regulated environments ## Scope -This guide covers installation, basic usage, GitHub and Azure DevOps integration, configuration, -and common use cases for BuildMark. It is intended for developers and CI/CD engineers who want to -automate build notes generation as part of their release workflow. +This guide covers installation prerequisites and setup in *Installation*, first-run workflows and +common command examples in *Getting Started*, the `.buildmark.yaml` configuration file reference in +*Configuration*, command-line option reference in *Command-Line Options*, item visibility and +version targeting controls in *Item Visibility and Version Controls*, and CI/CD integration, +report format, version selection rules, best practices, and troubleshooting in *Common Use Cases*. +It is intended for developers and CI/CD engineers who want to automate build notes generation as +part of their release workflow. A .NET SDK (version 8.0, 9.0, or 10.0) is required. The following topics are out of scope: - Internal implementation details - Contributing to BuildMark development -## Key Features - -- **Git Integration** - Analyze Git repository history, tags, and branches -- **Markdown Reports** - Generate structured build notes from repository data -- **Issue Tracking** - Extract changes and bug fixes from GitHub and Azure DevOps -- **Configurable Routing** - Route items into custom report sections by label or work-item type -- **Customizable Output** - Configure report depth, sections, and known-issue inclusion -- **CI/CD Ready** - Automate build notes generation in GitHub Actions and Azure Pipelines -- **Multi-Platform** - Windows, Linux, and macOS with .NET 8, 9, and 10 -- **Self-Validation** - Built-in qualification tests without external tooling -- **Dependency Updates** - Built-in tracking of dependency changes from Dependabot and Renovate - ## References -- [BuildMark Releases](https://github.com/demaconsulting/BuildMark/releases) — compiled user guide and documentation -- [.NET SDK Download][dotnet-download] -- [Continuous Compliance][continuous-compliance] - -# Continuous Compliance - -BuildMark follows the [Continuous Compliance][continuous-compliance] methodology, which ensures -compliance evidence is generated automatically on every CI run. - -## Key Practices - -- **Requirements Traceability**: Every requirement is linked to passing tests, and a trace matrix is - auto-generated on each release -- **Linting Enforcement**: markdownlint, cspell, and yamllint are enforced before any build proceeds -- **Automated Audit Documentation**: Each release ships with generated requirements, justifications, - trace matrix, and quality reports -- **CodeQL and SonarCloud**: Security and quality analysis runs on every build - -# Installation - -## Prerequisites - -- [.NET SDK][dotnet-download] 8.0, 9.0, or 10.0 - -## Global Installation - -Install BuildMark as a global .NET tool for system-wide access: - -```bash -dotnet tool install --global DemaConsulting.BuildMark -``` - -Verify the installation: - -```bash -buildmark --version -``` - -## Local Installation - -For team projects, install BuildMark as a local tool to ensure version consistency: - -```bash -# Create tool manifest if it doesn't exist -dotnet new tool-manifest - -# Install the tool -dotnet tool install DemaConsulting.BuildMark -``` - -Run the locally installed tool: - -```bash -dotnet buildmark --version -``` - -## Update - -To update to the latest version: - -```bash -# Global installation -dotnet tool update --global DemaConsulting.BuildMark - -# Local installation -dotnet tool update DemaConsulting.BuildMark -``` - -# Getting Started - -## Basic Usage - -The most basic usage requires specifying a build version and report file: - -```bash -buildmark --build-version v1.2.3 --report build-notes.md -``` - -This will analyze the Git repository in the current directory, find the previous version tag, and generate a -markdown report with all changes, bug fixes, and other relevant information. - -## With GitHub Token - -For accessing private repositories or to avoid GitHub API rate limits, provide a GitHub token: - -```bash -# Using environment variable -export GH_TOKEN=ghp_abc123... -buildmark --build-version v1.2.3 --report build-notes.md - -# Or using GITHUB_TOKEN -export GITHUB_TOKEN=ghp_abc123... -buildmark --build-version v1.2.3 --report build-notes.md -``` - -## With Azure DevOps Token - -For Azure DevOps repositories, provide a Personal Access Token (PAT): - -```bash -# Using Personal Access Token -export AZURE_DEVOPS_PAT=your-pat-token... -buildmark --build-version v1.2.3 --report build-notes.md -``` - -In Azure Pipelines, the pipeline service connection token is picked up automatically from -`SYSTEM_ACCESSTOKEN` when you grant the pipeline permission to access it. - -## Including Known Issues - -To include known issues in the report: - -```bash -buildmark --build-version v1.2.3 --report build-notes.md --include-known-issues -``` - -[dotnet-download]: https://dotnet.microsoft.com/download -[continuous-compliance]: https://github.com/demaconsulting/ContinuousCompliance +- [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) — compiled user guide + and documentation +- [.NET SDK](https://dotnet.microsoft.com/download) +- [Continuous Compliance](https://github.com/demaconsulting/ContinuousCompliance) diff --git a/docs/user_guide/title.txt b/docs/user_guide/title.txt index d02133d..f023afe 100644 --- a/docs/user_guide/title.txt +++ b/docs/user_guide/title.txt @@ -1,16 +1,17 @@ --- -title: BuildMark User Guide -subtitle: A .NET Command-Line Tool for Build Notes Generation -author: DEMA Consulting -description: A .NET Command-Line Tool for Build Notes Generation from Git repositories +title: "BuildMark User Guide" +subtitle: "Markdown Build Notes Generation Tool" +author: "DEMA Consulting" +description: "User Guide for BuildMark" lang: en-US keywords: - BuildMark + - User Guide - Build Notes - Release Notes - Git - GitHub + - Azure DevOps - .NET - Command-Line Tool - - Documentation --- diff --git a/docs/verification/build-mark.md b/docs/verification/build-mark.md index c95f1e1..93baedd 100644 --- a/docs/verification/build-mark.md +++ b/docs/verification/build-mark.md @@ -1,234 +1,130 @@ # BuildMark -## Verification Strategy +## Verification Approach -BuildMark is verified at two levels: +BuildMark is verified at two levels. -**System-level (integration)** testing is provided by `IntegrationTests.cs`, which runs the -BuildMark executable end-to-end via `Runner.Run()` (`dotnet `). These tests invoke the -full compiled binary, exercising the complete pipeline from CLI argument parsing through build -notes generation, and validate exit codes and console output without any in-process mocking. +System-level integration testing is provided by `IntegrationTests.cs`, which runs the BuildMark +executable end-to-end via `Runner.Run()` (`dotnet `). These tests invoke the full compiled +binary, exercising the complete pipeline from CLI argument parsing through build notes generation, +and validate exit codes and console output without any in-process mocking. -**Unit-level** testing is provided by `ProgramTests.cs`, which calls `Program.Run()` directly -with a controlled `Context` object. These tests validate individual flags and error conditions -with fast, isolated, in-process invocations. +Unit-level testing of the system entry point is provided by `ProgramTests.cs`, which calls +`Program.Run()` directly with a controlled `Context` object. These tests validate individual flags +and error conditions with fast, isolated, in-process invocations. The connector factory is injected +via a context override to avoid live API calls where needed. -The `RepoConnectorsTests.cs` file exercises the full data pipeline, from connector factory -creation through `GetBuildInformationAsync`, using mock data to cover GitHub, Azure DevOps, and -Mock connector paths. +The `RepoConnectorsTests.cs` file exercises the full data pipeline, from connector factory creation +through `GetBuildInformationAsync`, using mock data to cover GitHub, Azure DevOps, and Mock +connector paths. Self-test (`--validate`) is covered by `BuildMark_ValidateFlag_RunsSelfValidation` in -`IntegrationTests.cs` and the self-test suite in `ValidationTests.cs`. The CI pipeline -additionally runs the full build notes generation chain with live GitHub metadata to confirm -end-to-end operation. +`IntegrationTests.cs`. The CI pipeline additionally runs the full build notes generation chain +with live GitHub metadata to confirm end-to-end operation. -## Dependencies - -| Mock / Stub | Reason | -| ------------------------ | ------------------------------------------------------------- | -| `MockRepoConnector` | Provides deterministic repository data without live API calls | -| `MockHttpMessageHandler` | Used by GraphQL/REST client unit tests | -| Context output capture | Replaces `Console.Out` with `StringWriter` for assertion | +Mock objects used at the system boundary: `MockRepoConnector` provides deterministic repository +data without live API calls; `MockHttpMessageHandler` intercepts HTTP communication used by +GraphQL/REST client tests; and context output capture replaces `Console.Out` with `StringWriter` +for assertion. ## Test Environment -Tests run via `dotnet test` on the CI matrix (Windows, Ubuntu, macOS) against .NET 8, 9, -and 10. No external services are required for unit and integration tests; all HTTP -communication is intercepted by `MockHttpMessageHandler`. A live GitHub Actions environment -is used for the end-to-end CI validation of the report generation pipeline. +Tests run via `dotnet test` on the CI matrix (Windows, Ubuntu, macOS) against .NET 8, 9, and 10. +No external services are required for unit and integration tests; all HTTP communication is +intercepted by `MockHttpMessageHandler`. A live GitHub Actions environment is used for the +end-to-end CI validation of the report generation pipeline. ## Acceptance Criteria -The system-level test run passes when: all automated tests in `ProgramTests.cs` and -`RepoConnectorsTests.cs` complete with zero failures; the CI pipeline executes the -end-to-end build notes generation step without error; and there are no unresolved -anomalies of Error severity. - -## Test Scenarios (System-Level) - -### BuildMark_VersionFlag_OutputsVersion - -**Scenario**: BuildMark executable is invoked with the `--version` flag via `Runner.Run()`. - -**Expected**: Version string is written to output; exit code is 0. - -**Requirement coverage**: `BuildMark-Command-Version` - -### BuildMark_HelpFlag_OutputsUsageInformation - -**Scenario**: BuildMark executable is invoked with the `--help` flag via `Runner.Run()`. - -**Expected**: Usage information including available options is written to output; exit code is 0. - -**Requirement coverage**: `BuildMark-Command-Help` - -### BuildMark_SilentFlag_SuppressesOutput - -**Scenario**: BuildMark executable is invoked with `--silent --help` flags via `Runner.Run()`. - -**Expected**: No banner is written to output; exit code is 0. - -**Requirement coverage**: `BuildMark-Command-Silent` - -### BuildMark_InvalidArgument_ShowsError - -**Scenario**: BuildMark executable is invoked with an unrecognized argument via `Runner.Run()`. - -**Expected**: An error message containing "Unsupported argument" is written to output; exit code is 1. - -**Requirement coverage**: `BuildMark-Command-ExitCode` - -### BuildMark_ValidateFlag_RunsSelfValidation - -**Scenario**: BuildMark executable is invoked with the `--validate` flag via `Runner.Run()`. - -**Expected**: Self-validation output is written; exit code is 0. - -**Requirement coverage**: `BuildMark-Validation-SelfValidation` - -### BuildMark_LogParameter_IsAccepted - -**Scenario**: BuildMark executable is invoked with `--log test.log --help` via `Runner.Run()`. - -**Expected**: Exit code is 0; no "Unsupported argument" error in output. - -**Requirement coverage**: `BuildMark-Command-Log` - -### BuildMark_ReportParameter_IsAccepted - -**Scenario**: BuildMark executable is invoked with `--report output.md --help` via `Runner.Run()`. - -**Expected**: Exit code is 0; no "Unsupported argument" error in output. - -**Requirement coverage**: `BuildMark-Report-Markdown` - -### BuildMark_DepthParameter_IsAccepted - -**Scenario**: BuildMark executable is invoked with `--depth 2 --help` via `Runner.Run()`. - -**Expected**: Exit code is 0; no "Unsupported argument" error in output. - -**Requirement coverage**: `BuildMark-Command-Depth` - -### BuildMark_BuildVersionParameter_IsAccepted - -**Scenario**: BuildMark executable is invoked with `--build-version 1.0.0 --help` via `Runner.Run()`. - -**Expected**: Exit code is 0; no "Unsupported argument" error in output. - -**Requirement coverage**: `BuildMark-Command-BuildVersion` - -### BuildMark_ResultsParameter_IsAccepted - -**Scenario**: BuildMark executable is invoked with `--results results.trx --help` via `Runner.Run()`. - -**Expected**: Exit code is 0; no "Unsupported argument" error in output. - -**Requirement coverage**: `BuildMark-Command-Results` - -### BuildMark_LintFlag_IsAccepted - -**Scenario**: BuildMark executable is invoked with the `--lint` flag via `Runner.Run()`. - -**Expected**: Exit code is 0; no "Unsupported argument" error in output. - -**Requirement coverage**: `BuildMark-Config-Lint` - -### Program_Version_ReturnsValidVersion - -**Scenario**: `Program.Version` property is accessed. - -**Expected**: Returns a non-null, non-empty version string in semver format. - -**Requirement coverage**: `BuildMark-Command-Version` - -### Program_Run_VersionFlag_OutputsVersionToConsole - -**Scenario**: `Program.Run` is called with a context having `Version = true`. - -**Expected**: Version string is written to context output; exit code is 0. - -**Requirement coverage**: `BuildMark-Command-Version` - -### Program_Run_HelpFlag_OutputsHelpMessage - -**Scenario**: `Program.Run` is called with a context having `Help = true`. - -**Expected**: Help text is written to context output; exit code is 0. - -**Requirement coverage**: `BuildMark-Command-Help` - -### Program_Run_QuestionMarkFlag_OutputsHelpMessage - -**Scenario**: `Program.Run` is called with `?` flag. - -**Expected**: Help text is written to context output; exit code is 0. - -**Requirement coverage**: `BuildMark-Command-Help` - -### Program_Run_LongHelpFlag_OutputsHelpMessage - -**Scenario**: `Program.Run` is called with `--help` flag. - -**Expected**: Help text is written to context output; exit code is 0. - -**Requirement coverage**: `BuildMark-Command-Help` +- All automated tests in `ProgramTests.cs` and `RepoConnectorsTests.cs` pass with zero failures. +- The CI pipeline executes the end-to-end build notes generation step without error. +- No unresolved anomalies of Error severity remain. -### Program_Run_ValidateFlag_OutputsValidationMessage +## Test Scenarios -**Scenario**: `Program.Run` is called with `Validate = true`. +**BuildMark_VersionFlag_OutputsVersion**: Verifies that the BuildMark executable invoked with +`--version` exits with code 0 and writes a non-empty version string to standard output. +This scenario is tested by `BuildMark_VersionFlag_OutputsVersion`. -**Expected**: Validation output is written; self-test completes; exit code is 0. +**BuildMark_HelpFlag_OutputsUsageInformation**: Verifies that invoking BuildMark with `--help` +exits with code 0 and writes usage information including available options to standard output. +This scenario is tested by `BuildMark_HelpFlag_OutputsUsageInformation`. -**Requirement coverage**: `BuildMark-Validation-SelfValidation` +**BuildMark_SilentFlag_SuppressesOutput**: Verifies that invoking BuildMark with `--silent --help` +suppresses the banner but still exits with code 0, confirming the silent flag suppresses non-error +output. This scenario is tested by `BuildMark_SilentFlag_SuppressesOutput`. -### Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues +**BuildMark_InvalidArgument_ShowsError**: Verifies that an unrecognized argument causes BuildMark +to write an error message containing "Unsupported argument" and exit with code 1. +This scenario is tested by `BuildMark_InvalidArgument_ShowsError`. -**Scenario**: `Program.Run` is called with report and include-known-issues flags set. +**BuildMark_ValidateFlag_RunsSelfValidation**: Verifies that invoking BuildMark with `--validate` +writes self-validation output and exits with code 0, confirming the self-test subsystem is +reachable from the CLI. This scenario is tested by `BuildMark_ValidateFlag_RunsSelfValidation`. -**Expected**: Build notes report is generated including known issues section; exit code is 0. +**BuildMark_LogParameter_IsAccepted**: Verifies that `--log test.log --help` is accepted without +an "Unsupported argument" error and exits with code 0. +This scenario is tested by `BuildMark_LogParameter_IsAccepted`. -**Requirement coverage**: `BuildMark-Report-Markdown` +**BuildMark_ReportParameter_IsAccepted**: Verifies that `--report output.md --help` is accepted +without error and exits with code 0. +This scenario is tested by `BuildMark_ReportParameter_IsAccepted`. -### Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero +**BuildMark_DepthParameter_IsAccepted**: Verifies that `--depth 2 --help` is accepted without +error and exits with code 0. +This scenario is tested by `BuildMark_DepthParameter_IsAccepted`. -**Scenario**: `Program.Run` is called with `Lint = true` but no configuration file present. +**BuildMark_BuildVersionParameter_IsAccepted**: Verifies that `--build-version 1.0.0 --help` is +accepted without error and exits with code 0. +This scenario is tested by `BuildMark_BuildVersionParameter_IsAccepted`. -**Expected**: Exit code remains 0 (lint with no config is not an error). +**BuildMark_ResultsParameter_IsAccepted**: Verifies that `--results results.trx --help` is accepted +without error and exits with code 0. +This scenario is tested by `BuildMark_ResultsParameter_IsAccepted`. -**Requirement coverage**: `BuildMark-Config-Lint` +**BuildMark_LintFlag_IsAccepted**: Verifies that `--lint` is accepted without error and exits with +code 0. This scenario is tested by `BuildMark_LintFlag_IsAccepted`. -### Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode +**Program_Version_ReturnsValidVersion**: Verifies that `Program.Version` returns a non-null, +non-empty version string in semver format, confirming version metadata is embedded in the assembly. +This scenario is tested by `Program_Version_ReturnsValidVersion`. -**Scenario**: `Program.Run` is called with an invalid build version string. +**Program_Run_VersionFlag_OutputsVersionToConsole**: Verifies that calling `Program.Run` with a +context having `Version = true` writes the version string to context output and exits with code 0. +This scenario is tested by `Program_Run_VersionFlag_OutputsVersionToConsole`. -**Expected**: Error message is written to stderr; exit code is 1. +**Program_Run_HelpFlag_OutputsHelpMessage**: Verifies that calling `Program.Run` with `Help = true` +writes help text to context output and exits with code 0. This scenario is tested by +`Program_Run_HelpFlag_OutputsHelpMessage`. -**Requirement coverage**: `BuildMark-Program-ErrorHandling-InvalidBuildVersion` +**Program_Run_QuestionMarkFlag_OutputsHelpMessage**: Verifies that the `?` short flag produces the +same help output as `--help`. This scenario is tested by +`Program_Run_QuestionMarkFlag_OutputsHelpMessage`. -### Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode +**Program_Run_LongHelpFlag_OutputsHelpMessage**: Verifies that the `--help` long flag produces +standard help output and exits with code 0. This scenario is tested by +`Program_Run_LongHelpFlag_OutputsHelpMessage`. -**Scenario**: `Program.Run` is called but the connector factory throws `InvalidOperationException`. +**Program_Run_ValidateFlag_OutputsValidationMessage**: Verifies that calling `Program.Run` with +`Validate = true` writes validation output and exits with code 0. +This scenario is tested by `Program_Run_ValidateFlag_OutputsValidationMessage`. -**Expected**: Error message is written to stderr; exit code is 1. +**Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues**: Verifies that +`Program.Run` with report and `IncludeKnownIssues = true` flags generates a report file and exits +with code 0. This scenario is tested by +`Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues`. -**Requirement coverage**: `BuildMark-Program-ErrorHandling-ConnectorFailure` +**Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero**: Verifies that running with +`Lint = true` when no configuration file is present leaves the exit code at 0, confirming that +lint mode is not an error without a config file. +This scenario is tested by `Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero`. -## Requirements Coverage +**Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode**: Verifies that an invalid build +version string causes an error message on stderr and exits with code 1. +This scenario is tested by `Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode`. -- **BuildMark-Command-Version**: BuildMark_VersionFlag_OutputsVersion, - Program_Version_ReturnsValidVersion, Program_Run_VersionFlag_OutputsVersionToConsole -- **BuildMark-Command-Help**: BuildMark_HelpFlag_OutputsUsageInformation, - Program_Run_HelpFlag_OutputsHelpMessage, - Program_Run_QuestionMarkFlag_OutputsHelpMessage, Program_Run_LongHelpFlag_OutputsHelpMessage -- **BuildMark-Validation-SelfValidation**: BuildMark_ValidateFlag_RunsSelfValidation, - Program_Run_ValidateFlag_OutputsValidationMessage -- **BuildMark-Report-Markdown**: BuildMark_ReportParameter_IsAccepted, - Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues -- **BuildMark-Config-Lint**: BuildMark_LintFlag_IsAccepted, - Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero -- **BuildMark-Command-ExitCode**: BuildMark_InvalidArgument_ShowsError -- **BuildMark-Program-ErrorHandling-InvalidBuildVersion**: - Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode -- **BuildMark-Program-ErrorHandling-ConnectorFailure**: - Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode +**Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode**: Verifies +that when the connector factory throws `InvalidOperationException`, an error message is written +to stderr and the exit code is 1. +This scenario is tested by +`Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode`. diff --git a/docs/verification/build-mark/build-notes.md b/docs/verification/build-mark/build-notes.md index 9d0b978..bd1de8d 100644 --- a/docs/verification/build-mark/build-notes.md +++ b/docs/verification/build-mark/build-notes.md @@ -1,64 +1,37 @@ ## BuildNotes -### Verification Strategy +### Verification Approach -`BuildNotes` is the subsystem encompassing `BuildInformation`, `ItemInfo`, and `WebLink`. It is -verified with dedicated subsystem tests in `BuildNotesTests.cs`. The subsystem uses -`MockRepoConnector` to supply deterministic `BuildInformation` instances; no other mocking or test -doubles are required. - -### Dependencies - -| Mock / Stub | Reason | -| ------------------- | -------------------------------------------------------------------- | -| `MockRepoConnector` | Provides deterministic `BuildInformation` for subsystem-level tests. | +The BuildNotes subsystem is verified with dedicated subsystem tests in `BuildNotesTests.cs`. The +subsystem tests call `MockRepoConnector.GetBuildInformationAsync` with specific version tags to +obtain deterministic `BuildInformation` instances, then invoke `ToMarkdown` and assert on the +rendered output. `MockRepoConnector` provides all repository data; no other mocking or test doubles +are required. Unit-level tests for the individual units (`BuildInformation`, `ItemInfo`, `WebLink`) +are in `BuildInformationTests.cs`. ### Test Environment -N/A - standard test environment. `BuildNotesTests.cs` runs within the standard -`dotnet test` host; no external services, live network, or special configuration -are required. +N/A - standard test environment. `BuildNotesTests.cs` runs within the standard `dotnet test` host; +no external services, live network, or special configuration are required. ### Acceptance Criteria -All tests in `BuildNotesTests.cs` pass with zero failures. All `BuildMark-BuildNotes-*` -requirements have at least one test in the Requirements Coverage mapping. +- All tests in `BuildNotesTests.cs` pass with zero failures. +- All `BuildMark-BuildNotes-*` requirements have at least one test in the subsystem test file. ### Test Scenarios -#### BuildNotes_ReportModel_GeneratesCorrectMarkdown - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync` is called with version `v2.0.0`; the -resulting `BuildInformation` is rendered via `ToMarkdown()`. - -**Expected**: Markdown contains `# Build Report`, `## Version Information`, `## Changes`, -`## Bugs Fixed`, `v2.0.0`, and `ver-1.1.0`. - -**Requirement coverage**: `BuildMark-BuildNotes-ReportModel`. - -#### BuildNotes_ReportModel_IncludesKnownIssues - -**Scenario**: `ToMarkdown(includeKnownIssues: true)` is called on a `BuildInformation` for `v2.0.0` -that has known issues. - -**Expected**: Markdown contains `## Known Issues`, `Known bug A`, and `Known bug C`; `Known bug B` -(which has `affected-versions [5.0.0,)`) does not appear. - -**Requirement coverage**: `BuildMark-BuildNotes-ReportModel`. - -#### BuildNotes_ReportModel_IncludesFullChangelog - -**Scenario**: `ToMarkdown()` is called on a `BuildInformation` for `v2.0.0` that has a changelog -link. - -**Expected**: Markdown contains `## Full Changelog` and the comparison link text -`ver-1.1.0...v2.0.0`. - -**Requirement coverage**: `BuildMark-BuildNotes-ReportModel`. +**BuildNotes_ReportModel_GeneratesCorrectMarkdown**: Verifies that `BuildInformation` obtained from +`MockRepoConnector` for version `v2.0.0` renders markdown containing the expected section headings +(`# Build Report`, `## Version Information`, `## Changes`, `## Bugs Fixed`) and version strings +(`v2.0.0`, `ver-1.1.0`). This scenario is tested by +`BuildNotes_ReportModel_GeneratesCorrectMarkdown`. -### Requirements Coverage +**BuildNotes_ReportModel_IncludesKnownIssues**: Verifies that calling `ToMarkdown(includeKnownIssues: true)` +on a `BuildInformation` for `v2.0.0` produces a `## Known Issues` section containing `Known bug A` +and `Known bug C` but excluding `Known bug B` (whose affected-versions interval does not include +`v2.0.0`). This scenario is tested by `BuildNotes_ReportModel_IncludesKnownIssues`. -- **`BuildMark-BuildNotes-ReportModel`**: - - BuildNotes_ReportModel_GeneratesCorrectMarkdown - - BuildNotes_ReportModel_IncludesKnownIssues - - BuildNotes_ReportModel_IncludesFullChangelog +**BuildNotes_ReportModel_IncludesFullChangelog**: Verifies that rendering `BuildInformation` for +`v2.0.0` produces a `## Full Changelog` section containing the comparison link text +`ver-1.1.0...v2.0.0`. This scenario is tested by `BuildNotes_ReportModel_IncludesFullChangelog`. diff --git a/docs/verification/build-mark/build-notes/build-information.md b/docs/verification/build-mark/build-notes/build-information.md index d68243b..c9f99f0 100644 --- a/docs/verification/build-mark/build-notes/build-information.md +++ b/docs/verification/build-mark/build-notes/build-information.md @@ -4,295 +4,144 @@ `BuildInformation` is verified with dedicated unit tests in `BuildInformationTests.cs`. Tests construct `BuildInformation` instances either directly or via `MockRepoConnector`, invoke -`ToMarkdown`, and assert on the rendered output. `NSubstitute` is used in a small number of tests -to simulate connector error conditions; `MockRepoConnector` is used for the remaining tests. No -further mocking is needed. - -#### Dependencies - -| Mock / Stub | Reason | -| --- | --- | -| `MockRepoConnector` | Supplies deterministic `BuildInformation` instances for rendering tests. | -| `NSubstitute` (`IRepoConnector`) | Simulates error conditions that `MockRepoConnector` cannot reproduce. | +`ToMarkdown`, and assert on the rendered output. `MockRepoConnector` supplies deterministic +`BuildInformation` instances for rendering tests. `NSubstitute` is used in a small number of tests +to simulate connector error conditions that `MockRepoConnector` cannot reproduce (for example, +`InvalidOperationException` on missing tags). No further mocking is needed. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. `BuildInformationTests.cs` runs within the standard `dotnet test` +host; no external services or environment setup beyond a `MockRepoConnector` instance are required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All tests in `BuildInformationTests.cs` pass with zero failures. +- Both success and error paths of `GetBuildInformationAsync` and `ToMarkdown` are covered. #### Test Scenarios -##### BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndNoTags - -**Scenario**: A substitute connector is configured to throw `InvalidOperationException` with the -message "No tags found"; `GetBuildInformationAsync()` is called without a version argument. - -**Expected**: `InvalidOperationException` is thrown; message contains "No tags found". - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndCommitDoesNotMatchTag - -**Scenario**: A substitute connector is configured to throw `InvalidOperationException` with the -message "does not match any tag"; `GetBuildInformationAsync()` is called. - -**Expected**: `InvalidOperationException` is thrown; message contains "does not match any tag". - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_WorksWithExplicitVersion - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("v2.1.0"))` is called. - -**Expected**: `CurrentVersionTag.VersionTag.Tag` equals `"v2.1.0"`; commit hash is -`"current123hash456"`; `BaselineVersionTag.VersionTag.Tag` equals `"v2.0.0"`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_WorksWhenCurrentCommitMatchesLatestTag - -**Scenario**: A substitute connector returns a `BuildInformation` where `CurrentVersionTag` is -`v2.0.0`; `GetBuildInformationAsync()` is called. - -**Expected**: Returned `BuildInformation.CurrentVersionTag.VersionTag.Tag` equals `"v2.0.0"`; -`BaselineVersionTag.VersionTag.Tag` equals `"ver-1.1.0"`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_PreReleaseUsesPreviousTag - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("v2.0.0-beta.1"))` is -called. - -**Expected**: `CurrentVersionTag.VersionTag.Tag` equals `"v2.0.0-beta.1"`; -`BaselineVersionTag.VersionTag.Tag` equals `"v2.0.0"`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_ReleaseSkipsPreReleases - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("v2.0.0"))` is called. - -**Expected**: `CurrentVersionTag.VersionTag.Tag` equals `"v2.0.0"`; -`BaselineVersionTag.VersionTag.Tag` equals `"ver-1.1.0"` (pre-releases are skipped). - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_CollectsIssuesCorrectly - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("ver-1.1.0"))` is -called. - -**Expected**: `Changes` contains 2 items (ids `"1"` and `"#13"`); `Bugs` is empty; `KnownIssues` -contains 2 items (ids `"4"` and `"6"`). - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("ver-1.1.0"))` is -called. - -**Expected**: `Changes` are ordered by `Index`; the item with `Index` 10 precedes the item with -`Index` 13. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_SeparatesBugAndChangeIssues - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("v2.0.0"))` is called. - -**Expected**: `Changes` contains 1 item; `Bugs` contains 1 item (id `"2"`, title `"Fix bug in Y"`). - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_GetBuildInformationAsync_HandlesFirstReleaseCorrectly - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("v1.0.0"))` is called. - -**Expected**: `BaselineVersionTag` is null; `CurrentVersionTag.VersionTag.Tag` equals `"v1.0.0"`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_GeneratesCorrectMarkdownWithDefaults - -**Scenario**: `ToMarkdown()` is called on `BuildInformation` for `v2.0.0` without any optional -arguments. - -**Expected**: Markdown contains `# Build Report`, `## Version Information`, `## Changes`, -`## Bugs Fixed`, `v2.0.0`, and `ver-1.1.0`; `## Known Issues` is absent. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_IncludesKnownIssuesWhenRequested - -**Scenario**: `ToMarkdown(includeKnownIssues: true)` is called on `BuildInformation` for `v2.0.0`. - -**Expected**: Markdown contains `## Known Issues`, `Known bug A`, and `Known bug C`; `Known bug B` -is absent. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_RespectsCustomHeadingDepth - -**Scenario**: `ToMarkdown(headingDepth: 3)` is called on `BuildInformation` for `v2.0.0`. - -**Expected**: Top-level heading is `### Build Report`; sub-headings are `#### Version Information`, -`#### Changes`, and `#### Bugs Fixed`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_DisplaysNAForEmptyChanges - -**Scenario**: A `BuildInformation` with an empty `Changes` list is rendered via `ToMarkdown()`. - -**Expected**: The Changes section contains `- N/A`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_DisplaysNAForEmptyBugs - -**Scenario**: A `BuildInformation` with an empty `Bugs` list is rendered via `ToMarkdown()`. - -**Expected**: The Bugs Fixed section contains `- N/A`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_IncludesIssueLinks - -**Scenario**: `ToMarkdown()` is called on `BuildInformation` for `v2.0.0` which has items with -GitHub URLs. - -**Expected**: Markdown contains formatted links such as -`- [3](https://github.com/example/repo/issues/3)` and -`- [2](https://github.com/example/repo/issues/2)`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_HandlesFirstReleaseWithNA - -**Scenario**: `ToMarkdown()` is called on `BuildInformation` for `v1.0.0` (no baseline). - -**Expected**: Version Information section contains `| **Previous Version** | N/A |` and -`| **Previous Commit Hash** | N/A |`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_IncludesFullChangelogWhenLinkPresent - -**Scenario**: `ToMarkdown()` is called on `BuildInformation` for `v2.0.0` which has a changelog -link. - -**Expected**: Markdown contains `## Full Changelog`, the text `See the full changelog at`, and the +**BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndNoTags**: Verifies that when the +connector throws `InvalidOperationException` with "No tags found", calling +`GetBuildInformationAsync()` propagates the exception. +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndNoTags`. + +**BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndCommitDoesNotMatchTag**: Verifies +that when the connector throws with "does not match any tag", the exception propagates unchanged. +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndCommitDoesNotMatchTag`. + +**BuildInformation_GetBuildInformationAsync_WorksWithExplicitVersion**: Verifies that calling with +`VersionTag.Create("v2.1.0")` returns a `BuildInformation` with `CurrentVersionTag.VersionTag.Tag` +equal to `"v2.1.0"` and `BaselineVersionTag.VersionTag.Tag` equal to `"v2.0.0"`. +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_WorksWithExplicitVersion`. + +**BuildInformation_GetBuildInformationAsync_WorksWhenCurrentCommitMatchesLatestTag**: Verifies that +when the current commit matches the latest tag `v2.0.0`, the returned baseline is `ver-1.1.0`. +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_WorksWhenCurrentCommitMatchesLatestTag`. + +**BuildInformation_GetBuildInformationAsync_PreReleaseUsesPreviousTag**: Verifies that a +pre-release version `v2.0.0-beta.1` uses the preceding release tag `v2.0.0` as its baseline. +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_PreReleaseUsesPreviousTag`. + +**BuildInformation_GetBuildInformationAsync_ReleaseSkipsPreReleases**: Verifies that a release +version `v2.0.0` skips pre-release tags and selects `ver-1.1.0` as the baseline. +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_ReleaseSkipsPreReleases`. + +**BuildInformation_GetBuildInformationAsync_CollectsIssuesCorrectly**: Verifies that for +`ver-1.1.0`, `Changes` contains 2 items (ids `"1"` and `"#13"`), `Bugs` is empty, and +`KnownIssues` contains 2 items (ids `"4"` and `"6"`). +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_CollectsIssuesCorrectly`. + +**BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex**: Verifies that `Changes` items +for `ver-1.1.0` are sorted by `Index` in ascending order, with `Index` 10 preceding `Index` 13. +This scenario is tested by +`BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex`. + +**BuildInformation_GetBuildInformationAsync_SeparatesBugAndChangeIssues**: Verifies that for +`v2.0.0`, items labelled as bugs appear in `Bugs` (id `"2"`, title `"Fix bug in Y"`) and not in +`Changes`. This scenario is tested by +`BuildInformation_GetBuildInformationAsync_SeparatesBugAndChangeIssues`. + +**BuildInformation_GetBuildInformationAsync_HandlesFirstReleaseCorrectly**: Verifies that the +first release `v1.0.0` returns `BaselineVersionTag` as null with `CurrentVersionTag.VersionTag.Tag` +equal to `"v1.0.0"`. This scenario is tested by +`BuildInformation_GetBuildInformationAsync_HandlesFirstReleaseCorrectly`. + +**BuildInformation_ToMarkdown_GeneratesCorrectMarkdownWithDefaults**: Verifies that `ToMarkdown()` +on `v2.0.0` produces the expected section headings and version strings, and that `## Known Issues` +is absent by default. This scenario is tested by +`BuildInformation_ToMarkdown_GeneratesCorrectMarkdownWithDefaults`. + +**BuildInformation_ToMarkdown_IncludesKnownIssuesWhenRequested**: Verifies that +`ToMarkdown(includeKnownIssues: true)` on `v2.0.0` includes `Known bug A` and `Known bug C` while +excluding `Known bug B`. This scenario is tested by +`BuildInformation_ToMarkdown_IncludesKnownIssuesWhenRequested`. + +**BuildInformation_ToMarkdown_RespectsCustomHeadingDepth**: Verifies that +`ToMarkdown(headingDepth: 3)` uses `### Build Report` as the top heading and +`#### Version Information`, `#### Changes`, `#### Bugs Fixed` as sub-headings. +This scenario is tested by `BuildInformation_ToMarkdown_RespectsCustomHeadingDepth`. + +**BuildInformation_ToMarkdown_DisplaysNAForEmptyChanges**: Verifies that a `BuildInformation` +with an empty `Changes` list renders `- N/A` in the Changes section. +This scenario is tested by `BuildInformation_ToMarkdown_DisplaysNAForEmptyChanges`. + +**BuildInformation_ToMarkdown_DisplaysNAForEmptyBugs**: Verifies that a `BuildInformation` with +an empty `Bugs` list renders `- N/A` in the Bugs Fixed section. +This scenario is tested by `BuildInformation_ToMarkdown_DisplaysNAForEmptyBugs`. + +**BuildInformation_ToMarkdown_IncludesIssueLinks**: Verifies that items with GitHub URLs are +rendered as formatted links such as `- [3](https://github.com/example/repo/issues/3)`. +This scenario is tested by `BuildInformation_ToMarkdown_IncludesIssueLinks`. + +**BuildInformation_ToMarkdown_HandlesFirstReleaseWithNA**: Verifies that `v1.0.0` (no baseline) +renders `| **Previous Version** | N/A |` and `| **Previous Commit Hash** | N/A |` in the version +information table. This scenario is tested by +`BuildInformation_ToMarkdown_HandlesFirstReleaseWithNA`. + +**BuildInformation_ToMarkdown_IncludesFullChangelogWhenLinkPresent**: Verifies that when a +changelog link is present, rendering produces a `## Full Changelog` section with the comparison URL containing `ver-1.1.0...v2.0.0`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_ExcludesFullChangelogWhenNoBaseline - -**Scenario**: `ToMarkdown()` is called on `BuildInformation` for `v1.0.0` (no baseline version). - -**Expected**: Markdown does not contain `## Full Changelog`. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### BuildInformation_ToMarkdown_UsesBulletLists - -**Scenario**: `ToMarkdown(includeKnownIssues: true)` is called on `BuildInformation` for `v2.0.0`. - -**Expected**: Changes, Bugs Fixed, and Known Issues sections each use `- [` bullet format; no -markdown table notation (`| :-: | :---------- |`) is present in those sections. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### VersionCommitTag_Constructor_StoresVersionAndHash - -**Scenario**: A `VersionCommitTag` is constructed with a `VersionTag` and a commit hash string. - -**Expected**: `VersionTag` property equals the supplied tag; `CommitHash` equals the supplied hash -string. - -**Requirement coverage**: `BuildMark-BuildInformation-Markdown`. - -##### WebLink_Constructor_StoresTextAndUrl - -**Scenario**: A `WebLink` is constructed with display text and a target URL. - -**Expected**: `LinkText` property equals the supplied text; `TargetUrl` property equals the -supplied URL. - -**Requirement coverage**: `BuildMark-WebLink-Record`. - -##### BuildInformation_ToMarkdown_WithRoutedSections_RendersCustomSections - -**Scenario**: A `BuildInformation` is constructed with a populated `RoutedSections` list containing -two custom sections (Features, Bugs); `ToMarkdown()` is called. - -**Expected**: Markdown contains `## Features` and `## Bugs` headings with their respective items; -`## Changes` and `## Bugs Fixed` are absent. - -**Requirement coverage**: `BuildMark-BuildInformation-RoutedSections`. - -##### BuildInformation_ToMarkdown_WithoutRoutedSections_RendersDefaultSections - -**Scenario**: A `BuildInformation` is constructed with `RoutedSections` left as null; -`ToMarkdown()` is called. - -**Expected**: Markdown contains the default `## Changes` and `## Bugs Fixed` headings. - -**Requirement coverage**: `BuildMark-BuildInformation-RoutedSections`. - -##### BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssues_RendersKnownIssuesSection - -**Scenario**: A `BuildInformation` is constructed with a populated `RoutedSections` list and a -non-empty `KnownIssues` list; `ToMarkdown(includeKnownIssues: true)` is called. - -**Expected**: Markdown contains the routed section headings (e.g. `## Features`) and also contains -a `## Known Issues` section appearing after all routed sections. - -**Requirement coverage**: `BuildMark-BuildInformation-RoutedSections`. - -##### BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssuesFlagFalse_DoesNotRenderKnownIssuesSection - -**Scenario**: A `BuildInformation` is constructed with a populated `RoutedSections` list and a -non-empty `KnownIssues` list; `ToMarkdown(includeKnownIssues: false)` is called. - -**Expected**: Markdown does not contain a `## Known Issues` section or any known-issue item text, -confirming the flag is respected in routed mode as well as legacy mode. - -**Requirement coverage**: `BuildMark-BuildInformation-RoutedSections`. - -#### Requirements Coverage - -- **`BuildMark-BuildInformation-Markdown`**: - - BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndNoTags - - BuildInformation_GetBuildInformationAsync_ThrowsWhenNoVersionAndCommitDoesNotMatchTag - - BuildInformation_GetBuildInformationAsync_WorksWithExplicitVersion - - BuildInformation_GetBuildInformationAsync_WorksWhenCurrentCommitMatchesLatestTag - - BuildInformation_GetBuildInformationAsync_PreReleaseUsesPreviousTag - - BuildInformation_GetBuildInformationAsync_ReleaseSkipsPreReleases - - BuildInformation_GetBuildInformationAsync_CollectsIssuesCorrectly - - BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex - - BuildInformation_GetBuildInformationAsync_SeparatesBugAndChangeIssues - - BuildInformation_GetBuildInformationAsync_HandlesFirstReleaseCorrectly - - BuildInformation_ToMarkdown_GeneratesCorrectMarkdownWithDefaults - - BuildInformation_ToMarkdown_IncludesKnownIssuesWhenRequested - - BuildInformation_ToMarkdown_RespectsCustomHeadingDepth - - BuildInformation_ToMarkdown_DisplaysNAForEmptyChanges - - BuildInformation_ToMarkdown_DisplaysNAForEmptyBugs - - BuildInformation_ToMarkdown_IncludesIssueLinks - - BuildInformation_ToMarkdown_HandlesFirstReleaseWithNA - - BuildInformation_ToMarkdown_IncludesFullChangelogWhenLinkPresent - - BuildInformation_ToMarkdown_ExcludesFullChangelogWhenNoBaseline - - BuildInformation_ToMarkdown_UsesBulletLists - - VersionCommitTag_Constructor_StoresVersionAndHash -- **`BuildMark-WebLink-Record`**: - - WebLink_Constructor_StoresTextAndUrl -- **`BuildMark-BuildInformation-RoutedSections`**: - - BuildInformation_ToMarkdown_WithRoutedSections_RendersCustomSections - - BuildInformation_ToMarkdown_WithoutRoutedSections_RendersDefaultSections - - BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssues_RendersKnownIssuesSection - - BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssuesFlagFalse_DoesNotRenderKnownIssuesSection +This scenario is tested by `BuildInformation_ToMarkdown_IncludesFullChangelogWhenLinkPresent`. + +**BuildInformation_ToMarkdown_ExcludesFullChangelogWhenNoBaseline**: Verifies that `v1.0.0` (no +baseline) does not produce a `## Full Changelog` section. +This scenario is tested by `BuildInformation_ToMarkdown_ExcludesFullChangelogWhenNoBaseline`. + +**BuildInformation_ToMarkdown_UsesBulletLists**: Verifies that Changes, Bugs Fixed, and Known +Issues sections each use `- [` bullet format with no markdown table notation. +This scenario is tested by `BuildInformation_ToMarkdown_UsesBulletLists`. + +**BuildInformation_ToMarkdown_WithRoutedSections_RendersCustomSections**: Verifies that when +`RoutedSections` is populated with custom sections (e.g., Features, Bugs), `ToMarkdown()` renders +those headings instead of the default `## Changes` and `## Bugs Fixed`. +This scenario is tested by +`BuildInformation_ToMarkdown_WithRoutedSections_RendersCustomSections`. + +**BuildInformation_ToMarkdown_WithoutRoutedSections_RendersDefaultSections**: Verifies that when +`RoutedSections` is null, the default `## Changes` and `## Bugs Fixed` headings are rendered. +This scenario is tested by +`BuildInformation_ToMarkdown_WithoutRoutedSections_RendersDefaultSections`. + +**BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssues_RendersKnownIssuesSection**: Verifies +that when both `RoutedSections` and `KnownIssues` are populated, `ToMarkdown(includeKnownIssues: true)` +renders the routed section headings and also appends `## Known Issues`. +This scenario is tested by +`BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssues_RendersKnownIssuesSection`. + +**BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssuesFlagFalse_DoesNotRenderKnownIssuesSection**: +Verifies that `ToMarkdown(includeKnownIssues: false)` suppresses the Known Issues section even +when `RoutedSections` and `KnownIssues` are populated. +This scenario is tested by +`BuildInformation_ToMarkdown_WithRoutedSectionsAndKnownIssuesFlagFalse_DoesNotRenderKnownIssuesSection`. + +**VersionCommitTag_Constructor_StoresVersionAndHash**: Verifies that constructing a +`VersionCommitTag` stores the supplied `VersionTag` and commit hash string in the corresponding +properties. This scenario is tested by `VersionCommitTag_Constructor_StoresVersionAndHash`. diff --git a/docs/verification/build-mark/build-notes/item-info.md b/docs/verification/build-mark/build-notes/item-info.md index bfa5e21..de98044 100644 --- a/docs/verification/build-mark/build-notes/item-info.md +++ b/docs/verification/build-mark/build-notes/item-info.md @@ -4,47 +4,28 @@ `ItemInfo` is a record type that carries no logic of its own. It is verified through `BuildInformationTests.cs`, which asserts on the ordering, identity, and link properties of -`ItemInfo` entries returned by `MockRepoConnector`. No mocking beyond `MockRepoConnector` is -needed. - -#### Dependencies - -| Mock / Stub | Reason | -| ------------------- | -------------------------------------------------------------------- | -| `MockRepoConnector` | Provides `BuildInformation` instances with known `ItemInfo` entries. | +`ItemInfo` entries returned by `MockRepoConnector`. `MockRepoConnector` provides `BuildInformation` +instances with known `ItemInfo` entries; no other mocking is needed. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. `BuildInformationTests.cs` runs within the standard `dotnet test` +host; no external dependencies or environment setup beyond a `MockRepoConnector` instance are +required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All `ItemInfo`-related tests in `BuildInformationTests.cs` pass with zero failures. +- Both ordering and rendered output of `ItemInfo` entries are covered. #### Test Scenarios -##### BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex - -**Scenario**: `MockRepoConnector.GetBuildInformationAsync(VersionTag.Create("ver-1.1.0"))` is -called; the `Changes` collection is inspected. - -**Expected**: `ItemInfo` entries in `Changes` are ordered by `Index` in ascending order; the first -entry has `Index` 10 and `Id` `"1"`; the second has `Index` 13. - -**Requirement coverage**: `BuildMark-ItemInfo-Record`. - -##### BuildInformation_ToMarkdown_UsesBulletLists - -**Scenario**: `ToMarkdown(includeKnownIssues: true)` is called on `BuildInformation` for `v2.0.0`; -the rendered bullet list items are inspected. - -**Expected**: Each `ItemInfo` entry is rendered as a `- [id](url)` bullet; no table-row format is -present. - -**Requirement coverage**: `BuildMark-ItemInfo-Record`. - -#### Requirements Coverage +**BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex**: Verifies that `ItemInfo` +entries in the `Changes` collection for `ver-1.1.0` are ordered by `Index` in ascending order, +with the first entry having `Index` 10 and `Id` `"1"` and the second having `Index` 13. +This scenario is tested by `BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex`. -- **`BuildMark-ItemInfo-Record`**: - - BuildInformation_GetBuildInformationAsync_OrdersChangesByIndex - - BuildInformation_ToMarkdown_UsesBulletLists +**BuildInformation_ToMarkdown_UsesBulletLists**: Verifies that each `ItemInfo` entry is rendered +as a `- [id](url)` bullet in the Changes, Bugs Fixed, and Known Issues sections, with no +table-row format present. +This scenario is tested by `BuildInformation_ToMarkdown_UsesBulletLists`. diff --git a/docs/verification/build-mark/build-notes/web-link.md b/docs/verification/build-mark/build-notes/web-link.md index 40a1dc6..0dd8b75 100644 --- a/docs/verification/build-mark/build-notes/web-link.md +++ b/docs/verification/build-mark/build-notes/web-link.md @@ -6,32 +6,18 @@ `BuildInformationTests.cs` that constructs a `WebLink` directly and asserts on its properties. No mocking is required. -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | --------------- | -| None | No mocks needed | - #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. `BuildInformationTests.cs` runs within the standard `dotnet test` +host; no external dependencies or environment setup are required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All `WebLink`-related tests in `BuildInformationTests.cs` pass with zero failures. +- Both `LinkText` and `TargetUrl` properties are verified. #### Test Scenarios -##### WebLink_Constructor_StoresTextAndUrl - -**Scenario**: A `WebLink` is constructed with display text `"v1.0.0...v2.0.0"` and a GitHub -compare URL. - -**Expected**: `LinkText` equals `"v1.0.0...v2.0.0"`; `TargetUrl` equals the supplied URL. - -**Requirement coverage**: `BuildMark-WebLink-Record`. - -#### Requirements Coverage - -- **`BuildMark-WebLink-Record`**: - - WebLink_Constructor_StoresTextAndUrl +**WebLink_Constructor_StoresTextAndUrl**: Verifies that a `WebLink` constructed with display text +`"v1.0.0...v2.0.0"` and a GitHub compare URL stores the values in `LinkText` and `TargetUrl` +properties respectively. This scenario is tested by `WebLink_Constructor_StoresTextAndUrl`. diff --git a/docs/verification/build-mark/cli.md b/docs/verification/build-mark/cli.md index c6ce649..7081520 100644 --- a/docs/verification/build-mark/cli.md +++ b/docs/verification/build-mark/cli.md @@ -1,204 +1,91 @@ ## Cli -### Verification Strategy +### Verification Approach -The Cli subsystem is verified through `CliTests.cs`, which exercises the `Context` -class directly by constructing instances with various argument combinations and -asserting on the resulting property values. Each test targets a specific flag or -argument combination and validates correct parsing behavior, including error conditions -and output behavior. - -### Dependencies - -| Mock / Stub | Reason | -| -------------------- | ------------------------------------------------------------------ | -| `StringWriter` | Captures context output for assertion without console side effects | -| In-process arguments | Passed directly to `Context` constructor instead of `args[]` | +The Cli subsystem is verified through `CliTests.cs` (subsystem-level) and `ContextTests.cs` +(unit-level). `CliTests.cs` exercises the `Context` class directly by constructing instances with +various argument combinations and asserting on the resulting property values. Each test targets a +specific flag or argument combination and validates correct parsing behavior, including error +conditions and output behavior. `StringWriter` captures context output for assertion without console +side effects, and arguments are passed directly to the `Context` constructor rather than through +`args[]`. ### Test Environment -N/A - standard test environment. `CliTests.cs` runs within the standard `dotnet test` -host; no external services, live network, or file system side effects beyond an -in-process `StringWriter` are required. +N/A - standard test environment. Both `CliTests.cs` and `ContextTests.cs` run within the standard +`dotnet test` host; no external services, live network, or file system side effects beyond an +in-process `StringWriter` and temporary log files are required. ### Acceptance Criteria -All tests in `CliTests.cs` pass with zero failures. All `BuildMark-Cli-*` and referenced -`BuildMark-Program-*` requirements have at least one test in the Requirements Coverage -mapping. +- All tests in `CliTests.cs` pass with zero failures. +- All `BuildMark-Cli-*` and referenced `BuildMark-Program-*` requirements have at least one + test in the subsystem test file. ### Test Scenarios -#### Cli_Context_EmptyArguments_CreatesValidContext - -**Scenario**: A `Context` is created with no arguments. - -**Expected**: Context is created without error; all flags default to false. - -**Requirement coverage**: `BuildMark-Cli-Context` - -#### Cli_VersionFlag_SetsProperty - -**Scenario**: Context is created with `--version` argument. - -**Expected**: `Version` property is `true`. - -**Requirement coverage**: `BuildMark-Program-Version` - -#### Cli_HelpFlag_SetsProperty - -**Scenario**: Context is created with `--help` argument. - -**Expected**: `Help` property is `true`. - -**Requirement coverage**: `BuildMark-Program-Help` - -#### Cli_SilentFlag_SetsProperty - -**Scenario**: Context is created with `--silent` argument. - -**Expected**: `Silent` property is `true`. - -**Requirement coverage**: `BuildMark-Program-Silent` - -#### Cli_SilentFlag_SuppressesConsoleOutput - -**Scenario**: Context is created with `--silent` argument and a write is performed. - -**Expected**: Output is suppressed; nothing is written to console. - -**Requirement coverage**: `BuildMark-Program-Silent` - -#### Cli_BuildVersionFlag_SetsProperty - -**Scenario**: Context is created with `--build-version 1.2.3` argument. - -**Expected**: `BuildVersion` property equals `"1.2.3"`. - -**Requirement coverage**: `BuildMark-Program-BuildVersion` - -#### Cli_ReportFlags_SetProperties - -**Scenario**: Context is created with `["--report", "output.md", "--depth", "3", -"--include-known-issues"]`. - -**Expected**: `ReportFile` equals `"output.md"`; `Depth` equals 3; `IncludeKnownIssues` is true. - -**Requirement coverage**: `BuildMark-Program-Report`, `BuildMark-Program-Depth` - -#### Cli_LogFlag_CreatesLogFile - -**Scenario**: Context is created with `--log path.log` argument. - -**Expected**: `Log` property is set; log file is created at the specified path. - -**Requirement coverage**: `BuildMark-Program-Log` - -#### Cli_ValidateFlag_SetsProperty - -**Scenario**: Context is created with `--validate` argument. - -**Expected**: `Validate` property is `true`. - -**Requirement coverage**: `BuildMark-Program-Validate` - -#### Cli_ResultsFlag_SetsProperty - -**Scenario**: Context is created with `["--results", "results.trx"]`. - -**Expected**: `ResultsFile` property equals `"results.trx"`. - -**Requirement coverage**: `BuildMark-Program-Results` - -#### Cli_ResultFlag_SetsProperty - -**Scenario**: Context is created with `["--result", "results.trx"]` (alias). - -**Expected**: `ResultsFile` property equals `"results.trx"`. - -**Requirement coverage**: `BuildMark-Program-Results` - -#### Cli_ErrorOutput_WritesToStderr - -**Scenario**: `context.WriteError` is called with an error message. - -**Expected**: The message `"Subsystem error test"` appears in the standard error stream. - -**Requirement coverage**: `BuildMark-Program-ErrorHandling` - -#### Cli_InvalidArgument_ThrowsException - -**Scenario**: Context is created with `["--unsupported"]`. - -**Expected**: `ArgumentException` is thrown with a message containing -`"Unsupported argument '--unsupported'"`. - -**Requirement coverage**: `BuildMark-Cli-Context` - -#### Cli_MissingArgumentValue_ThrowsException - -**Scenario**: Context is created with `["--build-version"]` (value missing). - -**Expected**: `ArgumentException` is thrown with a message containing -`"--build-version requires a version argument"`. - -**Requirement coverage**: `BuildMark-Cli-Context` - -#### Cli_ExitCode_DefaultsToZero - -**Scenario**: Context is created; `ExitCode` property is read without any errors. - -**Expected**: `ExitCode` is 0. - -**Requirement coverage**: `BuildMark-Cli-Context` +**Cli_Context_EmptyArguments_CreatesValidContext**: Verifies that a `Context` created with no +arguments initializes successfully with all flags defaulting to false. +This scenario is tested by `Cli_Context_EmptyArguments_CreatesValidContext`. -#### Cli_WriteError_SetsExitCodeToOne +**Cli_VersionFlag_SetsProperty**: Verifies that constructing a context with `--version` sets the +`Version` property to true. This scenario is tested by `Cli_VersionFlag_SetsProperty`. -**Scenario**: `context.WriteError` is called. +**Cli_HelpFlag_SetsProperty**: Verifies that constructing a context with `--help` sets the `Help` +property to true. This scenario is tested by `Cli_HelpFlag_SetsProperty`. -**Expected**: `ExitCode` is 1 after the call. +**Cli_SilentFlag_SetsProperty**: Verifies that constructing a context with `--silent` sets the +`Silent` property to true. This scenario is tested by `Cli_SilentFlag_SetsProperty`. -**Requirement coverage**: `BuildMark-Program-ErrorHandling` +**Cli_SilentFlag_SuppressesConsoleOutput**: Verifies that a context created with `--silent` does +not write to the console when a write is performed, confirming output suppression. +This scenario is tested by `Cli_SilentFlag_SuppressesConsoleOutput`. -#### Cli_VersionShortFlag_SetsProperty +**Cli_BuildVersionFlag_SetsProperty**: Verifies that `--build-version 1.2.3` sets the +`BuildVersion` property to `"1.2.3"`. This scenario is tested by +`Cli_BuildVersionFlag_SetsProperty`. -**Scenario**: Context is created with `-v` short argument. +**Cli_ReportFlags_SetProperties**: Verifies that `--report output.md --depth 3 +--include-known-issues` sets `ReportFile` to `"output.md"`, `Depth` to 3, and `IncludeKnownIssues` +to true. This scenario is tested by `Cli_ReportFlags_SetProperties`. -**Expected**: `Version` property is `true`. +**Cli_LogFlag_CreatesLogFile**: Verifies that `--log path.log` sets the `Log` property and creates +the log file at the specified path. +This scenario is tested by `Cli_LogFlag_CreatesLogFile`. -**Requirement coverage**: `BuildMark-Program-Version` +**Cli_ValidateFlag_SetsProperty**: Verifies that `--validate` sets the `Validate` property to +true. This scenario is tested by `Cli_ValidateFlag_SetsProperty`. -#### Cli_HelpShortFlags_SetProperty +**Cli_ResultsFlag_SetsProperty**: Verifies that `--results results.trx` sets `ResultsFile` to +`"results.trx"`. This scenario is tested by `Cli_ResultsFlag_SetsProperty`. -**Scenario**: Context is created with `-h` or `-?` short arguments. +**Cli_ResultFlag_SetsProperty**: Verifies that the `--result` alias sets `ResultsFile` to +`"results.trx"` identically to `--results`. +This scenario is tested by `Cli_ResultFlag_SetsProperty`. -**Expected**: `Help` property is `true`. +**Cli_ErrorOutput_WritesToStderr**: Verifies that `context.WriteError` writes the error message +to the standard error stream. This scenario is tested by `Cli_ErrorOutput_WritesToStderr`. -**Requirement coverage**: `BuildMark-Program-Help` +**Cli_InvalidArgument_ThrowsException**: Verifies that an unrecognized argument causes an +`ArgumentException` containing "Unsupported argument '--unsupported'". +This scenario is tested by `Cli_InvalidArgument_ThrowsException`. -#### Cli_LintFlag_SetsProperty +**Cli_MissingArgumentValue_ThrowsException**: Verifies that `--build-version` without a following +value causes an `ArgumentException` containing the missing-value message. +This scenario is tested by `Cli_MissingArgumentValue_ThrowsException`. -**Scenario**: Context is created with `--lint` argument. +**Cli_ExitCode_DefaultsToZero**: Verifies that a freshly created context has `ExitCode` of 0 +before any errors are written. +This scenario is tested by `Cli_ExitCode_DefaultsToZero`. -**Expected**: `Lint` property is `true`. +**Cli_WriteError_SetsExitCodeToOne**: Verifies that calling `context.WriteError` sets `ExitCode` +to 1. This scenario is tested by `Cli_WriteError_SetsExitCodeToOne`. -**Requirement coverage**: `BuildMark-Program-Lint` +**Cli_VersionShortFlag_SetsProperty**: Verifies that the `-v` short argument sets the `Version` +property to true. This scenario is tested by `Cli_VersionShortFlag_SetsProperty`. -### Requirements Coverage +**Cli_HelpShortFlags_SetProperty**: Verifies that `-h` and `-?` short arguments set the `Help` +property to true. This scenario is tested by `Cli_HelpShortFlags_SetProperty`. -- **BuildMark-Cli-Context**: Cli_Context_EmptyArguments_CreatesValidContext, - Cli_InvalidArgument_ThrowsException, Cli_MissingArgumentValue_ThrowsException, - Cli_ExitCode_DefaultsToZero -- **BuildMark-Program-Version**: Cli_VersionFlag_SetsProperty, Cli_VersionShortFlag_SetsProperty -- **BuildMark-Program-Help**: Cli_HelpFlag_SetsProperty, Cli_HelpShortFlags_SetProperty -- **BuildMark-Program-Silent**: Cli_SilentFlag_SetsProperty, - Cli_SilentFlag_SuppressesConsoleOutput -- **BuildMark-Program-BuildVersion**: Cli_BuildVersionFlag_SetsProperty -- **BuildMark-Program-Report**: Cli_ReportFlags_SetProperties -- **BuildMark-Program-Depth**: Cli_ReportFlags_SetProperties -- **BuildMark-Program-Log**: Cli_LogFlag_CreatesLogFile -- **BuildMark-Program-Validate**: Cli_ValidateFlag_SetsProperty -- **BuildMark-Program-Results**: Cli_ResultsFlag_SetsProperty, Cli_ResultFlag_SetsProperty -- **BuildMark-Program-Lint**: Cli_LintFlag_SetsProperty -- **BuildMark-Program-ErrorHandling**: Cli_ErrorOutput_WritesToStderr, - Cli_WriteError_SetsExitCodeToOne +**Cli_LintFlag_SetsProperty**: Verifies that `--lint` sets the `Lint` property to true. +This scenario is tested by `Cli_LintFlag_SetsProperty`. diff --git a/docs/verification/build-mark/cli/context.md b/docs/verification/build-mark/cli/context.md index 054195b..d9732cc 100644 --- a/docs/verification/build-mark/cli/context.md +++ b/docs/verification/build-mark/cli/context.md @@ -1,398 +1,173 @@ -### Context Verification - -This document describes the unit-level verification design for the `Context` unit. It defines the -test scenarios, dependency usage, and requirement coverage for `Cli/Context.cs`. +### Context #### Verification Approach -`Context` is verified with unit tests defined in `ContextTests.cs`. Because `Context` depends only -on .NET base class library types (`Console`, `StreamWriter`, `Path`), no mocking or test doubles -are required. Tests call `Context.Create` with controlled argument arrays, inspect the resulting +`Context` is verified with unit tests in `ContextTests.cs`. Because `Context` depends only on .NET +base class library types (`Console`, `StreamWriter`, `Path`), no mocking or test doubles are +required. Tests call `Context.Create` with controlled argument arrays, inspect the resulting properties and exit codes, and verify output written to captured streams. -#### Dependencies - -`Context` has no dependencies on other tool units. All dependencies are real .NET BCL types; -no mocking is needed at this level. - #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. `ContextTests.cs` runs within the standard `dotnet test` host; +no external dependencies are required beyond temporary log files created by log-related tests. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All tests in `ContextTests.cs` pass with zero failures. +- Flag parsing, argument parsing, output routing, silent mode, log file, exit code, and error + handling paths are all covered. #### Test Scenarios -##### Context_Create_EmptyArguments_CreatesValidContext - -**Scenario**: `Context.Create` is called with an empty argument array. - -**Expected**: All boolean flags are false; `ResultsFile` is null; `Depth` is null; -exit code is 0. - -**Requirement coverage**: `BuildMark-Context-DefaultConstruction`. - -##### Context_Create_ShortVersionFlag_SetsVersionProperty - -**Scenario**: `Context.Create` is called with `["-v"]`. - -**Expected**: `Version` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_LongVersionFlag_SetsVersionProperty - -**Scenario**: `Context.Create` is called with `["--version"]`. - -**Expected**: `Version` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_QuestionMarkHelpFlag_SetsHelpProperty - -**Scenario**: `Context.Create` is called with `["-?"]`. - -**Expected**: `Help` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_ShortHelpFlag_SetsHelpProperty - -**Scenario**: `Context.Create` is called with `["-h"]`. - -**Expected**: `Help` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_LongHelpFlag_SetsHelpProperty - -**Scenario**: `Context.Create` is called with `["--help"]`. - -**Expected**: `Help` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_SilentFlag_SetsSilentProperty - -**Scenario**: `Context.Create` is called with `["--silent"]`. - -**Expected**: `Silent` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_ValidateFlag_SetsValidateProperty - -**Scenario**: `Context.Create` is called with `["--validate"]`. - -**Expected**: `Validate` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_LintFlag_SetsLintProperty - -**Scenario**: `Context.Create` is called with `["--lint"]`. - -**Expected**: `Lint` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_BuildVersionArgument_SetsBuildVersionProperty - -**Scenario**: `Context.Create` is called with `["--build-version", "1.2.3"]`. - -**Expected**: `BuildVersion` property equals `"1.2.3"`. - -**Requirement coverage**: `BuildMark-Context-ArgumentParsing`. - -##### Context_Create_ReportArgument_SetsReportFileProperty - -**Scenario**: `Context.Create` is called with `["--report", "output.md"]`. - -**Expected**: `ReportFile` property equals `"output.md"`. - -**Requirement coverage**: `BuildMark-Context-ArgumentParsing`. - -##### Context_Create_DepthArgument_SetsDepthProperty - -**Scenario**: `Context.Create` is called with `["--depth", "3"]`. - -**Expected**: `Depth` property equals 3. - -**Requirement coverage**: `BuildMark-Context-ArgumentParsing`. - -##### Context_Create_LegacyReportDepthArgument_SetsDepthProperty - -**Scenario**: `Context.Create` is called with `["--report-depth", "3"]` (legacy alias for -`--depth`). - -**Expected**: `Depth` property equals 3. - -**Requirement coverage**: `BuildMark-Context-ArgumentParsing`. - -##### Context_Create_IncludeKnownIssuesFlag_SetsIncludeKnownIssuesProperty - -**Scenario**: `Context.Create` is called with `["--include-known-issues"]`. - -**Expected**: `IncludeKnownIssues` property is true. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`. - -##### Context_Create_ResultsArgument_SetsResultsFileProperty - -**Scenario**: `Context.Create` is called with `["--results", "output.trx"]`. - -**Expected**: `ResultsFile` property equals `"output.trx"`. - -**Requirement coverage**: `BuildMark-Context-ArgumentParsing`. - -##### Context_Create_ResultArgument_SetsResultsFileProperty - -**Scenario**: `Context.Create` is called with `["--result", "output.trx"]` (alias). - -**Expected**: `ResultsFile` property equals `"output.trx"`. - -**Requirement coverage**: `BuildMark-Context-ArgumentParsing`. - -##### Context_Create_LogArgument_CreatesLogFile - -**Scenario**: `Context.Create` is called with `["--log", ".log"]`; `WriteLine` is then called -with a test message. - -**Expected**: The log file is created; the test message is written to it. - -**Requirement coverage**: `BuildMark-Context-LogFile`. - -##### Context_Create_MultipleArguments_SetsAllPropertiesCorrectly - -**Scenario**: `Context.Create` is called with `["--silent", "--validate", "--lint", -"--build-version", "1.2.3", "--report", "report.md", "--depth", "2", -"--include-known-issues", "--results", "results.trx"]`. - -**Expected**: `Silent`, `Validate`, `Lint`, and `IncludeKnownIssues` are true; `BuildVersion` -equals `"1.2.3"`; `ReportFile` equals `"report.md"`; `Depth` equals 2; `ResultsFile` equals -`"results.trx"`; no exception is thrown. - -**Requirement coverage**: `BuildMark-Context-FlagParsing`, `BuildMark-Context-ArgumentParsing`. - -##### Context_Create_UnsupportedArgument_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--unsupported"]`. - -**Expected**: An `ArgumentException` is thrown containing the text "Unsupported argument". - -**Boundary / error path**: Unknown argument rejection. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_BuildVersionWithoutValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--build-version"]` (value missing). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_ReportWithoutValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--report"]` (value missing). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_DepthWithoutValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--depth"]` (value missing). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_DepthWithNonIntegerValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--depth", "abc"]`. - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_DepthWithZeroValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--depth", "0"]` (below minimum of 1). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_DepthWithNegativeValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--depth", "-1"]` (negative value). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_DepthExceedingMaximum_ThrowsArgumentOutOfRangeException - -**Scenario**: `Context.Create` is called with `["--depth", "7"]` (above the maximum of 6). - -**Expected**: An `ArgumentOutOfRangeException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_ResultsWithoutValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--results"]` (value missing). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_ResultWithoutValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--result"]` (value missing). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_LogWithoutValue_ThrowsArgumentException - -**Scenario**: `Context.Create` is called with `["--log"]` (value missing). - -**Expected**: An `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. - -##### Context_Create_InvalidLogFilePath_ThrowsInvalidOperationException - -**Scenario**: `Context.Create` is called with `["--log", ""]`. - -**Expected**: An `InvalidOperationException` is thrown when the log file cannot be created. - -**Requirement coverage**: `BuildMark-Context-ErrorHandling`. +**Context_Create_EmptyArguments_CreatesValidContext**: Verifies that `Context.Create` with an empty +argument array initializes successfully with all boolean flags false, `ResultsFile` null, `Depth` +null, and `ExitCode` 0. +This scenario is tested by `Context_Create_EmptyArguments_CreatesValidContext`. -##### Context_WriteLine_NotSilent_WritesToConsole +**Context_Create_ShortVersionFlag_SetsVersionProperty**: Verifies that `["-v"]` sets the `Version` +property to true. This scenario is tested by +`Context_Create_ShortVersionFlag_SetsVersionProperty`. -**Scenario**: A non-silent `Context` is created and `WriteLine` is called with a test message. +**Context_Create_LongVersionFlag_SetsVersionProperty**: Verifies that `["--version"]` sets the +`Version` property to true. This scenario is tested by +`Context_Create_LongVersionFlag_SetsVersionProperty`. -**Expected**: The test message appears on standard output. +**Context_Create_QuestionMarkHelpFlag_SetsHelpProperty**: Verifies that `["-?"]` sets the `Help` +property to true. This scenario is tested by +`Context_Create_QuestionMarkHelpFlag_SetsHelpProperty`. -**Requirement coverage**: `BuildMark-Context-Output`. +**Context_Create_ShortHelpFlag_SetsHelpProperty**: Verifies that `["-h"]` sets the `Help` property +to true. This scenario is tested by `Context_Create_ShortHelpFlag_SetsHelpProperty`. -##### Context_WriteLine_Silent_DoesNotWriteToConsole +**Context_Create_LongHelpFlag_SetsHelpProperty**: Verifies that `["--help"]` sets the `Help` +property to true. This scenario is tested by `Context_Create_LongHelpFlag_SetsHelpProperty`. -**Scenario**: A silent `Context` (created with `["--silent"]`) calls `WriteLine`. +**Context_Create_SilentFlag_SetsSilentProperty**: Verifies that `["--silent"]` sets the `Silent` +property to true. This scenario is tested by `Context_Create_SilentFlag_SetsSilentProperty`. -**Expected**: Standard output receives nothing. +**Context_Create_ValidateFlag_SetsValidateProperty**: Verifies that `["--validate"]` sets the +`Validate` property to true. +This scenario is tested by `Context_Create_ValidateFlag_SetsValidateProperty`. -**Requirement coverage**: `BuildMark-Context-SilentMode`. +**Context_Create_LintFlag_SetsLintProperty**: Verifies that `["--lint"]` sets the `Lint` property +to true. This scenario is tested by `Context_Create_LintFlag_SetsLintProperty`. -##### Context_WriteLine_WithLogFile_WritesToLogFile +**Context_Create_BuildVersionArgument_SetsBuildVersionProperty**: Verifies that +`["--build-version", "1.2.3"]` sets `BuildVersion` to `"1.2.3"`. +This scenario is tested by `Context_Create_BuildVersionArgument_SetsBuildVersionProperty`. -**Scenario**: A `Context` created with a log file calls `WriteLine` with a test message. +**Context_Create_ReportArgument_SetsReportFileProperty**: Verifies that `["--report", "output.md"]` +sets `ReportFile` to `"output.md"`. +This scenario is tested by `Context_Create_ReportArgument_SetsReportFileProperty`. -**Expected**: The test message appears in the log file. +**Context_Create_DepthArgument_SetsDepthProperty**: Verifies that `["--depth", "3"]` sets `Depth` +to 3. This scenario is tested by `Context_Create_DepthArgument_SetsDepthProperty`. -**Requirement coverage**: `BuildMark-Context-LogFile`. +**Context_Create_LegacyReportDepthArgument_SetsDepthProperty**: Verifies that the legacy alias +`["--report-depth", "3"]` sets `Depth` to 3 identically to `--depth`. +This scenario is tested by `Context_Create_LegacyReportDepthArgument_SetsDepthProperty`. -##### Context_WriteError_NotSilent_WritesToConsole +**Context_Create_IncludeKnownIssuesFlag_SetsIncludeKnownIssuesProperty**: Verifies that +`["--include-known-issues"]` sets `IncludeKnownIssues` to true. +This scenario is tested by +`Context_Create_IncludeKnownIssuesFlag_SetsIncludeKnownIssuesProperty`. -**Scenario**: A non-silent `Context` calls `WriteError` with a test message. +**Context_Create_ResultsArgument_SetsResultsFileProperty**: Verifies that +`["--results", "output.trx"]` sets `ResultsFile` to `"output.trx"`. +This scenario is tested by `Context_Create_ResultsArgument_SetsResultsFileProperty`. -**Expected**: The test message appears on standard error. +**Context_Create_ResultArgument_SetsResultsFileProperty**: Verifies that the `--result` alias sets +`ResultsFile` identically to `--results`. +This scenario is tested by `Context_Create_ResultArgument_SetsResultsFileProperty`. -**Requirement coverage**: `BuildMark-Context-Output`. +**Context_Create_LogArgument_CreatesLogFile**: Verifies that `["--log", ".log"]` creates the +log file and routes a subsequent `WriteLine` call to it. +This scenario is tested by `Context_Create_LogArgument_CreatesLogFile`. -##### Context_WriteError_Silent_DoesNotWriteToConsole +**Context_Create_MultipleArguments_SetsAllPropertiesCorrectly**: Verifies that all flags and +arguments in a combined invocation are parsed correctly in a single context creation. +This scenario is tested by `Context_Create_MultipleArguments_SetsAllPropertiesCorrectly`. -**Scenario**: A silent `Context` calls `WriteError`. +**Context_Create_UnsupportedArgument_ThrowsArgumentException**: Verifies that `["--unsupported"]` +throws an `ArgumentException` containing "Unsupported argument". +This scenario is tested by `Context_Create_UnsupportedArgument_ThrowsArgumentException`. -**Expected**: Standard error receives nothing. +**Context_Create_BuildVersionWithoutValue_ThrowsArgumentException**: Verifies that +`["--build-version"]` without a value throws an `ArgumentException`. +This scenario is tested by `Context_Create_BuildVersionWithoutValue_ThrowsArgumentException`. -**Requirement coverage**: `BuildMark-Context-SilentMode`. +**Context_Create_ReportWithoutValue_ThrowsArgumentException**: Verifies that `["--report"]` +without a value throws an `ArgumentException`. +This scenario is tested by `Context_Create_ReportWithoutValue_ThrowsArgumentException`. -##### Context_WriteError_WithLogFile_WritesToLogFile +**Context_Create_DepthWithoutValue_ThrowsArgumentException**: Verifies that `["--depth"]` without +a value throws an `ArgumentException`. +This scenario is tested by `Context_Create_DepthWithoutValue_ThrowsArgumentException`. -**Scenario**: A `Context` created with a log file calls `WriteError` with a test message. +**Context_Create_DepthWithNonIntegerValue_ThrowsArgumentException**: Verifies that +`["--depth", "abc"]` throws an `ArgumentException`. +This scenario is tested by `Context_Create_DepthWithNonIntegerValue_ThrowsArgumentException`. -**Expected**: The test message appears in the log file. +**Context_Create_DepthWithZeroValue_ThrowsArgumentException**: Verifies that `["--depth", "0"]` +(below the minimum of 1) throws an `ArgumentException`. +This scenario is tested by `Context_Create_DepthWithZeroValue_ThrowsArgumentException`. -**Requirement coverage**: `BuildMark-Context-LogFile`. +**Context_Create_DepthWithNegativeValue_ThrowsArgumentException**: Verifies that +`["--depth", "-1"]` (negative value) throws an `ArgumentException`. +This scenario is tested by `Context_Create_DepthWithNegativeValue_ThrowsArgumentException`. -##### Context_WriteError_SetsExitCodeToOne +**Context_Create_DepthExceedingMaximum_ThrowsArgumentOutOfRangeException**: Verifies that +`["--depth", "7"]` (above the maximum of 6) throws an `ArgumentOutOfRangeException`. +This scenario is tested by +`Context_Create_DepthExceedingMaximum_ThrowsArgumentOutOfRangeException`. -**Scenario**: A `Context` calls `WriteError`. +**Context_Create_ResultsWithoutValue_ThrowsArgumentException**: Verifies that `["--results"]` +without a value throws an `ArgumentException`. +This scenario is tested by `Context_Create_ResultsWithoutValue_ThrowsArgumentException`. -**Expected**: `ExitCode` is 1 after the call. +**Context_Create_ResultWithoutValue_ThrowsArgumentException**: Verifies that `["--result"]` +without a value throws an `ArgumentException`. +This scenario is tested by `Context_Create_ResultWithoutValue_ThrowsArgumentException`. -**Requirement coverage**: `BuildMark-Context-ExitCode`. +**Context_Create_LogWithoutValue_ThrowsArgumentException**: Verifies that `["--log"]` without a +value throws an `ArgumentException`. +This scenario is tested by `Context_Create_LogWithoutValue_ThrowsArgumentException`. -##### Context_ExitCode_NoErrors_RemainsZero +**Context_Create_InvalidLogFilePath_ThrowsInvalidOperationException**: Verifies that supplying an +invalid log file path throws an `InvalidOperationException`. +This scenario is tested by `Context_Create_InvalidLogFilePath_ThrowsInvalidOperationException`. -**Scenario**: A `Context` is created and no errors are written. +**Context_WriteLine_NotSilent_WritesToConsole**: Verifies that a non-silent context writes to +standard output when `WriteLine` is called. +This scenario is tested by `Context_WriteLine_NotSilent_WritesToConsole`. -**Expected**: `ExitCode` remains 0. +**Context_WriteLine_Silent_DoesNotWriteToConsole**: Verifies that a silent context does not write +to standard output when `WriteLine` is called. +This scenario is tested by `Context_WriteLine_Silent_DoesNotWriteToConsole`. -**Requirement coverage**: `BuildMark-Context-ExitCode`. +**Context_WriteLine_WithLogFile_WritesToLogFile**: Verifies that a context with a log file routes +`WriteLine` output to the log file. +This scenario is tested by `Context_WriteLine_WithLogFile_WritesToLogFile`. -##### Context_Dispose_ClosesLogFileProperly +**Context_WriteError_NotSilent_WritesToConsole**: Verifies that a non-silent context writes to +standard error when `WriteError` is called. +This scenario is tested by `Context_WriteError_NotSilent_WritesToConsole`. -**Scenario**: A `Context` with a log file is disposed. +**Context_WriteError_Silent_DoesNotWriteToConsole**: Verifies that a silent context does not write +to standard error when `WriteError` is called. +This scenario is tested by `Context_WriteError_Silent_DoesNotWriteToConsole`. -**Expected**: The log file is properly closed without error. +**Context_WriteError_WithLogFile_WritesToLogFile**: Verifies that a context with a log file routes +`WriteError` output to the log file. +This scenario is tested by `Context_WriteError_WithLogFile_WritesToLogFile`. -**Requirement coverage**: `BuildMark-Context-LogFile`. +**Context_WriteError_SetsExitCodeToOne**: Verifies that calling `WriteError` on a context sets +`ExitCode` to 1. This scenario is tested by `Context_WriteError_SetsExitCodeToOne`. -#### Requirements Coverage +**Context_ExitCode_NoErrors_RemainsZero**: Verifies that a context with no errors written retains +`ExitCode` of 0. This scenario is tested by `Context_ExitCode_NoErrors_RemainsZero`. -- **`BuildMark-Context-DefaultConstruction`**: - - Context_Create_EmptyArguments_CreatesValidContext -- **`BuildMark-Context-FlagParsing`**: - - Context_Create_ShortVersionFlag_SetsVersionProperty - - Context_Create_LongVersionFlag_SetsVersionProperty - - Context_Create_QuestionMarkHelpFlag_SetsHelpProperty - - Context_Create_ShortHelpFlag_SetsHelpProperty - - Context_Create_LongHelpFlag_SetsHelpProperty - - Context_Create_SilentFlag_SetsSilentProperty - - Context_Create_ValidateFlag_SetsValidateProperty - - Context_Create_LintFlag_SetsLintProperty - - Context_Create_IncludeKnownIssuesFlag_SetsIncludeKnownIssuesProperty - - Context_Create_MultipleArguments_SetsAllPropertiesCorrectly -- **`BuildMark-Context-ArgumentParsing`**: - - Context_Create_BuildVersionArgument_SetsBuildVersionProperty - - Context_Create_ReportArgument_SetsReportFileProperty - - Context_Create_DepthArgument_SetsDepthProperty - - Context_Create_LegacyReportDepthArgument_SetsDepthProperty - - Context_Create_ResultsArgument_SetsResultsFileProperty - - Context_Create_ResultArgument_SetsResultsFileProperty - - Context_Create_MultipleArguments_SetsAllPropertiesCorrectly -- **`BuildMark-Context-LogFile`**: - - Context_Create_LogArgument_CreatesLogFile - - Context_WriteLine_WithLogFile_WritesToLogFile - - Context_WriteError_WithLogFile_WritesToLogFile - - Context_Dispose_ClosesLogFileProperly -- **`BuildMark-Context-ErrorHandling`**: - - Context_Create_UnsupportedArgument_ThrowsArgumentException - - Context_Create_BuildVersionWithoutValue_ThrowsArgumentException - - Context_Create_ReportWithoutValue_ThrowsArgumentException - - Context_Create_DepthWithoutValue_ThrowsArgumentException - - Context_Create_DepthWithNonIntegerValue_ThrowsArgumentException - - Context_Create_DepthWithZeroValue_ThrowsArgumentException - - Context_Create_DepthWithNegativeValue_ThrowsArgumentException - - Context_Create_DepthExceedingMaximum_ThrowsArgumentOutOfRangeException - - Context_Create_ResultsWithoutValue_ThrowsArgumentException - - Context_Create_ResultWithoutValue_ThrowsArgumentException - - Context_Create_LogWithoutValue_ThrowsArgumentException - - Context_Create_InvalidLogFilePath_ThrowsInvalidOperationException -- **`BuildMark-Context-Output`**: - - Context_WriteLine_NotSilent_WritesToConsole - - Context_WriteError_NotSilent_WritesToConsole -- **`BuildMark-Context-SilentMode`**: - - Context_WriteLine_Silent_DoesNotWriteToConsole - - Context_WriteError_Silent_DoesNotWriteToConsole -- **`BuildMark-Context-ExitCode`**: - - Context_WriteError_SetsExitCodeToOne - - Context_ExitCode_NoErrors_RemainsZero +**Context_Dispose_ClosesLogFileProperly**: Verifies that disposing a context with an open log file +closes the file without error. +This scenario is tested by `Context_Dispose_ClosesLogFileProperly`. diff --git a/docs/verification/build-mark/configuration.md b/docs/verification/build-mark/configuration.md index 5e59e6a..9039793 100644 --- a/docs/verification/build-mark/configuration.md +++ b/docs/verification/build-mark/configuration.md @@ -1,120 +1,70 @@ ## Configuration -### Verification Strategy +### Verification Approach -The Configuration subsystem is verified with dedicated subsystem tests in -`ConfigurationSubsystemTests.cs`. Tests create temporary `.buildmark.yaml` files, call -`BuildMarkConfigReader.ReadAsync`, and assert on the returned `ConfigurationLoadResult`. No mocking -is required; the real file system is used with temporary directories. - -### Dependencies - -| Mock / Stub | Reason | -| ----------- | --------------------------------------------------------------------------------------------------------- | -| File system | Tests create temporary `.buildmark.yaml` files via `TemporaryDirectory` in the current working directory. | +The Configuration subsystem is verified with dedicated subsystem-level integration tests in +`ConfigurationSubsystemTests.cs`. Tests exercise the full subsystem boundary by creating temporary +`.buildmark.yaml` files on the real file system, invoking `BuildMarkConfigReader.ReadAsync`, and +asserting on the returned `ConfigurationLoadResult`. No mocking is required; the real file system +is used with temporary directories managed by `TemporaryDirectory`. Error-reporting behavior is +verified by constructing `ConfigurationLoadResult` instances directly with controlled +`ConfigurationIssue` entries and calling `ReportTo` on a silent `Context`. ### Test Environment -Tests create temporary `.buildmark.yaml` files through `TemporaryDirectory`, which -creates a unique `tmp-*` subdirectory under the current working directory. Write -access to the current working directory is required. No network access or external -services are needed. +Tests create temporary directories via `TemporaryDirectory`, which produces unique `tmp-*` +subdirectories under the current working directory. Write access to the current working directory +is required. No network access or external services are needed. ### Acceptance Criteria -All tests in `ConfigurationSubsystemTests.cs` pass with zero failures. All -`BuildMark-Configuration-*` requirements have at least one test in the Requirements -Coverage mapping. +- All tests in `ConfigurationSubsystemTests.cs` pass with zero failures. +- All `BuildMark-Configuration-*` requirements have at least one test mapped in the requirements + traceability matrix. ### Test Scenarios -#### Configuration_ReadAsync_ValidFile_ReturnsConfiguration - -**Scenario**: A valid `.buildmark.yaml` containing a GitHub connector, one section, and one rule -is written to a temp directory; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: Result has no errors; `Config.Connector.Type` is `"github"`; -`Config.Connector.GitHub.Owner` is `"test-owner"`; one section and one rule are parsed. - -**Requirement coverage**: `BuildMark-Configuration-Read`. - -#### Configuration_ReadAsync_MissingFile_ReturnsEmptyResult - -**Scenario**: `BuildMarkConfigReader.ReadAsync` is called on a temp directory containing no -`.buildmark.yaml`. - -**Expected**: `Config` is null; `HasErrors` is false; `Issues` is empty. - -**Requirement coverage**: `BuildMark-Configuration-Read`. - -#### Configuration_ReadAsync_MalformedFile_ReportsError - -**Scenario**: A `.buildmark.yaml` with a tab character (malformed YAML) is written; -`BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config` is null; `HasErrors` is true; `Issues` contains at least one entry with -`Error` severity. - -**Requirement coverage**: `BuildMark-Configuration-Read`. - -#### Configuration_Issues_ErrorIssue_SetsExitCode - -**Scenario**: A `ConfigurationLoadResult` containing one `Error`-severity `ConfigurationIssue` is -created; `ReportTo(context)` is called on a silent context. - -**Expected**: `context.ExitCode` equals 1. - -**Requirement coverage**: `BuildMark-Configuration-Issues`. - -#### Configuration_Issues_WarningIssue_DoesNotSetExitCode - -**Scenario**: A `ConfigurationLoadResult` containing one `Warning`-severity `ConfigurationIssue` -is created; `ReportTo(context)` is called on a silent context. - -**Expected**: `context.ExitCode` remains 0. - -**Requirement coverage**: `BuildMark-Configuration-Issues`. - -#### Configuration_Issues_ValidationError_ReportsAccurateLine - -**Scenario**: A `.buildmark.yaml` with an unsupported key on line 3 is written; -`BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: The resulting issue reports `Line` equal to 3. - -**Requirement coverage**: `BuildMark-Configuration-Issues`. - -#### Configuration_ConnectorConfig_ValidFile_ParsesConnectorSettings - -**Scenario**: A `.buildmark.yaml` with a GitHub connector block (owner, repo, base-url) is -written; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config.Connector.Type` is `"github"`; `GitHub.Owner`, `GitHub.Repo`, and -`GitHub.BaseUrl` match the file values. - -**Requirement coverage**: `BuildMark-Configuration-ConnectorConfig`. - -#### Configuration_ConnectorConfig_ValidFile_ParsesAzureDevOpsSettings - -**Scenario**: A `.buildmark.yaml` with an Azure DevOps connector block (url, organization, -project, repository) is written; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config.Connector.Type` is `"azure-devops"`; `AzureDevOps.OrganizationUrl`, -`AzureDevOps.Organization`, `AzureDevOps.Project`, and `AzureDevOps.Repository` match the file -values. - -**Requirement coverage**: `BuildMark-Configuration-ConnectorConfig`. - -### Requirements Coverage - -- **`BuildMark-Configuration-Read`**: - - Configuration_ReadAsync_ValidFile_ReturnsConfiguration - - Configuration_ReadAsync_MissingFile_ReturnsEmptyResult - - Configuration_ReadAsync_MalformedFile_ReportsError -- **`BuildMark-Configuration-Issues`**: - - Configuration_Issues_ErrorIssue_SetsExitCode - - Configuration_Issues_WarningIssue_DoesNotSetExitCode - - Configuration_Issues_ValidationError_ReportsAccurateLine -- **`BuildMark-Configuration-ConnectorConfig`**: - - Configuration_ConnectorConfig_ValidFile_ParsesConnectorSettings - - Configuration_ConnectorConfig_ValidFile_ParsesAzureDevOpsSettings +**Configuration_ReadAsync_ValidFile_ReturnsConfiguration**: A valid `.buildmark.yaml` containing a +GitHub connector, one section, and one routing rule is written to a temporary directory and read +via `BuildMarkConfigReader.ReadAsync`. The result must be non-null, free of errors, and correctly +reflect the connector type, owner, repo, section id, and rule route. This scenario is tested by +`Configuration_ReadAsync_ValidFile_ReturnsConfiguration`. + +**Configuration_ReadAsync_MissingFile_ReturnsEmptyResult**: `BuildMarkConfigReader.ReadAsync` is +called on a temporary directory containing no `.buildmark.yaml`. The result must have a null +`Config`, `HasErrors` false, and an empty `Issues` collection. This scenario is tested by +`Configuration_ReadAsync_MissingFile_ReturnsEmptyResult`. + +**Configuration_ReadAsync_MalformedFile_ReportsError**: A `.buildmark.yaml` containing a tab +character (invalid YAML) is written to a temporary directory and read via +`BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, `HasErrors` true, and at +least one `Error`-severity issue. This scenario is tested by +`Configuration_ReadAsync_MalformedFile_ReportsError`. + +**Configuration_Issues_ErrorIssue_SetsExitCode**: A `ConfigurationLoadResult` carrying one +`Error`-severity `ConfigurationIssue` is created and `ReportTo` is called on a silent `Context`. +The context exit code must be set to 1, confirming that error issues are escalated correctly. This +scenario is tested by `Configuration_Issues_ErrorIssue_SetsExitCode`. + +**Configuration_Issues_WarningIssue_DoesNotSetExitCode**: A `ConfigurationLoadResult` carrying one +`Warning`-severity `ConfigurationIssue` is created and `ReportTo` is called on a silent `Context`. +The context exit code must remain 0, confirming that warning issues do not fail the process. This +scenario is tested by `Configuration_Issues_WarningIssue_DoesNotSetExitCode`. + +**Configuration_Issues_ValidationError_ReportsAccurateLine**: A `.buildmark.yaml` with an +unsupported key placed on line 3 is written and read via `BuildMarkConfigReader.ReadAsync`. The +resulting issue must report `Line` equal to 3, confirming that 1-based line numbers are preserved +through the YAML parser. This scenario is tested by +`Configuration_Issues_ValidationError_ReportsAccurateLine`. + +**Configuration_ConnectorConfig_ValidFile_ParsesConnectorSettings**: A `.buildmark.yaml` with a +GitHub connector block containing owner, repo, and base-url fields is written and read via +`BuildMarkConfigReader.ReadAsync`. The connector type, owner, repo, and base URL must all be parsed +correctly into the `ConnectorConfig` model. This scenario is tested by +`Configuration_ConnectorConfig_ValidFile_ParsesConnectorSettings`. + +**Configuration_ConnectorConfig_ValidFile_ParsesAzureDevOpsSettings**: A `.buildmark.yaml` with an +Azure DevOps connector block containing url, organization, project, and repository fields is written +and read via `BuildMarkConfigReader.ReadAsync`. All Azure DevOps connector fields must be parsed +correctly into the `ConnectorConfig` model. This scenario is tested by +`Configuration_ConnectorConfig_ValidFile_ParsesAzureDevOpsSettings`. diff --git a/docs/verification/build-mark/configuration/azure-devops-connector-config.md b/docs/verification/build-mark/configuration/azure-devops-connector-config.md index 63baa54..edb1cab 100644 --- a/docs/verification/build-mark/configuration/azure-devops-connector-config.md +++ b/docs/verification/build-mark/configuration/azure-devops-connector-config.md @@ -2,117 +2,95 @@ #### Verification Approach -`AzureDevOpsConnectorConfig` is verified through `ConfigurationTests.cs`. Tests write -`.buildmark.yaml` files with Azure DevOps connector blocks and assert that `OrganizationUrl`, -`Organization`, `Project`, `Repository`, and `AreaPath` properties are correctly parsed, including -alias key support. No mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | -------------------------------------------------------------------- | -| File system | Tests create temporary `.buildmark.yaml` files in `Path.GetTempPath` | +`AzureDevOpsConnectorConfig` is verified through `ConfigurationTests.cs` and the +`AzureDevOpsRepoConnector` integration tests. The `ConfigurationTests.cs` tests write +`.buildmark.yaml` files with Azure DevOps connector blocks and call `BuildMarkConfigReader.ReadAsync`, +asserting that `OrganizationUrl`, `Organization`, `Project`, `Repository`, `AreaPath`, and +`TokenVariable` are correctly parsed, including alias key support and empty/non-scalar area-path +edge cases. Integration tests in the RepoConnectors test suite verify that the `AreaPath` property +is applied correctly to WIQL queries at runtime. The real file system is used via +`TemporaryDirectory`; no mocking is required for the configuration parsing tests. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +Tests write temporary `.buildmark.yaml` files to directories created by `TemporaryDirectory`. +Write access to the current working directory is required. Integration tests that verify `AreaPath` +runtime behavior use a mock HTTP client to capture WIQL requests; no real Azure DevOps endpoint is +needed. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` targeting `AzureDevOpsConnectorConfig` pass with zero + failures. +- All `AzureDevOpsRepoConnector` area-path integration tests pass with zero failures. #### Test Scenarios -##### BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with an Azure DevOps connector block using canonical keys -(`organization`, `repository`) is written; `BuildMarkConfigReader.ReadAsync` is called; -`Config.Connector.AzureDevOps` is inspected. - -**Expected**: `OrganizationUrl` equals `"https://dev.azure.com/myorg"`; `Organization` equals -`"myorg"`; `Project` equals `"myproject"`; `Repository` equals `"myrepo"`. - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -##### BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with Azure DevOps connector using alias keys (`org`, `repo`) is -written; `BuildMarkConfigReader.ReadAsync` is called; `Config.Connector.AzureDevOps` is inspected. - -**Expected**: `OrganizationUrl`, `Organization`, `Project`, and `Repository` are all populated -correctly from the alias keys. - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -##### BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAreaPath_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with an Azure DevOps connector block containing `area-path` is -written; `BuildMarkConfigReader.ReadAsync` is called; `Config.Connector.AzureDevOps` is inspected. - -**Expected**: `AreaPath` equals the configured area path string. - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -##### BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorEmptyAreaPath_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with an Azure DevOps connector block containing `area-path: ""` -is written; `BuildMarkConfigReader.ReadAsync` is called; `Config.Connector.AzureDevOps` is inspected. - -**Expected**: `AreaPath` equals `string.Empty` (not `null`), confirming that an explicit empty -value is preserved and will disable area-path filtering at runtime. - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -##### AzureDevOpsRepoConnector_GetBuildInformationAsync_WithAreaPath_ScopesWiqlQueryToAreaPath - -**Scenario**: A connector is created with `AreaPath` set to `"MyProject\\MyRepo"`; -`GetBuildInformationAsync` is called; the captured WIQL request body is inspected. - -**Expected**: The WIQL request body contains `System.AreaPath` and the configured area path value, -confirming that known-issues queries are scoped to the specified area. - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -##### AzureDevOpsRepoConnector_GetBuildInformationAsync_WithoutAreaPath_DefaultsToProject - -**Scenario**: A connector is created with no `AreaPath` configured; the git origin URL resolves to -project `project`; `GetBuildInformationAsync` is called; the captured WIQL request body is inspected. - -**Expected**: The WIQL request body contains `System.AreaPath` scoped to `project`, confirming that -the default area path is the parsed project name (not the repository name). - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -##### AzureDevOpsRepoConnector_GetBuildInformationAsync_WithEmptyAreaPath_DisablesAreaPathFilter - -**Scenario**: A connector is created with `AreaPath` set to an empty string; -`GetBuildInformationAsync` is called; the captured WIQL request body is inspected. - -**Expected**: The WIQL request body does not contain `System.AreaPath`, confirming that an empty -area path disables area-path filtering and produces a project-wide query. - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -##### AzureDevOpsRepoConnector_GetBuildInformationAsync_WithInvalidAreaPath_ThrowsWithAdoErrorMessage - -**Scenario**: A connector is created with `AreaPath` set to a path that does not exist in ADO; -the mock WIQL endpoint returns HTTP 400 with an ADO-style JSON error body; `GetBuildInformationAsync` -is called. - -**Expected**: An `InvalidOperationException` is thrown and its message contains the ADO error -description from the 400 response body, so the user receives a meaningful diagnostic rather than -a generic HTTP failure. - -**Requirement coverage**: `BuildMark-AzureDevOpsConnectorConfig-Properties`. - -#### Requirements Coverage - -- **`BuildMark-AzureDevOpsConnectorConfig-Properties`**: - - BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration - - BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration - - BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAreaPath_ReturnsParsedConfiguration - - BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorEmptyAreaPath_ReturnsParsedConfiguration - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithAreaPath_ScopesWiqlQueryToAreaPath - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithoutAreaPath_DefaultsToProject - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithEmptyAreaPath_DisablesAreaPathFilter - - AzureDevOpsRepoConnector_GetBuildInformationAsync_WithInvalidAreaPath_ThrowsWithAdoErrorMessage +**BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with canonical Azure DevOps connector keys (organization, repository) is written +and read via `BuildMarkConfigReader.ReadAsync`; `Config.Connector.AzureDevOps` is inspected. All +fields (`OrganizationUrl`, `Organization`, `Project`, `Repository`) must match the values written +to the file. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with Azure DevOps connector alias keys (`org`, `repo`) is written and read via +`BuildMarkConfigReader.ReadAsync`; all fields must be populated correctly from the alias keys, +confirming alias support is equivalent to canonical keys. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAreaPath_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with an Azure DevOps connector block containing an `area-path` scalar value is +written and read via `BuildMarkConfigReader.ReadAsync`. The `AreaPath` property must equal the +configured path string. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAreaPath_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorEmptyAreaPath_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with `azure-devops.area-path: ""` is written and read via +`BuildMarkConfigReader.ReadAsync`. The `AreaPath` property must equal `string.Empty` (not `null`), +confirming that an explicit empty value is preserved to allow area-path filtering to be disabled +at runtime. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorEmptyAreaPath_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsNonScalarAreaPath_ReturnsErrorIssue**: A +`.buildmark.yaml` with `azure-devops.area-path` set to a YAML sequence instead of a scalar string +is written and read via `BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, +`HasErrors` true, and an issue description containing +`"Azure DevOps area-path must be a scalar string value"`. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsNonScalarAreaPath_ReturnsErrorIssue`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsEmptyTokenVariable_ReturnsErrorIssue**: A +`.buildmark.yaml` with `azure-devops.token-variable: ""` is written and read via +`BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, `HasErrors` true, and an +issue description containing `"token-variable"`, confirming that an empty token-variable is +rejected. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsEmptyTokenVariable_ReturnsErrorIssue`. + +**AzureDevOpsRepoConnector_GetBuildInformationAsync_WithAreaPath_ScopesWiqlQueryToAreaPath**: A +connector is created with `AreaPath` set to `"MyProject\\MyRepo"` and +`GetBuildInformationAsync` is called; the captured WIQL request body is inspected. The request +body must contain `System.AreaPath` and the configured area path value, confirming that known-issue +queries are scoped to the specified area. This scenario is tested by +`AzureDevOpsRepoConnector_GetBuildInformationAsync_WithAreaPath_ScopesWiqlQueryToAreaPath`. + +**AzureDevOpsRepoConnector_GetBuildInformationAsync_WithoutAreaPath_DefaultsToProject**: A +connector is created with no `AreaPath` configured and `GetBuildInformationAsync` is called; the +captured WIQL request body is inspected. The request body must contain `System.AreaPath` scoped to +the parsed project name, confirming that the default area path is the project name rather than the +repository name. This scenario is tested by +`AzureDevOpsRepoConnector_GetBuildInformationAsync_WithoutAreaPath_DefaultsToProject`. + +**AzureDevOpsRepoConnector_GetBuildInformationAsync_WithEmptyAreaPath_DisablesAreaPathFilter**: A +connector is created with `AreaPath` set to an empty string and `GetBuildInformationAsync` is +called; the captured WIQL request body is inspected. The request body must not contain +`System.AreaPath`, confirming that an empty area path disables area-path filtering and produces a +project-wide query. This scenario is tested by +`AzureDevOpsRepoConnector_GetBuildInformationAsync_WithEmptyAreaPath_DisablesAreaPathFilter`. + +**AzureDevOpsRepoConnector_GetBuildInformationAsync_WithInvalidAreaPath_ThrowsWithAdoErrorMessage**: +A connector is created with `AreaPath` set to a non-existent path; the mock WIQL endpoint returns +HTTP 400 with an ADO-style JSON error body; `GetBuildInformationAsync` is called. An +`InvalidOperationException` must be thrown and its message must contain the ADO error description +from the 400 response body, so the user receives a meaningful diagnostic. This scenario is tested +by +`AzureDevOpsRepoConnector_GetBuildInformationAsync_WithInvalidAreaPath_ThrowsWithAdoErrorMessage`. diff --git a/docs/verification/build-mark/configuration/build-mark-config-reader.md b/docs/verification/build-mark/configuration/build-mark-config-reader.md index 8e09498..e2e5ff5 100644 --- a/docs/verification/build-mark/configuration/build-mark-config-reader.md +++ b/docs/verification/build-mark/configuration/build-mark-config-reader.md @@ -2,113 +2,103 @@ #### Verification Approach -`BuildMarkConfigReader` is verified with dedicated unit tests in `ConfigurationTests.cs`. Tests -write `.buildmark.yaml` files to temporary directories and call `BuildMarkConfigReader.ReadAsync`, -asserting on the returned `ConfigurationLoadResult`. No mocking is required; the real file system -is used. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | -------------------------------------------------------------------- | -| File system | Tests create temporary `.buildmark.yaml` files in `Path.GetTempPath` | +`BuildMarkConfigReader` is verified with unit tests in `ConfigurationTests.cs`. Tests write +`.buildmark.yaml` files to temporary directories using `TemporaryDirectory` and call +`BuildMarkConfigReader.ReadAsync`, asserting on the returned `ConfigurationLoadResult`. The real +file system is used; no mocking is required. Tests cover valid GitHub and Azure DevOps +configurations, alias key support, token-variable validation, area-path parsing, and all malformed +input error paths. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +Tests write temporary `.buildmark.yaml` files to directories created by `TemporaryDirectory`. +Write access to the current working directory is required. No network access or external services +are needed. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` targeting `BuildMarkConfigReader` pass with zero + failures. #### Test Scenarios -##### BuildMarkConfigReader_ReadAsync_MissingFile_ReturnsEmptyResult - -**Scenario**: `BuildMarkConfigReader.ReadAsync` is called on a temp directory containing no -`.buildmark.yaml`. - -**Expected**: `Config` is null; `HasErrors` is false; `Issues` is empty. - -**Requirement coverage**: `BuildMark-ConfigReader-MissingFile`. - -##### BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with a GitHub connector, sections, and rules is written; -`BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config` is non-null; `HasErrors` is false; connector type, owner, repo, base-url, -sections, and rules are parsed correctly. - -**Requirement coverage**: `BuildMark-ConfigReader-ReadAsync`. - -##### BuildMarkConfigReader_ReadAsync_InvalidRepositoryValue_ReturnsErrorIssue - -**Scenario**: A `.buildmark.yaml` with `repository: invalid` (not in `owner/repo` format) is -written; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config` is null; `HasErrors` is true; issue description contains `"owner/repo"`. - -**Requirement coverage**: `BuildMark-ConfigReader-MalformedFile`. - -##### BuildMarkConfigReader_ReadAsync_MalformedFile_ReturnsErrorIssue - -**Scenario**: A `.buildmark.yaml` containing a tab character (invalid YAML) is written; -`BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config` is null; `HasErrors` is true; issue description contains `"tab"` -(case-insensitive). - -**Requirement coverage**: `BuildMark-ConfigReader-MalformedFile`. - -##### BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with an Azure DevOps connector block (url, organization, -project, repository) is written; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config.Connector.Type` is `"azure-devops"`; all Azure DevOps fields are parsed -correctly. - -**Requirement coverage**: `BuildMark-ConfigReader-ReadAsync`. - -##### BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with Azure DevOps connector using alias keys (`org`, `repo`) is -written; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: All Azure DevOps fields are parsed correctly using the alias keys. - -**Requirement coverage**: `BuildMark-ConfigReader-ReadAsync`. - -##### BuildMarkConfigReader_ReadAsync_AzureDevOpsUnsupportedKey_ReturnsErrorIssue - -**Scenario**: A `.buildmark.yaml` with an unknown key inside the Azure DevOps connector block is -written; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config` is null; `HasErrors` is true; issue description contains -`"Unsupported Azure DevOps connector key"`. - -**Requirement coverage**: `BuildMark-ConfigReader-MalformedFile`. - -##### BuildMarkConfigReader_ReadAsync_AzureDevOpsNonMapping_ReturnsErrorIssue - -**Scenario**: A `.buildmark.yaml` where `azure-devops:` is a scalar value instead of a mapping is -written; `BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config` is null; `HasErrors` is true; issue description contains `"YAML mapping"`. - -**Requirement coverage**: `BuildMark-ConfigReader-MalformedFile`. - -#### Requirements Coverage - -- **`BuildMark-ConfigReader-ReadAsync`**: - - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - - BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration - - BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration -- **`BuildMark-ConfigReader-MissingFile`**: - - BuildMarkConfigReader_ReadAsync_MissingFile_ReturnsEmptyResult -- **`BuildMark-ConfigReader-MalformedFile`**: - - BuildMarkConfigReader_ReadAsync_InvalidRepositoryValue_ReturnsErrorIssue - - BuildMarkConfigReader_ReadAsync_MalformedFile_ReturnsErrorIssue - - BuildMarkConfigReader_ReadAsync_AzureDevOpsUnsupportedKey_ReturnsErrorIssue - - BuildMarkConfigReader_ReadAsync_AzureDevOpsNonMapping_ReturnsErrorIssue +**BuildMarkConfigReader_ReadAsync_MissingFile_ReturnsEmptyResult**: `BuildMarkConfigReader.ReadAsync` +is called on a temporary directory containing no `.buildmark.yaml`. The result must have a null +`Config`, `HasErrors` false, and an empty `Issues` collection, confirming graceful handling of an +absent configuration file. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_MissingFile_ReturnsEmptyResult`. + +**BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration**: A `.buildmark.yaml` with +a GitHub connector block, one section, and one rule is written and read via +`BuildMarkConfigReader.ReadAsync`. The result must be non-null, free of errors, and correctly +reflect all connector fields, section id, and rule route. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_InvalidRepositoryValue_ReturnsErrorIssue**: A `.buildmark.yaml` +with `github.repository: invalid` (not in `owner/repo` format) is written and read via +`BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, `HasErrors` true, and an +issue description containing `"owner/repo"`. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_InvalidRepositoryValue_ReturnsErrorIssue`. + +**BuildMarkConfigReader_ReadAsync_MalformedFile_ReturnsErrorIssue**: A `.buildmark.yaml` +containing a tab character (invalid YAML) is written and read via `BuildMarkConfigReader.ReadAsync`. +The result must have a null `Config`, `HasErrors` true, and an issue description containing +`"tab"` (case-insensitive). This scenario is tested by +`BuildMarkConfigReader_ReadAsync_MalformedFile_ReturnsErrorIssue`. + +**BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with an Azure DevOps connector block using canonical keys (organization, +repository) is written and read via `BuildMarkConfigReader.ReadAsync`. All Azure DevOps fields +including `OrganizationUrl`, `Organization`, `Project`, and `Repository` must be parsed correctly. +This scenario is tested by +`BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with Azure DevOps connector using alias keys (`org`, `repo`) is written and read +via `BuildMarkConfigReader.ReadAsync`. All Azure DevOps fields must be populated correctly from the +alias keys, confirming alias support is equivalent to the canonical keys. This scenario is tested +by `BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAliases_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAreaPath_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with an Azure DevOps connector block containing an `area-path` value is written +and read via `BuildMarkConfigReader.ReadAsync`. The `AreaPath` property must equal the configured +path string. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorAreaPath_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorEmptyAreaPath_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with `azure-devops.area-path: ""` is written and read via +`BuildMarkConfigReader.ReadAsync`. The `AreaPath` property must equal `string.Empty` (not `null`), +confirming that an explicit empty value is preserved to disable area-path filtering. This scenario +is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsConnectorEmptyAreaPath_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsUnsupportedKey_ReturnsErrorIssue**: A `.buildmark.yaml` +with an unknown key inside the Azure DevOps connector block is written and read via +`BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, `HasErrors` true, and an +issue description containing `"Unsupported Azure DevOps connector key"`. This scenario is tested +by `BuildMarkConfigReader_ReadAsync_AzureDevOpsUnsupportedKey_ReturnsErrorIssue`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsNonMapping_ReturnsErrorIssue**: A `.buildmark.yaml` +where `azure-devops:` is a scalar value instead of a mapping is written and read via +`BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, `HasErrors` true, and an +issue description containing `"YAML mapping"`. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsNonMapping_ReturnsErrorIssue`. + +**BuildMarkConfigReader_ReadAsync_GitHubEmptyTokenVariable_ReturnsErrorIssue**: A `.buildmark.yaml` +with `github.token-variable: ""` is written and read via `BuildMarkConfigReader.ReadAsync`. The +result must have a null `Config`, `HasErrors` true, and an issue description containing +`"token-variable"`. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_GitHubEmptyTokenVariable_ReturnsErrorIssue`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsEmptyTokenVariable_ReturnsErrorIssue**: A +`.buildmark.yaml` with `azure-devops.token-variable: ""` is written and read via +`BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, `HasErrors` true, and an +issue description containing `"token-variable"`. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsEmptyTokenVariable_ReturnsErrorIssue`. + +**BuildMarkConfigReader_ReadAsync_AzureDevOpsNonScalarAreaPath_ReturnsErrorIssue**: A +`.buildmark.yaml` with `azure-devops.area-path` set to a YAML sequence instead of a scalar string +is written and read via `BuildMarkConfigReader.ReadAsync`. The result must have a null `Config`, +`HasErrors` true, and an issue description containing +`"Azure DevOps area-path must be a scalar string value"`. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_AzureDevOpsNonScalarAreaPath_ReturnsErrorIssue`. diff --git a/docs/verification/build-mark/configuration/build-mark-config.md b/docs/verification/build-mark/configuration/build-mark-config.md index c76b50a..4834499 100644 --- a/docs/verification/build-mark/configuration/build-mark-config.md +++ b/docs/verification/build-mark/configuration/build-mark-config.md @@ -2,41 +2,23 @@ #### Verification Approach -`BuildMarkConfig` is verified with dedicated unit tests in `ConfigurationTests.cs`. The test -`BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection` calls -`BuildMarkConfig.CreateDefault()` and asserts on the returned sections and routing rules. No -mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | --------------- | -| None | No mocks needed | +`BuildMarkConfig` is a data model unit with no external dependencies. It is verified with unit +tests in `ConfigurationTests.cs` that call `BuildMarkConfig.CreateDefault()` and assert on the +returned sections and routing rules. No mocking or file system access is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` targeting `BuildMarkConfig` pass with zero failures. #### Test Scenarios -##### BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection - -**Scenario**: `BuildMarkConfig.CreateDefault()` is called. - -**Expected**: The result contains 3 sections (`changes`, `bugs-fixed`, `dependency-updates`) with -correct titles; 6 rules are present with correct routes and match conditions; the final catch-all -rule has a null match. - -**Requirement coverage**: `BuildMark-SectionConfig-Properties`, -`BuildMark-RuleConfig-Properties`. - -#### Requirements Coverage - -- **`BuildMark-SectionConfig-Properties`**: - - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection -- **`BuildMark-RuleConfig-Properties`**: - - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection +**BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection**: `BuildMarkConfig.CreateDefault()` +is called and the returned configuration is inspected for correctness. Three sections with ids +`changes`, `bugs-fixed`, and `dependency-updates` and their corresponding titles must be present; +six routing rules must exist with correct routes, label conditions, work-item-type conditions, and +a null match on the final catch-all rule that routes to `changes`. This scenario is tested by +`BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection`. diff --git a/docs/verification/build-mark/configuration/configuration-issue.md b/docs/verification/build-mark/configuration/configuration-issue.md index cbb5a94..29bd8ed 100644 --- a/docs/verification/build-mark/configuration/configuration-issue.md +++ b/docs/verification/build-mark/configuration/configuration-issue.md @@ -2,58 +2,36 @@ #### Verification Approach -`ConfigurationIssue` is a record type with no logic. It is verified through -`ConfigurationTests.cs`, which constructs `ConfigurationIssue` instances directly and asserts on -their `FilePath`, `Line`, `Severity`, and `Description` properties. No mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | --------------- | -| None | No mocks needed | +`ConfigurationIssue` is a record type with no logic. It is verified through `ConfigurationTests.cs` +via `ConfigurationLoadResult`, which constructs `ConfigurationIssue` instances directly with known +`FilePath`, `Line`, `Severity`, and `Description` values, then inspects those properties after +calling `ReportTo`. No mocking is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` that construct `ConfigurationIssue` instances pass with + zero failures. #### Test Scenarios -##### ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode - -**Scenario**: A `ConfigurationIssue` with `Error` severity is constructed and placed in a -`ConfigurationLoadResult`; `ReportTo` is called. - -**Expected**: `context.ExitCode` equals 1, confirming the issue record carries severity correctly. - -**Requirement coverage**: `BuildMark-ConfigurationIssue-Record`. - -##### ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode - -**Scenario**: A `ConfigurationIssue` with `Warning` severity is constructed and placed in a -`ConfigurationLoadResult`; `ReportTo` is called. - -**Expected**: `context.ExitCode` remains 0, confirming severity is preserved and evaluated -correctly. - -**Requirement coverage**: `BuildMark-ConfigurationIssue-Record`. - -##### ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber - -**Scenario**: A `ConfigurationIssue` is constructed with `FilePath` `"/repo/.buildmark.yaml"`, -`Line` 7, `Error` severity, and description `"Unexpected value"`; properties are inspected. - -**Expected**: `FilePath` equals `"/repo/.buildmark.yaml"`; `Line` equals 7; `Severity` equals -`Error`; `Description` equals `"Unexpected value"`. - -**Requirement coverage**: `BuildMark-ConfigurationIssue-Record`. - -#### Requirements Coverage - -- **`BuildMark-ConfigurationIssue-Record`**: - - ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode - - ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode - - ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber +**ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode**: A `ConfigurationIssue` with `Error` +severity is constructed and placed in a `ConfigurationLoadResult`; `ReportTo` is called on a +silent `Context`. The context exit code must equal 1, confirming that the severity value carried +by the record is read and evaluated correctly. This scenario is tested by +`ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode`. + +**ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode**: A `ConfigurationIssue` with +`Warning` severity is constructed and placed in a `ConfigurationLoadResult`; `ReportTo` is called +on a silent `Context`. The context exit code must remain 0, confirming the severity is preserved +and evaluated correctly. This scenario is tested by +`ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode`. + +**ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber**: A `ConfigurationIssue` is +constructed with `FilePath` `"/repo/.buildmark.yaml"`, `Line` 7, `Error` severity, and description +`"Unexpected value"`; all properties are inspected. The record must expose exactly the values +supplied at construction, confirming that all four fields are stored and accessible. This scenario +is tested by `ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber`. diff --git a/docs/verification/build-mark/configuration/configuration-load-result.md b/docs/verification/build-mark/configuration/configuration-load-result.md index 484ec33..e7f3f21 100644 --- a/docs/verification/build-mark/configuration/configuration-load-result.md +++ b/docs/verification/build-mark/configuration/configuration-load-result.md @@ -2,59 +2,37 @@ #### Verification Approach -`ConfigurationLoadResult` is verified with dedicated unit tests in `ConfigurationTests.cs`. Tests -construct `ConfigurationLoadResult` instances directly with controlled `ConfigurationIssue` entries -and assert on the behavior of `ReportTo(context)`. No mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | --------------- | -| None | No mocks needed | +`ConfigurationLoadResult` is verified with unit tests in `ConfigurationTests.cs`. Tests construct +`ConfigurationLoadResult` instances directly with controlled `ConfigurationIssue` entries and call +`ReportTo` on a silent `Context`. No mocking is required; the real `Context` is used in silent +mode. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` targeting `ConfigurationLoadResult` pass with zero + failures. #### Test Scenarios -##### ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode - -**Scenario**: A `ConfigurationLoadResult` containing one `Error`-severity issue is created; -`ReportTo` is called on a silent `Context`. - -**Expected**: `context.ExitCode` equals 1. - -**Requirement coverage**: `BuildMark-ConfigLoadResult-ReportTo`. - -##### ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode - -**Scenario**: A `ConfigurationLoadResult` containing one `Warning`-severity issue is created; -`ReportTo` is called on a silent `Context`. - -**Expected**: `context.ExitCode` remains 0. - -**Requirement coverage**: `BuildMark-ConfigLoadResult-ReportTo`. - -##### ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber - -**Scenario**: A `ConfigurationLoadResult` containing an `Error`-severity issue at `FilePath` -`"/repo/.buildmark.yaml"`, `Line` 7, with description `"Unexpected value"` is created; `ReportTo` -is called. - -**Expected**: `result.HasErrors` is true; `context.ExitCode` is 1; -`result.Issues[0].FilePath` equals `"/repo/.buildmark.yaml"`; `result.Issues[0].Line` equals 7; -`result.Issues[0].Description` equals `"Unexpected value"`. - -**Requirement coverage**: `BuildMark-ConfigLoadResult-ReportTo`. - -#### Requirements Coverage - -- **`BuildMark-ConfigLoadResult-ReportTo`**: - - ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode - - ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode - - ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber +**ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode**: A `ConfigurationLoadResult` +containing one `Error`-severity `ConfigurationIssue` is created and `ReportTo` is called on a +silent `Context`. The context exit code must equal 1, confirming that error-severity issues cause +the process to report a failure. This scenario is tested by +`ConfigurationLoadResult_ReportTo_ErrorIssue_SetsExitCode`. + +**ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode**: A `ConfigurationLoadResult` +containing one `Warning`-severity `ConfigurationIssue` is created and `ReportTo` is called on a +silent `Context`. The context exit code must remain 0, confirming that warning-severity issues do +not escalate to a process failure. This scenario is tested by +`ConfigurationLoadResult_ReportTo_WarningIssue_DoesNotSetExitCode`. + +**ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber**: A `ConfigurationLoadResult` +containing an `Error`-severity issue with `FilePath` `"/repo/.buildmark.yaml"`, `Line` 7, and +description `"Unexpected value"` is created and `ReportTo` is called. The `HasErrors` flag must +be true, exit code must be 1, and the issue record must expose the exact `FilePath`, `Line`, +`Severity`, and `Description` values supplied at construction. This scenario is tested by +`ConfigurationLoadResult_ReportTo_IssueMessage_IncludesLineNumber`. diff --git a/docs/verification/build-mark/configuration/connector-config.md b/docs/verification/build-mark/configuration/connector-config.md index 7a7876d..69ac563 100644 --- a/docs/verification/build-mark/configuration/connector-config.md +++ b/docs/verification/build-mark/configuration/connector-config.md @@ -3,48 +3,31 @@ #### Verification Approach `ConnectorConfig` is verified through `ConfigurationTests.cs`. Tests write `.buildmark.yaml` files -with connector blocks and assert that `ConnectorConfig.Type`, `ConnectorConfig.GitHub`, and -`ConnectorConfig.AzureDevOps` are correctly populated by `BuildMarkConfigReader.ReadAsync`. No -mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | -------------------------------------------------------------------- | -| File system | Tests create temporary `.buildmark.yaml` files in `Path.GetTempPath` | +with GitHub and Azure DevOps connector blocks and call `BuildMarkConfigReader.ReadAsync`, asserting +that `ConnectorConfig.Type`, `ConnectorConfig.GitHub`, and `ConnectorConfig.AzureDevOps` are +populated correctly. The real file system is used via `TemporaryDirectory`; no mocking is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +Tests write temporary `.buildmark.yaml` files to directories created by `TemporaryDirectory`. +Write access to the current working directory is required. No network access or external services +are needed. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` targeting `ConnectorConfig` pass with zero failures. #### Test Scenarios -##### BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with a GitHub connector block is written; -`BuildMarkConfigReader.ReadAsync` is called; `Config.Connector` is inspected. - -**Expected**: `Config.Connector.Type` equals `"github"`; `Config.Connector.GitHub` is non-null; -`Config.Connector.AzureDevOps` is null. - -**Requirement coverage**: `BuildMark-ConnectorConfig-Properties`. - -##### BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with an Azure DevOps connector block is written; -`BuildMarkConfigReader.ReadAsync` is called; `Config.Connector` is inspected. - -**Expected**: `Config.Connector.Type` equals `"azure-devops"`; -`Config.Connector.AzureDevOps` is non-null with all fields set; `Config.Connector.GitHub` is null. - -**Requirement coverage**: `BuildMark-ConnectorConfig-Properties`. - -#### Requirements Coverage - -- **`BuildMark-ConnectorConfig-Properties`**: - - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - - BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration +**BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration**: A `.buildmark.yaml` with +a GitHub connector block is written and read via `BuildMarkConfigReader.ReadAsync`; the +`Config.Connector` is inspected. `ConnectorConfig.Type` must equal `"github"`, `GitHub` must be +non-null, and `AzureDevOps` must be null, confirming the connector discriminator is set correctly. +This scenario is tested by `BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration**: A +`.buildmark.yaml` with an Azure DevOps connector block is written and read via +`BuildMarkConfigReader.ReadAsync`; the `Config.Connector` is inspected. `ConnectorConfig.Type` +must equal `"azure-devops"`, `AzureDevOps` must be non-null with all fields set, and `GitHub` must +be null. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_ValidAzureDevOpsConnector_ReturnsParsedConfiguration`. diff --git a/docs/verification/build-mark/configuration/git-hub-connector-config.md b/docs/verification/build-mark/configuration/git-hub-connector-config.md index 79f633d..2a61124 100644 --- a/docs/verification/build-mark/configuration/git-hub-connector-config.md +++ b/docs/verification/build-mark/configuration/git-hub-connector-config.md @@ -3,36 +3,33 @@ #### Verification Approach `GitHubConnectorConfig` is verified through `ConfigurationTests.cs`. Tests write `.buildmark.yaml` -files with a GitHub connector block and assert that `Owner`, `Repo`, and `BaseUrl` properties are -correctly parsed. No mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | -------------------------------------------------------------------- | -| File system | Tests create temporary `.buildmark.yaml` files in `Path.GetTempPath` | +files with GitHub connector blocks and call `BuildMarkConfigReader.ReadAsync`, asserting that +`Owner`, `Repo`, `BaseUrl`, and `TokenVariable` are correctly parsed or rejected. The real file +system is used via `TemporaryDirectory`; no mocking is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +Tests write temporary `.buildmark.yaml` files to directories created by `TemporaryDirectory`. +Write access to the current working directory is required. No network access or external services +are needed. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` targeting `GitHubConnectorConfig` pass with zero + failures. #### Test Scenarios -##### BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration - -**Scenario**: A `.buildmark.yaml` with `github.owner`, `github.repo`, and `github.base-url` fields -is written; `BuildMarkConfigReader.ReadAsync` is called; `Config.Connector.GitHub` is inspected. - -**Expected**: `Owner` equals `"example-owner"`; `Repo` equals `"hello-world"`; `BaseUrl` equals -`"https://api.github.com"`. - -**Requirement coverage**: `BuildMark-GitHubConnectorConfig-Properties`. - -#### Requirements Coverage - -- **`BuildMark-GitHubConnectorConfig-Properties`**: - - BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration +**BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration**: A `.buildmark.yaml` with +`github.owner`, `github.repo`, and `github.base-url` fields is written and read via +`BuildMarkConfigReader.ReadAsync`; `Config.Connector.GitHub` is inspected. The `Owner`, `Repo`, +and `BaseUrl` properties must match the values written to the file, confirming all fields are +mapped correctly. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_ValidFile_ReturnsParsedConfiguration`. + +**BuildMarkConfigReader_ReadAsync_GitHubEmptyTokenVariable_ReturnsErrorIssue**: A `.buildmark.yaml` +with `github.token-variable: ""` is written and read via `BuildMarkConfigReader.ReadAsync`. The +result must have a null `Config`, `HasErrors` true, and an issue description containing +`"token-variable"`, confirming that an empty token-variable value is rejected as invalid. This +scenario is tested by +`BuildMarkConfigReader_ReadAsync_GitHubEmptyTokenVariable_ReturnsErrorIssue`. diff --git a/docs/verification/build-mark/configuration/report-config.md b/docs/verification/build-mark/configuration/report-config.md index ac584ae..c0cf2bd 100644 --- a/docs/verification/build-mark/configuration/report-config.md +++ b/docs/verification/build-mark/configuration/report-config.md @@ -3,48 +3,30 @@ #### Verification Approach `ReportConfig` is verified through `ConfigurationTests.cs`. Tests write `.buildmark.yaml` files -with a `report:` block and assert that `File`, `Depth`, and `IncludeKnownIssues` properties are -correctly parsed or that invalid values produce error issues. No mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | -------------------------------------------------------------------- | -| File system | Tests create temporary `.buildmark.yaml` files in `Path.GetTempPath` | +with a `report:` block and call `BuildMarkConfigReader.ReadAsync`, asserting that `File`, `Depth`, +and `IncludeKnownIssues` are parsed correctly or that invalid values produce error issues. The real +file system is used via `TemporaryDirectory`; no mocking is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +Tests write temporary `.buildmark.yaml` files to directories created by `TemporaryDirectory`. +Write access to the current working directory is required. No network access or external services +are needed. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` targeting `ReportConfig` pass with zero failures. #### Test Scenarios -##### BuildMarkConfigReader_ReadAsync_ValidReportSection_ReturnsParsedReportConfig - -**Scenario**: A `.buildmark.yaml` with `report.file`, `report.depth: 2`, and -`report.include-known-issues: true` is written; `BuildMarkConfigReader.ReadAsync` is called; -`Config.Report` is inspected. - -**Expected**: `Config.Report.File` equals `"build-notes.md"`; `Config.Report.Depth` equals 2; -`Config.Report.IncludeKnownIssues` is true. - -**Requirement coverage**: `BuildMark-ReportConfig-Properties`. - -##### BuildMarkConfigReader_ReadAsync_InvalidReportDepth_ReturnsErrorIssue - -**Scenario**: A `.buildmark.yaml` with `report.depth: -1` is written; -`BuildMarkConfigReader.ReadAsync` is called. - -**Expected**: `Config` is null; `HasErrors` is true; issue description contains -`"positive integer"`. - -**Requirement coverage**: `BuildMark-ReportConfig-Properties`. - -#### Requirements Coverage - -- **`BuildMark-ReportConfig-Properties`**: - - BuildMarkConfigReader_ReadAsync_ValidReportSection_ReturnsParsedReportConfig - - BuildMarkConfigReader_ReadAsync_InvalidReportDepth_ReturnsErrorIssue +**BuildMarkConfigReader_ReadAsync_ValidReportSection_ReturnsParsedReportConfig**: A `.buildmark.yaml` +with `report.file`, `report.depth: 2`, and `report.include-known-issues: true` is written and read +via `BuildMarkConfigReader.ReadAsync`; `Config.Report` is inspected. The `File` property must equal +`"build-notes.md"`, `Depth` must equal 2, and `IncludeKnownIssues` must be true. This scenario is +tested by `BuildMarkConfigReader_ReadAsync_ValidReportSection_ReturnsParsedReportConfig`. + +**BuildMarkConfigReader_ReadAsync_InvalidReportDepth_ReturnsErrorIssue**: A `.buildmark.yaml` with +`report.depth: -1` is written and read via `BuildMarkConfigReader.ReadAsync`. The result must have +a null `Config`, `HasErrors` true, and an issue description containing `"positive integer"`, +confirming that a negative depth value is rejected. This scenario is tested by +`BuildMarkConfigReader_ReadAsync_InvalidReportDepth_ReturnsErrorIssue`. diff --git a/docs/verification/build-mark/configuration/rule-config.md b/docs/verification/build-mark/configuration/rule-config.md index e0e3e84..8276542 100644 --- a/docs/verification/build-mark/configuration/rule-config.md +++ b/docs/verification/build-mark/configuration/rule-config.md @@ -2,40 +2,24 @@ #### Verification Approach -`RuleConfig` is verified through `ConfigurationTests.cs`. The test -`BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection` calls -`BuildMarkConfig.CreateDefault()` and asserts on the `Route` and `Match` properties of the -returned rules. No mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | --------------- | -| None | No mocks needed | +`RuleConfig` is a data model unit with no external dependencies. It is verified through +`ConfigurationTests.cs` via `BuildMarkConfig.CreateDefault()`, which constructs a `RuleConfig` +collection and allows `Route` and `Match` properties to be asserted. No mocking is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` that inspect `RuleConfig` instances pass with zero + failures. #### Test Scenarios -##### BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection - -**Scenario**: `BuildMarkConfig.CreateDefault()` is called; the returned `Rules` collection is -inspected. - -**Expected**: Six rules are present; the first three rules have `dependency-updates`, -`bugs-fixed`, and `bugs-fixed` as routes with appropriate label and work-item-type match -conditions; the fourth and fifth rules have `suppressed` routes; the sixth rule has `changes` as -route with a null match. - -**Requirement coverage**: `BuildMark-RuleConfig-Properties`. - -#### Requirements Coverage - -- **`BuildMark-RuleConfig-Properties`**: - - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection +**BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection**: `BuildMarkConfig.CreateDefault()` +is called and the returned `Rules` collection is inspected. Six rules must be present; the first +three rules must have routes `dependency-updates`, `bugs-fixed`, and `bugs-fixed` with appropriate +label and work-item-type match conditions; the fourth and fifth rules must have `suppressed` routes; +the sixth rule must have route `changes` with a null `Match`, confirming the catch-all rule. This +scenario is tested by `BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection`. diff --git a/docs/verification/build-mark/configuration/rule-match-config.md b/docs/verification/build-mark/configuration/rule-match-config.md index f265faf..ccd2328 100644 --- a/docs/verification/build-mark/configuration/rule-match-config.md +++ b/docs/verification/build-mark/configuration/rule-match-config.md @@ -2,56 +2,35 @@ #### Verification Approach -`RuleMatchConfig` is a data model class verified indirectly through `ItemRouterTests.cs`. -Tests that exercise label-based and type-based matching use `RuleMatchConfig` instances -within `RuleConfig` to control item routing. Case-insensitive matching tests confirm -the match comparison behavior. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Data class | +`RuleMatchConfig` is a data model unit with no external dependencies. It is verified indirectly +through `ItemRouterTests.cs`, which places `RuleMatchConfig` instances inside `RuleConfig` objects +and exercises label-based and work-item-type-based matching via `ItemRouter`. No mocking is +required; the real `ItemRouter` logic is used. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. - -#### Test Scenarios (Integration) - -##### ItemRouter_Route_WithWorkItemTypeMatch_RoutesMatchingItem - -**Scenario**: A `RuleMatchConfig` specifying a work item type is used; item with -matching type is routed. - -**Expected**: Item appears in the correct section. - -**Requirement coverage**: `BuildMark-Configuration-RuleMatchConfig` - -##### ItemRouter_Route_WithCaseInsensitiveLabelMatch_RoutesItem - -**Scenario**: A `RuleMatchConfig` specifying a label is used; item with matching -label (case-insensitive) is routed. - -**Expected**: Item appears in the correct section regardless of label case. - -**Requirement coverage**: `BuildMark-Configuration-RuleMatchConfig` - -##### ItemRouter_Route_WithCaseInsensitiveSuppressedRoute_OmitsMatchingItem - -**Scenario**: A `RuleMatchConfig` on a suppressed rule matches an item case-insensitively. +- All `ItemRouterTests.cs` tests that exercise `RuleMatchConfig`-driven routing pass with zero + failures. -**Expected**: Item is omitted from all sections. +#### Test Scenarios -**Requirement coverage**: `BuildMark-Configuration-RuleMatchConfig` +**ItemRouter_Route_WithWorkItemTypeMatch_RoutesMatchingItem**: A `RuleMatchConfig` specifying a +work-item type is placed in a `RuleConfig` and an item with that type is routed via `ItemRouter`. +The item must appear in the correct section, confirming that work-item-type matching is evaluated +correctly. This scenario is tested by `ItemRouter_Route_WithWorkItemTypeMatch_RoutesMatchingItem`. -#### Requirements Coverage +**ItemRouter_Route_WithCaseInsensitiveLabelMatch_RoutesItem**: A `RuleMatchConfig` specifying a +label is placed in a `RuleConfig` and an item carrying that label (in a different case) is routed +via `ItemRouter`. The item must appear in the correct section regardless of label case, confirming +that label matching is case-insensitive. This scenario is tested by +`ItemRouter_Route_WithCaseInsensitiveLabelMatch_RoutesItem`. -- **BuildMark-Configuration-RuleMatchConfig**: - ItemRouter_Route_WithWorkItemTypeMatch_RoutesMatchingItem, - ItemRouter_Route_WithCaseInsensitiveLabelMatch_RoutesItem, - ItemRouter_Route_WithCaseInsensitiveSuppressedRoute_OmitsMatchingItem +**ItemRouter_Route_WithCaseInsensitiveSuppressedRoute_OmitsMatchingItem**: A `RuleMatchConfig` on +a suppressed rule matches an item case-insensitively via `ItemRouter`. The item must be omitted +from all sections, confirming that suppression works together with case-insensitive label matching. +This scenario is tested by +`ItemRouter_Route_WithCaseInsensitiveSuppressedRoute_OmitsMatchingItem`. diff --git a/docs/verification/build-mark/configuration/section-config.md b/docs/verification/build-mark/configuration/section-config.md index 080c82b..2c59cbe 100644 --- a/docs/verification/build-mark/configuration/section-config.md +++ b/docs/verification/build-mark/configuration/section-config.md @@ -2,39 +2,24 @@ #### Verification Approach -`SectionConfig` is verified through `ConfigurationTests.cs`. The test -`BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection` calls -`BuildMarkConfig.CreateDefault()` and asserts on the `Id` and `Title` properties of the returned -sections. No mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | --------------- | -| None | No mocks needed | +`SectionConfig` is a data model unit with no external dependencies. It is verified through +`ConfigurationTests.cs` via `BuildMarkConfig.CreateDefault()`, which constructs a `SectionConfig` +collection and allows `Id` and `Title` properties to be asserted. No mocking is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All unit tests in `ConfigurationTests.cs` that inspect `SectionConfig` instances pass with zero + failures. #### Test Scenarios -##### BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection - -**Scenario**: `BuildMarkConfig.CreateDefault()` is called; the returned `Sections` collection is -inspected. - -**Expected**: Three sections are present with ids `"changes"`, `"bugs-fixed"`, and -`"dependency-updates"` and corresponding titles `"Changes"`, `"Bugs Fixed"`, and -`"Dependency Updates"`. - -**Requirement coverage**: `BuildMark-SectionConfig-Properties`. - -#### Requirements Coverage - -- **`BuildMark-SectionConfig-Properties`**: - - BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection +**BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection**: `BuildMarkConfig.CreateDefault()` +is called and the returned `Sections` collection is inspected. Three sections must be present with +ids `"changes"`, `"bugs-fixed"`, and `"dependency-updates"` and their corresponding titles +`"Changes"`, `"Bugs Fixed"`, and `"Dependency Updates"`, confirming that all section id and title +fields are mapped correctly. This scenario is tested by +`BuildMarkConfig_CreateDefault_ContainsDependencyUpdatesSection`. diff --git a/docs/verification/build-mark/program.md b/docs/verification/build-mark/program.md index cd6b889..e3e6d05 100644 --- a/docs/verification/build-mark/program.md +++ b/docs/verification/build-mark/program.md @@ -2,161 +2,84 @@ ### Verification Approach -`Program` unit tests are in `ProgramTests.cs`. Each test constructs a `Context` object -with controlled arguments and output capture, calls `Program.Run`, then asserts on the -context output and exit code. The connector factory is injected via a context override -to avoid live API calls where needed. - -### Dependencies - -| Mock / Stub | Reason | -| ---------------------- | -------------------------------------------------------- | -| `Context` | Constructed with controlled arguments and output capture | -| Connector factory mock | Injected to avoid live API calls | +`Program` unit tests are in `ProgramTests.cs`. Each test constructs a `Context` object with +controlled arguments and output capture, calls `Program.Run`, then asserts on the context output +and exit code. The connector factory is injected via a context override to avoid live API calls +where needed. No framework mocking library is used; a local `ThrowingConnector` stub simulates +connector failure conditions. ### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. `ProgramTests.cs` runs within the standard `dotnet test` host; +no external services, live network, or file system side effects are required beyond a temporary +directory used by report-generation tests. ### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All tests in `ProgramTests.cs` pass with zero failures. +- Exit code assertions cover both success (0) and error (1) paths. ### Test Scenarios -#### Program_Version_ReturnsValidVersion - -**Scenario**: `Program.Version` is accessed directly. - -**Expected**: Returns a non-null semver string. - -**Requirement coverage**: `BuildMark-Program-Version` - -#### Program_Run_VersionFlag_OutputsVersionToConsole - -**Scenario**: `Program.Run` is called with `Version = true` in context. - -**Expected**: Version string appears in output; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Version` - -#### Program_Run_HelpFlag_OutputsHelpMessage - -**Scenario**: `Program.Run` is called with `Help = true` in context. - -**Expected**: Help text appears in output; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Help` - -#### Program_Run_QuestionMarkFlag_OutputsHelpMessage - -**Scenario**: `Program.Run` is called with `?` argument. - -**Expected**: Help text appears in output; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Help` - -#### Program_Run_LongHelpFlag_OutputsHelpMessage - -**Scenario**: `Program.Run` is called with `--help` argument. - -**Expected**: Help text appears in output; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Help` - -#### Program_Run_ValidateFlag_OutputsValidationMessage - -**Scenario**: `Program.Run` is called with `Validate = true`. - -**Expected**: Validation output appears; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Validate` - -#### Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues - -**Scenario**: `Program.Run` is called with report flags and `IncludeKnownIssues = true`. - -**Expected**: Report is generated including known issues; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Report` - -#### Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero - -**Scenario**: `Program.Run` is called with `Lint = true` but no config present. - -**Expected**: Exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Lint` - -#### Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode - -**Scenario**: `Program.Run` is called with an invalid build version. - -**Expected**: Error is written to stderr; exit code is 1. - -**Requirement coverage**: `BuildMark-Program-ErrorHandling-InvalidBuildVersion` - -#### Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode - -**Scenario**: `Program.Run` is called but connector factory throws `InvalidOperationException`. - -**Expected**: Error is written to stderr; exit code is 1. - -**Requirement coverage**: `BuildMark-Program-ErrorHandling-ConnectorFailure` - -#### Program_Run_WithSilentFlag_SuppressesOutput - -**Scenario**: `Program.Run` is called with `--silent` and `--help` flags in context. - -**Expected**: Banner text is suppressed from console output; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Silent` - -#### Program_Run_WithLogFlag_WritesToLogFile - -**Scenario**: `Program.Run` is called with `--log ` flag pointing to a temporary file. - -**Expected**: Log file is created and contains non-empty output; exit code is 0. - -**Requirement coverage**: `BuildMark-Program-Log` +**Program_Version_ReturnsValidVersion**: Verifies that `Program.Version` returns a non-null, +non-empty version string in semver format, confirming version metadata is embedded in the assembly. +This scenario is tested by `Program_Version_ReturnsValidVersion`. -#### Program_Run_WithResultsFlag_WritesResultsFile +**Program_Run_VersionFlag_OutputsVersionToConsole**: Verifies that calling `Program.Run` with a +context having `Version = true` writes the version string to standard output and exits with code 0. +This scenario is tested by `Program_Run_VersionFlag_OutputsVersionToConsole`. -**Scenario**: `Program.Run` is called with `--validate` and `--results ` flags. +**Program_Run_HelpFlag_OutputsHelpMessage**: Verifies that calling `Program.Run` with `-h` writes +usage text including "Usage: buildmark" and "Options:" to standard output and exits with code 0. +This scenario is tested by `Program_Run_HelpFlag_OutputsHelpMessage`. -**Expected**: Results file is created; exit code is 0. +**Program_Run_QuestionMarkFlag_OutputsHelpMessage**: Verifies that the `-?` short flag produces the +same help output as `-h`. This scenario is tested by +`Program_Run_QuestionMarkFlag_OutputsHelpMessage`. -**Requirement coverage**: `BuildMark-Program-Results` +**Program_Run_LongHelpFlag_OutputsHelpMessage**: Verifies that the `--help` long flag produces +standard help output and exits with code 0. This scenario is tested by +`Program_Run_LongHelpFlag_OutputsHelpMessage`. -#### Program_Run_WithBuildVersionFlag_AcceptsBuildVersion +**Program_Run_ValidateFlag_OutputsValidationMessage**: Verifies that calling `Program.Run` with +`Validate = true` writes output containing "Self-validation" and exits with code 0. +This scenario is tested by `Program_Run_ValidateFlag_OutputsValidationMessage`. -**Scenario**: `Program.Run` is called with `--build-version 3.2.1` and a mock connector. +**Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues**: Verifies that +`Program.Run` with report and `IncludeKnownIssues = true` flags creates the report file and exits +with code 0. This scenario is tested by +`Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues`. -**Expected**: Report is generated containing the specified version string; exit code is 0. +**Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero**: Verifies that running with +`Lint = true` when no configuration file is present leaves the exit code at 0, confirming lint +mode is not an error when no config exists. +This scenario is tested by `Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero`. -**Requirement coverage**: `BuildMark-Program-BuildVersion` +**Program_Run_WithSilentFlag_SuppressesOutput**: Verifies that `--silent --help` suppresses the +banner text from console output while still exiting with code 0. +This scenario is tested by `Program_Run_WithSilentFlag_SuppressesOutput`. -#### Program_Run_WithDepthFlag_SetsHeadingDepth +**Program_Run_WithLogFlag_WritesToLogFile**: Verifies that `--log --help` creates the log +file and writes non-empty output to it, confirming log routing through `Context`. +This scenario is tested by `Program_Run_WithLogFlag_WritesToLogFile`. -**Scenario**: `Program.Run` is called with `--depth 3` and a mock connector. +**Program_Run_WithResultsFlag_WritesResultsFile**: Verifies that `--validate --results ` +creates the results file and exits with code 0. +This scenario is tested by `Program_Run_WithResultsFlag_WritesResultsFile`. -**Expected**: Report uses level-three headings (`###`) for the title; exit code is 0. +**Program_Run_WithBuildVersionFlag_AcceptsBuildVersion**: Verifies that `--build-version 3.2.1` +produces a report containing the version string "3.2.1" and exits with code 0. +This scenario is tested by `Program_Run_WithBuildVersionFlag_AcceptsBuildVersion`. -**Requirement coverage**: `BuildMark-Program-Depth` +**Program_Run_WithDepthFlag_SetsHeadingDepth**: Verifies that `--depth 3` causes the generated +report to use level-three headings (`###`) for the title section. +This scenario is tested by `Program_Run_WithDepthFlag_SetsHeadingDepth`. -### Requirements Coverage +**Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode**: Verifies that an invalid build +version string causes an error message on stderr and exits with code 1. +This scenario is tested by `Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode`. -- **BuildMark-Program-Version**: Program_Version_ReturnsValidVersion, - Program_Run_VersionFlag_OutputsVersionToConsole -- **BuildMark-Program-Help**: Program_Run_HelpFlag_OutputsHelpMessage, - Program_Run_QuestionMarkFlag_OutputsHelpMessage, Program_Run_LongHelpFlag_OutputsHelpMessage -- **BuildMark-Program-Validate**: Program_Run_ValidateFlag_OutputsValidationMessage -- **BuildMark-Program-Report**: Program_Run_ReportWithIncludeKnownIssuesFlag_GeneratesReportWithKnownIssues -- **BuildMark-Program-Lint**: Program_Run_LintFlagWithoutConfiguration_LeavesExitCodeAtZero -- **BuildMark-Program-Silent**: Program_Run_WithSilentFlag_SuppressesOutput -- **BuildMark-Program-Log**: Program_Run_WithLogFlag_WritesToLogFile -- **BuildMark-Program-Results**: Program_Run_WithResultsFlag_WritesResultsFile -- **BuildMark-Program-BuildVersion**: Program_Run_WithBuildVersionFlag_AcceptsBuildVersion -- **BuildMark-Program-Depth**: Program_Run_WithDepthFlag_SetsHeadingDepth -- **BuildMark-Program-ErrorHandling-InvalidBuildVersion**: Program_Run_InvalidBuildVersion_WritesErrorAndSetsExitCode -- **BuildMark-Program-ErrorHandling-ConnectorFailure**: Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode +**Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode**: Verifies +that when the connector factory throws `InvalidOperationException`, an error message is written +to stderr and the exit code is 1. This scenario is tested by +`Program_Run_ConnectorThrowsInvalidOperationException_WritesErrorAndSetsExitCode`. diff --git a/docs/verification/build-mark/repo-connectors.md b/docs/verification/build-mark/repo-connectors.md index 8d3c6ab..72f1787 100644 --- a/docs/verification/build-mark/repo-connectors.md +++ b/docs/verification/build-mark/repo-connectors.md @@ -1,12 +1,12 @@ ## RepoConnectors -### Verification Strategy +### Verification Approach -The RepoConnectors subsystem is verified through `RepoConnectorsTests.cs`, which -contains 33 subsystem-level integration tests. These tests exercise the connector -factory, the GitHub connector, the Azure DevOps connector, and the Mock connector -through the full `GetBuildInformationAsync` pipeline using mock HTTP data. Individual -unit tests for sub-components are described in the unit-level chapters. +The RepoConnectors subsystem is verified through `RepoConnectorsTests.cs`, which contains 33 +subsystem-level integration tests. These tests exercise the connector factory, the GitHub connector, +the Azure DevOps connector, and the Mock connector through the full `GetBuildInformationAsync` +pipeline using mock HTTP data. Individual unit tests for sub-components are described in the +unit-level chapters. ### Dependencies @@ -18,15 +18,15 @@ unit tests for sub-components are described in the unit-level chapters. ### Test Environment -No external network access is required; all HTTP calls to the GitHub GraphQL API and -Azure DevOps REST API are intercepted by `MockHttpMessageHandler`. Tests run within -the standard `dotnet test` host. +No external network access is required; all HTTP calls to the GitHub GraphQL API and Azure DevOps +REST API are intercepted by `MockHttpMessageHandler`. Tests run within the standard `dotnet test` +host. ### Acceptance Criteria All 33 integration tests in `RepoConnectorsTests.cs` pass with zero failures. All -`BuildMark-RepoConnectors-*` requirements have at least one test in the Requirements -Coverage mapping. +`BuildMark-RepoConnectors-*` requirements have at least one test traced in the ReqStream trace +matrix. ### Test Scenarios @@ -293,27 +293,3 @@ Coverage mapping. **Expected**: Baseline is a previous release tag. **Requirement coverage**: `BuildMark-RepoConnectors-AzureDevOps` - -### Requirements Coverage - -- **BuildMark-RepoConnectors-IRepoConnector**: RepoConnectors_GitHubConnector_ImplementsInterface_ReturnsTrue, - RepoConnectors_ConnectorBase_MockConnector_ImplementsInterface, - RepoConnectors_MockConnector_ImplementsInterface_ReturnsTrue, - RepoConnectors_AzureDevOps_ImplementsInterface_ReturnsTrue -- **BuildMark-RepoConnectors-RepoConnectorBase**: RepoConnectors_ConnectorBase_GitHubConnector_ImplementsInterface -- **BuildMark-RepoConnectors-RepoConnectorFactory**: RepoConnectors_Factory_Create_ReturnsConnector, - RepoConnectors_Factory_Create_ReturnsGitHubConnectorForThisRepo -- **BuildMark-RepoConnectors-ItemRouter**: RepoConnectors_ItemRouter_MatchingRule_RoutesToSection, - RepoConnectors_ItemRouter_SuppressedRoute_OmitsItem -- **BuildMark-RepoConnectors-ItemControlsParser**: RepoConnectors_ItemControls_VisibilityPublic_ReturnsPublicVisibility, - RepoConnectors_ItemControls_VisibilityInternal_ReturnsInternalVisibility, - RepoConnectors_ItemControls_TypeBug_ReturnsBugType, - RepoConnectors_ItemControls_TypeFeature_ReturnsFeatureType, - RepoConnectors_ItemControls_AffectedVersions_ReturnsIntervalSet, - RepoConnectors_ItemControls_HiddenBlock_ReturnsControls, - RepoConnectors_ItemControls_NoBlock_ReturnsNull -- **BuildMark-RepoConnectors-GitHub**: Multiple GitHub connector tests -- **BuildMark-RepoConnectors-AzureDevOps**: Multiple Azure DevOps connector tests -- **BuildMark-RepoConnectors-Mock**: RepoConnectors_MockConnector_Constructor_CreatesInstance, - RepoConnectors_MockConnector_GetBuildInformation_ReturnsExpectedVersion, - RepoConnectors_MockConnector_GetBuildInformation_ReturnsCompleteInformation diff --git a/docs/verification/build-mark/repo-connectors/azure-devops.md b/docs/verification/build-mark/repo-connectors/azure-devops.md index 4e21763..7e788b6 100644 --- a/docs/verification/build-mark/repo-connectors/azure-devops.md +++ b/docs/verification/build-mark/repo-connectors/azure-devops.md @@ -1,12 +1,11 @@ ### Azure DevOps -#### Verification Strategy +#### Verification Approach -The Azure DevOps sub-subsystem is verified through `AzureDevOpsTests.cs` (5 subsystem- -level tests), `AzureDevOpsRepoConnectorTests.cs` (32 unit tests), -`AzureDevOpsRestClientTests.cs` (12 unit tests), and `WorkItemMapperTests.cs` (13 unit -tests). The subsystem tests exercise the full Azure DevOps data pipeline through mock -HTTP responses. The unit tests are described in the individual unit chapters. +The Azure DevOps sub-subsystem is verified through `AzureDevOpsTests.cs` (5 subsystem-level tests), +`AzureDevOpsRepoConnectorTests.cs` (32 unit tests), `AzureDevOpsRestClientTests.cs` (12 unit tests), +and `WorkItemMapperTests.cs` (13 unit tests). The subsystem tests exercise the full Azure DevOps data +pipeline through mock HTTP responses. The unit tests are described in the individual unit chapters. #### Dependencies @@ -16,14 +15,14 @@ HTTP responses. The unit tests are described in the individual unit chapters. #### Test Environment -N/A - standard test environment. All HTTP calls to the Azure DevOps REST API are -intercepted by `MockHttpMessageHandler`; no live network access is required. +N/A - standard test environment. All HTTP calls to the Azure DevOps REST API are intercepted by +`MockHttpMessageHandler`; no live network access is required. #### Acceptance Criteria All 5 subsystem tests in `AzureDevOpsTests.cs` pass with zero failures. All -`BuildMark-AzureDevOps-SubSystem` requirements have at least one test in the -Requirements Coverage mapping. +`BuildMark-RepoConnectors-AzureDevOps` requirements have at least one test traced in the ReqStream +trace matrix. #### Test Scenarios (Subsystem-Level, AzureDevOpsTests.cs) @@ -33,7 +32,7 @@ Requirements Coverage mapping. **Expected**: Implements the interface. -**Requirement coverage**: `BuildMark-AzureDevOps-SubSystem` +**Requirement coverage**: `BuildMark-RepoConnectors-IRepoConnector` ##### AzureDevOps_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation @@ -41,7 +40,7 @@ Requirements Coverage mapping. **Expected**: Returns valid `BuildInformation` with correct fields. -**Requirement coverage**: `BuildMark-AzureDevOps-SubSystem` +**Requirement coverage**: `BuildMark-RepoConnectors-AzureDevOps` ##### AzureDevOps_GetBuildInformation_WithPullRequests_GathersChanges @@ -49,7 +48,7 @@ Requirements Coverage mapping. **Expected**: Work items appear in `BuildInformation.Changes`. -**Requirement coverage**: `BuildMark-AzureDevOps-SubSystem` +**Requirement coverage**: `BuildMark-RepoConnectors-AzureDevOps` ##### AzureDevOps_GetBuildInformation_WithOpenWorkItems_IdentifiesKnownIssues @@ -57,7 +56,7 @@ Requirements Coverage mapping. **Expected**: Bugs appear in `BuildInformation.KnownIssues`. -**Requirement coverage**: `BuildMark-AzureDevOps-SubSystem` +**Requirement coverage**: `BuildMark-RepoConnectors-AzureDevOps` ##### AzureDevOps_GetBuildInformation_ReleaseVersion_SkipsPreReleases @@ -65,12 +64,4 @@ Requirements Coverage mapping. **Expected**: Baseline is the previous release tag. -**Requirement coverage**: `BuildMark-AzureDevOps-SubSystem` - -#### Requirements Coverage - -- **BuildMark-AzureDevOps-SubSystem**: AzureDevOps_IRepoConnector_ConnectorInstance_ImplementsInterface, - AzureDevOps_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation, - AzureDevOps_GetBuildInformation_WithPullRequests_GathersChanges, - AzureDevOps_GetBuildInformation_WithOpenWorkItems_IdentifiesKnownIssues, - AzureDevOps_GetBuildInformation_ReleaseVersion_SkipsPreReleases +**Requirement coverage**: `BuildMark-RepoConnectors-AzureDevOps` diff --git a/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md b/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md index 39f722f..0a074ec 100644 --- a/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md +++ b/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-api-types.md @@ -55,8 +55,3 @@ All tests in the test class pass with no errors or warnings. **Expected**: Pull request DTO fields are populated correctly. **Requirement coverage**: `BuildMark-AzureDevOps-ApiTypes` - -##### Requirements Coverage - -- **BuildMark-AzureDevOps-ApiTypes**: Verified indirectly through all 12 tests in - `AzureDevOpsRestClientTests.cs` and all 13 tests in `WorkItemMapperTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md b/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md index 56dc6ba..9c88cdc 100644 --- a/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md +++ b/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-repo-connector.md @@ -225,10 +225,3 @@ range. **Expected**: Generated changelog link uses the Azure DevOps compare format. **Requirement coverage**: `BuildMark-RepoConnectors-AzureDevOps` - -##### Requirements Coverage - -- **BuildMark-RepoConnectors-IRepoConnector**: - AzureDevOpsRepoConnector_ImplementsInterface_ReturnsTrue -- **BuildMark-RepoConnectors-AzureDevOps**: All remaining 24 tests in - `AzureDevOpsRepoConnectorTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md b/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md index f390f72..ac0db3c 100644 --- a/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md +++ b/docs/verification/build-mark/repo-connectors/azure-devops/azure-devops-rest-client.md @@ -118,7 +118,3 @@ All tests in the test class pass with no errors or warnings. **Expected**: Returns an empty list without making any HTTP call. **Requirement coverage**: `BuildMark-AzureDevOps-RestClient` - -##### Requirements Coverage - -- **BuildMark-AzureDevOps-RestClient**: All 12 tests in `AzureDevOpsRestClientTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/azure-devops/work-item-mapper.md b/docs/verification/build-mark/repo-connectors/azure-devops/work-item-mapper.md index 1cfd34d..d29c59d 100644 --- a/docs/verification/build-mark/repo-connectors/azure-devops/work-item-mapper.md +++ b/docs/verification/build-mark/repo-connectors/azure-devops/work-item-mapper.md @@ -131,21 +131,3 @@ interval set. block value. **Requirement coverage**: `BuildMark-AzureDevOps-CustomFields` - -##### Requirements Coverage - -- **BuildMark-AzureDevOps-WorkItemMapper**: `WorkItemMapper_MapWorkItemToItemInfo_BugType_ReturnsBugItem`, - `WorkItemMapper_MapWorkItemToItemInfo_IssueType_ReturnsBugItem`, - `WorkItemMapper_MapWorkItemToItemInfo_UserStoryType_ReturnsFeatureItem`, - `WorkItemMapper_MapWorkItemToItemInfo_FeatureType_ReturnsFeatureItem`, - `WorkItemMapper_MapWorkItemToItemInfo_EpicType_ReturnsFeatureItem`, - `WorkItemMapper_MapWorkItemToItemInfo_TaskType_ReturnsTaskItem`, - `WorkItemMapper_IsWorkItemResolved_ResolvedState_ReturnsTrue`, - `WorkItemMapper_IsWorkItemResolved_ActiveState_ReturnsFalse`, - `WorkItemMapper_GetWorkItemTypeForRuleMatching_ReturnsWorkItemTypeName` in `WorkItemMapperTests.cs` -- **BuildMark-AzureDevOps-SuppressRemovedWorkItems**: - `WorkItemMapper_MapWorkItemToItemInfo_RemovedState_ReturnsNull` in `WorkItemMapperTests.cs` -- **BuildMark-AzureDevOps-CustomFields**: - `WorkItemMapper_ExtractItemControls_CustomVisibilityField_ReturnsMappedControls`, - `WorkItemMapper_ExtractItemControls_CustomAffectedVersionsField_ReturnsMappedVersionSet`, - `WorkItemMapper_ExtractItemControls_CustomFieldsTakePrecedenceOverBuildmarkBlock` in `WorkItemMapperTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/github.md b/docs/verification/build-mark/repo-connectors/github.md index daaeae8..f72f8d2 100644 --- a/docs/verification/build-mark/repo-connectors/github.md +++ b/docs/verification/build-mark/repo-connectors/github.md @@ -1,11 +1,11 @@ ### GitHub -#### Verification Strategy +#### Verification Approach -The GitHub sub-subsystem is verified through `GitHubTests.cs` (6 subsystem-level -tests), `GitHubRepoConnectorTests.cs` (22 unit tests), and 5 `GitHubGraphQLClient*Tests.cs` -files (41 tests). The subsystem tests exercise the full GitHub data pipeline through -mock HTTP responses. The unit tests are described in the individual unit chapters. +The GitHub sub-subsystem is verified through `GitHubTests.cs` (6 subsystem-level tests), +`GitHubRepoConnectorTests.cs` (27 unit tests), and six `GitHubGraphQLClient*Tests.cs` files +(49 tests). The subsystem tests exercise the full GitHub data pipeline through mock HTTP responses. +The unit tests are described in the individual unit chapters. #### Dependencies @@ -15,14 +15,14 @@ mock HTTP responses. The unit tests are described in the individual unit chapter #### Test Environment -N/A - standard test environment. All HTTP calls to the GitHub GraphQL API are -intercepted by `MockHttpMessageHandler`; no live network access is required. +N/A - standard test environment. All HTTP calls to the GitHub GraphQL API are intercepted by +`MockHttpMessageHandler`; no live network access is required. #### Acceptance Criteria All 6 subsystem tests in `GitHubTests.cs` pass with zero failures. All -`BuildMark-RepoConnectors-GitHub` requirements have at least one test in the -Requirements Coverage mapping. +`BuildMark-RepoConnectors-GitHub` requirements have at least one test traced in the ReqStream trace +matrix. #### Test Scenarios (Subsystem-Level, GitHubTests.cs) @@ -73,12 +73,3 @@ Requirements Coverage mapping. **Expected**: Baseline is the previous release tag. **Requirement coverage**: `BuildMark-RepoConnectors-GitHub` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-IRepoConnector**: GitHub_ImplementsInterface_ReturnsTrue -- **BuildMark-RepoConnectors-GitHub**: GitHub_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation, - GitHub_GetBuildInformation_WithMultipleVersions_SelectsCorrectBaseline, - GitHub_GetBuildInformation_WithPullRequests_GathersChanges, - GitHub_GetBuildInformation_WithOpenIssues_IdentifiesKnownIssues, - GitHub_GetBuildInformation_ReleaseVersion_SkipsPreReleases diff --git a/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-client.md b/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-client.md index 8f9b917..6abac4e 100644 --- a/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-client.md +++ b/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-client.md @@ -424,10 +424,3 @@ All tests in the test class pass with no errors or warnings. **Expected**: All pages are fetched and all release tag names are returned. **Requirement coverage**: `BuildMark-GitHub-GraphQLClient` - -##### Requirements Coverage - -- **BuildMark-GitHub-GraphQLClient**: All 49 tests across the six - `GitHubGraphQLClient*Tests.cs` files -- **BuildMark-GitHub-ErrorHandling**: HTTP error, invalid JSON, and exception tests - across all six `GitHubGraphQLClient*Tests.cs` files diff --git a/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-types.md b/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-types.md index 60317e8..87ea273 100644 --- a/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-types.md +++ b/docs/verification/build-mark/repo-connectors/github/git-hub-graph-ql-types.md @@ -46,8 +46,3 @@ All tests in the test class pass with no errors or warnings. **Expected**: Tag node DTOs contain `name` and target commit hash fields. **Requirement coverage**: `BuildMark-GitHub-GraphQLClient` - -##### Requirements Coverage - -- **BuildMark-GitHub-GraphQLClient**: Verified indirectly through all - 49 tests in the `GitHubGraphQLClient*Tests.cs` files diff --git a/docs/verification/build-mark/repo-connectors/github/git-hub-repo-connector.md b/docs/verification/build-mark/repo-connectors/github/git-hub-repo-connector.md index e30b0e8..2eb82ef 100644 --- a/docs/verification/build-mark/repo-connectors/github/git-hub-repo-connector.md +++ b/docs/verification/build-mark/repo-connectors/github/git-hub-repo-connector.md @@ -231,31 +231,3 @@ corresponding environment variable is not set (null). **Expected**: `InvalidOperationException` is thrown. **Requirement coverage**: `BuildMark-GitHub-TokenVariable` - -##### Requirements Coverage - -- **BuildMark-RepoConnectorBase-Interface**: GitHubRepoConnector_ImplementsInterface_ReturnsTrue -- **BuildMark-GitHub-ConnectorConfig**: GitHubRepoConnector_Constructor_CreatesInstance, - GitHubRepoConnector_Constructor_WithConfig_StoresConfigurationOverrides -- **BuildMark-GitHub-BuildInformation**: GitHubRepoConnector_GetBuildInformationAsync_WithMockedData_ReturnsValidBuildInformation, - GitHubRepoConnector_GetBuildInformationAsync_WithMultipleVersions_SelectsCorrectPreviousVersionAndGeneratesChangelogLink, - GitHubRepoConnector_GetBuildInformationAsync_WithPullRequests_GathersChangesCorrectly, - GitHubRepoConnector_GetBuildInformationAsync_WithOpenIssues_IdentifiesKnownIssues, - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseWithSameCommitHash_SkipsToNextDifferentHash, - GitHubRepoConnector_GetBuildInformationAsync_ReleaseVersion_SkipsAllPreReleases, - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseNotInHistory_UsesLatestDifferentHash, - GitHubRepoConnector_GetBuildInformationAsync_PreReleaseAllPreviousSameHash_ReturnsNullBaseline, - GitHubRepoConnector_GetBuildInformationAsync_WithDuplicateMergeCommitSha_DoesNotThrow, - GitHubRepoConnector_GetBuildInformationAsync_PrWithSubstringMatchLabel_NotClassifiedAsBug, - GitHubRepoConnector_GetBuildInformationAsync_IssueWithSubstringMatchLabel_NotClassifiedAsKnownIssue, - GitHubRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions, - GitHubRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue -- **BuildMark-GitHub-ItemControls**: GitHubRepoConnector_GetBuildInformationAsync_VisibilityInternal_ExcludesItem, - GitHubRepoConnector_GetBuildInformationAsync_VisibilityPublic_IncludesItem, - GitHubRepoConnector_GetBuildInformationAsync_TypeBugOverride_ClassifiesAsBug, - GitHubRepoConnector_GetBuildInformationAsync_TypeFeatureOverride_ClassifiesAsFeature -- **BuildMark-GitHub-Rules**: GitHubRepoConnector_Configure_WithRules_HasRulesReturnsTrue, - GitHubRepoConnector_GetBuildInformationAsync_WithConfiguredRules_PopulatesRoutedSections -- **BuildMark-GitHub-TokenVariable**: GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_UsesCustomVariable, - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_EmptyValue_ThrowsInvalidOperationException, - GitHubRepoConnector_GetBuildInformationAsync_WithTokenVariable_NotSet_ThrowsInvalidOperationException diff --git a/docs/verification/build-mark/repo-connectors/i-repo-connector.md b/docs/verification/build-mark/repo-connectors/i-repo-connector.md index 7f6d537..9997c4c 100644 --- a/docs/verification/build-mark/repo-connectors/i-repo-connector.md +++ b/docs/verification/build-mark/repo-connectors/i-repo-connector.md @@ -2,11 +2,10 @@ #### Verification Approach -`IRepoConnector` is an interface with no dedicated test class. Its contract is -verified through all tests that exercise concrete implementations: `GitHubRepoConnector`, -`AzureDevOpsRepoConnector`, and `MockRepoConnector`. Each implementation is checked -against the interface via cast or type-assertion tests that confirm the concrete class -implements `IRepoConnector`. +`IRepoConnector` is an interface with no dedicated test class. Its contract is verified through all +tests that exercise concrete implementations: `GitHubRepoConnector`, `AzureDevOpsRepoConnector`, and +`MockRepoConnector`. Each implementation is checked against the interface via cast or type-assertion +tests that confirm the concrete class implements `IRepoConnector`. #### Dependencies @@ -20,9 +19,12 @@ Standard dotnet test host; no external dependencies or environment setup require #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +All interface-implementation tests across `RepoConnectorsTests.cs`, `GitHubTests.cs`, +`AzureDevOpsTests.cs`, `MockTests.cs`, `GitHubRepoConnectorTests.cs`, +`AzureDevOpsRepoConnectorTests.cs`, and `MockRepoConnectorTests.cs` that verify +`IRepoConnector` pass with no errors or warnings. -#### Test Scenarios (Integration via Implementations) +#### Test Scenarios ##### RepoConnectors_GitHubConnector_ImplementsInterface_ReturnsTrue @@ -42,8 +44,7 @@ All tests in the test class pass with no errors or warnings. ##### RepoConnectors_AzureDevOps_ImplementsInterface_ReturnsTrue -**Scenario**: `AzureDevOpsRepoConnector` instance is checked for `IRepoConnector` -implementation. +**Scenario**: `AzureDevOpsRepoConnector` instance is checked for `IRepoConnector` implementation. **Expected**: Returns `true`. @@ -72,13 +73,3 @@ implementation. **Expected**: Returns `true`. **Requirement coverage**: `BuildMark-RepoConnectors-IRepoConnector` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-IRepoConnector**: - RepoConnectors_GitHubConnector_ImplementsInterface_ReturnsTrue, - RepoConnectors_MockConnector_ImplementsInterface_ReturnsTrue, - RepoConnectors_AzureDevOps_ImplementsInterface_ReturnsTrue, - GitHubRepoConnector_ImplementsInterface_ReturnsTrue, - MockRepoConnector_ImplementsInterface, - AzureDevOpsRepoConnector_ImplementsInterface_ReturnsTrue diff --git a/docs/verification/build-mark/repo-connectors/item-controls-info.md b/docs/verification/build-mark/repo-connectors/item-controls-info.md index 255a782..9cf8ac1 100644 --- a/docs/verification/build-mark/repo-connectors/item-controls-info.md +++ b/docs/verification/build-mark/repo-connectors/item-controls-info.md @@ -2,10 +2,10 @@ #### Verification Approach -`ItemControlsInfo` is a data model class with no dedicated test class. It is verified -indirectly through `ItemControlsTests.cs` and `ItemControlsParserTests.cs`. The parser -tests assert on the resulting `ItemControlsInfo` instances, confirming that visibility, -type, and affected versions fields are populated correctly. +`ItemControlsInfo` is a data model class with no dedicated test class. It is verified indirectly +through `ItemControlsTests.cs` and `ItemControlsParserTests.cs`. The parser tests assert on the +resulting `ItemControlsInfo` instances, confirming that visibility, type, and affected versions +fields are populated correctly. #### Dependencies @@ -19,9 +19,10 @@ Standard dotnet test host; no external dependencies or environment setup require #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +All tests in `ItemControlsTests.cs` and `ItemControlsParserTests.cs` that produce and assert on +`ItemControlsInfo` instances pass with no errors or warnings. -#### Test Scenarios (via ItemControlsTests.cs - 13 tests) +#### Test Scenarios ##### ItemControls_Parse_WithVisibilityPublic_ReturnsPublicVisibility @@ -78,7 +79,3 @@ All tests in the test class pass with no errors or warnings. **Expected**: Returns `null` (no `ItemControlsInfo`). **Requirement coverage**: `BuildMark-RepoConnectors-ItemControlsInfo` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-ItemControlsInfo**: All 13 tests in `ItemControlsTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/item-controls-parser.md b/docs/verification/build-mark/repo-connectors/item-controls-parser.md index dd0d9bd..cb1bbe6 100644 --- a/docs/verification/build-mark/repo-connectors/item-controls-parser.md +++ b/docs/verification/build-mark/repo-connectors/item-controls-parser.md @@ -2,11 +2,10 @@ #### Verification Approach -`ItemControlsParser` is tested through `ItemControlsParserTests.cs`, which contains -15 unit tests. The tests cover parsing `null` and empty descriptions, descriptions -with no block, and descriptions containing a buildmark block with various field -combinations (visibility, type, affected-versions, hidden). Unknown keys and -unrecognized values are tested for graceful ignorance. +`ItemControlsParser` is tested through `ItemControlsParserTests.cs`, which contains 15 unit tests. +The tests cover parsing `null` and empty descriptions, descriptions with no block, and descriptions +containing a buildmark block with various field combinations (visibility, type, affected-versions, +hidden). Unknown keys and unrecognized values are tested for graceful ignorance. #### Dependencies @@ -20,7 +19,7 @@ Standard dotnet test host; no external dependencies or environment setup require #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +All 15 tests in `ItemControlsParserTests.cs` pass with no errors or warnings. #### Test Scenarios @@ -42,8 +41,7 @@ All tests in the test class pass with no errors or warnings. ##### ItemControlsParser_Parse_WithNoBlock_ReturnsNull -**Scenario**: `ItemControlsParser.Parse` is called with text that contains no -buildmark block. +**Scenario**: `ItemControlsParser.Parse` is called with text that contains no buildmark block. **Expected**: Returns `null`. @@ -144,8 +142,3 @@ buildmark block. **Expected**: `AffectedVersions` is not set or is empty; no exception thrown. **Requirement coverage**: `BuildMark-RepoConnectors-ItemControlsParser` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-ItemControlsParser**: All 15 tests in - `ItemControlsParserTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/item-router.md b/docs/verification/build-mark/repo-connectors/item-router.md index 001aa35..1634168 100644 --- a/docs/verification/build-mark/repo-connectors/item-router.md +++ b/docs/verification/build-mark/repo-connectors/item-router.md @@ -2,10 +2,9 @@ #### Verification Approach -`ItemRouter` is tested through `ItemRouterTests.cs`, which contains 8 unit tests. -The tests cover matching rules (with and without a match block), suppression rules, -type-based matching, label-based matching (case-insensitive), routing to new sections, -and default section fallback. +`ItemRouter` is tested through `ItemRouterTests.cs`, which contains 8 unit tests. The tests cover +matching rules (with and without a match block), suppression rules, type-based matching, label-based +matching (case-insensitive), routing to new sections, and default section fallback. #### Dependencies @@ -21,7 +20,7 @@ Standard dotnet test host; no external dependencies or environment setup require #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +All 8 tests in `ItemRouterTests.cs` pass with no errors or warnings. #### Test Scenarios @@ -88,7 +87,3 @@ All tests in the test class pass with no errors or warnings. **Expected**: Item is omitted from all sections. **Requirement coverage**: `BuildMark-RepoConnectors-ItemRouter` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-ItemRouter**: All 8 tests in `ItemRouterTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/mock.md b/docs/verification/build-mark/repo-connectors/mock.md index 9f4b0ef..c9ba9c5 100644 --- a/docs/verification/build-mark/repo-connectors/mock.md +++ b/docs/verification/build-mark/repo-connectors/mock.md @@ -1,11 +1,10 @@ ### Mock -#### Verification Strategy +#### Verification Approach -The Mock sub-subsystem is verified through `MockTests.cs` (3 subsystem-level tests) -and `MockRepoConnectorTests.cs` (11 unit tests). The subsystem tests confirm -integration of the mock connector within the broader pipeline. The unit tests are -described in the individual unit chapter. +The Mock sub-subsystem is verified through `MockTests.cs` (3 subsystem-level tests) and +`MockRepoConnectorTests.cs` (12 unit tests). The subsystem tests confirm integration of the mock +connector within the broader pipeline. The unit tests are described in the individual unit chapter. #### Dependencies @@ -21,8 +20,8 @@ N/A - standard test environment. The Mock sub-subsystem has no external dependen #### Acceptance Criteria All 3 subsystem tests in `MockTests.cs` pass with zero failures. All -`BuildMark-RepoConnectors-Mock` requirements have at least one test in the Requirements -Coverage mapping. +`BuildMark-RepoConnectors-Mock` requirements have at least one test traced in the ReqStream trace +matrix. #### Test Scenarios (Subsystem-Level, MockTests.cs) @@ -36,8 +35,7 @@ Coverage mapping. ##### Mock_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation -**Scenario**: Mock connector is configured with direct data and `GetBuildInformationAsync` -is called. +**Scenario**: Mock connector is configured with direct data and `GetBuildInformationAsync` is called. **Expected**: Returns the configured `BuildInformation` directly. @@ -50,9 +48,3 @@ is called. **Expected**: Returns an empty `BuildInformation`. **Requirement coverage**: `BuildMark-RepoConnectors-Mock` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-IRepoConnector**: Mock_ImplementsInterface_ReturnsTrue -- **BuildMark-RepoConnectors-Mock**: Mock_GetBuildInformation_WithMockedData_ReturnsValidBuildInformation, - Mock_GetBuildInformation_WithNoData_ReturnsEmptyBuildInformation diff --git a/docs/verification/build-mark/repo-connectors/mock/mock-repo-connector.md b/docs/verification/build-mark/repo-connectors/mock/mock-repo-connector.md index 735e8bf..724a37c 100644 --- a/docs/verification/build-mark/repo-connectors/mock/mock-repo-connector.md +++ b/docs/verification/build-mark/repo-connectors/mock/mock-repo-connector.md @@ -2,10 +2,10 @@ ##### Verification Approach -`MockRepoConnector` is tested through `MockRepoConnectorTests.cs`, which contains -12 unit tests. The tests verify that the connector correctly returns in-memory data -supplied via its configuration API, handles all routing and `HasRules` logic, and -correctly implements all members of `IRepoConnector`. +`MockRepoConnector` is tested through `MockRepoConnectorTests.cs`, which contains 12 unit tests. +The tests verify that the connector correctly returns in-memory data supplied via its configuration +API, handles all routing and `HasRules` logic, and correctly implements all members of +`IRepoConnector`. ##### Dependencies @@ -17,13 +17,13 @@ correctly implements all members of `IRepoConnector`. Standard dotnet test host; no external dependencies or environment setup required. -#### Acceptance Criteria +##### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +All 12 tests in `MockRepoConnectorTests.cs` pass with no errors or warnings. -#### Test Scenarios +##### Test Scenarios -##### MockRepoConnector_ImplementsInterface +###### MockRepoConnector_ImplementsInterface **Scenario**: `MockRepoConnector` is checked against `IRepoConnector`. @@ -59,13 +59,15 @@ All tests in the test class pass with no errors or warnings. **Scenario**: `GetBuildInformationAsync` is called for a version that has associated changes. -**Expected**: All expected components (`Changes`, `Bugs`, `KnownIssues`, `CurrentVersionTag`) are present and non-null. +**Expected**: All expected components (`Changes`, `Bugs`, `KnownIssues`, `CurrentVersionTag`) are +present and non-null. **Requirement coverage**: `BuildMark-RepoConnectors-Mock` ###### MockRepoConnector_GetBuildInformationAsync_CategorizesChangesCorrectly -**Scenario**: `GetBuildInformationAsync` is called for a version that has both bug and non-bug changes. +**Scenario**: `GetBuildInformationAsync` is called for a version that has both bug and non-bug +changes. **Expected**: Items with type `bug` appear only in `Bugs`; all items in `Bugs` have type `bug`. @@ -73,15 +75,18 @@ All tests in the test class pass with no errors or warnings. ###### MockRepoConnector_Configure_StoresRulesAndSections -**Scenario**: `Configure` is called with a non-empty rules and sections list, then `GetBuildInformationAsync` is called. +**Scenario**: `Configure` is called with a non-empty rules and sections list, then +`GetBuildInformationAsync` is called. -**Expected**: `BuildInformation.RoutedSections` is non-null, confirming rules were stored and applied. +**Expected**: `BuildInformation.RoutedSections` is non-null, confirming rules were stored and +applied. **Requirement coverage**: `BuildMark-RepoConnectors-Mock` ###### MockRepoConnector_GetBuildInformationAsync_WithRules_ReturnsRoutedSections -**Scenario**: Connector is configured with two routing rules (`bug` label → `bugs`, catch-all → `features`). +**Scenario**: Connector is configured with two routing rules (`bug` label → `bugs`, catch-all +→ `features`). **Expected**: `RoutedSections` contains exactly two sections with titles `Features` and `Bugs`. @@ -97,8 +102,8 @@ All tests in the test class pass with no errors or warnings. ###### MockRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions -**Scenario**: Version v2.0.0 is requested; issue 5 has affected-versions `[5.0.0,)` (outside range) -while issues 4 and 6 have no affected-versions restriction. +**Scenario**: Version v2.0.0 is requested; issue 5 has affected-versions `[5.0.0,)` (outside +range) while issues 4 and 6 have no affected-versions restriction. **Expected**: Issues 4 and 6 appear in `KnownIssues`; issue 5 does not. @@ -106,34 +111,21 @@ while issues 4 and 6 have no affected-versions restriction. ###### MockRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue -**Scenario**: Issue 7 is a closed bug with affected-versions `[1.0.0,1.0.0]`. Build is requested for v1.0.0 and then v2.0.0. +**Scenario**: Issue 7 is a closed bug with affected-versions `[1.0.0,1.0.0]`. Build is requested +for v1.0.0 and then v2.0.0. -**Expected**: Issue 7 appears in `KnownIssues` for v1.0.0 (in-range); issue 7 does not appear for v2.0.0 (out-of-range). +**Expected**: Issue 7 appears in `KnownIssues` for v1.0.0 (in-range); issue 7 does not appear for +v2.0.0 (out-of-range). **Requirement coverage**: `BuildMark-RepoConnectors-Mock` ###### MockRepoConnector_GetBuildInformationAsync_WithRulesAndKnownIssues_KnownIssuesNotInRoutedSections -**Scenario**: Connector is configured with routing rules; `GetBuildInformationAsync` is called for a -version that has known issues; routing rules include a rule that would match bug items. +**Scenario**: Connector is configured with routing rules; `GetBuildInformationAsync` is called for +a version that has known issues; routing rules include a rule that would match bug items. **Expected**: `BuildInformation.KnownIssues` is non-empty and `BuildInformation.RoutedSections` is populated, but no item ID that appears in `KnownIssues` also appears in any routed section, proving that known issues are excluded from the routing path and kept in their dedicated collection. **Requirement coverage**: `BuildMark-RepoConnectors-Mock` - -##### Requirements Coverage - -- **BuildMark-RepoConnectors-IRepoConnector**: MockRepoConnector_ImplementsInterface -- **BuildMark-RepoConnectors-Mock**: MockRepoConnector_Constructor_CreatesInstance, - MockRepoConnector_GetBuildInformationAsync_ReturnsExpectedVersion, - MockRepoConnector_GetBuildInformationAsync_WithValidVersionFromTags_ReturnsCorrectBaseline, - MockRepoConnector_GetBuildInformationAsync_ReturnsCompleteInformation, - MockRepoConnector_GetBuildInformationAsync_CategorizesChangesCorrectly, - MockRepoConnector_Configure_StoresRulesAndSections, - MockRepoConnector_GetBuildInformationAsync_WithRules_ReturnsRoutedSections, - MockRepoConnector_GetBuildInformationAsync_WithoutRules_ReturnsNullRoutedSections, - MockRepoConnector_GetBuildInformationAsync_KnownIssues_FilteredByAffectedVersions, - MockRepoConnector_GetBuildInformationAsync_ClosedBugWithMatchingAffectedVersions_IsKnownIssue, - MockRepoConnector_GetBuildInformationAsync_WithRulesAndKnownIssues_KnownIssuesNotInRoutedSections diff --git a/docs/verification/build-mark/repo-connectors/repo-connector-base.md b/docs/verification/build-mark/repo-connectors/repo-connector-base.md index 2464710..51360b7 100644 --- a/docs/verification/build-mark/repo-connectors/repo-connector-base.md +++ b/docs/verification/build-mark/repo-connectors/repo-connector-base.md @@ -2,10 +2,10 @@ #### Verification Approach -`RepoConnectorBase` is tested through `RepoConnectorBaseTests.cs`, which contains -5 unit tests. The tests exercise `Configure` (storing rules and sections and setting -`HasRules`), `ApplyRules` (routing items to sections), and `FindVersionIndex` (locating -a version tag in a list, including cross-prefix equality). +`RepoConnectorBase` is tested through `RepoConnectorBaseTests.cs`, which contains 5 unit tests. +The tests exercise `Configure` (storing rules and sections and setting `HasRules`), `ApplyRules` +(routing items to sections), and `FindVersionIndex` (locating a version tag in a list, including +cross-prefix equality). #### Dependencies @@ -19,7 +19,7 @@ Standard dotnet test host; no external dependencies or environment setup require #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +All 5 tests in `RepoConnectorBaseTests.cs` pass with no errors or warnings. #### Test Scenarios @@ -49,8 +49,8 @@ All tests in the test class pass with no errors or warnings. ##### RepoConnectorBase_FindVersionIndex_DifferentPrefixSameVersion_ReturnsCorrectIndex -**Scenario**: `FindVersionIndex` is called with a tag list containing a tag with a -different prefix but the same version as the search target. +**Scenario**: `FindVersionIndex` is called with a tag list containing a tag with a different +prefix but the same version as the search target. **Expected**: The index of the matching tag is returned. @@ -63,7 +63,3 @@ different prefix but the same version as the search target. **Expected**: Returns `-1`. **Requirement coverage**: `BuildMark-RepoConnectors-RepoConnectorBase` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-RepoConnectorBase**: All 5 tests in `RepoConnectorBaseTests.cs` diff --git a/docs/verification/build-mark/repo-connectors/repo-connector-factory.md b/docs/verification/build-mark/repo-connectors/repo-connector-factory.md index 7828771..7241b32 100644 --- a/docs/verification/build-mark/repo-connectors/repo-connector-factory.md +++ b/docs/verification/build-mark/repo-connectors/repo-connector-factory.md @@ -2,10 +2,10 @@ #### Verification Approach -`RepoConnectorFactory` is tested through `RepoConnectorFactoryTests.cs`, which contains -11 unit tests. The tests cover connector creation from default settings, from explicit -connector type configuration, from environment variables (GitHub Actions, Azure DevOps), -and from remote URL detection. +`RepoConnectorFactory` is tested through `RepoConnectorFactoryTests.cs`, which contains 11 unit +tests. The tests cover connector creation from default settings, from explicit connector type +configuration, from environment variables (GitHub Actions, Azure DevOps), and from remote URL +detection. #### Dependencies @@ -20,7 +20,7 @@ Standard dotnet test host; no external dependencies or environment setup require #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +All 11 tests in `RepoConnectorFactoryTests.cs` pass with no errors or warnings. #### Test Scenarios @@ -111,8 +111,3 @@ All tests in the test class pass with no errors or warnings. **Expected**: Factory defaults to returning a `GitHubRepoConnector`. **Requirement coverage**: `BuildMark-RepoConnectors-RepoConnectorFactory` - -#### Requirements Coverage - -- **BuildMark-RepoConnectors-RepoConnectorFactory**: All 11 tests in - `RepoConnectorFactoryTests.cs` diff --git a/docs/verification/build-mark/self-test.md b/docs/verification/build-mark/self-test.md index 8776f53..93231a5 100644 --- a/docs/verification/build-mark/self-test.md +++ b/docs/verification/build-mark/self-test.md @@ -1,85 +1,46 @@ ## SelfTest -### Verification Strategy +### Verification Approach The SelfTest subsystem is verified with dedicated subsystem tests in `SelfTestTests.cs`. Tests invoke `Validation.Run` through a `Context` constructed with controlled argument arrays, then -inspect created results files and log output. `MockRepoConnector` is used so that no real -repository access is needed. - -### Dependencies - -| Mock / Stub | Reason | -| --- | --- | -| `MockRepoConnector` | Provides a real connector factory that does not require external network access. | +inspect created results files and log output. `MockRepoConnector` is used as the connector factory +so that no real repository access is needed. Unit-level tests for `Validation` are in +`ValidationTests.cs`. ### Test Environment -Tests create temporary directories and results files (`.trx`, `.xml`) through -`TemporaryDirectory`, which creates a unique `tmp-*` subdirectory under the current -working directory. Write access to the current working directory is required. No -network access or external API calls are made; `MockRepoConnector` provides all -repository data. +Tests create temporary directories and results files (`.trx`, `.xml`) through `TemporaryDirectory`, +which creates a unique `tmp-*` subdirectory under the current working directory. Write access to +the current working directory is required. No network access or external API calls are made; +`MockRepoConnector` provides all repository data. ### Acceptance Criteria -All tests in `SelfTestTests.cs` pass with zero failures. All `BuildMark-SelfTest-*` -requirements have at least one test in the Requirements Coverage mapping. +- All tests in `SelfTestTests.cs` pass with zero failures. +- All `BuildMark-SelfTest-*` requirements have at least one test in the subsystem test file. ### Test Scenarios -#### SelfTest_Validation_WithTrxFile_WritesResults - -**Scenario**: `Validation.Run` is called with `--validate --results .trx --silent`; the -results file path ends in `.trx`. - -**Expected**: A `.trx` file is created; its content contains `TestRun` and -`BuildMark Self-Validation`. - -**Requirement coverage**: `BuildMark-SelfTest-Qualification`. - -#### SelfTest_Validation_WithXmlFile_WritesResults - -**Scenario**: `Validation.Run` is called with `--validate --results .xml --silent`; the -results file path ends in `.xml`. - -**Expected**: An `.xml` file is created; its content contains `testsuites` and -`BuildMark Self-Validation`. - -**Requirement coverage**: `BuildMark-SelfTest-Qualification`. - -#### SelfTest_ResultsOutput_WithTrxFile_CreatesFile +**SelfTest_Validation_WithTrxFile_WritesResults**: Verifies that running the SelfTest subsystem +with `--validate --results .trx --silent` creates a `.trx` file whose content contains +`TestRun` and `BuildMark Self-Validation`, confirming TRX output at subsystem level. +This scenario is tested by `SelfTest_Validation_WithTrxFile_WritesResults`. -**Scenario**: `Validation.Run` is called with `--validate --results output.trx --silent`. +**SelfTest_Validation_WithXmlFile_WritesResults**: Verifies that running with +`--validate --results .xml --silent` creates an `.xml` file whose content contains +`testsuites` and `BuildMark Self-Validation`, confirming JUnit XML output at subsystem level. +This scenario is tested by `SelfTest_Validation_WithXmlFile_WritesResults`. -**Expected**: The `.trx` results file is created and has a non-zero file size. +**SelfTest_ResultsOutput_WithTrxFile_CreatesFile**: Verifies that the results file is created +with non-zero size when a `.trx` path is specified, confirming file I/O at subsystem level. +This scenario is tested by `SelfTest_ResultsOutput_WithTrxFile_CreatesFile`. -**Requirement coverage**: `BuildMark-SelfTest-ResultsOutput`. +**SelfTest_ResultsOutput_WithXmlFile_CreatesFile**: Verifies that the results file is created +with non-zero size when an `.xml` path is specified. +This scenario is tested by `SelfTest_ResultsOutput_WithXmlFile_CreatesFile`. -#### SelfTest_ResultsOutput_WithXmlFile_CreatesFile - -**Scenario**: `Validation.Run` is called with `--validate --results output.xml --silent`. - -**Expected**: The `.xml` results file is created and has a non-zero file size. - -**Requirement coverage**: `BuildMark-SelfTest-ResultsOutput`. - -#### SelfTest_Qualification_WithoutResultsFile_Succeeds - -**Scenario**: `Validation.Run` is called with `--validate --log /validation.log --silent`; no -`--results` argument is supplied. - -**Expected**: Validation completes without error; the log file is created; its content contains +**SelfTest_Qualification_WithoutResultsFile_Succeeds**: Verifies that when no `--results` argument +is supplied, validation completes without error, the log file is created, and its content contains `BuildMark Self-validation` and `Total Tests:`. - -**Requirement coverage**: `BuildMark-SelfTest-Qualification`. - -### Requirements Coverage - -- **`BuildMark-SelfTest-Qualification`**: - - SelfTest_Validation_WithTrxFile_WritesResults - - SelfTest_Validation_WithXmlFile_WritesResults - - SelfTest_Qualification_WithoutResultsFile_Succeeds -- **`BuildMark-SelfTest-ResultsOutput`**: - - SelfTest_ResultsOutput_WithTrxFile_CreatesFile - - SelfTest_ResultsOutput_WithXmlFile_CreatesFile +This scenario is tested by `SelfTest_Qualification_WithoutResultsFile_Succeeds`. diff --git a/docs/verification/build-mark/self-test/validation.md b/docs/verification/build-mark/self-test/validation.md index 0e334e0..f2716ad 100644 --- a/docs/verification/build-mark/self-test/validation.md +++ b/docs/verification/build-mark/self-test/validation.md @@ -5,81 +5,42 @@ `Validation` is verified with dedicated unit tests in `ValidationTests.cs`. Tests construct a `Context` with controlled arguments, call `Validation.Run`, and assert on the created results files, console error output, and exit code. `MockRepoConnector` is provided as the connector -factory; no further mocking is required. - -#### Dependencies - -| Mock / Stub | Reason | -| ------------------- | --------------------------------------------------------------------- | -| `MockRepoConnector` | Supplies connector factory so self-check runs without network access. | +factory so the self-check runs without network access; no further mocking is required. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. `ValidationTests.cs` runs within the standard `dotnet test` host. +Tests create temporary result files using `TemporaryDirectory`; write access to the current working +directory is required. No network access or external API calls are made. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All tests in `ValidationTests.cs` pass with zero failures. +- TRX output, JUnit XML output, unsupported-format error, invalid-path error, and + no-results-file paths are all covered. #### Test Scenarios -##### Validation_Run_WithTrxResultsFile_WritesTrxFile - -**Scenario**: `Validation.Run` is called with `--validate --results /results.trx`; console -output is captured. - -**Expected**: `results.trx` is created; its content contains `TestRun` and -`BuildMark Self-Validation`. - -**Requirement coverage**: `BuildMark-Validation-Run`, `BuildMark-Validation-TrxOutput`. - -##### Validation_Run_WithXmlResultsFile_WritesJUnitFile - -**Scenario**: `Validation.Run` is called with `--validate --results /results.xml`; console -output is captured. - -**Expected**: `results.xml` is created; its content contains `testsuites` and -`BuildMark Self-Validation`. - -**Requirement coverage**: `BuildMark-Validation-Run`, `BuildMark-Validation-JUnitOutput`. - -##### Validation_Run_WithUnsupportedResultsFileExtension_ShowsError - -**Scenario**: `Validation.Run` is called with `--validate --results /results.json` -(unsupported extension); console error is captured. - -**Expected**: Console error contains `"Unsupported results file format"`; exit code is 1. - -**Requirement coverage**: `BuildMark-Validation-TrxOutput`, `BuildMark-Validation-JUnitOutput`. - -##### Validation_Run_WithInvalidResultsFilePath_ShowsError - -**Scenario**: `Validation.Run` is called with -`--validate --results /invalid_path_that_does_not_exist/results.trx`; console error is captured. - -**Expected**: Console error contains `"Failed to write results file"`; exit code is 1. - -**Requirement coverage**: `BuildMark-Validation-TrxOutput`. - -##### Validation_Run_WithoutResultsFile_CompletesSuccessfully - -**Scenario**: `Validation.Run` is called with `--validate --silent`; no `--results` argument is -supplied. - -**Expected**: Validation completes without error; exit code is 0. - -**Requirement coverage**: `BuildMark-Validation-Run`. - -#### Requirements Coverage - -- **`BuildMark-Validation-Run`**: - - Validation_Run_WithTrxResultsFile_WritesTrxFile - - Validation_Run_WithXmlResultsFile_WritesJUnitFile - - Validation_Run_WithoutResultsFile_CompletesSuccessfully -- **`BuildMark-Validation-TrxOutput`**: - - Validation_Run_WithTrxResultsFile_WritesTrxFile - - Validation_Run_WithUnsupportedResultsFileExtension_ShowsError - - Validation_Run_WithInvalidResultsFilePath_ShowsError -- **`BuildMark-Validation-JUnitOutput`**: - - Validation_Run_WithXmlResultsFile_WritesJUnitFile - - Validation_Run_WithUnsupportedResultsFileExtension_ShowsError +**Validation_Run_WithTrxResultsFile_WritesTrxFile**: Verifies that `Validation.Run` with +`--validate --results /results.trx` creates a `.trx` file whose content contains `TestRun` +and `BuildMark Self-Validation`, confirming TRX results output. +This scenario is tested by `Validation_Run_WithTrxResultsFile_WritesTrxFile`. + +**Validation_Run_WithXmlResultsFile_WritesJUnitFile**: Verifies that `Validation.Run` with +`--validate --results /results.xml` creates an `.xml` file whose content contains +`testsuites` and `BuildMark Self-Validation`, confirming JUnit XML results output. +This scenario is tested by `Validation_Run_WithXmlResultsFile_WritesJUnitFile`. + +**Validation_Run_WithUnsupportedResultsFileExtension_ShowsError**: Verifies that supplying a +`.json` results file path causes an error message containing "Unsupported results file format" +on stderr and sets the exit code to 1. +This scenario is tested by `Validation_Run_WithUnsupportedResultsFileExtension_ShowsError`. + +**Validation_Run_WithInvalidResultsFilePath_ShowsError**: Verifies that supplying an +inaccessible results file path causes an error message containing "Failed to write results file" +on stderr and sets the exit code to 1. +This scenario is tested by `Validation_Run_WithInvalidResultsFilePath_ShowsError`. + +**Validation_Run_WithoutResultsFile_CompletesSuccessfully**: Verifies that when no `--results` +argument is supplied, validation completes without error and the exit code is 0. +This scenario is tested by `Validation_Run_WithoutResultsFile_CompletesSuccessfully`. diff --git a/docs/verification/build-mark/utilities.md b/docs/verification/build-mark/utilities.md index 420ae48..abc1e26 100644 --- a/docs/verification/build-mark/utilities.md +++ b/docs/verification/build-mark/utilities.md @@ -1,162 +1,61 @@ ## Utilities -### Verification Strategy +### Verification Approach -The Utilities subsystem is verified through `PathHelpersTests.cs` (7 unit tests for -`PathHelpers`), `TemporaryDirectoryTests.cs` (7 unit tests for `TemporaryDirectory`), -and through `RepoConnectorsTests.cs` (for `ProcessRunner`). There is no -dedicated `UtilitiesTests.cs` subsystem file; unit coverage is provided by the -dedicated class-level test files described above. +The Utilities subsystem is verified through `UtilitiesTests.cs`, which contains six +integration tests. These tests exercise `PathHelpers.SafePathCombine` for valid path +handling and rejection of unsafe inputs, and they exercise `ProcessRunner.TryRunAsync` +and `ProcessRunner.RunAsync` for successful command execution and failure handling. -### Dependencies - -| Mock / Stub | Reason | -| ------------- | --------------------------------------------------------------------- | -| None required | `ProcessRunner` tests use real processes; `PathHelpers` is pure logic | +No mocks or stubs are required at the subsystem boundary because `ProcessRunner` uses +real OS processes and `PathHelpers` is pure logic. ### Test Environment -`ProcessRunner` tests invoke real OS commands (e.g., `git --version`) and therefore -require a working shell and a `git` executable on the host. Tests run on Windows, -Ubuntu, and macOS in the CI matrix. `PathHelpers` tests have no external dependencies. +`ProcessRunner` integration tests invoke real OS commands through portable shell +constructs (`cmd /c echo` on Windows and `echo` on Unix) and therefore require a +working shell on the host. Tests run on Windows, Ubuntu, and macOS in the CI matrix. +`PathHelpers` integration tests have no external dependencies. ### Acceptance Criteria -All `ProcessRunner` integration tests in `RepoConnectorsTests.cs` pass with zero -failures on all supported operating systems. All `BuildMark-Utilities-*` requirements -have at least one test in the Requirements Coverage mapping. - -### Test Scenarios (Integration) - -The following integration tests in `RepoConnectorsTests.cs` exercise `ProcessRunner`: - -#### RepoConnectors_ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput - -**Scenario**: `ProcessRunner.TryRunAsync` is called with a valid system command. - -**Expected**: Returns non-null output string from the process. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -#### RepoConnectors_ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull - -**Scenario**: `ProcessRunner.TryRunAsync` is called with an invalid/nonexistent command. - -**Expected**: Returns `null` rather than throwing. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -#### RepoConnectors_ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull - -**Scenario**: `ProcessRunner.TryRunAsync` is called with a command that exits non-zero. - -**Expected**: Returns `null` due to non-zero exit code. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -#### RepoConnectors_ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput - -**Scenario**: `ProcessRunner.RunAsync` is called with a valid command. - -**Expected**: Returns process output string. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -#### RepoConnectors_ProcessRunner_RunAsync_WithFailingCommand_ThrowsException - -**Scenario**: `ProcessRunner.RunAsync` is called with a command that fails. - -**Expected**: Throws an exception. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -### Test Scenarios (Unit) - -The following unit tests in `TemporaryDirectoryTests.cs` exercise `TemporaryDirectory`: - -#### TemporaryDirectory_Constructor_CreatesDirectory - -**Scenario**: A `TemporaryDirectory` instance is constructed. - -**Expected**: `DirectoryPath` refers to a directory that exists on disk. - -**Requirement coverage**: `BuildMark-Utilities-TemporaryDirectory` - -#### TemporaryDirectory_Constructor_CreatesUniqueDirectories - -**Scenario**: Two `TemporaryDirectory` instances are constructed in sequence. - -**Expected**: Each instance has a distinct `DirectoryPath`; neither directory collides -with the other. - -**Requirement coverage**: `BuildMark-Utilities-TemporaryDirectory` - -#### TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory - -**Scenario**: `GetFilePath` is called with a simple filename such as `"file.txt"`. - -**Expected**: Returns a path that starts with `DirectoryPath` and ends with the -supplied filename. - -**Requirement coverage**: `BuildMark-Utilities-TemporaryDirectory` - -#### TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories - -**Scenario**: `GetFilePath` is called with a nested relative path such as -`"sub/dir/file.txt"`. - -**Expected**: Returns the expected absolute path and the intermediate directory -`sub/dir` is created on disk. - -**Requirement coverage**: `BuildMark-Utilities-TemporaryDirectory` - -#### TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException - -**Scenario**: `GetFilePath` is called with a traversal path such as `"../outside.txt"`. - -**Expected**: `ArgumentException` is thrown; no file is created outside the temporary -directory. - -**Requirement coverage**: `BuildMark-Utilities-TemporaryDirectory` - -#### TemporaryDirectory_Dispose_DeletesDirectory - -**Scenario**: A `TemporaryDirectory` instance is disposed. - -**Expected**: The directory referred to by `DirectoryPath` no longer exists on disk -after `Dispose` returns. - -**Requirement coverage**: `BuildMark-Utilities-TemporaryDirectory` - -#### TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow - -**Scenario**: The temporary directory is manually deleted before `Dispose` is called. - -**Expected**: `Dispose` completes without throwing any exception. - -**Requirement coverage**: `BuildMark-Utilities-TemporaryDirectory` - -### Requirements Coverage - -- **BuildMark-Utilities-ProcessRunner**: - RepoConnectors_ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput, - RepoConnectors_ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull, - RepoConnectors_ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull, - RepoConnectors_ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput, - RepoConnectors_ProcessRunner_RunAsync_WithFailingCommand_ThrowsException -- **BuildMark-Utilities-PathHelpers**: - PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly, - PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException, - PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException, - PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException, - PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException, - PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException, - PathHelpers_SafePathCombine_PathStartingWithDots_CombinesCorrectly -- **BuildMark-Utilities-TemporaryDirectory**: - TemporaryDirectory_Constructor_CreatesDirectory, - TemporaryDirectory_Constructor_CreatesUniqueDirectories, - TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory, - TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories, - TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException, - TemporaryDirectory_Dispose_DeletesDirectory, - TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow +- All six tests in `UtilitiesTests.cs` pass with zero failures on all supported + operating systems. +- All `BuildMark-Utilities-*` requirements have at least one test in the ReqStream + trace matrix. + +### Test Scenarios + +**Valid paths combine correctly**: This scenario verifies that +`PathHelpers.SafePathCombine` accepts a valid base path and relative path, then returns +one combined path that ends with the expected relative portion. This scenario is tested +by `Utilities_SafePaths_ValidPaths_CombinesCorrectly`. + +**Traversal paths are rejected**: This scenario verifies that +`PathHelpers.SafePathCombine` rejects `"../../etc/passwd"` so path traversal cannot +escape the intended base path. The expected outcome is an `ArgumentException`. This +scenario is tested by `Utilities_SafePaths_TraversalPath_ThrowsException`. + +**Absolute paths are rejected**: This scenario verifies that +`PathHelpers.SafePathCombine` rejects a platform absolute path passed as the relative +argument so callers cannot bypass the base path restriction. The expected outcome is an +`ArgumentException`. This scenario is tested by +`Utilities_SafePaths_AbsolutePath_ThrowsException`. + +**Valid commands return output**: This scenario verifies that `ProcessRunner.RunAsync` +executes a portable echo command and returns non-null output containing the expected +text. This matters because the subsystem must capture command output correctly during +normal execution. This scenario is tested by +`Utilities_ProcessRunner_ValidCommand_ReturnsOutput`. + +**Invalid commands return null**: This scenario verifies that +`ProcessRunner.TryRunAsync` handles a non-existent command gracefully and returns `null` +without throwing. This matters because callers rely on the non-throwing path for +optional command execution. This scenario is tested by +`Utilities_ProcessRunner_InvalidCommand_ReturnsNull`. + +**Failing commands throw exceptions**: This scenario verifies that +`ProcessRunner.RunAsync` throws an `InvalidOperationException` containing +`"failed with exit code"` when a command exits with code 1. This matters because +callers must receive a clear failure signal for mandatory command execution. This +scenario is tested by `Utilities_ProcessRunner_FailingCommand_ThrowsException`. diff --git a/docs/verification/build-mark/utilities/path-helpers.md b/docs/verification/build-mark/utilities/path-helpers.md index 3310d1a..9cf3de5 100644 --- a/docs/verification/build-mark/utilities/path-helpers.md +++ b/docs/verification/build-mark/utilities/path-helpers.md @@ -2,98 +2,53 @@ #### Verification Approach -`PathHelpers` is a pure utility class. It is verified through dedicated unit tests in -`PathHelpersTests.cs`, which contains 7 tests covering valid path combination, null -argument rejection, path traversal prevention (double-dots), absolute path rejection, -and acceptance of valid dot-prefixed directory names such as `"..data"`. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Pure logic | +`PathHelpers` is a pure logic unit with no dependencies to mock or stub. It is verified through +`PathHelpersTests.cs`, which contains 7 unit tests covering valid path combination, null argument +rejection, path-traversal prevention, absolute path rejection, and acceptance of valid dot-prefixed +names such as `"..data"`. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. No external dependencies or environment setup required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 7 tests in `PathHelpersTests.cs` pass with zero failures. #### Test Scenarios -##### PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly - -**Scenario**: `PathHelpers.SafePathCombine` is called with a valid base path and a -relative path. - -**Expected**: Returns `Path.Combine(basePath, relativePath)`. - -**Requirement coverage**: `BuildMark-Utilities-PathHelpers` - -##### PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException - -**Scenario**: `PathHelpers.SafePathCombine` is called with a `null` base path. - -**Expected**: `ArgumentNullException` is thrown with `ParamName` equal to `"basePath"`. - -**Requirement coverage**: `BuildMark-Utilities-PathHelpers` - -##### PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException - -**Scenario**: `PathHelpers.SafePathCombine` is called with a `null` relative path. - -**Expected**: `ArgumentNullException` is thrown with `ParamName` equal to -`"relativePath"`. - -**Requirement coverage**: `BuildMark-Utilities-PathHelpers` - -##### PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException - -**Scenario**: `PathHelpers.SafePathCombine` is called with `"../etc/passwd"` as the -relative path. - -**Expected**: `ArgumentException` is thrown with a message containing -`"Invalid path component"`. - -**Requirement coverage**: `BuildMark-Utilities-PathHelpers` - -##### PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException - -**Scenario**: `PathHelpers.SafePathCombine` is called with `"subfolder/../../../etc/passwd"`. - -**Expected**: `ArgumentException` is thrown with a message containing -`"Invalid path component"`. - -**Requirement coverage**: `BuildMark-Utilities-PathHelpers` - -##### PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException - -**Scenario**: `PathHelpers.SafePathCombine` is called with an absolute path as the -relative argument. - -**Expected**: `ArgumentException` is thrown with a message containing -`"Invalid path component"`. - -**Requirement coverage**: `BuildMark-Utilities-PathHelpers` - -##### PathHelpers_SafePathCombine_PathStartingWithDots_CombinesCorrectly - -**Scenario**: `PathHelpers.SafePathCombine` is called with `"..data/file.txt"` (a valid -directory name that begins with dots but is not a traversal component). - -**Expected**: Returns `Path.Combine(basePath, "..data/file.txt")` without error. - -**Requirement coverage**: `BuildMark-Utilities-PathHelpers` - -#### Requirements Coverage - -- **BuildMark-Utilities-PathHelpers**: - PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly, - PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException, - PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException, - PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException, - PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException, - PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException, - PathHelpers_SafePathCombine_PathStartingWithDots_CombinesCorrectly +**PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly**: This scenario verifies that +`SafePathCombine` accepts a valid base path and relative path and returns +`Path.Combine(basePath, relativePath)`. This scenario is tested by +`PathHelpers_SafePathCombine_ValidPaths_CombinesCorrectly`. + +**PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException**: This scenario verifies +that a `null` base path is rejected so callers receive a clear contract violation with +`ParamName` set to `"basePath"`. This scenario is tested by +`PathHelpers_SafePathCombine_NullBasePath_ThrowsArgumentNullException`. + +**PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException**: This scenario +verifies that a `null` relative path is rejected so callers receive a clear contract violation with +`ParamName` set to `"relativePath"`. This scenario is tested by +`PathHelpers_SafePathCombine_NullRelativePath_ThrowsArgumentNullException`. + +**PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException**: This +scenario verifies that a traversal attempt such as `"../etc/passwd"` is rejected to prevent access +outside the intended base path. The expected outcome is an `ArgumentException` containing +`"Invalid path component"`. This scenario is tested by +`PathHelpers_SafePathCombine_PathTraversalWithDoubleDots_ThrowsArgumentException`. + +**PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException**: This scenario verifies +that traversal segments embedded within a longer relative path are also rejected. The expected +outcome is an `ArgumentException` containing `"Invalid path component"`. This scenario is tested by +`PathHelpers_SafePathCombine_DoubleDotsInMiddle_ThrowsArgumentException`. + +**PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException**: This scenario verifies that +an absolute path supplied as the relative argument is rejected so the caller cannot escape the base +path. The expected outcome is an `ArgumentException` containing `"Invalid path component"`. This +scenario is tested by `PathHelpers_SafePathCombine_AbsolutePath_ThrowsArgumentException`. + +**PathHelpers_SafePathCombine_PathStartingWithDots_CombinesCorrectly**: This scenario verifies +that a valid dot-prefixed directory name such as `"..data/file.txt"` is accepted when it is not a +traversal component. The expected outcome is successful combination without an exception. This +scenario is tested by `PathHelpers_SafePathCombine_PathStartingWithDots_CombinesCorrectly`. diff --git a/docs/verification/build-mark/utilities/process-runner.md b/docs/verification/build-mark/utilities/process-runner.md index 5c0ae79..8230f69 100644 --- a/docs/verification/build-mark/utilities/process-runner.md +++ b/docs/verification/build-mark/utilities/process-runner.md @@ -2,75 +2,57 @@ #### Verification Approach -`ProcessRunner` is tested through `RepoConnectorsTests.cs`. The five ProcessRunner -tests exercise `TryRunAsync` (which returns `null` on failure) and `RunAsync` (which -throws on failure) using real OS processes to confirm the process execution logic is -correct on the target operating system. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ----------------------------------------------------------- | -| None | Real OS processes are used to test actual process execution | +`ProcessRunner` has no mockable dependencies, so the unit tests use real OS processes to verify +actual command execution behavior. It is verified through `ProcessRunnerTests.cs`, which contains +7 unit tests covering `TryRunAsync` and `RunAsync` success paths, invalid commands, non-zero exit +codes, and exception handling by using portable echo and shell constructs. #### Test Environment -Tests invoke real OS processes. A working shell and `git` executable must be present on -the host. +Tests invoke real OS commands via portable shell constructs (`cmd /c echo` on Windows, `echo` on +Unix) and require a working shell on the host. Tests run on Windows, Ubuntu, and macOS in the CI +matrix. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 7 tests in `ProcessRunnerTests.cs` pass with zero failures on all supported operating + systems. #### Test Scenarios -##### RepoConnectors_ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput - -**Scenario**: `ProcessRunner.TryRunAsync` is called with a valid system command. - -**Expected**: Returns a non-null output string. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -##### RepoConnectors_ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull - -**Scenario**: `ProcessRunner.TryRunAsync` is called with an invalid command name. - -**Expected**: Returns `null` without throwing. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -##### RepoConnectors_ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull - -**Scenario**: `ProcessRunner.TryRunAsync` is called with a command that exits with -a non-zero code. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -##### RepoConnectors_ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput - -**Scenario**: `ProcessRunner.RunAsync` is called with a valid command. - -**Expected**: Returns the process standard output as a string. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -##### RepoConnectors_ProcessRunner_RunAsync_WithFailingCommand_ThrowsException - -**Scenario**: `ProcessRunner.RunAsync` is called with a command that returns a -non-zero exit code. - -**Expected**: An exception is thrown. - -**Requirement coverage**: `BuildMark-Utilities-ProcessRunner` - -#### Requirements Coverage - -- **BuildMark-Utilities-ProcessRunner**: - RepoConnectors_ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput, - RepoConnectors_ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull, - RepoConnectors_ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull, - RepoConnectors_ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput, - RepoConnectors_ProcessRunner_RunAsync_WithFailingCommand_ThrowsException +**ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput**: This scenario verifies that +`TryRunAsync` returns captured standard output when a valid portable echo command succeeds. This +matters because callers use `TryRunAsync` as the non-throwing execution path for optional process +work. This scenario is tested by `ProcessRunner_TryRunAsync_WithValidCommand_ReturnsOutput`. + +**ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull**: This scenario verifies that +`TryRunAsync` returns `null` instead of throwing when the command does not exist. This matters +because the method is expected to absorb lookup failures and report them through a null result. This +scenario is tested by `ProcessRunner_TryRunAsync_WithInvalidCommand_ReturnsNull`. + +**ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull**: This scenario verifies that +`TryRunAsync` returns `null` when a process starts but exits with a non-zero exit code. This +matters because callers should be able to treat command failure as an absent result without +exception handling. This scenario is tested by +`ProcessRunner_TryRunAsync_WithNonZeroExitCode_ReturnsNull`. + +**ProcessRunner_TryRunAsync_WithException_ReturnsNull**: This scenario verifies that +`TryRunAsync` catches internal execution exceptions, such as an empty command name, and returns +`null` rather than propagating the failure. This scenario is tested by +`ProcessRunner_TryRunAsync_WithException_ReturnsNull`. + +**ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput**: This scenario verifies that `RunAsync` +returns captured standard output for a successful portable echo command. This matters because +`RunAsync` is the strict execution path that should preserve successful process output. This +scenario is tested by `ProcessRunner_RunAsync_WithValidCommand_ReturnsOutput`. + +**ProcessRunner_RunAsync_WithFailingCommand_ThrowsException**: This scenario verifies that +`RunAsync` throws an `InvalidOperationException` when a command exits with a non-zero exit code. +This matters because callers rely on `RunAsync` to surface execution failures explicitly. This +scenario is tested by `ProcessRunner_RunAsync_WithFailingCommand_ThrowsException`. + +**ProcessRunner_RunAsync_WithNonexistentCommand_ThrowsDescriptiveException**: This scenario +verifies that `RunAsync` throws an `InvalidOperationException` that identifies the missing command +when process startup fails. This matters because the caller needs a descriptive error for diagnosis. +This scenario is tested by +`ProcessRunner_RunAsync_WithNonexistentCommand_ThrowsDescriptiveException`. diff --git a/docs/verification/build-mark/utilities/temporary-directory.md b/docs/verification/build-mark/utilities/temporary-directory.md index f39c739..bedd5e3 100644 --- a/docs/verification/build-mark/utilities/temporary-directory.md +++ b/docs/verification/build-mark/utilities/temporary-directory.md @@ -2,101 +2,55 @@ #### Verification Approach -`TemporaryDirectory` is verified through dedicated unit tests in -`TemporaryDirectoryTests.cs`, which contains 7 tests covering directory creation, -uniqueness, path resolution, intermediate-directory creation, traversal prevention, +`TemporaryDirectory` uses the real file system, so no dependencies are mocked or stubbed. It is +verified through `TemporaryDirectoryTests.cs`, which contains 7 unit tests covering directory +creation, uniqueness, path resolution, intermediate-directory creation, traversal prevention, disposal cleanup, and idempotent disposal when the directory has already been deleted. -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------------------------------------------------------- | -| None | Tests use the real file system under a temporary directory | - #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. -Tests create and delete real directories on the host file system. +N/A - standard dotnet test host. No external dependencies or environment setup are required. Tests +create and delete real directories on the host file system. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 7 tests in `TemporaryDirectoryTests.cs` pass with zero failures. #### Test Scenarios -##### TemporaryDirectory_Constructor_CreatesDirectory - -**Scenario**: A `TemporaryDirectory` instance is constructed. - -**Expected**: `DirectoryPath` refers to a directory that exists on disk. - -**Requirement coverage**: `BuildMark-TemporaryDirectory-Creation` - -##### TemporaryDirectory_Constructor_CreatesUniqueDirectories - -**Scenario**: Two `TemporaryDirectory` instances are constructed in sequence. - -**Expected**: Each instance has a distinct `DirectoryPath`; neither directory collides -with the other. - -**Requirement coverage**: `BuildMark-TemporaryDirectory-Creation` - -##### TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory - -**Scenario**: `GetFilePath` is called with a simple filename such as `"file.txt"`. - -**Expected**: Returns a path that starts with `DirectoryPath` and ends with the -supplied filename. - -**Requirement coverage**: `BuildMark-TemporaryDirectory-FilePath` - -##### TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories - -**Scenario**: `GetFilePath` is called with a nested relative path such as -`"sub/dir/file.txt"`. - -**Expected**: Returns the expected absolute path and the intermediate directory -`sub/dir` is created on disk. - -**Requirement coverage**: `BuildMark-TemporaryDirectory-FilePath` - -##### TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException - -**Scenario**: `GetFilePath` is called with a traversal path such as -`"../outside.txt"`. - -**Expected**: `ArgumentException` is thrown; no file is created outside the -temporary directory. - -**Requirement coverage**: `BuildMark-TemporaryDirectory-Traversal` - -##### TemporaryDirectory_Dispose_DeletesDirectory - -**Scenario**: A `TemporaryDirectory` instance is disposed. - -**Expected**: The directory referred to by `DirectoryPath` no longer exists on disk -after `Dispose` returns. - -**Requirement coverage**: `BuildMark-TemporaryDirectory-Cleanup` - -##### TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow - -**Scenario**: The temporary directory is manually deleted before `Dispose` is called. - -**Expected**: `Dispose` completes without throwing any exception. - -**Requirement coverage**: `BuildMark-TemporaryDirectory-Cleanup` - -#### Requirements Coverage - -- **BuildMark-TemporaryDirectory-Creation**: - TemporaryDirectory_Constructor_CreatesDirectory, - TemporaryDirectory_Constructor_CreatesUniqueDirectories -- **BuildMark-TemporaryDirectory-FilePath**: - TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory, - TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories -- **BuildMark-TemporaryDirectory-Traversal**: - TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException -- **BuildMark-TemporaryDirectory-Cleanup**: - TemporaryDirectory_Dispose_DeletesDirectory, - TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow +**TemporaryDirectory_Constructor_CreatesDirectory**: This scenario verifies that constructing a +`TemporaryDirectory` immediately creates a backing directory on disk. This matters because later +operations depend on `DirectoryPath` referring to an existing location. This scenario is tested by +`TemporaryDirectory_Constructor_CreatesDirectory`. + +**TemporaryDirectory_Constructor_CreatesUniqueDirectories**: This scenario verifies that two +instances created in sequence receive distinct directory paths with no collision. This matters +because each test or caller must get an isolated workspace. This scenario is tested by +`TemporaryDirectory_Constructor_CreatesUniqueDirectories`. + +**TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory**: This scenario verifies +that `GetFilePath("output.md")` returns a path rooted under `DirectoryPath` and ending with the +requested file name. This matters because callers rely on the helper to keep files inside the +temporary workspace. This scenario is tested by +`TemporaryDirectory_GetFilePath_SimpleFile_ReturnsPathUnderDirectory`. + +**TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories**: This scenario +verifies that `GetFilePath` accepts a nested relative path, returns the expected absolute path, and +creates the intermediate `sub/nested` directories on disk. This scenario is tested by +`TemporaryDirectory_GetFilePath_NestedPath_CreatesIntermediateDirectories`. + +**TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException**: This scenario +verifies that a traversal attempt such as `"../escaped.txt"` is rejected with an +`ArgumentException`. This matters because the helper must not allow file creation outside the +temporary directory. This scenario is tested by +`TemporaryDirectory_GetFilePath_TraversalAttempt_ThrowsArgumentException`. + +**TemporaryDirectory_Dispose_DeletesDirectory**: This scenario verifies that disposing the +instance removes the temporary directory and its contents from disk. This matters because the class +must clean up temporary artifacts reliably. This scenario is tested by +`TemporaryDirectory_Dispose_DeletesDirectory`. + +**TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow**: This scenario verifies that `Dispose` +remains safe when the directory has already been deleted manually. This matters because cleanup code +should be idempotent and resilient to prior deletion. This scenario is tested by +`TemporaryDirectory_Dispose_AlreadyDeleted_DoesNotThrow`. diff --git a/docs/verification/build-mark/version.md b/docs/verification/build-mark/version.md index c011e33..bc9ddf6 100644 --- a/docs/verification/build-mark/version.md +++ b/docs/verification/build-mark/version.md @@ -1,116 +1,66 @@ ## Version -### Verification Strategy +### Verification Approach -The Version subsystem is verified through `VersionTests.cs` (subsystem integration -tests), plus dedicated unit test files for each version class. The subsystem tests -exercise the interaction between version types - creating `VersionTag` instances, -extracting `VersionComparable`, and comparing via `VersionInterval`. The unit tests -are described in the individual unit chapters. - -### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Pure logic | +The Version subsystem is verified through `VersionTests.cs` with 8 integration tests. The tests +exercise all version type factory methods and constructors, semantic versioning precedence ordering, +and cross-type integration between `VersionTag` and `VersionComparable`. No mocks or stubs are +required — all version types are pure logic with no external dependencies. ### Test Environment -N/A - standard test environment. `VersionTests.cs` contains pure logic tests with no +N/A - standard test environment. All tests in `VersionTests.cs` are pure logic tests with no external dependencies, network access, or file system requirements. ### Acceptance Criteria -All tests in `VersionTests.cs` pass with zero failures. All `BuildMark-Version-*` -requirements have at least one test in the Requirements Coverage mapping. +- All 8 tests in `VersionTests.cs` pass with zero failures. +- All `BuildMark-Version-*` requirements have at least one test in the ReqStream trace matrix. ### Test Scenarios -#### VersionComparable_Create_ValidVersions_ReturnsVersionComparable - -**Scenario**: `VersionComparable.Create` is called with a valid version string. - -**Expected**: Returns a non-null `VersionComparable` instance. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -#### VersionSemantic_Create_ValidSemanticVersion_ReturnsVersionSemantic - -**Scenario**: `VersionSemantic.Create` is called with a valid semantic version string. - -**Expected**: Returns a non-null `VersionSemantic` instance. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -#### VersionTag_Create_ValidTag_ReturnsVersionTag - -**Scenario**: `VersionTag.Create` is called with a valid tag string. - -**Expected**: Returns a non-null `VersionTag` instance. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -#### VersionInterval_Create_ValidInterval_ReturnsVersionInterval - -**Scenario**: `VersionInterval.Parse` is called with a valid interval string. - -**Expected**: Returns a non-null `VersionInterval` instance. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -#### VersionIntervalSet_Parse_SingleInterval_ReturnsOneInterval - -**Scenario**: `VersionIntervalSet.Parse` is called with a single interval string. - -**Expected**: Returns a set containing exactly one `VersionInterval`. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -#### VersionCommitTag_Constructor_ValidParameters_CreatesInstance - -**Scenario**: `VersionCommitTag` is constructed with a valid tag and commit hash. - -**Expected**: Instance is created with the provided tag and commit hash properties set. - -**Requirement coverage**: `BuildMark-Version-VersionCommitTag` - -#### Version_Subsystem_CreateAllVersionTypes_WorksCorrectly - -**Scenario**: All version type factory methods are invoked in sequence. - -**Expected**: All instances are created without error. - -**Requirement coverage**: `BuildMark-Version-VersionComparable`, `BuildMark-Version-VersionSemantic`, -`BuildMark-Version-VersionTag` - -#### Version_Subsystem_SemanticVersioningCompliance_WorksCorrectly - -**Scenario**: Version strings from the semver specification are parsed and compared. - -**Expected**: Ordering follows the semver specification. - -**Requirement coverage**: `BuildMark-Version-VersionComparable`, `BuildMark-Version-VersionSemantic` - -#### Version_Subsystem_TagToComparableIntegration_WorksCorrectly - -**Scenario**: A `VersionTag` is created and its comparable representation is extracted. - -**Expected**: The `VersionComparable` extracted from the tag matches the expected version. - -**Requirement coverage**: `BuildMark-Version-VersionTag`, `BuildMark-Version-VersionComparable` - -### Requirements Coverage - -- **BuildMark-Version-VersionComparable**: VersionComparable_Create_ValidVersions_ReturnsVersionComparable, - Version_Subsystem_CreateAllVersionTypes_WorksCorrectly, - Version_Subsystem_SemanticVersioningCompliance_WorksCorrectly, - Version_Subsystem_TagToComparableIntegration_WorksCorrectly -- **BuildMark-Version-VersionSemantic**: VersionSemantic_Create_ValidSemanticVersion_ReturnsVersionSemantic, - Version_Subsystem_CreateAllVersionTypes_WorksCorrectly, - Version_Subsystem_SemanticVersioningCompliance_WorksCorrectly -- **BuildMark-Version-VersionTag**: VersionTag_Create_ValidTag_ReturnsVersionTag, - Version_Subsystem_CreateAllVersionTypes_WorksCorrectly, - Version_Subsystem_TagToComparableIntegration_WorksCorrectly -- **BuildMark-Version-VersionInterval**: VersionInterval_Create_ValidInterval_ReturnsVersionInterval -- **BuildMark-Version-VersionIntervalSet**: VersionIntervalSet_Parse_SingleInterval_ReturnsOneInterval -- **BuildMark-Version-VersionCommitTag**: VersionCommitTag_Constructor_ValidParameters_CreatesInstance +**VersionComparable_Create_ValidVersions_ReturnsVersionComparable**: Verifies that +`VersionComparable.Create` accepts valid version strings — a simple `major.minor.patch` version, a +pre-release version, and a complex pre-release — returning a non-null `VersionComparable` instance +for each input. +This scenario is tested by `VersionComparable_Create_ValidVersions_ReturnsVersionComparable`. + +**VersionSemantic_Create_ValidSemanticVersion_ReturnsVersionSemantic**: Verifies that +`VersionSemantic.Create` accepts a simple version, a version with build metadata, and a complex +version combining pre-release and build metadata, returning a non-null `VersionSemantic` instance +for each input. +This scenario is tested by `VersionSemantic_Create_ValidSemanticVersion_ReturnsVersionSemantic`. + +**VersionTag_Create_ValidTag_ReturnsVersionTag**: Verifies that `VersionTag.Create` correctly parses +a plain version string, a `v`-prefixed version, and a release-prefixed pre-release tag, returning a +non-null `VersionTag` instance for each input. +This scenario is tested by `VersionTag_Create_ValidTag_ReturnsVersionTag`. + +**VersionInterval_Create_ValidInterval_ReturnsVersionInterval**: Verifies that `VersionInterval` can +be constructed with fully-inclusive bounds, fully-exclusive bounds, and mixed lower/upper bounds, +returning a non-null instance for each construction. +This scenario is tested by `VersionInterval_Create_ValidInterval_ReturnsVersionInterval`. + +**VersionCommitTag_Constructor_ValidParameters_CreatesInstance**: Verifies that `VersionCommitTag` +constructed with a `VersionTag` and a commit hash string exposes the supplied values through its +`VersionTag` and `CommitHash` properties. +This scenario is tested by `VersionCommitTag_Constructor_ValidParameters_CreatesInstance`. + +**Version_Subsystem_CreateAllVersionTypes_WorksCorrectly**: Verifies that all version type factory +methods and constructors — `VersionComparable.Create`, `VersionSemantic.Create`, +`VersionTag.Create`, `new VersionInterval`, and `new VersionCommitTag` — can be invoked in +sequence without error, and that the resulting instances expose the supplied values through their +properties. +This scenario is tested by `Version_Subsystem_CreateAllVersionTypes_WorksCorrectly`. + +**Version_Subsystem_SemanticVersioningCompliance_WorksCorrectly**: Verifies that a sequence of +`VersionComparable` instances representing the SemVer 2.0.0 precedence chain +`1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta < 1.0.0-beta < 1.0.0-beta.2 < 1.0.0` produces a +negative value from `CompareTo` for each adjacent pair, confirming correct precedence ordering. +This scenario is tested by `Version_Subsystem_SemanticVersioningCompliance_WorksCorrectly`. + +**Version_Subsystem_TagToComparableIntegration_WorksCorrectly**: Verifies that `VersionTag` +instances created from prefix forms `v1.2.3`, `VER2.0.0-rc.1`, and `release-1.5.0` each yield a +`VersionComparable` via `Semantic.Comparable`, and that the ordering +`1.2.3 < 1.5.0 < 2.0.0-rc.1` holds, confirming correct tag-to-comparable integration. +This scenario is tested by `Version_Subsystem_TagToComparableIntegration_WorksCorrectly`. diff --git a/docs/verification/build-mark/version/version-commit-tag.md b/docs/verification/build-mark/version/version-commit-tag.md index 9887441..59965f0 100644 --- a/docs/verification/build-mark/version/version-commit-tag.md +++ b/docs/verification/build-mark/version/version-commit-tag.md @@ -2,36 +2,25 @@ #### Verification Approach -`VersionCommitTag` is a simple data class with no dedicated test class. It is verified -through `VersionTests.cs` via the test -`VersionCommitTag_Constructor_ValidParameters_CreatesInstance`, which constructs an -instance and asserts that the tag and commit-hash properties are stored correctly. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Data class | +`VersionCommitTag` is a simple data record. It has no external dependencies and no +dependencies to mock or stub. It is verified through the subsystem integration test in +`VersionTests.cs` via `VersionCommitTag_Constructor_ValidParameters_CreatesInstance`, +which constructs an instance and asserts that the version-tag and commit-hash properties are +stored correctly. No dedicated unit test class exists for this unit. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. No external dependencies or environment setup required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- `VersionCommitTag_Constructor_ValidParameters_CreatesInstance` in `VersionTests.cs` + passes with zero failures. #### Test Scenarios -##### VersionCommitTag_Constructor_ValidParameters_CreatesInstance - -**Scenario**: `VersionCommitTag` is constructed with a `VersionTag` and a commit hash -string. - -**Expected**: The `Tag` and `CommitHash` properties return the supplied values. - -**Requirement coverage**: `BuildMark-Version-VersionCommitTag` - -#### Requirements Coverage - -- **BuildMark-Version-VersionCommitTag**: VersionCommitTag_Constructor_ValidParameters_CreatesInstance +**VersionCommitTag_Constructor_ValidParameters_CreatesInstance**: `VersionCommitTag` is +constructed with a `VersionTag` and a commit hash string. The `VersionTag` and +`CommitHash` properties return the supplied values, confirming the data record stores its +constructor arguments unchanged. This scenario is tested by +`VersionCommitTag_Constructor_ValidParameters_CreatesInstance`. diff --git a/docs/verification/build-mark/version/version-comparable.md b/docs/verification/build-mark/version/version-comparable.md index a4e4122..06b1d81 100644 --- a/docs/verification/build-mark/version/version-comparable.md +++ b/docs/verification/build-mark/version/version-comparable.md @@ -2,235 +2,131 @@ #### Verification Approach -`VersionComparable` is tested through `VersionComparableTests.cs`, which contains -26 unit tests. The tests cover creation (valid, invalid, null, empty), comparison -operators, and numeric-vs-lexicographic pre-release ordering rules that follow the -Semantic Versioning specification. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Pure logic | +`VersionComparable` is a pure logic unit with no external dependencies, so no mocks or stubs are +needed. The unit is exercised through `VersionComparableTests.cs`, which contains 26 unit tests +covering creation through `Create` and `TryCreate`, invalid, null, and empty input handling, the +four comparison operators, and Semantic Versioning pre-release ordering rules. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. No external dependencies or environment setup required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 26 tests in `VersionComparableTests.cs` pass with zero failures. #### Test Scenarios -##### VersionComparable_Create_ValidVersion_ReturnsInstance - -**Scenario**: `VersionComparable.Create` is called with a valid version string. - -**Expected**: Returns a non-null instance. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_Create_SimpleVersion_ParsesVersion - -**Scenario**: `VersionComparable.Create` is called with a simple `major.minor.patch` string. - -**Expected**: Major, minor, and patch properties reflect parsed values. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_Create_PreReleaseVersion_ParsesVersion - -**Scenario**: `VersionComparable.Create` is called with a pre-release version string. - -**Expected**: Pre-release identifiers are parsed correctly. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_TryCreate_InvalidVersion_ReturnsNull - -**Scenario**: `VersionComparable.TryCreate` is called with an invalid version string. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_TryCreate_NullInput_ReturnsNull - -**Scenario**: `VersionComparable.TryCreate` is called with a `null` argument. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_TryCreate_EmptyInput_ReturnsNull - -**Scenario**: `VersionComparable.TryCreate` is called with an empty string. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_Create_InvalidVersion_ThrowsArgumentException - -**Scenario**: `VersionComparable.Create` is called with an invalid version string. - -**Expected**: `ArgumentException` is thrown. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_SameMajorMinorPatch_ReturnsZero - -**Scenario**: Two instances with identical major.minor.patch are compared. - -**Expected**: `CompareTo` returns 0. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_DifferentMajor_ReturnsCorrectOrder - -**Scenario**: Two instances with different major versions are compared. - -**Expected**: Higher major version compares as greater. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_DifferentMinor_ReturnsCorrectOrder - -**Scenario**: Two instances with different minor versions are compared. - -**Expected**: Higher minor version compares as greater. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_DifferentPatch_ReturnsCorrectOrder - -**Scenario**: Two instances with different patch versions are compared. - -**Expected**: Higher patch version compares as greater. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_PreReleaseVsRelease_ReturnsCorrectOrder - -**Scenario**: A pre-release version is compared to its release counterpart. - -**Expected**: Pre-release is less than release per semver rules. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_PreReleaseVersions_ReturnsLexicographicOrder - -**Scenario**: Two pre-release versions with non-numeric identifiers are compared. - -**Expected**: Comparison follows lexicographic order. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_Operators_LessThan_WorksCorrectly - -**Scenario**: The `<` operator is applied to two version instances. - -**Expected**: Returns the correct boolean result. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_Operators_GreaterThan_WorksCorrectly - -**Scenario**: The `>` operator is applied to two version instances. - -**Expected**: Returns the correct boolean result. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_Operators_LessThanOrEqual_WorksCorrectly - -**Scenario**: The `<=` operator is applied to two version instances. - -**Expected**: Returns the correct boolean result. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_Operators_GreaterThanOrEqual_WorksCorrectly - -**Scenario**: The `>=` operator is applied to two version instances. - -**Expected**: Returns the correct boolean result. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_SemanticVersions_ReturnsCorrectOrder - -**Scenario**: A series of semver-compliant versions is compared. - -**Expected**: Ordering matches the semver specification. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_NumericComparison_CorrectOrdering - -**Scenario**: Numeric pre-release identifiers are compared. - -**Expected**: Numeric comparison is used (11 > 9). - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_ReleaseGreaterThanPreRelease_CorrectOrdering - -**Scenario**: Release version `1.0.0` is compared to `1.0.0-alpha`. - -**Expected**: Release is greater than pre-release. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_PreReleaseLexicographic_CorrectOrdering - -**Scenario**: Pre-release identifiers with alphabetic content are compared. - -**Expected**: Lexicographic ordering is applied. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_PreReleaseNumeric_ComparesNumerically - -**Scenario**: Pre-release identifiers that are purely numeric are compared. - -**Expected**: Numeric comparison is used. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_PreReleaseSemVerRules_CorrectOrdering - -**Scenario**: Pre-release versions are compared following all semver rules. - -**Expected**: Ordering matches semver 2.0.0 specification section 11. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_NumericVsNonNumeric_NumericIsLess - -**Scenario**: A numeric pre-release identifier is compared to a non-numeric one. - -**Expected**: Numeric identifier has lower precedence. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_ShorterPreRelease_IsLess - -**Scenario**: Two pre-release versions with different numbers of identifiers are compared. - -**Expected**: Shorter pre-release is less than longer when all common fields are equal. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -##### VersionComparable_CompareTo_ComplexPreRelease_CorrectOrdering - -**Scenario**: Complex multi-identifier pre-release versions are compared. - -**Expected**: Correct ordering following semver field-by-field rules. - -**Requirement coverage**: `BuildMark-Version-VersionComparable` - -#### Requirements Coverage - -- **BuildMark-Version-VersionComparable**: All 26 tests in `VersionComparableTests.cs` +**VersionComparable_Create_ValidVersion_ReturnsInstance**: This scenario verifies that creating a +comparable version from a valid version string succeeds and returns a non-null instance. This +scenario is tested by `VersionComparable_Create_ValidVersion_ReturnsInstance`. + +**VersionComparable_Create_SimpleVersion_ParsesVersion**: This scenario verifies that a simple +`major.minor.patch` version string is parsed into the expected numeric properties so later +comparisons use the correct values. This scenario is tested by +`VersionComparable_Create_SimpleVersion_ParsesVersion`. + +**VersionComparable_Create_PreReleaseVersion_ParsesVersion**: This scenario verifies that a +pre-release version string is parsed correctly so pre-release identifiers participate in ordering as +intended. This scenario is tested by `VersionComparable_Create_PreReleaseVersion_ParsesVersion`. + +**VersionComparable_TryCreate_InvalidVersion_ReturnsNull**: This scenario verifies that +`TryCreate` rejects an invalid version string without throwing and reports the failure with a null +result. This scenario is tested by `VersionComparable_TryCreate_InvalidVersion_ReturnsNull`. + +**VersionComparable_TryCreate_NullInput_ReturnsNull**: This scenario verifies that `TryCreate` +handles a null input safely and returns null instead of creating an invalid instance. This scenario +is tested by `VersionComparable_TryCreate_NullInput_ReturnsNull`. + +**VersionComparable_TryCreate_EmptyInput_ReturnsNull**: This scenario verifies that `TryCreate` +rejects an empty version string and returns null so empty input does not enter comparison logic. +This scenario is tested by `VersionComparable_TryCreate_EmptyInput_ReturnsNull`. + +**VersionComparable_Create_InvalidVersion_ThrowsArgumentException**: This scenario verifies that +`Create` fails fast for an invalid version string by throwing `ArgumentException`, which protects +callers that require a valid instance. This scenario is tested by +`VersionComparable_Create_InvalidVersion_ThrowsArgumentException`. + +**VersionComparable_CompareTo_SameMajorMinorPatch_ReturnsZero**: This scenario verifies that two +versions with the same major, minor, and patch values compare as equal so equality checks remain +stable. This scenario is tested by +`VersionComparable_CompareTo_SameMajorMinorPatch_ReturnsZero`. + +**VersionComparable_CompareTo_DifferentMajor_ReturnsCorrectOrder**: This scenario verifies that a +higher major version compares as greater, which is the highest-priority numeric ordering rule. +This scenario is tested by `VersionComparable_CompareTo_DifferentMajor_ReturnsCorrectOrder`. + +**VersionComparable_CompareTo_DifferentMinor_ReturnsCorrectOrder**: This scenario verifies that a +higher minor version compares as greater when the major version matches, preserving expected semver +ordering. This scenario is tested by `VersionComparable_CompareTo_DifferentMinor_ReturnsCorrectOrder`. + +**VersionComparable_CompareTo_DifferentPatch_ReturnsCorrectOrder**: This scenario verifies that a +higher patch version compares as greater when major and minor values match. This scenario is tested +by `VersionComparable_CompareTo_DifferentPatch_ReturnsCorrectOrder`. + +**VersionComparable_CompareTo_PreReleaseVsRelease_ReturnsCorrectOrder**: This scenario verifies +that a pre-release version sorts before the corresponding release version, which is a core Semantic +Versioning rule. This scenario is tested by +`VersionComparable_CompareTo_PreReleaseVsRelease_ReturnsCorrectOrder`. + +**VersionComparable_CompareTo_PreReleaseVersions_ReturnsLexicographicOrder**: This scenario +verifies that non-numeric pre-release identifiers are compared lexicographically so alphabetic +labels sort correctly. This scenario is tested by +`VersionComparable_CompareTo_PreReleaseVersions_ReturnsLexicographicOrder`. + +**VersionComparable_Operators_LessThan_WorksCorrectly**: This scenario verifies that the `<` +operator returns the expected boolean result so callers can use natural relational syntax. This +scenario is tested by `VersionComparable_Operators_LessThan_WorksCorrectly`. + +**VersionComparable_Operators_GreaterThan_WorksCorrectly**: This scenario verifies that the `>` +operator returns the expected boolean result for comparable versions. This scenario is tested by +`VersionComparable_Operators_GreaterThan_WorksCorrectly`. + +**VersionComparable_Operators_LessThanOrEqual_WorksCorrectly**: This scenario verifies that the +`<=` operator returns the expected boolean result for equal and lower versions. This scenario is +tested by `VersionComparable_Operators_LessThanOrEqual_WorksCorrectly`. + +**VersionComparable_Operators_GreaterThanOrEqual_WorksCorrectly**: This scenario verifies that the +`>=` operator returns the expected boolean result for equal and greater versions. This scenario is +tested by `VersionComparable_Operators_GreaterThanOrEqual_WorksCorrectly`. + +**VersionComparable_CompareTo_SemanticVersions_ReturnsCorrectOrder**: This scenario verifies that +an ordered series of semantic versions follows the precedence rules defined by the specification. +This scenario is tested by `VersionComparable_CompareTo_SemanticVersions_ReturnsCorrectOrder`. + +**VersionComparable_CompareTo_NumericComparison_CorrectOrdering**: This scenario verifies that +numeric pre-release identifiers are compared numerically rather than lexicographically, so `11` +sorts after `9`. This scenario is tested by +`VersionComparable_CompareTo_NumericComparison_CorrectOrdering`. + +**VersionComparable_CompareTo_ReleaseGreaterThanPreRelease_CorrectOrdering**: This scenario +verifies the inverse release-versus-pre-release comparison and confirms the release version has +higher precedence. This scenario is tested by +`VersionComparable_CompareTo_ReleaseGreaterThanPreRelease_CorrectOrdering`. + +**VersionComparable_CompareTo_PreReleaseLexicographic_CorrectOrdering**: This scenario verifies +that alphabetic pre-release identifiers use lexicographic ordering when compared to one another. +This scenario is tested by `VersionComparable_CompareTo_PreReleaseLexicographic_CorrectOrdering`. + +**VersionComparable_CompareTo_PreReleaseNumeric_ComparesNumerically**: This scenario verifies that +purely numeric pre-release identifiers use integer comparison so numeric precedence is preserved. +This scenario is tested by `VersionComparable_CompareTo_PreReleaseNumeric_ComparesNumerically`. + +**VersionComparable_CompareTo_PreReleaseSemVerRules_CorrectOrdering**: This scenario verifies that +full pre-release precedence matches Semantic Versioning 2.0.0 section 11 for representative +examples. This scenario is tested by +`VersionComparable_CompareTo_PreReleaseSemVerRules_CorrectOrdering`. + +**VersionComparable_CompareTo_NumericVsNonNumeric_NumericIsLess**: This scenario verifies that a +numeric pre-release identifier has lower precedence than a non-numeric identifier at the same +position. This scenario is tested by +`VersionComparable_CompareTo_NumericVsNonNumeric_NumericIsLess`. + +**VersionComparable_CompareTo_ShorterPreRelease_IsLess**: This scenario verifies that when common +pre-release identifiers are equal, the shorter identifier list has lower precedence. This scenario +is tested by `VersionComparable_CompareTo_ShorterPreRelease_IsLess`. + +**VersionComparable_CompareTo_ComplexPreRelease_CorrectOrdering**: This scenario verifies that +multi-part pre-release identifiers are compared field by field so complex semantic versions sort +correctly. This scenario is tested by +`VersionComparable_CompareTo_ComplexPreRelease_CorrectOrdering`. diff --git a/docs/verification/build-mark/version/version-interval-set.md b/docs/verification/build-mark/version/version-interval-set.md index 047050b..50896d1 100644 --- a/docs/verification/build-mark/version/version-interval-set.md +++ b/docs/verification/build-mark/version/version-interval-set.md @@ -2,135 +2,79 @@ #### Verification Approach -`VersionIntervalSet` is tested through `VersionIntervalSetTests.cs`, which contains -13 unit tests. The tests cover parsing single and multiple intervals, handling of -internal commas in interval strings, empty input, discarding invalid tokens, and -`Contains` checks for strings, `VersionTag` instances, pre-release versions, and -`VersionComparable` instances. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Pure logic | +`VersionIntervalSet` is a pure logic unit with no external dependencies, so no mocks or stubs are +needed. The unit is exercised through `VersionIntervalSetTests.cs`, which contains 13 unit tests +covering parsing of single and multiple intervals, handling of internal commas within interval +expressions, empty input, silent discarding of invalid tokens, and `Contains` checks for strings, +`VersionTag`, pre-release versions, and `VersionComparable` values. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. No external dependencies or environment setup required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 13 tests in `VersionIntervalSetTests.cs` pass with zero failures. #### Test Scenarios -##### VersionIntervalSet_Parse_SingleInterval_ReturnsOneInterval - -**Scenario**: `VersionIntervalSet.Parse` is called with a single interval string. - -**Expected**: Returns a set containing one interval. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Parse_TwoIntervals_ReturnsTwoIntervals - -**Scenario**: `VersionIntervalSet.Parse` is called with two comma-separated intervals. - -**Expected**: Returns a set containing two intervals. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Parse_IntervalsWithInternalComma_ParsedCorrectly - -**Scenario**: `VersionIntervalSet.Parse` is called with an interval string that -contains a comma as the separator between lower and upper bound. - -**Expected**: Each interval is parsed as a unit; internal commas do not split intervals. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Parse_EmptyString_ReturnsEmptySet - -**Scenario**: `VersionIntervalSet.Parse` is called with an empty string. - -**Expected**: Returns an empty set. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Parse_InvalidToken_DiscardedSilently - -**Scenario**: `VersionIntervalSet.Parse` is called with a string containing invalid -tokens mixed with valid intervals. - -**Expected**: Invalid tokens are silently discarded; valid intervals are retained. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Contains_StringInsideFirstInterval_ReturnsTrue - -**Scenario**: `Contains` is called with a string version inside the first interval. - -**Expected**: Returns `true`. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Contains_StringInsideLaterInterval_ReturnsTrue - -**Scenario**: `Contains` is called with a string version inside a later interval. - -**Expected**: Returns `true`. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Contains_StringOutsideAllIntervals_ReturnsFalse - -**Scenario**: `Contains` is called with a string version outside all intervals. - -**Expected**: Returns `false`. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Contains_EmptySet_ReturnsFalse - -**Scenario**: `Contains` is called on an empty set. - -**Expected**: Returns `false`. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Contains_VersionTag_DelegatesToSemanticVersion - -**Scenario**: `Contains` is called with a `VersionTag` argument. - -**Expected**: Delegates to the tag's semantic version for comparison. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Contains_PreReleaseVersions_HandlesCorrectly - -**Scenario**: `Contains` is called with pre-release version strings. - -**Expected**: Correctly applies semver pre-release ordering rules. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Contains_VersionComparable_HandlesPreRelease - -**Scenario**: `Contains` is called with a `VersionComparable` that has pre-release. - -**Expected**: Pre-release ordering rules are applied correctly. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -##### VersionIntervalSet_Parse_PreReleaseBounds_ParsesCorrectly - -**Scenario**: `VersionIntervalSet.Parse` is called with intervals using pre-release -version bounds. - -**Expected**: Pre-release bounds are parsed and stored correctly. - -**Requirement coverage**: `BuildMark-Version-VersionIntervalSet` - -#### Requirements Coverage - -- **BuildMark-Version-VersionIntervalSet**: All 13 tests in `VersionIntervalSetTests.cs` +**VersionIntervalSet_Parse_SingleInterval_ReturnsOneInterval**: This scenario verifies that parsing +one interval string yields a set containing exactly one interval so simple range specifications are +stored correctly. This scenario is tested by +`VersionIntervalSet_Parse_SingleInterval_ReturnsOneInterval`. + +**VersionIntervalSet_Parse_TwoIntervals_ReturnsTwoIntervals**: This scenario verifies that two +comma-separated interval expressions are both retained in the parsed set so disjoint ranges can be +represented together. This scenario is tested by +`VersionIntervalSet_Parse_TwoIntervals_ReturnsTwoIntervals`. + +**VersionIntervalSet_Parse_IntervalsWithInternalComma_ParsedCorrectly**: This scenario verifies +that commas inside interval bounds are treated as part of the interval syntax and do not split the +set incorrectly. This scenario is tested by +`VersionIntervalSet_Parse_IntervalsWithInternalComma_ParsedCorrectly`. + +**VersionIntervalSet_Parse_EmptyString_ReturnsEmptySet**: This scenario verifies that an empty +input string produces an empty interval set rather than an invalid interval entry. This scenario is +tested by `VersionIntervalSet_Parse_EmptyString_ReturnsEmptySet`. + +**VersionIntervalSet_Parse_InvalidToken_DiscardedSilently**: This scenario verifies that invalid +interval tokens are ignored while valid intervals are preserved, which allows tolerant parsing of +mixed input. This scenario is tested by +`VersionIntervalSet_Parse_InvalidToken_DiscardedSilently`. + +**VersionIntervalSet_Contains_StringInsideFirstInterval_ReturnsTrue**: This scenario verifies that +`Contains` returns true when a string version falls inside the first interval in the set. This +scenario is tested by `VersionIntervalSet_Contains_StringInsideFirstInterval_ReturnsTrue`. + +**VersionIntervalSet_Contains_StringInsideLaterInterval_ReturnsTrue**: This scenario verifies that +`Contains` returns true when a string version falls inside a later interval, proving the full set +is evaluated rather than only the first entry. This scenario is tested by +`VersionIntervalSet_Contains_StringInsideLaterInterval_ReturnsTrue`. + +**VersionIntervalSet_Contains_StringOutsideAllIntervals_ReturnsFalse**: This scenario verifies +that `Contains` returns false when a version is outside every interval in the set. This scenario is +tested by `VersionIntervalSet_Contains_StringOutsideAllIntervals_ReturnsFalse`. + +**VersionIntervalSet_Contains_EmptySet_ReturnsFalse**: This scenario verifies that an empty set +contains no versions and therefore always returns false. This scenario is tested by +`VersionIntervalSet_Contains_EmptySet_ReturnsFalse`. + +**VersionIntervalSet_Contains_VersionTag_DelegatesToSemanticVersion**: This scenario verifies that +a `VersionTag` argument is evaluated through its semantic version representation instead of raw tag +text. This scenario is tested by +`VersionIntervalSet_Contains_VersionTag_DelegatesToSemanticVersion`. + +**VersionIntervalSet_Contains_PreReleaseVersions_HandlesCorrectly**: This scenario verifies that +pre-release version strings are evaluated using semantic-version ordering rules across the interval +set. This scenario is tested by +`VersionIntervalSet_Contains_PreReleaseVersions_HandlesCorrectly`. + +**VersionIntervalSet_Contains_VersionComparable_HandlesPreRelease**: This scenario verifies that a +`VersionComparable` argument with pre-release identifiers is checked using semantic-version +precedence rules. This scenario is tested by +`VersionIntervalSet_Contains_VersionComparable_HandlesPreRelease`. + +**VersionIntervalSet_Parse_PreReleaseBounds_ParsesCorrectly**: This scenario verifies that +intervals using pre-release version bounds are parsed and stored correctly so later membership +checks use the intended semantic range. This scenario is tested by +`VersionIntervalSet_Parse_PreReleaseBounds_ParsesCorrectly`. diff --git a/docs/verification/build-mark/version/version-interval.md b/docs/verification/build-mark/version/version-interval.md index c161d0a..7881cb0 100644 --- a/docs/verification/build-mark/version/version-interval.md +++ b/docs/verification/build-mark/version/version-interval.md @@ -2,199 +2,111 @@ #### Verification Approach -`VersionInterval` is tested through `VersionIntervalTests.cs`, which contains 21 unit -tests. The tests cover parsing of inclusive and exclusive lower/upper bounds, unbounded -intervals, invalid input handling, and `Contains` checks for string versions, semantic -versions, and pre-release versions. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Pure logic | +`VersionInterval` is a pure logic unit with no external dependencies, so no mocks or stubs are +needed. The unit is exercised through `VersionIntervalTests.cs`, which contains 21 unit tests +covering parsing of inclusive and exclusive lower and upper bounds, bounded and unbounded +intervals, invalid input handling, and `Contains` checks for strings, `VersionSemantic`, +pre-release versions, and `VersionComparable` values. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. No external dependencies or environment setup required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 21 tests in `VersionIntervalTests.cs` pass with zero failures. #### Test Scenarios -##### VersionInterval_Parse_InclusiveLower_IsInclusive - -**Scenario**: `VersionInterval.Parse` is called with `[1.0.0,2.0.0]`. - -**Expected**: Lower bound is inclusive; `Contains("1.0.0")` returns `true`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_ExclusiveLower_IsExclusive - -**Scenario**: `VersionInterval.Parse` is called with `(1.0.0,2.0.0)`. - -**Expected**: Lower bound is exclusive; `Contains("1.0.0")` returns `false`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_InclusiveUpper_IsInclusive - -**Scenario**: `VersionInterval.Parse` is called with an interval using `]` upper bracket. - -**Expected**: Upper bound is inclusive; `Contains` at the upper bound returns `true`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_ExclusiveUpper_IsExclusive - -**Scenario**: `VersionInterval.Parse` is called with an interval using `)` upper bracket. - -**Expected**: Upper bound is exclusive; `Contains` at the upper bound returns `false`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_UnboundedLower_HasNullLowerBound - -**Scenario**: `VersionInterval.Parse` is called with `(,2.0.0)` (no lower bound). - -**Expected**: Lower bound property is `null`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_UnboundedUpper_HasNullUpperBound - -**Scenario**: `VersionInterval.Parse` is called with `[1.0.0,)` (no upper bound). - -**Expected**: Upper bound property is `null`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_BothBoundsPresent_ReturnsInterval - -**Scenario**: `VersionInterval.Parse` is called with a fully bounded interval. - -**Expected**: Both bound properties are non-null. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_InvalidFormat_ReturnsNull - -**Scenario**: `VersionInterval.Parse` is called with a string that does not match -the interval format. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_NullInput_ReturnsNull - -**Scenario**: `VersionInterval.Parse` is called with `null`. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Parse_EmptyString_ReturnsNull - -**Scenario**: `VersionInterval.Parse` is called with an empty string. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_StringEqualToInclusiveLower_ReturnsTrue - -**Scenario**: `Contains` is called with a string equal to the inclusive lower bound. - -**Expected**: Returns `true`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_StringEqualToExclusiveLower_ReturnsFalse - -**Scenario**: `Contains` is called with a string equal to the exclusive lower bound. - -**Expected**: Returns `false`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_StringEqualToInclusiveUpper_ReturnsTrue - -**Scenario**: `Contains` is called with a string equal to the inclusive upper bound. - -**Expected**: Returns `true`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_StringEqualToExclusiveUpper_ReturnsFalse - -**Scenario**: `Contains` is called with a string equal to the exclusive upper bound. - -**Expected**: Returns `false`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_StringInsideUnboundedInterval_ReturnsTrue - -**Scenario**: `Contains` is called with a version inside an unbounded interval. - -**Expected**: Returns `true`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_StringOutsideInterval_ReturnsFalse - -**Scenario**: `Contains` is called with a version outside the interval bounds. - -**Expected**: Returns `false`. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_Version_DelegatesToSemanticVersion - -**Scenario**: `Contains` is called with a `VersionSemantic` argument. - -**Expected**: Comparison delegates to the semantic version correctly. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_PreReleaseBounds_HandlesCorrectly - -**Scenario**: An interval with pre-release bounds is created; `Contains` is called -with a pre-release version. - -**Expected**: Correctly determines membership using semver pre-release ordering. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_PreReleaseToPreRelease_HandlesCorrectly - -**Scenario**: An interval spanning two pre-release versions; `Contains` checks a -version between them. - -**Expected**: Returns `true` for versions in range, `false` outside. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_PreReleaseOrdering_UsesNumericComparison - -**Scenario**: Interval bounds use numeric pre-release identifiers; `Contains` is -called with intermediate numeric pre-releases. - -**Expected**: Numeric comparison is applied correctly. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -##### VersionInterval_Contains_VersionComparable_HandlesPreRelease - -**Scenario**: `Contains` is called with a `VersionComparable` that has a pre-release. - -**Expected**: Comparison uses semver pre-release ordering rules. - -**Requirement coverage**: `BuildMark-Version-VersionInterval` - -#### Requirements Coverage - -- **BuildMark-Version-VersionInterval**: All 21 tests in `VersionIntervalTests.cs` +**VersionInterval_Parse_InclusiveLower_IsInclusive**: This scenario verifies that an interval with +an inclusive lower bound contains a version exactly equal to that bound, which confirms correct +bracket semantics. This scenario is tested by +`VersionInterval_Parse_InclusiveLower_IsInclusive`. + +**VersionInterval_Parse_ExclusiveLower_IsExclusive**: This scenario verifies that an interval with +an exclusive lower bound rejects a version exactly equal to that bound. This scenario is tested by +`VersionInterval_Parse_ExclusiveLower_IsExclusive`. + +**VersionInterval_Parse_InclusiveUpper_IsInclusive**: This scenario verifies that an interval with +an inclusive upper bound contains a version exactly equal to that upper limit. This scenario is +tested by `VersionInterval_Parse_InclusiveUpper_IsInclusive`. + +**VersionInterval_Parse_ExclusiveUpper_IsExclusive**: This scenario verifies that an interval with +an exclusive upper bound rejects a version exactly equal to that upper limit. This scenario is +tested by `VersionInterval_Parse_ExclusiveUpper_IsExclusive`. + +**VersionInterval_Parse_UnboundedLower_HasNullLowerBound**: This scenario verifies that parsing an +interval with no lower bound leaves the lower-bound property unset so the range extends downward +without restriction. This scenario is tested by +`VersionInterval_Parse_UnboundedLower_HasNullLowerBound`. + +**VersionInterval_Parse_UnboundedUpper_HasNullUpperBound**: This scenario verifies that parsing an +interval with no upper bound leaves the upper-bound property unset so the range extends upward +without restriction. This scenario is tested by +`VersionInterval_Parse_UnboundedUpper_HasNullUpperBound`. + +**VersionInterval_Parse_BothBoundsPresent_ReturnsInterval**: This scenario verifies that a fully +bounded interval retains both parsed bound values so closed and open range checks can be applied. +This scenario is tested by `VersionInterval_Parse_BothBoundsPresent_ReturnsInterval`. + +**VersionInterval_Parse_InvalidFormat_ReturnsNull**: This scenario verifies that a malformed +interval string is rejected by returning null rather than creating an unusable interval. This +scenario is tested by `VersionInterval_Parse_InvalidFormat_ReturnsNull`. + +**VersionInterval_Parse_NullInput_ReturnsNull**: This scenario verifies that null input is handled +safely and returns null so callers can probe optional interval values. This scenario is tested by +`VersionInterval_Parse_NullInput_ReturnsNull`. + +**VersionInterval_Parse_EmptyString_ReturnsNull**: This scenario verifies that an empty string does +not parse into an interval and instead returns null. This scenario is tested by +`VersionInterval_Parse_EmptyString_ReturnsNull`. + +**VersionInterval_Contains_StringEqualToInclusiveLower_ReturnsTrue**: This scenario verifies that +`Contains` returns true for a string version equal to an inclusive lower bound. This scenario is +tested by `VersionInterval_Contains_StringEqualToInclusiveLower_ReturnsTrue`. + +**VersionInterval_Contains_StringEqualToExclusiveLower_ReturnsFalse**: This scenario verifies that +`Contains` returns false for a string version equal to an exclusive lower bound. This scenario is +tested by `VersionInterval_Contains_StringEqualToExclusiveLower_ReturnsFalse`. + +**VersionInterval_Contains_StringEqualToInclusiveUpper_ReturnsTrue**: This scenario verifies that +`Contains` returns true for a string version equal to an inclusive upper bound. This scenario is +tested by `VersionInterval_Contains_StringEqualToInclusiveUpper_ReturnsTrue`. + +**VersionInterval_Contains_StringEqualToExclusiveUpper_ReturnsFalse**: This scenario verifies that +`Contains` returns false for a string version equal to an exclusive upper bound. This scenario is +tested by `VersionInterval_Contains_StringEqualToExclusiveUpper_ReturnsFalse`. + +**VersionInterval_Contains_StringInsideUnboundedInterval_ReturnsTrue**: This scenario verifies +that a version inside an interval with an unbounded side is accepted when it satisfies the present +bound. This scenario is tested by +`VersionInterval_Contains_StringInsideUnboundedInterval_ReturnsTrue`. + +**VersionInterval_Contains_StringOutsideInterval_ReturnsFalse**: This scenario verifies that a +version outside the configured bounds is rejected so interval filtering remains reliable. This +scenario is tested by `VersionInterval_Contains_StringOutsideInterval_ReturnsFalse`. + +**VersionInterval_Contains_Version_DelegatesToSemanticVersion**: This scenario verifies that a +`VersionSemantic` argument is evaluated using its semantic version information rather than string +comparison. This scenario is tested by +`VersionInterval_Contains_Version_DelegatesToSemanticVersion`. + +**VersionInterval_Contains_PreReleaseBounds_HandlesCorrectly**: This scenario verifies that +interval bounds containing pre-release versions use semantic-version precedence rules when checking +membership. This scenario is tested by +`VersionInterval_Contains_PreReleaseBounds_HandlesCorrectly`. + +**VersionInterval_Contains_PreReleaseToPreRelease_HandlesCorrectly**: This scenario verifies that +an interval spanning two pre-release versions accepts in-range values and rejects out-of-range +values across the pre-release boundary. This scenario is tested by +`VersionInterval_Contains_PreReleaseToPreRelease_HandlesCorrectly`. + +**VersionInterval_Contains_PreReleaseOrdering_UsesNumericComparison**: This scenario verifies that +numeric pre-release identifiers inside interval bounds are ordered numerically instead of +lexicographically. This scenario is tested by +`VersionInterval_Contains_PreReleaseOrdering_UsesNumericComparison`. + +**VersionInterval_Contains_VersionComparable_HandlesPreRelease**: This scenario verifies that a +`VersionComparable` argument with pre-release identifiers is evaluated using semantic-version +precedence rules. This scenario is tested by +`VersionInterval_Contains_VersionComparable_HandlesPreRelease`. diff --git a/docs/verification/build-mark/version/version-semantic.md b/docs/verification/build-mark/version/version-semantic.md index b4d3ced..6a23738 100644 --- a/docs/verification/build-mark/version/version-semantic.md +++ b/docs/verification/build-mark/version/version-semantic.md @@ -2,133 +2,76 @@ #### Verification Approach -`VersionSemantic` is tested through `VersionSemanticTests.cs`, which contains 12 unit -tests. The tests cover creation with and without build metadata, property delegation -to the underlying `VersionComparable`, string formatting, and comparison. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Pure logic | +`VersionSemantic` is a pure logic unit with no external dependencies, so no mocks or stubs are +needed. The unit is exercised through `VersionSemanticTests.cs`, which contains 12 unit tests +covering creation with and without build metadata, delegation of comparison properties to the +underlying `VersionComparable`, formatting of the full version string, and comparison through the +`Comparable` property. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 12 tests in `VersionSemanticTests.cs` pass with zero failures. #### Test Scenarios -##### VersionSemantic_Create_WithBuildMetadata_ReturnsInstance - -**Scenario**: `VersionSemantic.Create` is called with `"1.2.3+build.123"`. - -**Expected**: `Metadata` equals `"build.123"`; `FullVersion` equals `"1.2.3+build.123"`. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Create_WithoutBuildMetadata_ReturnsInstance - -**Scenario**: `VersionSemantic.Create` is called with `"1.2.3"`. - -**Expected**: `Metadata` is `null`; `FullVersion` equals `"1.2.3"`. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Properties_DelegateToComparable_Correctly - -**Scenario**: `VersionSemantic.Create` is called with `"1.2.3-alpha"` and the `Major`, -`Minor`, `Patch`, `PreRelease`, and `CompareVersion` properties are read. - -**Expected**: `Major` equals 1; `Minor` equals 2; `Patch` equals 3; `PreRelease` equals -`"alpha"`; `CompareVersion` equals `"1.2.3-alpha"`. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_ToString_FormatsCompletely_WithAllComponents - -**Scenario**: `VersionSemantic.Create` is called with `"1.2.3-alpha+build.123"` and -`FullVersion` is read. - -**Expected**: `FullVersion` equals `"1.2.3-alpha+build.123"`. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_PreRelease_ReturnsEmptyStringForRelease - -**Scenario**: `PreRelease` property is accessed on a release version (no `-` suffix). - -**Expected**: Returns empty string. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Parse_ValidSemanticVersions_ParsesCorrectly - -**Scenario**: A series of standard semver strings are parsed. - -**Expected**: Each parses without error with correct field values. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Create_SimpleVersion_ParsesVersion - -**Scenario**: `VersionSemantic.Create` is called with `"1.2.3"`. - -**Expected**: `Major` equals 1; `Minor` equals 2; `Patch` equals 3; `Numbers` equals -`"1.2.3"`; `PreRelease` equals `""`; `Metadata` is `null`; `CompareVersion` equals -`"1.2.3"`; `FullVersion` equals `"1.2.3"`; `IsPreRelease` is false. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Create_VersionWithMetadata_ParsesVersion - -**Scenario**: `VersionSemantic.Create` is called with `"1.2.3+build.5"`. - -**Expected**: `Numbers` equals `"1.2.3"`; `PreRelease` equals `""`; `Metadata` equals -`"build.5"`; `CompareVersion` equals `"1.2.3"`; `FullVersion` equals `"1.2.3+build.5"`; -`IsPreRelease` is false. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Create_PreReleaseWithMetadata_ParsesVersion - -**Scenario**: `VersionSemantic.Create` is called with `"2.0.0-alpha.1+linux.x64"`. - -**Expected**: `Numbers` equals `"2.0.0"`; `PreRelease` equals `"alpha.1"`; `Metadata` -equals `"linux.x64"`; `CompareVersion` equals `"2.0.0-alpha.1"`; `FullVersion` equals -`"2.0.0-alpha.1+linux.x64"`; `IsPreRelease` is true. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_TryCreate_InvalidVersion_ReturnsNull - -**Scenario**: `VersionSemantic.TryCreate` is called with `"not-a-version"`. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Create_InvalidVersion_ThrowsArgumentException - -**Scenario**: `VersionSemantic.Create` is called with `"not-a-version"`. - -**Expected**: `ArgumentException` is thrown with a message containing -`"does not match semantic version format"`. - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -##### VersionSemantic_Comparable_AllowsComparison - -**Scenario**: `Comparable` is compared for `"1.2.3+build1"` and `"1.2.4+build2"`. - -**Expected**: `version1.Comparable < version2.Comparable` is true (i.e., `"1.2.3"` sorts -before `"1.2.4"`). - -**Requirement coverage**: `BuildMark-Version-VersionSemantic` - -#### Requirements Coverage - -- **BuildMark-Version-VersionSemantic**: All 12 tests in `VersionSemanticTests.cs` +**VersionSemantic_Create_WithBuildMetadata_ReturnsInstance**: This scenario verifies that creating +`VersionSemantic` from `1.2.3+build.123` preserves the build metadata and full version string so +metadata is exposed without affecting comparison data. This scenario is tested by +`VersionSemantic_Create_WithBuildMetadata_ReturnsInstance`. + +**VersionSemantic_Create_WithoutBuildMetadata_ReturnsInstance**: This scenario verifies that +creating `VersionSemantic` from `1.2.3` leaves metadata unset and preserves the original full +version string for a plain release version. This scenario is tested by +`VersionSemantic_Create_WithoutBuildMetadata_ReturnsInstance`. + +**VersionSemantic_Properties_DelegateToComparable_Correctly**: This scenario verifies that major, +minor, patch, pre-release, and compare-version values are delegated correctly from the underlying +`VersionComparable`. This scenario is tested by +`VersionSemantic_Properties_DelegateToComparable_Correctly`. + +**VersionSemantic_ToString_FormatsCompletely_WithAllComponents**: This scenario verifies that a +version containing both pre-release and build metadata is formatted into the expected full version +string. This scenario is tested by +`VersionSemantic_ToString_FormatsCompletely_WithAllComponents`. + +**VersionSemantic_PreRelease_ReturnsEmptyStringForRelease**: This scenario verifies that a release +version reports an empty pre-release value so callers do not need null handling for normal +releases. This scenario is tested by +`VersionSemantic_PreRelease_ReturnsEmptyStringForRelease`. + +**VersionSemantic_Parse_ValidSemanticVersions_ParsesCorrectly**: This scenario verifies that a +representative set of valid semantic version strings parses successfully and exposes the expected +data. This scenario is tested by +`VersionSemantic_Parse_ValidSemanticVersions_ParsesCorrectly`. + +**VersionSemantic_Create_SimpleVersion_ParsesVersion**: This scenario verifies that a simple +release version populates numeric, compare, and display properties consistently and reports that it +is not a pre-release. This scenario is tested by +`VersionSemantic_Create_SimpleVersion_ParsesVersion`. + +**VersionSemantic_Create_VersionWithMetadata_ParsesVersion**: This scenario verifies that a +version with build metadata preserves the metadata in `FullVersion` while keeping +`CompareVersion` limited to comparable semantic fields. This scenario is tested by +`VersionSemantic_Create_VersionWithMetadata_ParsesVersion`. + +**VersionSemantic_Create_PreReleaseWithMetadata_ParsesVersion**: This scenario verifies that a +version containing both pre-release and metadata components populates all properties correctly and +reports `IsPreRelease` as true. This scenario is tested by +`VersionSemantic_Create_PreReleaseWithMetadata_ParsesVersion`. + +**VersionSemantic_TryCreate_InvalidVersion_ReturnsNull**: This scenario verifies that `TryCreate` +returns null for an invalid semantic version string rather than throwing, which supports safe input +probing. This scenario is tested by `VersionSemantic_TryCreate_InvalidVersion_ReturnsNull`. + +**VersionSemantic_Create_InvalidVersion_ThrowsArgumentException**: This scenario verifies that +`Create` rejects an invalid semantic version string with an `ArgumentException` that explains the +format problem. This scenario is tested by +`VersionSemantic_Create_InvalidVersion_ThrowsArgumentException`. + +**VersionSemantic_Comparable_AllowsComparison**: This scenario verifies that the `Comparable` +property enables ordering between semantic versions while ignoring build metadata in precedence. +This scenario is tested by `VersionSemantic_Comparable_AllowsComparison`. diff --git a/docs/verification/build-mark/version/version-tag.md b/docs/verification/build-mark/version/version-tag.md index f6b0ab1..ac89ebd 100644 --- a/docs/verification/build-mark/version/version-tag.md +++ b/docs/verification/build-mark/version/version-tag.md @@ -2,202 +2,103 @@ #### Verification Approach -`VersionTag` is tested through `VersionTagTests.cs`, which contains 19 unit tests. -The tests cover parsing of standard tags, prefixed tags (e.g., `v1.2.3`), path-prefix -tags (e.g., `mylib/1.2.3`), pre-release normalization (dots converted to hyphens), -and error handling for invalid tags. - -#### Dependencies - -| Mock / Stub | Reason | -| ----------- | ---------- | -| None | Pure logic | +`VersionTag` is a pure logic unit with no external dependencies, so no mocks or stubs are needed. +The unit is exercised through `VersionTagTests.cs`, which contains 19 unit tests covering standard +and prefixed tags, path-prefix tags, multi-level path prefixes, normalization of dot-separated +pre-release suffixes to semantic-version form, invalid input handling, and comparison through +`Semantic.Comparable`. #### Test Environment -Standard dotnet test host; no external dependencies or environment setup required. +N/A - standard test environment. No external dependencies or environment setup required. #### Acceptance Criteria -All tests in the test class pass with no errors or warnings. +- All 19 tests in `VersionTagTests.cs` pass with zero failures. #### Test Scenarios -##### VersionTag_Create_ValidTag_ReturnsVersionTag - -**Scenario**: `VersionTag.Create` is called with a valid tag string. - -**Expected**: Returns a non-null `VersionTag` instance. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_StandardTag_ParsesCorrectly - -**Scenario**: `VersionTag.Create` is called with `"1.2.3"` (no prefix). - -**Expected**: `Tag` equals `"1.2.3"`; `FullVersion` equals `"1.2.3"`; `Numbers` equals `"1.2.3"`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_PrefixedTag_ParsesCorrectly - -**Scenario**: `VersionTag.Create` is called with `"v1.2.3"`. - -**Expected**: `Tag` equals `"v1.2.3"`; `FullVersion` equals `"1.2.3"`; `Numbers` equals `"1.2.3"`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_DotSeparatedPreRelease_NormalizesToHyphen - -**Scenario**: `VersionTag.Create` is called with `"v1.2.3.alpha.1"`. - -**Expected**: `Tag` equals `"v1.2.3.alpha.1"`; `FullVersion` equals `"1.2.3-alpha.1"`; -`PreRelease` equals `"alpha.1"`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_ComplexTag_ExtractsVersionCorrectly - -**Scenario**: `VersionTag.Create` is called with `"Release_1.2.3.beta.5+build.123"`. - -**Expected**: `Tag` equals `"Release_1.2.3.beta.5+build.123"`; `FullVersion` equals -`"1.2.3-beta.5+build.123"`; `Numbers` equals `"1.2.3"`; `PreRelease` equals `"beta.5"`; -`Metadata` equals `"build.123"`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Properties_ExposeOriginalAndParsed_Correctly - -**Scenario**: `VersionTag.Create` is called with `"v1.2.3-alpha"` and the `Tag`, -`FullVersion`, `Numbers`, and `PreRelease` properties are read. - -**Expected**: `Tag` equals `"v1.2.3-alpha"`; `FullVersion` equals `"1.2.3-alpha"`; -`Numbers` equals `"1.2.3"`; `PreRelease` equals `"alpha"`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_ToString_ReturnsOriginalTag - -**Scenario**: `ToString` is called on a `VersionTag` created from `"v1.2.3-alpha+build.123"`. - -**Expected**: Returns the original tag string unchanged. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_SimpleVPrefix_ParsesVersion - -**Scenario**: `VersionTag.Create` is called with `"v1.2.3"`. - -**Expected**: `Tag` equals `"v1.2.3"`; `FullVersion` equals `"1.2.3"`; `Numbers` equals -`"1.2.3"`; `PreRelease` equals `""`; `CompareVersion` equals `"1.2.3"`; `Metadata` equals -`""`; `IsPreRelease` is false. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_ComplexVersionWithMetadata_ParsesVersion - -**Scenario**: `VersionTag.Create` is called with `"Rel_1.2.3.rc.4+build.5"`. - -**Expected**: `Tag` equals `"Rel_1.2.3.rc.4+build.5"`; `FullVersion` equals -`"1.2.3-rc.4+build.5"`; `Numbers` equals `"1.2.3"`; `PreRelease` equals `"rc.4"`; -`CompareVersion` equals `"1.2.3-rc.4"`; `Metadata` equals `"build.5"`; `IsPreRelease` -is true. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_TryCreate_InvalidTag_ReturnsNull - -**Scenario**: `VersionTag.TryCreate` is called with `"not-a-version"`. - -**Expected**: Returns `null`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_InvalidTag_ThrowsArgumentException - -**Scenario**: `VersionTag.Create` is called with `"not-a-version"`. - -**Expected**: `ArgumentException` is thrown with a message containing -`"does not match version format"`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_NoPrefix_ParsesVersion - -**Scenario**: `VersionTag.Create` is called with `"1.0.0"`. - -**Expected**: `Tag` equals `"1.0.0"`; `FullVersion` equals `"1.0.0"`; `IsPreRelease` is false. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_HyphenPreReleaseWithMetadata_ParsesVersion - -**Scenario**: `VersionTag.Create` is called with `"Rel_1.2.3-rc.4+build.5"`. - -**Expected**: `Tag` equals `"Rel_1.2.3-rc.4+build.5"`; `FullVersion` equals -`"1.2.3-rc.4+build.5"`; `Numbers` equals `"1.2.3"`; `PreRelease` equals `"rc.4"`; -`CompareVersion` equals `"1.2.3-rc.4"`; `Metadata` equals `"build.5"`; `IsPreRelease` -is true. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Semantic_AllowsComparison - -**Scenario**: `Semantic.Comparable` is compared for tags `"v1.2.3"` and `"v1.11.2"`. - -**Expected**: `tag1.Semantic.Comparable < tag2.Semantic.Comparable` is true (i.e., -`"v1.2.3"` sorts before `"v1.11.2"`). - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionComparable_Equals_DifferentPrefixesSameVersion_ReturnsTrue - -**Scenario**: `Semantic.Comparable` is extracted from `"v1.2.3"`, `"VER1.2.3"`, -`"Release_1.2.3"`, and `"release/1.2.3"` and the four values are compared for equality. - -**Expected**: Comparable values are equal. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_GetVersionComparable_SemanticTags_ReturnsCorrectComparison - -**Scenario**: `Semantic.Comparable` is compared for `"v1.0.0-alpha"`, `"v1.0.0-beta"`, -and `"v1.0.0"`. - -**Expected**: alpha < beta < release: `"v1.0.0-alpha"` sorts before `"v1.0.0-beta"`, -which sorts before `"v1.0.0"`. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_PathSeparatorPrefix_ParsesCorrectly - -**Scenario**: `VersionTag.Create` is called with `"release/1.2.3"`. - -**Expected**: `Tag` equals `"release/1.2.3"`; `FullVersion` equals `"1.2.3"`; `Numbers` -equals `"1.2.3"`; `PreRelease` equals `""`; `IsPreRelease` is false. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_PathSeparatorPrefixWithPreRelease_ParsesCorrectly - -**Scenario**: `VersionTag.Create` is called with `"release/1.2.3-rc.4"`. - -**Expected**: `Tag` equals `"release/1.2.3-rc.4"`; `FullVersion` equals `"1.2.3-rc.4"`; -`Numbers` equals `"1.2.3"`; `PreRelease` equals `"rc.4"`; `CompareVersion` equals -`"1.2.3-rc.4"`; `IsPreRelease` is true. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -##### VersionTag_Create_MultiLevelPathPrefix_ParsesCorrectly - -**Scenario**: `VersionTag.Create` is called with `"builds/release/1.2.3-beta.1+build.99"`. - -**Expected**: `Tag` equals `"builds/release/1.2.3-beta.1+build.99"`; `FullVersion` equals -`"1.2.3-beta.1+build.99"`; `Numbers` equals `"1.2.3"`; `PreRelease` equals `"beta.1"`; -`Metadata` equals `"build.99"`; `IsPreRelease` is true. - -**Requirement coverage**: `BuildMark-Version-VersionTag` - -#### Requirements Coverage - -- **BuildMark-Version-VersionTag**: All 19 tests in `VersionTagTests.cs` +**VersionTag_Create_ValidTag_ReturnsVersionTag**: This scenario verifies that a valid tag string +produces a non-null `VersionTag` instance so downstream code can parse repository tags safely. This +scenario is tested by `VersionTag_Create_ValidTag_ReturnsVersionTag`. + +**VersionTag_Create_StandardTag_ParsesCorrectly**: This scenario verifies that a plain tag such as +`1.2.3` is parsed without normalization changes and exposes the expected original and semantic +values. This scenario is tested by `VersionTag_Create_StandardTag_ParsesCorrectly`. + +**VersionTag_Create_PrefixedTag_ParsesCorrectly**: This scenario verifies that a common `v` prefix +is ignored for semantic parsing while the original tag text is preserved. This scenario is tested +by `VersionTag_Create_PrefixedTag_ParsesCorrectly`. + +**VersionTag_Create_DotSeparatedPreRelease_NormalizesToHyphen**: This scenario verifies that a +pre-release suffix written with dots in the tag is normalized to semantic-version hyphen form for +comparison and display. This scenario is tested by +`VersionTag_Create_DotSeparatedPreRelease_NormalizesToHyphen`. + +**VersionTag_Create_ComplexTag_ExtractsVersionCorrectly**: This scenario verifies that a tag with +an arbitrary prefix, pre-release suffix, and build metadata is reduced to the expected semantic +version fields. This scenario is tested by +`VersionTag_Create_ComplexTag_ExtractsVersionCorrectly`. + +**VersionTag_Properties_ExposeOriginalAndParsed_Correctly**: This scenario verifies that the unit +retains the original tag while also exposing parsed semantic version properties for a pre-release +value. This scenario is tested by +`VersionTag_Properties_ExposeOriginalAndParsed_Correctly`. + +**VersionTag_ToString_ReturnsOriginalTag**: This scenario verifies that `ToString` returns the +original tag text unchanged so the source repository tag can be displayed exactly as received. This +scenario is tested by `VersionTag_ToString_ReturnsOriginalTag`. + +**VersionTag_Create_SimpleVPrefix_ParsesVersion**: This scenario verifies that a simple `v`-prefix +release tag populates all parsed properties consistently and reports that it is not a pre-release. +This scenario is tested by `VersionTag_Create_SimpleVPrefix_ParsesVersion`. + +**VersionTag_Create_ComplexVersionWithMetadata_ParsesVersion**: This scenario verifies that a tag +with a custom prefix, dot-separated pre-release, and metadata populates all semantic properties +correctly after normalization. This scenario is tested by +`VersionTag_Create_ComplexVersionWithMetadata_ParsesVersion`. + +**VersionTag_TryCreate_InvalidTag_ReturnsNull**: This scenario verifies that `TryCreate` safely +returns null for an invalid tag string rather than throwing. This scenario is tested by +`VersionTag_TryCreate_InvalidTag_ReturnsNull`. + +**VersionTag_Create_InvalidTag_ThrowsArgumentException**: This scenario verifies that `Create` +rejects an invalid tag with an `ArgumentException` so required parsing failures are explicit. This +scenario is tested by `VersionTag_Create_InvalidTag_ThrowsArgumentException`. + +**VersionTag_Create_NoPrefix_ParsesVersion**: This scenario verifies that a release tag with no +prefix is parsed directly and is not marked as a pre-release. This scenario is tested by +`VersionTag_Create_NoPrefix_ParsesVersion`. + +**VersionTag_Create_HyphenPreReleaseWithMetadata_ParsesVersion**: This scenario verifies that a +hyphenated pre-release tag with build metadata is parsed without dot-normalization changes and +reports pre-release state correctly. This scenario is tested by +`VersionTag_Create_HyphenPreReleaseWithMetadata_ParsesVersion`. + +**VersionTag_Semantic_AllowsComparison**: This scenario verifies that two parsed tags can be +compared numerically through `Semantic.Comparable`, so version precedence does not depend on the +original text prefix. This scenario is tested by `VersionTag_Semantic_AllowsComparison`. + +**VersionComparable_Equals_DifferentPrefixesSameVersion_ReturnsTrue**: This scenario verifies that +multiple tags with different textual prefixes normalize to equal comparable semantic versions when +the underlying version is the same. This scenario is tested by +`VersionComparable_Equals_DifferentPrefixesSameVersion_ReturnsTrue`. + +**VersionTag_GetVersionComparable_SemanticTags_ReturnsCorrectComparison**: This scenario verifies +that alpha, beta, and release tags compare in semantic-version precedence order through +`Semantic.Comparable`. This scenario is tested by +`VersionTag_GetVersionComparable_SemanticTags_ReturnsCorrectComparison`. + +**VersionTag_Create_PathSeparatorPrefix_ParsesCorrectly**: This scenario verifies that a tag with +a path-style prefix such as `release/1.2.3` still yields the expected semantic version values. +This scenario is tested by `VersionTag_Create_PathSeparatorPrefix_ParsesCorrectly`. + +**VersionTag_Create_PathSeparatorPrefixWithPreRelease_ParsesCorrectly**: This scenario verifies +that a path-style prefix combined with a pre-release suffix is parsed correctly and identified as a +pre-release version. This scenario is tested by +`VersionTag_Create_PathSeparatorPrefixWithPreRelease_ParsesCorrectly`. + +**VersionTag_Create_MultiLevelPathPrefix_ParsesCorrectly**: This scenario verifies that a +multi-level path prefix does not interfere with extracting semantic numbers, pre-release content, +and metadata from the tag. This scenario is tested by +`VersionTag_Create_MultiLevelPathPrefix_ParsesCorrectly`. diff --git a/docs/verification/introduction.md b/docs/verification/introduction.md index 72c04e2..61626f5 100644 --- a/docs/verification/introduction.md +++ b/docs/verification/introduction.md @@ -1,142 +1,84 @@ # Introduction -This document provides the verification design for BuildMark, a .NET command-line tool -that generates markdown build notes from Git repository metadata, including GitHub -and Azure DevOps repositories. +This document describes how each software item in BuildMark is verified. ## Purpose -The purpose of this document is to describe how each software requirement for BuildMark -is verified. For each unit, subsystem, and OTS component it identifies the test class, -test methods, mock or stub dependencies, and the requirement identifiers that each test -satisfies. The document provides a traceable record of verification coverage that -supports formal code review, compliance audit, and ongoing maintenance. +The purpose of this document is to describe how each software requirement for BuildMark is verified. +For each unit, subsystem, and OTS component it identifies the test class, test methods, mock or stub +dependencies, and the requirement identifiers that each test satisfies. The document provides a +traceable record of verification coverage that supports formal code review, compliance audit, and +ongoing maintenance. ## Scope -This document covers the verification design for the complete BuildMark system, -including all in-house subsystems and units and all Off-The-Shelf (OTS) components. - -In-house software items verified in this document: - -- **Program** - entry point and execution orchestrator -- **Cli** subsystem - `Context` unit (command-line argument parser and I/O owner) -- **BuildNotes** subsystem - `BuildInformation`, `ItemInfo`, and `WebLink` units -- **SelfTest** subsystem - `Validation` unit -- **Utilities** subsystem - `PathHelpers` and `ProcessRunner` units -- **Version** subsystem - `VersionComparable`, `VersionSemantic`, `VersionTag`, - `VersionInterval`, `VersionIntervalSet`, and `VersionCommitTag` units -- **Configuration** subsystem - `BuildMarkConfig`, `BuildMarkConfigReader`, - `ConfigurationLoadResult`, `ConfigurationIssue`, `ConnectorConfig`, - `GitHubConnectorConfig`, `AzureDevOpsConnectorConfig`, `ReportConfig`, - `SectionConfig`, `RuleConfig`, and `RuleMatchConfig` units -- **RepoConnectors** subsystem - `IRepoConnector`, `RepoConnectorBase`, - `RepoConnectorFactory`, `ItemRouter`, `ItemControlsInfo`, and `ItemControlsParser` - units, plus the following sub-subsystems: - - **GitHub** sub-subsystem - `GitHubRepoConnector`, `GitHubGraphQLClient`, - and `GitHubGraphQLTypes` units - - **AzureDevOps** sub-subsystem - `AzureDevOpsRepoConnector`, - `AzureDevOpsRestClient`, `AzureDevOpsApiTypes`, and `WorkItemMapper` units - - **Mock** sub-subsystem - `MockRepoConnector` unit - -OTS components verified in this document: - -- **BuildMark** - build notes generation tool (self-referential) -- **FileAssert** - file content assertion tool -- **Pandoc** - document conversion tool -- **ReqStream** - requirements traceability tool -- **ReviewMark** - code review enforcement tool -- **SarifMark** - SARIF report generation tool -- **SonarMark** - SonarCloud report generation tool -- **VersionMark** - tool version capture tool -- **WeasyPrint** - HTML-to-PDF renderer -- **xUnit** - unit testing framework +This document covers the verification design for the complete BuildMark system, including all +in-house subsystems and units and all Off-The-Shelf (OTS) components. + +Local items verified in this document: + +- **BuildMark** system: all subsystems and units listed below. + - **Program** unit — entry point and execution orchestrator. + - **Cli** subsystem — `Context` unit (command-line argument parser and I/O owner). + - **BuildNotes** subsystem — `BuildInformation`, `ItemInfo`, and `WebLink` units. + - **SelfTest** subsystem — `Validation` unit. + - **Utilities** subsystem — `PathHelpers` and `ProcessRunner` units. + - **Version** subsystem — `VersionComparable`, `VersionSemantic`, `VersionTag`, `VersionInterval`, + `VersionIntervalSet`, and `VersionCommitTag` units. + - **Configuration** subsystem — `BuildMarkConfig`, `BuildMarkConfigReader`, + `ConfigurationLoadResult`, `ConfigurationIssue`, `ConnectorConfig`, `GitHubConnectorConfig`, + `AzureDevOpsConnectorConfig`, `ReportConfig`, `SectionConfig`, `RuleConfig`, and + `RuleMatchConfig` units. + - **RepoConnectors** subsystem — `IRepoConnector`, `RepoConnectorBase`, `RepoConnectorFactory`, + `ItemRouter`, `ItemControlsInfo`, and `ItemControlsParser` units, plus the **GitHub**, + **AzureDevOps**, and **Mock** sub-subsystems. + +OTS items verified in this document: + +- **BuildMark** — build notes generation tool (self-referential). +- **FileAssert** — file content assertion tool. +- **Pandoc** — document conversion tool. +- **ReqStream** — requirements traceability tool. +- **ReviewMark** — code review enforcement tool. +- **SarifMark** — SARIF report generation tool. +- **SonarMark** — SonarCloud report generation tool. +- **VersionMark** — tool version capture tool. +- **WeasyPrint** — HTML-to-PDF renderer. +- **xUnit** — unit testing framework. The following topics are out of scope: -- External library internals not listed above -- Build pipeline configuration beyond the steps referenced as evidence -- Deployment and packaging - -## Software Structure - -The following tree shows how the BuildMark software items are organized across the -system, subsystem, and unit levels: - -```text -BuildMark (System) -├── Program (Unit) -├── Cli (Subsystem) -│ └── Context (Unit) -├── BuildNotes (Subsystem) -│ ├── BuildInformation (Unit) -│ ├── ItemInfo (Unit) -│ └── WebLink (Unit) -├── SelfTest (Subsystem) -│ └── Validation (Unit) -├── Utilities (Subsystem) -│ ├── PathHelpers (Unit) -│ └── ProcessRunner (Unit) -├── Version (Subsystem) -│ ├── VersionComparable (Unit) -│ ├── VersionSemantic (Unit) -│ ├── VersionTag (Unit) -│ ├── VersionInterval (Unit) -│ ├── VersionIntervalSet (Unit) -│ └── VersionCommitTag (Unit) -├── Configuration (Subsystem) -│ ├── BuildMarkConfig (Unit) -│ ├── BuildMarkConfigReader (Unit) -│ ├── ConfigurationLoadResult (Unit) -│ ├── ConfigurationIssue (Unit) -│ ├── ConnectorConfig (Unit) -│ ├── GitHubConnectorConfig (Unit) -│ ├── AzureDevOpsConnectorConfig (Unit) -│ ├── ReportConfig (Unit) -│ ├── SectionConfig (Unit) -│ ├── RuleConfig (Unit) -│ └── RuleMatchConfig (Unit) -└── RepoConnectors (Subsystem) - ├── IRepoConnector (Unit) - ├── RepoConnectorBase (Unit) - ├── RepoConnectorFactory (Unit) - ├── ItemRouter (Unit) - ├── ItemControlsInfo (Unit) - ├── ItemControlsParser (Unit) - ├── GitHub (Subsystem) - │ ├── GitHubRepoConnector (Unit) - │ ├── GitHubGraphQLClient (Unit) - │ └── GitHubGraphQLTypes (Unit) - ├── AzureDevOps (Subsystem) - │ ├── AzureDevOpsRepoConnector (Unit) - │ ├── AzureDevOpsRestClient (Unit) - │ ├── AzureDevOpsApiTypes (Unit) - │ └── WorkItemMapper (Unit) - └── Mock (Subsystem) - └── MockRepoConnector (Unit) -``` +- External library internals not listed above. +- Build pipeline configuration beyond the steps referenced as evidence. +- Deployment and packaging. ## Companion Artifact Structure -Verification design documents are companion artifacts to requirements, design, source -code, and tests. The parallel tree below shows how each artifact type maps to the same -software structure: +Local items have parallel artifacts in: -```text -docs/requirements_doc/ - compiled requirements document (generated) -docs/reqstream/ - requirements source YAML files -docs/design/ - software design document source -docs/verification/ - this document (verification design source) -src/DemaConsulting.BuildMark/ - implementation source -test/DemaConsulting.BuildMark.Tests/ - test source -``` +- Requirements: `docs/reqstream/build-mark.yaml`, + `docs/reqstream/build-mark[/{subsystem-name}...]/{item}.yaml` +- Design: `docs/design/build-mark.md`, `docs/design/build-mark[/{subsystem-name}...]/{item}.md` +- Verification: `docs/verification/build-mark.md`, + `docs/verification/build-mark[/{subsystem-name}...]/{item}.md` +- Source: `src/DemaConsulting.BuildMark[/{SubsystemName}...]/{Item}.cs` +- Tests: `test/DemaConsulting.BuildMark.Tests[/{SubsystemName}...]/{Item}Tests.cs` -Each chapter in this verification document corresponds to a unit or subsystem chapter -in the design document. Requirement IDs referenced in the Requirements Coverage sections -match identifiers defined in the ReqStream YAML files under `docs/reqstream/`. +OTS items have integration/usage design documentation parallel to system folders: + +- Requirements: `docs/reqstream/ots/{ots-name}.yaml` +- Design: `docs/design/ots/{ots-name}.md` +- Verification: `docs/verification/ots/{ots-name}.md` + +Shared Packages have integration/usage design documentation parallel to system and OTS folders: + +- Requirements: `docs/reqstream/shared/{package-name}.yaml` +- Design: `docs/design/shared/{package-name}.md` +- Verification: `docs/verification/shared/{package-name}.md` + +Review-sets: defined in `.reviewmark.yaml` ## References - [BuildMark releases](https://github.com/demaconsulting/BuildMark/releases) — - compiled design, requirements, and compliance documents -- See the BuildMark repository at . + compiled design, requirements, and compliance documents. diff --git a/docs/verification/ots/buildmark.md b/docs/verification/ots/buildmark.md index 172829e..4d8b302 100644 --- a/docs/verification/ots/buildmark.md +++ b/docs/verification/ots/buildmark.md @@ -23,8 +23,3 @@ The resulting TRX file is consumed by ReqStream to satisfy the OTS requirement. - *BuildMark self-validation*: CI pipeline executes `dotnet buildmark --validate --results artifacts/buildmark-self-validation.trx`; expects exit code 0 and a non-empty TRX file containing self-test results. - -### Requirements Coverage - -- **BuildMark-OTS-BuildMark**: CI pipeline self-validation TRX evidence from - `artifacts/buildmark-self-validation.trx` diff --git a/docs/verification/ots/fileassert.md b/docs/verification/ots/fileassert.md index e1271ea..1b60712 100644 --- a/docs/verification/ots/fileassert.md +++ b/docs/verification/ots/fileassert.md @@ -32,8 +32,3 @@ The resulting TRX file is consumed by ReqStream to satisfy the OTS requirement. collection (Build Notes, Code Quality, Review Plan, Review Report, Design, User Guide, Verification); expects that each assertion set passes and a non-empty TRX file is produced per collection. - -### Requirements Coverage - -- **BuildMark-OTS-FileAssert**: CI pipeline self-validation TRX evidence from - `artifacts/fileassert-self-validation.trx` diff --git a/docs/verification/ots/pandoc.md b/docs/verification/ots/pandoc.md index e496975..e198b40 100644 --- a/docs/verification/ots/pandoc.md +++ b/docs/verification/ots/pandoc.md @@ -29,8 +29,3 @@ FileAssert TRX files (`fileassert-build-notes.trx`, `fileassert-code-quality.trx (Build Notes, Code Quality, Review Plan, Review Report, Design, User Guide, Verification); FileAssert validates the generated HTML output; expects exit code 0 for each invocation and non-empty HTML files containing expected content markers. - -### Requirements Coverage - -- **BuildMark-OTS-Pandoc**: CI pipeline document generation evidence from multiple - FileAssert TRX results confirming successful HTML conversion diff --git a/docs/verification/ots/reqstream.md b/docs/verification/ots/reqstream.md index 6b5ac96..3b44658 100644 --- a/docs/verification/ots/reqstream.md +++ b/docs/verification/ots/reqstream.md @@ -31,8 +31,3 @@ The resulting TRX file is consumed by ReqStream itself to satisfy the OTS requir - *ReqStream requirements enforcement*: CI pipeline executes ReqStream in enforcement mode (`--enforce`) against the project requirements YAML files and evidence TRX files; expects exit code 0 confirming all requirements are fully satisfied. - -### Requirements Coverage - -- **BuildMark-OTS-ReqStream**: CI pipeline self-validation TRX evidence from - `artifacts/reqstream-self-validation.trx` diff --git a/docs/verification/ots/reviewmark.md b/docs/verification/ots/reviewmark.md index 34e691b..9c8d908 100644 --- a/docs/verification/ots/reviewmark.md +++ b/docs/verification/ots/reviewmark.md @@ -30,8 +30,3 @@ The resulting TRX file is consumed by ReqStream to satisfy the OTS requirement. - *ReviewMark document generation*: CI pipeline uses ReviewMark to generate the Review Plan and Review Report documents from the `.reviewmark.yaml` configuration; expects exit code 0 and non-empty output documents for both the plan and report. - -### Requirements Coverage - -- **BuildMark-OTS-ReviewMark**: CI pipeline self-validation TRX evidence from - `artifacts/reviewmark-self-validation.trx` diff --git a/docs/verification/ots/sarifmark.md b/docs/verification/ots/sarifmark.md index bd392b0..d5f4a61 100644 --- a/docs/verification/ots/sarifmark.md +++ b/docs/verification/ots/sarifmark.md @@ -30,8 +30,3 @@ The resulting TRX file is consumed by ReqStream to satisfy the OTS requirement. - *SarifMark SARIF report generation*: CI pipeline uses SarifMark to process the CodeQL SARIF output and generate the code quality markdown report; expects exit code 0 and a non-empty markdown report. - -### Requirements Coverage - -- **BuildMark-OTS-SarifMark**: CI pipeline self-validation TRX evidence from - `artifacts/sarifmark-self-validation.trx` diff --git a/docs/verification/ots/sonarmark.md b/docs/verification/ots/sonarmark.md index 062341b..34f74f4 100644 --- a/docs/verification/ots/sonarmark.md +++ b/docs/verification/ots/sonarmark.md @@ -30,8 +30,3 @@ The resulting TRX file is consumed by ReqStream to satisfy the OTS requirement. - *SonarMark quality report generation*: CI pipeline uses SonarMark to query the SonarCloud API and generate the SonarCloud quality report markdown; expects exit code 0 and a non-empty markdown report. - -### Requirements Coverage - -- **BuildMark-OTS-SonarMark**: CI pipeline self-validation TRX evidence from - `artifacts/sonarmark-self-validation.trx` diff --git a/docs/verification/ots/versionmark.md b/docs/verification/ots/versionmark.md index 11b9444..0a4bc7b 100644 --- a/docs/verification/ots/versionmark.md +++ b/docs/verification/ots/versionmark.md @@ -34,9 +34,3 @@ The resulting TRX files are consumed by ReqStream to satisfy the OTS requirement - *VersionMark operational use*: VersionMark is invoked in every CI job to capture and publish tool version information; expects exit code 0 and correct version output for each job. - -### Requirements Coverage - -- **BuildMark-OTS-VersionMark**: CI pipeline self-validation TRX evidence from - `artifacts/versionmark-self-validation.trx` and - `artifacts/versionmark-self-validation-quality.trx` diff --git a/docs/verification/ots/weasyprint.md b/docs/verification/ots/weasyprint.md index 7ed865e..3992807 100644 --- a/docs/verification/ots/weasyprint.md +++ b/docs/verification/ots/weasyprint.md @@ -30,8 +30,3 @@ FileAssert TRX files (`fileassert-build-notes.trx`, `fileassert-code-quality.trx (Build Notes, Code Quality, Review Plan, Review Report, Design, User Guide, Verification); FileAssert validates the generated PDF output; expects exit code 0 for each invocation and non-empty PDF files confirmed by FileAssert to contain expected content and metadata. - -### Requirements Coverage - -- **BuildMark-OTS-WeasyPrint**: CI pipeline document generation evidence from multiple - FileAssert TRX results confirming successful PDF rendering diff --git a/docs/verification/ots/xunit.md b/docs/verification/ots/xunit.md index d67150c..6f2aaa9 100644 --- a/docs/verification/ots/xunit.md +++ b/docs/verification/ots/xunit.md @@ -28,8 +28,3 @@ provides broad platform coverage evidence. - *xUnit test discovery and execution*: CI pipeline executes `dotnet test` across the full OS and .NET version matrix (Windows, Ubuntu, macOS × .NET 8, 9, 10); expects zero test failures and a non-empty TRX result file for each platform/version combination. - -### Requirements Coverage - -- **BuildMark-OTS-xUnit**: CI pipeline test execution TRX evidence confirming that - xUnit discovers and runs tests on all supported platforms diff --git a/docs/verification/title.txt b/docs/verification/title.txt index 374bcef..71fb8d6 100644 --- a/docs/verification/title.txt +++ b/docs/verification/title.txt @@ -1,8 +1,8 @@ --- title: BuildMark Verification Design Document -subtitle: Build Notes Generation Tool +subtitle: Markdown Build Notes Generation Tool author: DEMA Consulting -description: Verification design document for BuildMark +description: Verification Design Document for BuildMark lang: en-US keywords: - BuildMark