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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .bot/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# .bot Workspace

This folder is reserved for local-only AI working material such as:

- brainstorm notes
- draft implementation plans
- design alternatives
- temporary agent state

Keep this folder out of source control. Move only finalized, non-confidential guidance into `AGENTS.md` or `.github/copilot-instructions.md`.
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
---
uid: Codebelt.Extensions.BenchmarkDotNet.Console
summary: *content
---
The `Codebelt.Extensions.BenchmarkDotNet.Console` namespace contains types that provide a structured and opinionated console-hosted execution model for `BenchmarkDotNet`.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
---
uid: Codebelt.Extensions.BenchmarkDotNet.Console
summary: *content
---
The `Codebelt.Extensions.BenchmarkDotNet.Console` namespace contains types that provide a structured and opinionated console-hosted execution model for `BenchmarkDotNet`.

Use `BenchmarkProgram.Run` for synchronous benchmark hosts and `BenchmarkProgram.RunAsync` for asynchronous benchmark hosts; both entry points support the default `BenchmarkWorkspace` and custom `IBenchmarkWorkspace` implementations.

[!INCLUDE [availability-modern](../../includes/availability-modern.md)]
22 changes: 22 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,28 @@ Internal classes and methods must be validated by exercising the public API that
- Public entry points provide sufficient coverage of internal code paths.
- The internal implementation exists solely as a helper or utility for public-facing functionality.

## 10. ExcludeFromCodeCoverage Prohibition

**Do not use `ExcludeFromCodeCoverage` attribute on any code.** This includes:

- Test classes or test methods
- Production code
- Configuration code
- Any other code path

### Rationale

- Excluding code from coverage hides gaps and creates false confidence in test completeness.
- If a code path cannot or should not be tested, refactor the code to eliminate that path rather than hiding it from metrics.
- Every executable line should be covered by tests or be genuinely unreachable (dead code to be removed).

### Alternative Approaches

- **Untestable code paths**: Refactor to separate concerns and eliminate the untestable path.
- **External dependencies**: Use test doubles (fakes, stubs, spies) instead of excluding from coverage.
- **Configuration-only code**: Move to configuration files or extract into testable methods.
- **Generated or third-party code**: These should not be in the primary codebase; use NuGet packages or dedicated vendor folders if necessary.

---
description: 'Writing Performance Tests in Codebelt.Extensions.BenchmarkDotNet'
applyTo: "tuning/**, **/*Benchmark*.cs"
Expand Down
87 changes: 80 additions & 7 deletions .github/workflows/ci-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@ on:
options:
- Debug
- Release
run_mac_tests:
type: boolean
description: Run the macOS test matrix despite the additional cost and runtime.
default: false

permissions:
contents: read
Expand All @@ -21,6 +25,7 @@ jobs:
name: initialize
runs-on: ubuntu-24.04
outputs:
run-mac-tests: ${{ steps.vars.outputs.run-mac-tests }}
run-privileged-jobs: ${{ steps.vars.outputs.run-privileged-jobs }}
strong-name-key-filename: ${{ steps.vars.outputs.strong-name-key-filename }}
build-switches: ${{ steps.vars.outputs.build-switches }}
Expand All @@ -29,6 +34,12 @@ jobs:
name: calculate workflow variables
shell: bash
run: |
if [[ "${{ github.event_name }}" == "workflow_dispatch" && "${{ inputs.run_mac_tests }}" == "true" ]]; then
echo "run-mac-tests=true" >> "$GITHUB_OUTPUT"
else
echo "run-mac-tests=false" >> "$GITHUB_OUTPUT"
fi

if [[ "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.head.repo.full_name }}" != "${{ github.repository }}" ]]; then
echo "run-privileged-jobs=false" >> "$GITHUB_OUTPUT"
echo "strong-name-key-filename=" >> "$GITHUB_OUTPUT"
Expand Down Expand Up @@ -101,10 +112,72 @@ jobs:
restore: true # we need to restore due to xUnitv3
download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }}

test_mac:
if: ${{ needs.init.outputs.run-mac-tests == 'true' }}
name: call-test-mac
needs: [init, build]
strategy:
fail-fast: false
matrix:
arch: [X64, ARM64]
configuration: [Debug, Release]
uses: codebeltnet/jobs-dotnet-test/.github/workflows/default.yml@v3
with:
runs-on: ${{ matrix.arch == 'ARM64' && 'macos-26' || 'macos-26-intel' }}
configuration: ${{ matrix.configuration }}
build-switches: -p:SkipSignAssembly=true
restore: true
build: true
download-pattern: build-${{ matrix.configuration }}-${{ matrix.arch }}

