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
7 changes: 0 additions & 7 deletions .config/dotnet-tools.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,6 @@
],
"rollForward": false
},
"husky": {
"version": "0.9.1",
"commands": [
"husky"
],
"rollForward": false
},
"dotnet-outdated-tool": {
"version": "4.7.1",
"commands": [
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "ProjectTemplate",
"name": "ProjectTemplate (.NET)",
"image": "mcr.microsoft.com/devcontainers/dotnet:1-10.0",

"features": {
Expand Down Expand Up @@ -29,27 +29,19 @@
],

"remoteUser": "vscode",
// workspaceFolder defaults to /workspaces/${localWorkspaceFolderBasename},
// which makes the devcontainer config portable: when this template is
// forked into a repo with a different folder name, the mount path tracks
// the host folder name automatically.

// The bind-mount on macOS hosts surfaces /home/vscode/.ssh as root-owned;
// chown it back so writes from inside the container (known_hosts updates
// by gh / git) land cleanly. Idempotent on Linux/WSL2.
"onCreateCommand": "sudo install -d -m 700 -o vscode -g vscode /home/vscode/.ssh",

// Install uv for the Python sibling project, restore .NET local tools,
// and install the husky git hooks. uv is installed under $HOME/.local/bin
// and added to PATH by uv's install script.
"postCreateCommand": ".devcontainer/post-create.sh",
// Restore .NET local tools (csharpier, dotnet-outdated). No git hooks are
// installed by default — see README "Optional: enable git hooks locally".
"postCreateCommand": ".devcontainer/dotnet/post-create.sh",

"customizations": {
"vscode": {
// Mirror of `recommendations` in ProjectTemplate.code-workspace.
// Pyright type checking is provided by Pylance, which the
// ms-python.python extension auto-installs — no separate pyright
// extension needed (and the standalone one is in maintenance mode).
// Mirror of `recommendations` in DotNet.code-workspace.
"extensions": [
"csharpier.csharpier-vscode",
"davidanson.vscode-markdownlint",
Expand All @@ -59,9 +51,7 @@
"ms-azuretools.vscode-docker",
"ms-dotnettools.csdevkit",
"streetsidesoftware.code-spell-checker",
"yzhang.markdown-all-in-one",
"ms-python.python",
"charliermarsh.ruff"
"yzhang.markdown-all-in-one"
]
}
}
Expand Down
5 changes: 5 additions & 0 deletions .devcontainer/dotnet/post-create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/usr/bin/env bash
set -euo pipefail

# Restore the .NET local-tool manifest (csharpier, dotnet-outdated).
dotnet tool restore
58 changes: 58 additions & 0 deletions .devcontainer/python/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
{
"name": "ProjectTemplate (Python)",
"image": "mcr.microsoft.com/devcontainers/python:1-3.14-bookworm",

"features": {
"ghcr.io/devcontainers/features/common-utils:2": {},
"ghcr.io/devcontainers/features/github-cli:1": {}
},

"mounts": [
{
"source": "${localEnv:HOME}${localEnv:USERPROFILE}/.ssh/id_ed25519.pub",
"target": "/home/vscode/.ssh/id_ed25519.pub",
"type": "bind",
"readonly": true
},
{
"source": "${localEnv:HOME}${localEnv:USERPROFILE}/.config/git/allowed_signers",
"target": "/home/vscode/.config/git/allowed_signers",
"type": "bind",
"readonly": true
},
{
"source": "${localEnv:HOME}${localEnv:USERPROFILE}/.config/gh",
"target": "/home/vscode/.config/gh",
"type": "bind",
"readonly": false
}
],

"remoteUser": "vscode",

// The bind-mount on macOS hosts surfaces /home/vscode/.ssh as root-owned;
// chown it back so writes from inside the container (known_hosts updates
// by gh / git) land cleanly. Idempotent on Linux/WSL2.
"onCreateCommand": "sudo install -d -m 700 -o vscode -g vscode /home/vscode/.ssh",

// Install pinned uv and pre-warm the PyPiLibrary venv. No git hooks are
// installed by default — see README "Optional: enable git hooks locally".
"postCreateCommand": ".devcontainer/python/post-create.sh",

"customizations": {
"vscode": {
// Mirror of `recommendations` in Python.code-workspace.
"extensions": [
"charliermarsh.ruff",
"davidanson.vscode-markdownlint",
"editorconfig.editorconfig",
"github.vscode-github-actions",
"gruntfuggly.todo-tree",
"ms-azuretools.vscode-docker",
"ms-python.python",
"streetsidesoftware.code-spell-checker",
"yzhang.markdown-all-in-one"
]
}
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail

# Install uv (Astral) for the Python sibling project. Idempotent — re-running
# Install uv (Astral) for the Python project. Idempotent — re-running
# overwrites in place. The installer drops the binary in $HOME/.local/bin and
# updates user shell init to add it to PATH for new shells; we add it to the
# current PATH explicitly so the rest of this script can invoke `uv` without a
Expand Down Expand Up @@ -40,14 +40,6 @@ if [[ "$installed_uv_version" != "$UV_VERSION" ]]; then
export PATH="$HOME/.local/bin:$PATH"
fi

# Restore the .NET local-tool manifest (CSharpier, Husky.Net, dotnet-outdated).
dotnet tool restore

# Install Husky.Net git hooks so commits run pre-commit checks. Failures here
# (e.g. missing .git directory, broken tool restore) should surface — the
# devcontainer setup is not "successful" if hook installation fails silently.
dotnet husky install

# Pre-warm uv environment for PyPiLibrary if it exists. Guarded so this script
# is safe before PyPiLibrary lands in the repo.
if [[ -f PyPiLibrary/pyproject.toml ]]; then
Expand Down
1 change: 0 additions & 1 deletion .github/workflows/run-codegen-app-pull-request-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ jobs:
- name: Format code step
run: |
dotnet tool restore
dotnet husky install
dotnet csharpier format --log-level=debug .
git status

Expand Down
1 change: 0 additions & 1 deletion .github/workflows/run-codegen-pull-request-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ jobs:
- name: Format code step
run: |
dotnet tool restore
dotnet husky install
dotnet csharpier format --log-level=debug .
git status

Expand Down
13 changes: 8 additions & 5 deletions .github/workflows/test-release-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ jobs:
- name: Checkout code step
uses: actions/checkout@v6

- name: Check code style step
run: |
dotnet tool restore
dotnet husky install
dotnet husky run
- name: Restore .NET local tools step
run: dotnet tool restore

- name: Check formatting with CSharpier step
run: dotnet csharpier check .

- name: Verify .NET style with dotnet format step
run: dotnet format style --verify-no-changes --severity=info --verbosity=detailed
Comment thread
ptr727 marked this conversation as resolved.

- name: Run unit tests step
run: dotnet test
Expand Down
4 changes: 0 additions & 4 deletions .husky/pre-commit

This file was deleted.

58 changes: 0 additions & 58 deletions .husky/task-runner.json

This file was deleted.

16 changes: 0 additions & 16 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,22 +77,6 @@
"clear": false
}
},
{
"label": "Husky.Net Run",
"type": "process",
"command": "dotnet",
"args": [
"husky",
"run"
],
"problemMatcher": [
"$msCompile"
],
"presentation": {
"showReuseMessage": false,
"clear": false
}
},
{
"label": ".Net Benchmark",
"type": "process",
Expand Down
12 changes: 8 additions & 4 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -121,9 +121,11 @@ These conventions describe the target state. New and modified workflows must res

## Devcontainer

[.devcontainer/devcontainer.json](./.devcontainer/devcontainer.json) bind-mounts the host SSH signing key's *public half* (`~/.ssh/id_ed25519.pub`), `~/.config/git/allowed_signers`, and `~/.config/gh` so commits inside the container are SSH-signed (signing happens via the forwarded `ssh-agent` socket — the private key never enters the container) and, *when the host's `gh` token is file-backed*, `gh` is pre-authenticated. On Keychain (macOS) or libsecret (Linux) hosts, `~/.config/gh/hosts.yml` carries no `oauth_token`, so container `gh` is unauthenticated until the contributor opts into `gh auth login` inside the container. See [docs/devcontainer.md](./docs/devcontainer.md) for full setup, [docs/host-setup.md](./docs/host-setup.md) for prerequisites, and [docs/ssh-signing.md](./docs/ssh-signing.md) for the SSH commit signing details.
The repo ships **two per-language devcontainers** so each container carries only one toolchain (and the matching VS Code extensions): [`.devcontainer/dotnet/devcontainer.json`](./.devcontainer/dotnet/devcontainer.json) (.NET 10 SDK) and [`.devcontainer/python/devcontainer.json`](./.devcontainer/python/devcontainer.json) (Python 3.14 + version-pinned `uv`). Open [`DotNet.code-workspace`](./DotNet.code-workspace) or [`Python.code-workspace`](./Python.code-workspace) and pick **Reopen in Container** to land in the matching one.

The unified container hosts both `.NET 10` (base image) and Python via uv (installed in `.devcontainer/post-create.sh` from a version-pinned URL). The extension list in `.devcontainer/devcontainer.json` and `recommendations` in [`ProjectTemplate.code-workspace`](./ProjectTemplate.code-workspace) are kept identical — when you add an extension to one, add it to the other.
Both containers bind-mount the host SSH signing key's *public half* (`~/.ssh/id_ed25519.pub`), `~/.config/git/allowed_signers`, and `~/.config/gh` so commits inside the container are SSH-signed (signing happens via the forwarded `ssh-agent` socket — the private key never enters the container) and, *when the host's `gh` token is file-backed*, `gh` is pre-authenticated. On Keychain (macOS) or libsecret (Linux) hosts, `~/.config/gh/hosts.yml` carries no `oauth_token`, so container `gh` is unauthenticated until the contributor opts into `gh auth login` inside the container. See [docs/devcontainer.md](./docs/devcontainer.md) for full setup, [docs/host-setup.md](./docs/host-setup.md) for prerequisites, and [docs/ssh-signing.md](./docs/ssh-signing.md) for the SSH commit signing details.

Each devcontainer's `customizations.vscode.extensions` mirrors the `recommendations` array in its matching workspace file — when you add an extension to one, add it to the other.

## Project Structure (Languages)

Expand All @@ -139,7 +141,8 @@ The unified container hosts both `.NET 10` (base image) and Python via uv (insta
- **Style guide: [`PyPiLibrary/CODESTYLE.md`](./PyPiLibrary/CODESTYLE.md)**.
- **Cross-cutting**:
- `.github/` — workflows, Dependabot, Copilot instructions
- `.devcontainer/` — devcontainer config + post-create script
- `.devcontainer/dotnet/` and `.devcontainer/python/` — per-language devcontainer configs + post-create scripts
- `DotNet.code-workspace`, `Python.code-workspace` — per-language VS Code workspace files (each pairs with its devcontainer)
- `.vscode/` — debug configs and tasks (.NET-oriented)
- `Docker/` — multi-platform Linux container build for the Console app

Expand All @@ -152,6 +155,7 @@ When you touch code in either language, also respect that language's style guide
3. **Read** [CODESTYLE.md](./CODESTYLE.md) (.NET) and/or [PyPiLibrary/CODESTYLE.md](./PyPiLibrary/CODESTYLE.md) (Python) for the per-language style.
4. **Update project-specific values** — `PackageId`/`RootNamespace` in `.csproj`, `name` in `pyproject.toml`, namespace conventions, `README.md`, `HISTORY.md`, `version.json`, `LICENSE`, NuGet/PyPI badge URLs.
5. **Run tools before first commit**:
- .NET: `dotnet tool restore` and `dotnet husky install`.
- .NET: `dotnet tool restore`.
- Python: `cd PyPiLibrary && uv sync`.
- Optional pre-commit hooks (off by default) — see README "Optional: enable git hooks locally".
6. **Wire up release credentials** when ready to publish — see the README's release notes section and [PyPiLibrary/README.md](./PyPiLibrary/README.md) for PyPI Trusted Publisher setup.
15 changes: 6 additions & 9 deletions CODESTYLE.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,9 @@ Cross-cutting rules (PR titles, branching, US English, markdown style, workflow
- `<EnableNETAnalyzers>true</EnableNETAnalyzers>`
- Analyzer severity is `suggestion`, but all warnings must be addressed

3. **Husky.Net pre-commit hooks**
- Automated checks run before commits
3. **CI lint backstop**
- `dotnet csharpier check` and `dotnet format style --verify-no-changes` run on every PR
- No git hooks ship by default — see README "Optional: enable git hooks locally" to opt in

### Build Tasks

Expand All @@ -32,7 +33,6 @@ Available VS Code tasks (use via `run_task` tool):
- `CSharpier Format`: Auto-format code with CSharpier
- `.Net Tool Update`: Update dotnet tools
- `.Net Outdated Upgrade`: Upgrade outdated NuGet dependencies (interactive prompt)
- `Husky.Net Run`: Run pre-commit hooks manually

## Tooling and Editor

Expand All @@ -44,15 +44,12 @@ Available VS Code tasks (use via `run_task` tool):
2. **dotnet format**: Style verification
- Verify no changes: `dotnet format style --verify-no-changes --severity=info --verbosity=detailed`

3. **Husky.Net**: Git hooks for automated checks
- Installed as a local dotnet tool (via `dotnet tool restore`)
- Install Git hooks locally with `dotnet husky install`
- Pre-commit hooks run formatting and style checks

4. **Other tools**
3. **Other tools**
- `dotnet-outdated-tool`: Dependency update checks
- Nerdbank.GitVersioning: Version management

Pre-commit git hooks are not installed by default — CI is the lint backstop. See README "Optional: enable git hooks locally" if you want Husky.Net (or another runner) wired up locally.

### Editor Baseline

1. **Required VS Code extensions**: CSharpier, markdownlint, CSpell
Expand Down
Loading
Loading