Skip to content
Open
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
5 changes: 5 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ indent_size = 2

# Dotnet code style settings:
[*.{cs,vb}]
tab_width = 4

# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
# Avoid "this." and "Me." if not necessary
Expand Down Expand Up @@ -57,6 +59,9 @@ dotnet_style_require_accessibility_modifiers = omit_if_default:error
# IDE0040: Add accessibility modifiers
dotnet_diagnostic.IDE0040.severity = error

# IDE1100: Error reading content of source file 'Project.TargetFrameworkMoniker' (i.e. from ThisAssembly)
dotnet_diagnostic.IDE1100.severity = none

[*.cs]
# Top-level files are definitely OK
csharp_using_directive_placement = outside_namespace:silent
Expand Down
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# normalize by default
* text=auto encoding=UTF-8
*.sh text eol=lf
*.sbn eol=lf

# These are windows specific files which we may as well ensure are
# always crlf on checkout
Expand Down
94 changes: 94 additions & 0 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# .NET Repository

**Always reference these instructions first and fallback to search or bash commands only when you encounter unexpected information that does not match the info here.**

## Working Effectively

### Essential Build Commands
- **Restore dependencies**: `dotnet restore`

- **Build the entire solution**: `dotnet build`

- **Run tests**: `dnx --yes retest`
- Runs all unit tests across the solution
- If tests fail due to Azure Storage, run the following commands and retry: `npm install azurite` and `npx azurite &`

### Build Validation and CI Requirements
- **Always run before committing**:
* `dnx --yes retest`
* `dotnet format whitespace -v:diag --exclude ~/.nuget`
* `dotnet format style -v:diag --exclude ~/.nuget`

### Project Structure and Navigation

| Directory | Description |
|-----------|-------------|
| `src/` | Contains the repo source code. |
| `bin/` | Contains built packages (if any) |

### Code Style and Formatting

#### EditorConfig Rules
The repository uses `.editorconfig` at the repo root for consistent code style.

- **Indentation**: 4 spaces for C# files, 2 spaces for XML/YAML/JSON
- **Line endings**: LF (Unix-style)
- **Sort using directives**: System.* namespaces first (`dotnet_sort_system_directives_first = true`)
- **Type references**: Prefer language keywords over framework type names (`int` vs `Int32`)
- **Modern C# features**: Use object/collection initializers, coalesce expressions when possible, use var when the type is apparent from the right-hand side of the assignment
- **Visibility modifiers**: only explicitly specify visibility when different from the default (e.g. `public` for classes, no `internal` for classes or `private` for fields, etc.)

#### Formatting Validation
- CI enforces formatting with `dotnet format whitespace` and `dotnet format style`
- Run locally: `dotnet format whitespace --verify-no-changes -v:diag --exclude ~/.nuget`
- Fix formatting: `dotnet format` (without `--verify-no-changes`)

### Testing Practices

#### Test Framework
- **xUnit** for all unit and integration tests
- **Moq** for mocking dependencies
- Located in `src/*.Tests/`

#### Test Attributes
Custom xUnit attributes are sometimes used for conditional test execution:
- `[SecretsFact("XAI_API_KEY")]` - Skips test if required secrets are missing from user secrets or environment variables
- `[LocalFact("SECRET")]` - Runs only locally (skips in CI), requires specified secrets
- `[CIFact]` - Runs only in CI environment

### Dependency Management

#### Adding Dependencies
- Add to appropriate `.csproj` file
- Run `dotnet restore` to update dependencies
- Ensure version consistency across projects where applicable

#### CI/CD Pipeline
- **Build workflow**: `.github/workflows/build.yml` - runs on PR and push to main/rel/feature branches
- **Publish workflow**: Publishes to Sleet feed when `SLEET_CONNECTION` secret is available
- **OS matrix**: Configured in `.github/workflows/os-matrix.json` (defaults to ubuntu-latest)

### Special Files and Tools