test_qualitygate:
if: ${{ always() }}
name: test-qualitygate
needs: [init, test_linux, test_windows, test_mac]
runs-on: ubuntu-24.04
steps:
- name: Evaluate test results
shell: bash
env:
RUN_MAC_TESTS: ${{ needs.init.outputs.run-mac-tests }}
TEST_LINUX_RESULT: ${{ needs.test_linux.result }}
TEST_WINDOWS_RESULT: ${{ needs.test_windows.result }}
TEST_MAC_RESULT: ${{ needs.test_mac.result }}
run: |
require_success() {
local job_name="$1"
local job_result="$2"

if [[ "$job_result" != "success" ]]; then
echo "::error::$job_name finished with '$job_result'."
exit 1
fi
}

require_success_or_skip() {
local job_name="$1"
local job_enabled="$2"
local job_result="$3"

if [[ "$job_enabled" == "true" ]]; then
require_success "$job_name" "$job_result"
return
fi

if [[ "$job_result" != "success" && "$job_result" != "skipped" ]]; then
echo "::error::$job_name finished with '$job_result' while disabled."
exit 1
fi
}

require_success "test_linux" "$TEST_LINUX_RESULT"
require_success "test_windows" "$TEST_WINDOWS_RESULT"
require_success_or_skip "test_mac" "$RUN_MAC_TESTS" "$TEST_MAC_RESULT"

sonarcloud:
if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-sonarcloud
needs: [init, build, test_linux, test_windows]
needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-sonarcloud/.github/workflows/default.yml@v3
with:
organization: geekle
Expand All @@ -113,26 +186,26 @@ jobs:
secrets: inherit

codecov:
if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-codecov
needs: [init, build, test_linux, test_windows]
needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-codecov/.github/workflows/default.yml@v1
with:
repository: codebeltnet/benchmarkdotnet
secrets: inherit

codeql:
if: ${{ needs.init.outputs.run-privileged-jobs == 'true' }}
if: ${{always() && needs.init.outputs.run-privileged-jobs == 'true' && needs.build.result == 'success' && needs.test_qualitygate.result == 'success'}}
name: call-codeql
needs: [init, build, test_linux, test_windows]
needs: [init, build, test_qualitygate]
uses: codebeltnet/jobs-codeql/.github/workflows/default.yml@v3
permissions:
security-events: write

deploy:
if: github.event_name != 'pull_request'
name: call-nuget
needs: [build, pack, test_linux, test_windows, sonarcloud, codecov, codeql]
needs: [build, pack, test_qualitygate, sonarcloud, codecov, codeql]
uses: codebeltnet/jobs-nuget-push/.github/workflows/default.yml@v3
with:
version: ${{ needs.build.outputs.version }}
Expand Down
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -374,4 +374,8 @@ FodyWeavers.xsd
*.code-workspace

# Strong-Name Key
*.snk
*.snk

