diff --git a/.cspell.json b/.cspell.json new file mode 100644 index 0000000..8ff6bc1 --- /dev/null +++ b/.cspell.json @@ -0,0 +1,43 @@ +{ + "version": "0.2", + "language": "en", + "words": [ + "buildmark", + "BuildMark", + "copilot", + "cspell", + "csproj", + "Dema", + "demaconsulting", + "DEMACONSULTINGNUGETKEY", + "Dependabot", + "dependabot", + "dotnet", + "editorconfig", + "ibiqlik", + "markdownlint", + "mstest", + "ncipollo", + "nuget", + "nupkg", + "opencover", + "reqstream", + "snupkg", + "trx", + "yamllint" + ], + "ignorePaths": [ + "node_modules", + ".git", + "bin", + "obj", + "*.nupkg", + "*.snupkg", + "*.dll", + "*.exe", + "*.trx", + "*.spdx.json", + "package-lock.json", + "yarn.lock" + ] +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..de4966e --- /dev/null +++ b/.editorconfig @@ -0,0 +1,94 @@ +# EditorConfig is awesome: https://EditorConfig.org + +# top-most EditorConfig file +root = true + +# All files +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +insert_final_newline = true +trim_trailing_whitespace = true + +# Markdown files +[*.md] +trim_trailing_whitespace = false + +# YAML files +[*.{yml,yaml}] +indent_size = 2 + +# JSON files +[*.json] +indent_size = 2 + +# XML files +[*.{xml,csproj,props,targets}] +indent_size = 2 + +# C# files +[*.cs] +indent_size = 4 + +# Code style rules +csharp_prefer_braces = true:warning +csharp_prefer_simple_using_statement = true:suggestion +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_prefer_method_group_conversion = true:silent +csharp_style_prefer_top_level_statements = true:silent +csharp_style_expression_bodied_methods = false:silent +csharp_style_expression_bodied_constructors = false:silent +csharp_style_expression_bodied_operators = false:silent +csharp_style_expression_bodied_properties = true:silent +csharp_style_expression_bodied_indexers = true:silent +csharp_style_expression_bodied_accessors = true:silent +csharp_style_expression_bodied_lambdas = true:silent +csharp_style_expression_bodied_local_functions = false:silent + +# Naming conventions +dotnet_naming_rule.interface_should_be_begins_with_i.severity = warning +dotnet_naming_rule.interface_should_be_begins_with_i.symbols = interface +dotnet_naming_rule.interface_should_be_begins_with_i.style = begins_with_i + +dotnet_naming_rule.types_should_be_pascal_case.severity = warning +dotnet_naming_rule.types_should_be_pascal_case.symbols = types +dotnet_naming_rule.types_should_be_pascal_case.style = pascal_case + +dotnet_naming_rule.non_field_members_should_be_pascal_case.severity = warning +dotnet_naming_rule.non_field_members_should_be_pascal_case.symbols = non_field_members +dotnet_naming_rule.non_field_members_should_be_pascal_case.style = pascal_case + +# Symbol specifications +dotnet_naming_symbols.interface.applicable_kinds = interface +dotnet_naming_symbols.interface.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.interface.required_modifiers = + +dotnet_naming_symbols.types.applicable_kinds = class, struct, interface, enum +dotnet_naming_symbols.types.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.types.required_modifiers = + +dotnet_naming_symbols.non_field_members.applicable_kinds = property, event, method +dotnet_naming_symbols.non_field_members.applicable_accessibilities = public, internal, private, protected, protected_internal, private_protected +dotnet_naming_symbols.non_field_members.required_modifiers = + +# Naming styles +dotnet_naming_style.begins_with_i.required_prefix = I +dotnet_naming_style.begins_with_i.required_suffix = +dotnet_naming_style.begins_with_i.word_separator = +dotnet_naming_style.begins_with_i.capitalization = pascal_case + +dotnet_naming_style.pascal_case.required_prefix = +dotnet_naming_style.pascal_case.required_suffix = +dotnet_naming_style.pascal_case.word_separator = +dotnet_naming_style.pascal_case.capitalization = pascal_case + +# Organize usings +dotnet_sort_system_directives_first = true +dotnet_separate_import_directive_groups = false + +# Code quality - set to suggestion to not break existing code +dotnet_code_quality_unused_parameters = all:suggestion + +# Nullable reference types +csharp_nullable_reference_types = enable diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml new file mode 100644 index 0000000..70ba481 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -0,0 +1,115 @@ +--- +name: 🐛 Bug Report +description: Report a bug or issue with the BuildMark tool +title: "[Bug]: " +labels: ["bug"] +assignees: [] +body: + - type: markdown + attributes: + value: | + Thanks for taking the time to report a bug! Please fill out the sections below to help us understand and + fix the issue. + + - type: textarea + id: description + attributes: + label: Description + description: A clear and concise description of what the bug is. + placeholder: Describe the bug... + validations: + required: true + + - type: textarea + id: steps-to-reproduce + attributes: + label: Steps to Reproduce + description: Detailed steps to reproduce the behavior + placeholder: | + 1. Run BuildMark with command '...' + 2. Provide input file '...' + 3. Observe error... + value: | + 1. + 2. + 3. + validations: + required: true + + - type: textarea + id: expected-behavior + attributes: + label: Expected Behavior + description: A clear and concise description of what you expected to happen + placeholder: Describe what should happen... + validations: + required: true + + - type: textarea + id: actual-behavior + attributes: + label: Actual Behavior + description: A clear and concise description of what actually happened + placeholder: Describe what actually happens... + validations: + required: true + + - type: textarea + id: code-sample + attributes: + label: Code Sample + description: If applicable, provide a minimal code sample that reproduces the issue + placeholder: | + ```csharp + // Your code here + ``` + render: csharp + + - type: input + id: version + attributes: + label: Tool Version + description: What version of the BuildMark tool are you using? + placeholder: e.g., 1.0.0 + validations: + required: true + + - type: dropdown + id: dotnet-version + attributes: + label: .NET Version + description: What version of .NET are you using? + options: + - ".NET 8" + - ".NET 9" + - ".NET 10" + - Other (please specify in additional context) + validations: + required: true + + - type: input + id: os + attributes: + label: Operating System + description: What operating system are you using? + placeholder: e.g., Windows 11, Ubuntu 22.04, macOS 14.0 + + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: Add any other context about the problem here, such as error messages, stack traces, or screenshots + placeholder: Any additional information... + + - type: checkboxes + id: checklist + attributes: + label: Checklist + description: Please confirm the following + options: + - label: I have searched existing issues to ensure this is not a duplicate + required: true + - label: I have provided a clear description of the problem + required: true + - label: I have included steps to reproduce the issue + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..820af86 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,9 @@ +--- +blank_issues_enabled: false +contact_links: + - name: 📚 Documentation + url: https://github.com/demaconsulting/BuildMark + about: Read the documentation for BuildMark + - name: 💬 Discussions + url: https://github.com/demaconsulting/BuildMark/discussions + about: Ask questions and discuss with the community diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml new file mode 100644 index 0000000..fd52f52 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -0,0 +1,102 @@ +--- +name: ✨ Feature Request +description: Suggest a new feature or enhancement for the BuildMark tool +title: "[Feature]: " +labels: ["enhancement"] +assignees: [] +body: + - type: markdown + attributes: + value: | + Thanks for suggesting a feature! Please fill out the sections below to help us understand your request. + + - type: textarea + id: problem + attributes: + label: Problem Statement + description: Is your feature request related to a problem? Please describe. + placeholder: I'm frustrated when... / I need to be able to... + validations: + required: true + + - type: textarea + id: solution + attributes: + label: Proposed Solution + description: Describe the solution you'd like to see + placeholder: A clear and concise description of what you want to happen + validations: + required: true + + - type: textarea + id: alternatives + attributes: + label: Alternatives Considered + description: Describe any alternative solutions or features you've considered + placeholder: A clear and concise description of any alternative solutions or features + + - type: textarea + id: examples + attributes: + label: Usage Examples + description: If applicable, provide examples of how this feature would be used + placeholder: | + ```csharp + // Example usage + buildmark --input report.json --output report.md --feature-flag + ``` + render: csharp + + - type: textarea + id: benefits + attributes: + label: Benefits + description: Explain why this enhancement would be useful to BuildMark users + placeholder: This would be useful because... + validations: + required: true + + - type: dropdown + id: priority + attributes: + label: Priority + description: How important is this feature to you? + options: + - Low - Nice to have + - Medium - Would improve my workflow + - High - Blocking my use case + validations: + required: true + + - type: dropdown + id: willingness + attributes: + label: Willingness to Contribute + description: Would you be willing to contribute this feature? + options: + - "Yes, I can submit a pull request" + - "Yes, with guidance from maintainers" + - "No, but I can help test it" + - "No, I'm just suggesting" + validations: + required: true + + - type: textarea + id: additional-context + attributes: + label: Additional Context + description: Add any other context, screenshots, or links about the feature request here + placeholder: Any additional information... + + - type: checkboxes + id: checklist + attributes: + label: Checklist + description: Please confirm the following + options: + - label: I have searched existing issues to ensure this is not a duplicate + required: true + - label: I have provided a clear description of the feature + required: true + - label: I have explained why this feature would be useful + required: true diff --git a/.github/agents/documentation-writer.md b/.github/agents/documentation-writer.md new file mode 100644 index 0000000..41d5dba --- /dev/null +++ b/.github/agents/documentation-writer.md @@ -0,0 +1,47 @@ +--- +name: Documentation Writer +description: Expert agent for BuildMark documentation, requirements.yaml maintenance, and markdown/spell/YAML linting +--- + +# Documentation Writer - BuildMark + +Create and maintain clear, accurate documentation for the BuildMark .NET CLI tool. + +## When to Invoke This Agent + +Invoke the documentation-writer agent for: + +- Documentation updates and reviews (README.md, guides, CONTRIBUTING.md, etc.) +- Requirements updates in `requirements.yaml` (adding, modifying, or reviewing requirements) +- Ensuring requirements are properly linked to tests +- Markdown, spell checking, and YAML linting issues +- Documentation structure and organization improvements + +For requirements quality: After this agent updates requirements, invoke the software-quality-enforcer +agent to ensure requirements have proper test coverage and quality. + +## BuildMark-Specific Rules + +### Markdown + +- **README.md ONLY**: Absolute URLs (shipped in NuGet) - `https://github.com/demaconsulting/BuildMark/blob/main/FILE.md` +- **All other .md**: Reference-style links - `[text][ref]` with `[ref]: url` at file end +- Max 120 chars/line, lists need blank lines (MD032) + +### Requirements (requirements.yaml) + +- All requirements MUST link to tests (prefer `BuildMark_*` self-validation over unit tests) +- When adding features: add requirement + test linkage +- Test CLI commands before documenting +- After updating requirements, recommend invoking software-quality-enforcer to verify test quality + +### Linting Before Commit + +- markdownlint (see CI workflow) +- cspell (add terms to `.cspell.json`) +- yamllint + +## Don't + +- Change code to match docs +- Add docs for non-existent features diff --git a/.github/agents/project-maintainer.md b/.github/agents/project-maintainer.md new file mode 100644 index 0000000..508d314 --- /dev/null +++ b/.github/agents/project-maintainer.md @@ -0,0 +1,50 @@ +--- +name: Project Maintainer +description: Expert agent for BuildMark project management, dependencies, CI/CD, releases, and requirements traceability +--- + +# Project Maintainer - BuildMark + +Maintain BuildMark .NET CLI tool infrastructure, dependencies, releases, and requirements traceability. + +## BuildMark-Specific + +### Build + +- Targets: .NET 8.0, 9.0, 10.0 +- Zero warnings required (TreatWarningsAsErrors=true) + +### Workflows (.github/workflows) + +- **build.yaml**: Reusable (checkout, setup .NET, restore, build Release, test, pack, upload) +- **build_on_push.yaml**: Main CI/CD (quality checks, Windows+Linux builds) + +### Requirements Traceability (Critical) + +- `requirements.yaml` defines all project requirements +- ALL requirements MUST link to tests +- Enforced: `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce` +- Published as PDFs: "BuildMark Requirements.pdf", "BuildMark Trace Matrix.pdf" + +### Quality Gates (Must Pass) + +1. Build (zero warnings) +2. All tests pass +3. Markdown/spell/YAML linting +4. Requirements enforcement +5. CodeQL security + +### Commands + +```bash +dotnet tool restore && dotnet restore +dotnet build --no-restore --configuration Release +dotnet test --no-build --configuration Release +dotnet pack --no-build --configuration Release +``` + +## Don't + +- Merge without CI passing +- Ignore failing tests/builds +- Disable quality checks diff --git a/.github/agents/software-quality-enforcer.md b/.github/agents/software-quality-enforcer.md new file mode 100644 index 0000000..47e57a3 --- /dev/null +++ b/.github/agents/software-quality-enforcer.md @@ -0,0 +1,34 @@ +--- +name: Software Quality Enforcer +description: Code quality specialist for BuildMark - enforce testing, coverage >80%, static analysis, and zero warnings +--- + +# Software Quality Enforcer - BuildMark + +Enforce quality standards for BuildMark .NET CLI tool. + +## Quality Gates (ALL Must Pass) + +- Zero build warnings (TreatWarningsAsErrors=true) +- All tests passing +- Code coverage >80% +- Static analysis (Microsoft.CodeAnalysis.NetAnalyzers, SonarAnalyzer.CSharp) +- Code formatting (.editorconfig compliance) +- Markdown/spell/YAML linting +- Requirements traceability (all linked to tests) + +## BuildMark-Specific + +- **Test Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior` (for requirements traceability) +- **Test Linkage**: All requirements MUST link to tests (prefer `BuildMark_*` self-validation) +- **XML Docs**: On ALL members (public/internal/private) with spaces after `///` +- **No external runtime deps**: Only essential dependencies allowed + +## Commands + +```bash +dotnet build --configuration Release # Zero warnings required +dotnet test --configuration Release --collect "XPlat Code Coverage" +dotnet format --verify-no-changes +dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce +``` diff --git a/.github/codeql-config.yml b/.github/codeql-config.yml new file mode 100644 index 0000000..a291005 --- /dev/null +++ b/.github/codeql-config.yml @@ -0,0 +1,10 @@ +--- +name: "CodeQL Configuration for BuildMark" + +# Paths to exclude from analysis +paths-ignore: + - '**/bin/**' + - '**/obj/**' + - '**/TestResults/**' + - '**/*.Designer.cs' + - '**/*.generated.cs' diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..72aa9c9 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,20 @@ +--- +version: 2 +updates: + # GitHub Actions + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" + - "github-actions" + + # NuGet dependencies + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" + - "nuget" diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000..ad3c25c --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,63 @@ +# Pull Request + +## Description + + + +## Type of Change + + + +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) +- [ ] Documentation update +- [ ] Code quality improvement + +## Related Issues + + + +Closes # + +## Pre-Submission Checklist + +Before submitting this pull request, ensure you have completed the following: + +### Build and Test + +- [ ] Code builds successfully: `dotnet build --configuration Release` +- [ ] All tests pass: `dotnet test --configuration Release` +- [ ] Code produces zero warnings + +### Code Quality + +- [ ] Code formatting is correct: `dotnet format --verify-no-changes` +- [ ] New code has appropriate XML documentation comments +- [ ] Static analyzer warnings have been addressed + +### Quality Checks + +Please run the following checks before submitting: + +- [ ] **Spell checker passes**: `cspell "**/*.{md,cs}"` +- [ ] **Markdown linter passes**: `markdownlint "**/*.md"` +- [ ] **YAML linter passes**: `yamllint '**/*.{yml,yaml}'` + +### Testing + +- [ ] Added unit tests for new functionality +- [ ] Updated existing tests if behavior changed +- [ ] All tests follow the AAA (Arrange, Act, Assert) pattern +- [ ] Test coverage is maintained or improved + +### Documentation + +- [ ] Updated README.md (if applicable) +- [ ] Updated ARCHITECTURE.md (if applicable) +- [ ] Added code examples for new features (if applicable) +- [ ] Updated requirements.yaml (if applicable) + +## Additional Notes + + diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..fc5f08a --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,206 @@ +--- +on: + workflow_call: + inputs: + version: + required: true + type: string + secrets: + SONAR_TOKEN: + required: true + +jobs: + quality-checks: + name: Quality Checks + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Checkout + uses: actions/checkout@v6 + + - name: Run markdown linter + uses: DavidAnson/markdownlint-cli2-action@v22 + with: + globs: '**/*.md' + + - name: Run spell checker + uses: streetsidesoftware/cspell-action@v8 + with: + files: '**/*.{md,cs}' + + - name: Run YAML linter + uses: ibiqlik/action-yamllint@v3 + with: + config_file: .yamllint.yaml + + build: + name: Build ${{ matrix.os }} + needs: quality-checks + permissions: + contents: read + pull-requests: write + + strategy: + matrix: + os: [windows-latest, ubuntu-latest] + + runs-on: ${{ matrix.os }} + + steps: + + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Setup dotnet + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 8.x + 9.x + 10.x + + - name: Restore Dependencies + run: > + dotnet restore + + - name: Build + run: > + dotnet build + --no-restore + --configuration Release + --property:Version=${{ inputs.version }} + + - name: Test + run: > + dotnet test + --no-build + --configuration Release + --property:Version=${{ inputs.version }} + --collect "XPlat Code Coverage;Format=opencover" + --logger "trx;LogFilePrefix=${{ matrix.os }}" + --results-directory test-results + + - name: Create Dotnet Tool + run: > + dotnet pack + --no-build + --no-restore + --property:PackageVersion=${{ inputs.version }} + + - name: Upload Test Results + uses: actions/upload-artifact@v6 + with: + name: test-results-${{ matrix.os }} + path: test-results/*.trx + + - name: Upload Artifacts + uses: actions/upload-artifact@v6 + with: + name: artifacts-${{ matrix.os }} + path: | + src/DemaConsulting.BuildMark/bin/Release/*.nupkg + src/DemaConsulting.BuildMark/bin/Release/*.snupkg + + codeql: + name: CodeQL Analysis + runs-on: ubuntu-latest + needs: quality-checks + permissions: + actions: read + contents: read + security-events: write + + steps: + - name: Checkout + uses: actions/checkout@v6 + with: + fetch-depth: 0 + + - name: Initialize CodeQL + uses: github/codeql-action/init@v4 + with: + languages: csharp + queries: security-and-quality + config-file: ./.github/codeql-config.yml + + - name: Setup dotnet + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 8.x + 9.x + 10.x + + - name: Restore Dependencies + run: > + dotnet restore + + - name: Build + run: > + dotnet build + --no-restore + --configuration Release + --property:Version=${{ inputs.version }} + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v4 + with: + category: "/language:csharp" + output: sarif-results + upload: false + + - name: Upload CodeQL SARIF + uses: actions/upload-artifact@v6 + with: + name: codeql-sarif + path: sarif-results/csharp.sarif + + integration-test: + name: Integration Test ${{ matrix.os }} .NET ${{ matrix.dotnet-version }} + runs-on: ${{ matrix.os }} + needs: build + permissions: + contents: read + + strategy: + matrix: + os: [windows-latest, ubuntu-latest] + dotnet-version: ['8.x', '9.x', '10.x'] + + steps: + - name: Download package + uses: actions/download-artifact@v7 + with: + name: artifacts-${{ matrix.os }} + path: packages + + - name: Setup dotnet + uses: actions/setup-dotnet@v5 + with: + dotnet-version: ${{ matrix.dotnet-version }} + + - name: Install tool from package + shell: bash + run: | + echo "Installing package version ${{ inputs.version }} from: packages/" + dotnet tool install --global \ + --add-source packages \ + --version ${{ inputs.version }} \ + DemaConsulting.BuildMark + + - name: Test version display + shell: bash + run: | + echo "Testing buildmark --version..." + buildmark --version || { echo "✗ Version command failed"; exit 1; } + echo "✓ Version command succeeded" + + - name: Test help display + shell: bash + run: | + echo "Testing buildmark --help..." + buildmark --help || { echo "✗ Help command failed"; exit 1; } + echo "✓ Help command succeeded" diff --git a/.github/workflows/build_on_push.yaml b/.github/workflows/build_on_push.yaml new file mode 100644 index 0000000..d536b8e --- /dev/null +++ b/.github/workflows/build_on_push.yaml @@ -0,0 +1,22 @@ +--- +name: Build on Push + +on: + push: # On push to any branch + workflow_dispatch: # Allow manual trigger + schedule: # 5PM UTC every Monday + - cron: '0 17 * * 1' + +jobs: + build: + name: Build + permissions: + actions: read + contents: read + pull-requests: write + security-events: write + uses: ./.github/workflows/build.yaml + with: + version: 0.0.0-run.${{ github.run_number }} + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..7b1331c --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,71 @@ +--- +name: Release + +on: + workflow_dispatch: + inputs: + version: + description: 'Release version (1.0.0)' + required: true + type: string + publish: + description: 'Publish type' + required: true + type: choice + options: + - none + - release + - publish + +jobs: + build: + name: Build + permissions: + actions: read + contents: read + pull-requests: write + security-events: write + uses: ./.github/workflows/build.yaml + with: + version: ${{ inputs.version }} + secrets: + SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} + + release: + name: Release + runs-on: ubuntu-latest + needs: build + permissions: + contents: write + + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v5 + with: + dotnet-version: | + 8.x + 9.x + 10.x + + - name: Download package artifacts + uses: actions/download-artifact@v7 + with: + name: artifacts-ubuntu-latest + path: artifacts + + - name: Create GitHub Release + if: inputs.publish == 'release' || inputs.publish == 'publish' + uses: ncipollo/release-action@v1 + with: + tag: ${{ inputs.version }} + artifacts: artifacts/* + generateReleaseNotes: true + + - name: Publish to NuGet.org + if: inputs.publish == 'publish' + run: | + set -e + dotnet nuget push artifacts/*.nupkg \ + --api-key ${{ secrets.DEMACONSULTINGNUGETKEY }} \ + --source https://api.nuget.org/v3/index.json \ + --skip-duplicate diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ea48538 --- /dev/null +++ b/.gitignore @@ -0,0 +1,37 @@ +.vs +*.bak +*.user + +bin/ +obj/ +TestResults/ + +# Code coverage reports +coverage/ +*.coverage +*.coveragexml +*.opencover.xml + +# Test results +*.trx +test-results/ +*.log + +# Temporary files +*.tmp +.DS_Store + +# Node.js dependencies +node_modules/ +package-lock.json + +# Generated documentation +docs/*.pdf +docs/guide/*.html +docs/requirements/requirements.md +docs/requirements/*.html +docs/tracematrix/tracematrix.md +docs/tracematrix/*.html +docs/quality/sonar-quality.md +docs/quality/codeql-quality.md +docs/quality/*.html diff --git a/.markdownlint.json b/.markdownlint.json new file mode 100644 index 0000000..e3884ab --- /dev/null +++ b/.markdownlint.json @@ -0,0 +1,8 @@ +{ + "default": true, + "MD003": { "style": "atx" }, + "MD007": { "indent": 2 }, + "MD013": { "line_length": 120 }, + "MD033": false, + "MD041": false +} diff --git a/.yamllint.yaml b/.yamllint.yaml new file mode 100644 index 0000000..9cb6241 --- /dev/null +++ b/.yamllint.yaml @@ -0,0 +1,25 @@ +--- +# yamllint configuration for BuildMark +# This configuration defines the rules for YAML file linting + +extends: default + +rules: + # Allow 'on:' in GitHub Actions workflows (not a boolean value) + truthy: + allowed-values: ['true', 'false', 'on', 'off'] + check-keys: true + + # Allow longer lines for URLs and complex expressions + line-length: + max: 120 + level: error + + # Ensure proper indentation + indentation: + spaces: 2 + indent-sequences: true + + # Ensure proper comment formatting + comments: + min-spaces-from-content: 2 diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..e613609 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,62 @@ +# Agent Quick Reference + +Project-specific guidance for agents working on BuildMark - a .NET CLI tool for generating markdown build notes. + +## Tech Stack + +- C# 12, .NET 8.0/9.0/10.0, MSTest, dotnet CLI, NuGet + +## Key Files + +- **`requirements.yaml`** - All requirements with test linkage (enforced via `dotnet reqstream --enforce`) +- **`.editorconfig`** - Code style (file-scoped namespaces, 4-space indent, UTF-8+BOM, LF endings) +- **`.cspell.json`, `.markdownlint.json`, `.yamllint.yaml`** - Linting configs + +## Requirements (BuildMark-Specific) + +- Link ALL requirements to tests (prefer `BuildMark_*` self-validation over unit tests) +- Enforced in CI: `dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce` +- When adding features: add requirement + link to test + +## Testing (BuildMark-Specific) + +- **Test Naming**: `ClassName_MethodUnderTest_Scenario_ExpectedBehavior` (for requirements traceability) +- **MSTest v4**: Use `Assert.HasCount()`, `Assert.IsEmpty()`, `Assert.DoesNotContain()` (not old APIs) +- **Console Tests**: Always save/restore `Console.Out` in try/finally + +## Code Style (BuildMark-Specific) + +- **XML Docs**: On ALL members (public/internal/private) with spaces after `///` in summaries +- **Errors**: `ArgumentException` for parsing, `InvalidOperationException` for runtime, Write* only after success +- **No code duplication**: Extract to properties/methods + +## Linting (BuildMark-Specific) + +- **README.md**: Absolute URLs only (shipped in NuGet package) +- **Other .md**: Reference-style links `[text][ref]` with `[ref]: url` at end +- **All linters must pass locally**: markdownlint, cspell, yamllint (see CI workflows for commands) + +## Build & Quality (Quick Reference) + +```bash +# Standard build/test +dotnet build --configuration Release && dotnet test --configuration Release + +# Pre-finalization checklist (in order): +# 1. Build/test (zero warnings required) +# 2. code_review tool +# 3. codeql_checker tool +# 4. All linters (markdownlint, cspell, yamllint) +# 5. Requirements: dotnet reqstream --requirements requirements.yaml --tests "test-results/**/*.trx" --enforce +``` + +## Custom Agents + +Delegate tasks to specialized agents for better results: + +- **documentation-writer** - Invoke for: documentation updates/reviews, requirements.yaml changes, + markdown/spell/YAML linting +- **project-maintainer** - Invoke for: dependency updates, CI/CD maintenance, releases, requirements + traceability enforcement +- **software-quality-enforcer** - Invoke for: code quality reviews, test coverage verification (>80%), + static analysis, zero-warning builds, requirements test quality diff --git a/DemaConsulting.BuildMark.slnx b/DemaConsulting.BuildMark.slnx new file mode 100644 index 0000000..8b257ba --- /dev/null +++ b/DemaConsulting.BuildMark.slnx @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/Icon.png b/Icon.png new file mode 100644 index 0000000..fe8a0ae Binary files /dev/null and b/Icon.png differ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..a665927 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 DEMA Consulting + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index e60336e..28dae75 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # BuildMark + Tool to generate Markdown Build Notes diff --git a/src/DemaConsulting.BuildMark/DemaConsulting.BuildMark.csproj b/src/DemaConsulting.BuildMark/DemaConsulting.BuildMark.csproj new file mode 100644 index 0000000..0a93b8b --- /dev/null +++ b/src/DemaConsulting.BuildMark/DemaConsulting.BuildMark.csproj @@ -0,0 +1,71 @@ + + + + Exe + net8.0;net9.0;net10.0 + 12 + enable + enable + + + true + buildmark + DemaConsulting.BuildMark + 0.0.0 + DEMA Consulting + DEMA Consulting + Tool to generate Markdown Build Notes + MIT + https://github.com/demaconsulting/BuildMark + https://github.com/demaconsulting/BuildMark + README.md + Icon.png + build;markdown;documentation + Copyright DEMA Consulting + BuildMark Tool + DemaConsulting.BuildMark + + + true + snupkg + true + true + true + + + true + True + true + true + latest + + + true + $(PackageId) + $(Version) + Organization: $(Company) + + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + + + + + + diff --git a/src/DemaConsulting.BuildMark/Program.cs b/src/DemaConsulting.BuildMark/Program.cs new file mode 100644 index 0000000..ae5c8f5 --- /dev/null +++ b/src/DemaConsulting.BuildMark/Program.cs @@ -0,0 +1,74 @@ +// Copyright (c) DEMA Consulting +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System.Reflection; + +namespace DemaConsulting.BuildMark; + +/// +/// Main program entry point for the BuildMark tool. +/// +internal static class Program +{ + /// + /// Gets the application version string. + /// + public static string Version + { + get + { + var assembly = typeof(Program).Assembly; + return assembly.GetCustomAttribute()?.InformationalVersion + ?? assembly.GetName().Version?.ToString() + ?? "0.0.0"; + } + } + + /// + /// Main entry point for the BuildMark tool. + /// + /// Command-line arguments. + /// Exit code: 0 for success, non-zero for failure. + private static int Main(string[] args) + { + // Print version if --version is specified + if (args.Length > 0 && args[0] == "--version") + { + Console.WriteLine($"BuildMark version {Version}"); + return 0; + } + + // Print help if --help is specified or no arguments + if (args.Length == 0 || args[0] == "--help") + { + Console.WriteLine("BuildMark - Tool to generate Markdown Build Notes"); + Console.WriteLine(); + Console.WriteLine("Usage: buildmark [options]"); + Console.WriteLine(); + Console.WriteLine("Options:"); + Console.WriteLine(" --version Display version information"); + Console.WriteLine(" --help Display this help message"); + return 0; + } + + Console.WriteLine("Hello from BuildMark!"); + return 0; + } +} diff --git a/test/DemaConsulting.BuildMark.Tests/AssemblyInfo.cs b/test/DemaConsulting.BuildMark.Tests/AssemblyInfo.cs new file mode 100644 index 0000000..495b4f8 --- /dev/null +++ b/test/DemaConsulting.BuildMark.Tests/AssemblyInfo.cs @@ -0,0 +1,21 @@ +// Copyright (c) DEMA Consulting +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +[assembly: DoNotParallelize] diff --git a/test/DemaConsulting.BuildMark.Tests/DemaConsulting.BuildMark.Tests.csproj b/test/DemaConsulting.BuildMark.Tests/DemaConsulting.BuildMark.Tests.csproj new file mode 100644 index 0000000..540e396 --- /dev/null +++ b/test/DemaConsulting.BuildMark.Tests/DemaConsulting.BuildMark.Tests.csproj @@ -0,0 +1,39 @@ + + + net8.0;net9.0;net10.0 + 12 + enable + enable + true + true + true + latest + + false + true + True + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + + diff --git a/test/DemaConsulting.BuildMark.Tests/ProgramTests.cs b/test/DemaConsulting.BuildMark.Tests/ProgramTests.cs new file mode 100644 index 0000000..44937ad --- /dev/null +++ b/test/DemaConsulting.BuildMark.Tests/ProgramTests.cs @@ -0,0 +1,42 @@ +// Copyright (c) DEMA Consulting +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +namespace DemaConsulting.BuildMark.Tests; + +/// +/// Tests for the Program class. +/// +[TestClass] +public class ProgramTests +{ + /// + /// Test that the version property returns a valid version string. + /// + [TestMethod] + public void Program_Version_ReturnsValidVersion() + { + // Act + var version = Program.Version; + + // Assert + Assert.IsNotNull(version); + Assert.IsFalse(string.IsNullOrWhiteSpace(version)); + } +}