#### dnx Command
- **Purpose**: built-in tool for running arbitrary dotnet tools that are published on nuget.org. `--yes` auto-confirms install before run.
- **Example**: `dnx --yes retest` - runs tests with automatic retry on transient failures (retest being a tool package published at https://www.nuget.org/packages/retest)
- **In CI**: `dnx --yes retest -- --no-build` (skips build, runs tests only)

#### Directory.Build.rsp
- MSBuild response file with default build arguments
- `-nr:false` - disables node reuse
- `-m:1` - single-threaded build (for stability)
- `-v:m` - minimal verbosity

#### Code Quality
- All PRs must pass format validation
- Tests must pass on all target frameworks
- Follow existing patterns and conventions in the codebase

## Documenting Work

Project implemention details, design and key decisions should be documented in a top-level AGENTS.md file at the repo root.
Keep this file updated whenever you make change significant changes for future reference.

User-facing features and APIs should be documented to highlight (not extensively, as an overview) key project features and capabilities, in the readme.md file at the repo root.
5 changes: 5 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ updates:
Extensions:
patterns:
- "Microsoft.Extensions*"
exclude-patterns:
- "Microsoft.Extensions.AI*"
ExtensionsAI:
patterns:
- "Microsoft.Extensions.AI*"
Web:
patterns:
- "Microsoft.AspNetCore*"
Expand Down
16 changes: 5 additions & 11 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ on:
- Release
- Debug
push:
branches: [ main, dev, 'dev/*', 'feature/*', 'rel/*' ]
branches: [ main, 'feature/*', 'rel/*' ]
paths-ignore:
- changelog.md
- readme.md
Expand Down Expand Up @@ -66,15 +66,14 @@ jobs:
fetch-depth: 0

- name: ⚙ dotnet
uses: ./.github/actions/dotnet
uses: devlooped/actions-dotnet-env@v1

- name: 🙏 build
run: dotnet build -m:1 -bl:build.binlog

- name: 🧪 test
run: |
dotnet tool update -g dotnet-retest
dotnet retest -- --no-build
shell: pwsh
run: dnx --yes retest -- --no-build

- name: 🐛 logs
uses: actions/upload-artifact@v4
Expand All @@ -101,12 +100,7 @@ jobs:
fetch-depth: 0

- name: ⚙ dotnet
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.x
8.x
9.x
uses: devlooped/actions-dotnet-env@v1

- name: ✓ ensure format
run: |
Expand Down
44 changes: 44 additions & 0 deletions .github/workflows/dotnet-env.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
name: dotnet-env
on:
workflow_dispatch:
push:
branches:
- main
paths:
- '**/*.*proj'

jobs:
which-dotnet:
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write

steps:
- name: 🤖 defaults
uses: devlooped/actions-bot@v1
with:
name: ${{ secrets.BOT_NAME }}
email: ${{ secrets.BOT_EMAIL }}
gh_token: ${{ secrets.GH_TOKEN }}
github_token: ${{ secrets.GITHUB_TOKEN }}

- name: 🤘 checkout
uses: actions/checkout@v4
with:
token: ${{ env.GH_TOKEN }}

- name: 🤌 dotnet
uses: devlooped/actions-which-dotnet@v1

- name: ✍ pull request
uses: peter-evans/create-pull-request@v7
with:
base: main
branch: which-dotnet
delete-branch: true
labels: dependencies
title: "⚙ Update dotnet versions"
body: "Update dotnet versions"
commit-message: "Update dotnet versions"
token: ${{ env.GH_TOKEN }}
28 changes: 24 additions & 4 deletions .github/workflows/includes.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ on:
branches:
- 'main'
paths:
- '**.md'
- '**.md'
- '!changelog.md'
- 'osmfeula.txt'

jobs:
includes:
Expand All @@ -31,14 +32,33 @@ jobs:
- name: +Mᐁ includes
uses: devlooped/actions-includes@v1

- name: 📝 OSMF EULA
shell: pwsh
run: |
$file = "osmfeula.txt"
$props = "src/Directory.Build.props"
if (-not (test-path $file) -or -not (test-path $props)) {
exit 0
}

$product = dotnet msbuild $props -getproperty:Product
if (-not $product) {
write-error 'To use OSMF EULA, ensure the $(Product) property is set in Directory.props'
exit 1
}

((get-content -raw $file) -replace '\$product\$',$product).trim() | set-content $file

- name: ✍ pull request
uses: peter-evans/create-pull-request@v6
uses: peter-evans/create-pull-request@v8
with:
add-paths: '**.md'
add-paths: |
**.md
*.txt
base: main
branch: markdown-includes
delete-branch: true
labels: docs
labels: dependencies
author: ${{ env.BOT_AUTHOR }}
committer: ${{ env.BOT_AUTHOR }}
commit-message: +Mᐁ includes
Expand Down
7 changes: 3 additions & 4 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,14 @@ jobs:
fetch-depth: 0

- name: ⚙ dotnet
uses: ./.github/actions/dotnet
uses: devlooped/actions-dotnet-env@v1

- name: 🙏 build
run: dotnet build -m:1 -bl:build.binlog

- name: 🧪 test
run: |
dotnet tool update -g dotnet-retest
dotnet retest -- --no-build
shell: pwsh
run: dnx --yes retest -- --no-build

- name: 🐛 logs
uses: actions/upload-artifact@v4
Expand Down
6 changes: 5 additions & 1 deletion .github/workflows/triage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,11 @@ jobs:
# if we don't have at least 100 requests left, wait until reset
if ($rate.remaining -lt 100) {
$wait = ($rate.reset - (Get-Date (Get-Date).ToUniversalTime() -UFormat %s))
echo "Rate limit remaining is $($rate.remaining), waiting for $($wait / 1000) seconds to reset"
if ($wait -gt 300) {
echo "Rate limit remaining is $($rate.remaining), reset in $wait seconds (more than 5'). Aborting."
exit 1
}
echo "Rate limit remaining is $($rate.remaining), waiting $wait seconds to reset"
sleep $wait
$rate = gh api rate_limit | convertfrom-json | select -expandproperty rate
echo "Rate limit has reset to $($rate.remaining) requests"
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ BenchmarkDotNet.Artifacts
.genaiscript
.idea
local.settings.json
.env
*.local

*.suo
*.sdf
Expand Down
Loading
Loading