# Bot workspace (local-only AI agent ideation, PRDs, and agentic loop state)
.bot/*
!.bot/README.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
Version: 1.2.7
Version: 1.3.0
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)


# ALM
- CHANGED Microsoft.NET.Test.Sdk has been upgraded from version 18.5.1 to 18.6.0 for improved test framework reliability

# Improvements
- EXTENDED BenchmarkProgram class in the Codebelt.Extensions.BenchmarkDotNet.Console namespace to include RunAsync equivalent methods of the existing Run methods for improved asynchronous hosting scenarios

Version: 1.2.7
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 1.2.6
Availability: .NET 10 and .NET 9

Expand Down
16 changes: 11 additions & 5 deletions .nuget/Codebelt.Extensions.BenchmarkDotNet/PackageReleaseNotes.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
Version: 1.2.7
Version: 1.3.0
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)


# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 1.2.7
Availability: .NET 10 and .NET 9

# ALM
- CHANGED Dependencies have been upgraded to the latest compatible versions for all supported target frameworks (TFMs)

Version: 1.2.6
Availability: .NET 10 and .NET 9

Expand Down
66 changes: 66 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Agent Instructions for Codebelt.Extensions.BenchmarkDotNet

This document provides guidance for AI agents working in this repository.

## Project Overview

Codebelt.Extensions.BenchmarkDotNet is a .NET library that provides a uniform, opinionated, and extensible way of working with BenchmarkDotNet. The solution targets .NET 10.0 and .NET 9.0.

## Coding Standards

- **Text encoding:** UTF-8 for text files (enforced via `.editorconfig`)
- **Template rewrites:** Preserve UTF-8 explicitly when scripts or tools rewrite text files; avoid locale-dependent encoding defaults
- **Namespaces:** File-scoped namespaces are required (enforced via `.editorconfig`)
- **Top-level statements:** Not allowed (enforced via `.editorconfig`)
- **Language version:** Always use the latest C# features (`LangVersion=latest`)
- **Nullable:** Enable nullable reference types in all new code
- **XML documentation:** All public APIs must have XML documentation comments
- **Testing:** Use xUnit v3 with Codebelt.Extensions.Xunit.App base classes

## Project Structure

- `src/` — Production source code
- `test/` — Unit and integration tests (project names end with `Tests`)
- `tuning/` — Benchmark projects and benchmark source code
- `tooling/` — Solution-level executable tooling such as the benchmark runner host
- `reports/` — Benchmark reports and tuning output produced by tooling
- `.nuget/` — Per-package NuGet metadata (icon, README, release notes)
- `.docfx/` — DocFX documentation configuration
- `.github/` — CI/CD workflows, contributing guidelines, Copilot instructions

## Test Conventions

- Test project names must end with `Tests` (e.g. `{PROJECT_NAME}.Tests`)
- Test classes should inherit from the appropriate base class in `Codebelt.Extensions.Xunit`
- Use `Microsoft.Testing.Platform` as the test runner (`UseMicrosoftTestingPlatformRunner=true`)
- All tests are executable (`OutputType=Exe`)

## Build & CI

- Centralized package versions via `Directory.Packages.props`
- Resolve new or updated `Directory.Packages.props` versions from NuGet.org and keep them on the latest stable listed releases
- Centralized build configuration via `Directory.Build.props`
- MinVer for semantic versioning from Git tags
- Strong-name signing is enabled in CI environments (`CI=true`)
- Keep `.github/dependabot.yml` enabled at the repo root so central NuGet package management stays current

## .bot/ Folder

If a `.bot/` folder exists at the root, it contains **confidential, local-only** working material for AI agents — product requirement documents (PRDs), design proposals, agentic loop state, and brainstorming outputs. This folder is gitignored and never committed.

When starting creative or design work (new features, architecture decisions, PRD drafts), use the [brainstorming skill](https://skills.sh/obra/superpowers/brainstorming) and save outputs to `.bot/`. Only move finalized, non-confidential instructions into `AGENTS.md` or `.github/copilot-instructions.md`.

## Git Operations Safeguards

Agents must never automatically commit code changes or push to remote repositories. Both actions require explicit user approval:

- **Commits**: Always request confirmation from the user before staging and committing code. Present a clear summary of the changes and wait for approval before executing the commit.
- **Remote Operations**: Do not push, pull, fetch, or interact with `origin` or any remote repository without explicit user instruction. These operations modify repository history and can cause data loss if performed unexpectedly.

**Rationale:** Automatic commits can clutter history with incomplete work, temporary debugging code, or unintended changes. Unexpected remote operations risk overwriting or losing commits on shared branches. Always require explicit user approval before performing these actions.

## Official Documentation

- Public API conventions belong in `.docfx/api/namespaces/` and should be treated as the official documentation source for library behavior and naming vocabulary.
- When adding or renaming public APIs, update the relevant namespace page in `.docfx/api/namespaces/` if the change introduces or clarifies a convention.
- Keep internal reasoning, exploratory notes, and agent discussion out of DocFX pages; summarize only stable public guidance.
26 changes: 25 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),

For more details, please refer to `PackageReleaseNotes.txt` on a per assembly basis in the `.nuget` folder.

## [1.3.0] - 2026-06-05

This is a minor release focused on code organization improvements, test coverage expansion, CI/CD pipeline hardening, and comprehensive agent guidance. The release refactors target framework parsing logic for better testability, expands the test suite for core workspace classes, extends CI/CD support to macOS environments, and establishes clear conventions and standards for AI agent collaboration in the repository.

### Added

- Comprehensive agent guidance document (AGENTS.md) for AI agents working in the repository, covering project overview, coding standards, project structure, test conventions, and CI/CD practices,
- Local-only `.bot/` folder for agent ideation, product requirement documents, design proposals, and agentic loop state,
- Code coverage standards to agent guidance establishing that `ExcludeFromCodeCoverage` attribute must not be used; unmeasurable code paths should be refactored or removed,
- macOS test matrix to CI/CD pipeline with conditional execution for platform-specific testing,
- Extracted `ParseTargetFrameworkMoniker` method in `BenchmarkWorkspaceOptions` class for improved code organization and testability,
- Expanded test coverage for `BenchmarkWorkspaceOptions`, `BenchmarkProgram`, and `ServiceCollectionExtensions` classes.

### Changed

- `BenchmarkProgram` class in the Codebelt.Extensions.BenchmarkDotNet.Console namespace was significantly enhanced with comprehensive async support including `RunAsync()` method overloads (both generic and non-generic variants) for asynchronous benchmark execution,
- Refactored target framework moniker parsing logic in `BenchmarkWorkspaceOptions` for better separation of concerns and improved testability,
- Upgraded `Microsoft.NET.Test.Sdk` from 18.5.1 to 18.6.0,
- Improved CI/CD pipeline configuration with more robust conditional execution logic,
- Updated documentation API references in Console namespace.

## [1.2.7] - 2026-05-22

This is a service update that focuses on package dependencies.
Expand Down Expand Up @@ -87,7 +108,10 @@ This is the initial stable release of the `Codebelt.Extensions.BenchmarkDotNet`
- ADDED `BenchmarkProgram` class in the Codebelt.Extensions.BenchmarkDotNet.Console namespace that provides the main entry point for hosting and running benchmarks using BenchmarkDotNet,
- ADDED `BenchmarkWorker` class in the Codebelt.Extensions.BenchmarkDotNet.Console namespace that is responsible for executing benchmarks within the console host.

[Unreleased]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.2.5...HEAD
[Unreleased]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.3.0...HEAD
[1.3.0]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.2.7...v1.3.0
[1.2.7]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.2.6...v1.2.7
[1.2.6]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.2.5...v1.2.6
[1.2.5]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.2.4...v1.2.5
[1.2.4]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.2.3...v1.2.4
[1.2.3]: https://github.com/codebeltnet/benchmarkdotnet/compare/v1.2.2...v1.2.3
Expand Down
2 changes: 2 additions & 0 deletions Codebelt.Extensions.BenchmarkDotNet.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
<Project Path="src/Codebelt.Extensions.BenchmarkDotNet/Codebelt.Extensions.BenchmarkDotNet.csproj" />
</Folder>
<Folder Name="/test/">
<Project Path="test/Codebelt.Extensions.BenchmarkDotNet.Console.FunctionalTests/Codebelt.Extensions.BenchmarkDotNet.Console.FunctionalTests.csproj" />
<Project Path="test/Codebelt.Extensions.BenchmarkDotNet.Console.Tests/Codebelt.Extensions.BenchmarkDotNet.Console.Tests.csproj" />
<Project Path="test/Codebelt.Extensions.BenchmarkDotNet.FunctionalTests/Codebelt.Extensions.BenchmarkDotNet.FunctionalTests.csproj" />
<Project Path="test/Codebelt.Extensions.BenchmarkDotNet.Tests/Codebelt.Extensions.BenchmarkDotNet.Tests.csproj" />
</Folder>
<Folder Name="/tooling/">
Expand Down
8 changes: 4 additions & 4 deletions Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
<ItemGroup>
<PackageVersion Include="BenchmarkDotNet" Version="0.15.8" />
<PackageVersion Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.15.8" />
<PackageVersion Include="Codebelt.Bootstrapper.Console" Version="5.0.7" />
<PackageVersion Include="Codebelt.Extensions.Xunit.App" Version="11.0.10" />
<PackageVersion Include="Cuemon.Core" Version="10.5.2" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.5.1" />
<PackageVersion Include="Codebelt.Bootstrapper.Console" Version="5.1.0" />
<PackageVersion Include="Codebelt.Extensions.Xunit.App" Version="11.1.0" />
<PackageVersion Include="Cuemon.Core" Version="10.5.3" />
<PackageVersion Include="Microsoft.NET.Test.Sdk" Version="18.6.0" />
<PackageVersion Include="MinVer" Version="7.0.0" />
<PackageVersion Include="coverlet.collector" Version="10.0.1" />
<PackageVersion Include="coverlet.msbuild" Version="10.0.1" />
Expand Down
Loading
Loading