Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
65 changes: 65 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
{
"name": "ProjectTemplate",
"image": "mcr.microsoft.com/devcontainers/dotnet:1-10.0",

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

"mounts": [
{
"source": "${localEnv:HOME}/.ssh/id_ed25519.pub",
"target": "/home/vscode/.ssh/id_ed25519.pub",
"type": "bind",
"readonly": true
},
{
"source": "${localEnv:HOME}/.config/git/allowed_signers",
"target": "/home/vscode/.config/git/allowed_signers",
"type": "bind",
"readonly": true
},
{
"source": "${localEnv:HOME}/.config/gh",
Comment thread
ptr727 marked this conversation as resolved.
Outdated
"target": "/home/vscode/.config/gh",
"type": "bind",
"readonly": false
}
],

"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",

"customizations": {
"vscode": {
"extensions": [
"csharpier.csharpier-vscode",
"davidanson.vscode-markdownlint",
"editorconfig.editorconfig",
"github.vscode-github-actions",
"gruntfuggly.todo-tree",
"ms-azuretools.vscode-docker",
"ms-dotnettools.csdevkit",
"streetsidesoftware.code-spell-checker",
"yzhang.markdown-all-in-one",
"ms-python.python",
"charliermarsh.ruff",
"ms-pyright.pyright"
]
}
}
}
26 changes: 26 additions & 0 deletions .devcontainer/post-create.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/usr/bin/env bash
set -euo pipefail

# Install uv (Astral) for the Python sibling 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
# hard-coded path.
if ! command -v uv >/dev/null 2>&1; then
Comment thread
ptr727 marked this conversation as resolved.
Outdated
curl -LsSf https://astral.sh/uv/install.sh | sh
Comment thread
ptr727 marked this conversation as resolved.
Outdated
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
(cd PyPiLibrary && uv sync)
fi
Comment thread
ptr727 marked this conversation as resolved.
12 changes: 6 additions & 6 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

**ProjectTemplate** is a C# .NET template project that demonstrates best practices for C# .NET development. The project includes:

- **Library**: Core library with AOT compatibility (`Library.csproj`)
- **NuGetLibrary**: Core .NET NuGet library with AOT compatibility (`NuGetLibrary.csproj`, published as `ptr727.ProjectTemplate.Library`)
- **Console**: Command-line application using System.CommandLine (`Console.csproj`)
- **Tests**: Unit tests using xUnit and AwesomeAssertions (`Tests.csproj`)
- **Benchmarks**: Performance benchmarks using BenchmarkDotNet (`Benchmarks.csproj`)
Expand Down Expand Up @@ -43,7 +43,7 @@ Available VS Code tasks (use via `run_task` tool):

1. **File-Scoped Namespaces**: Always use file-scoped namespaces
```csharp
namespace ptr727.ProjectTemplate.Library;
namespace ptr727.ProjectTemplate.NuGetLibrary;
```

2. **Nullable Reference Types**: Enabled (`<Nullable>enable</Nullable>`)
Expand Down Expand Up @@ -92,7 +92,7 @@ Available VS Code tasks (use via `run_task` tool):
```

4. **Namespace**: Follow format `ptr727.ProjectTemplate.<ProjectName>`
- Library: `ptr727.ProjectTemplate.Library`
- NuGetLibrary: `ptr727.ProjectTemplate.NuGetLibrary`
- Console: `ptr727.ProjectTemplate.Console`
- Tests: `ptr727.ProjectTemplate.Tests`

Expand All @@ -110,7 +110,7 @@ Available VS Code tasks (use via `run_task` tool):
```csharp
using System.CommandLine;
using System.Runtime.CompilerServices;
using ptr727.ProjectTemplate.Library;
using ptr727.ProjectTemplate.NuGetLibrary;

namespace ptr727.ProjectTemplate.Console;
```
Expand Down Expand Up @@ -211,7 +211,7 @@ Available VS Code tasks (use via `run_task` tool):

1. **Target Framework**: .NET 10.0 (`<TargetFramework>net10.0</TargetFramework>`)

2. **AOT Compatibility**: Library is AOT compatible
2. **AOT Compatibility**: NuGetLibrary is AOT compatible
- `<IsAotCompatible>true</IsAotCompatible>`
- `<VerifyReferenceAotCompatibility>true</VerifyReferenceAotCompatibility>`

Expand Down Expand Up @@ -292,7 +292,7 @@ Available VS Code tasks (use via `run_task` tool):
- `CodeGen/` - Code generation utilities (internal tooling)
- `Console/` - Console/CLI application using System.CommandLine
- `Docker/` - Docker build scripts and Dockerfile
- `Library/` - Core reusable library
- `NuGetLibrary/` - Core reusable .NET NuGet library (published as `ptr727.ProjectTemplate.Library`)
- `Tests/` - Unit tests using xUnit and AwesomeAssertions

## Best Practices
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
name: Build library task
name: Build NuGet library task

on:
workflow_call:
inputs:
# Input to control whether to push the library to NuGet.org
# Input to control whether to push the NuGet library to NuGet.org
push:
required: false
type: boolean
default: false
outputs:
# Output of the uploaded artifact id
artifact-id:
value: ${{ jobs.build-library.outputs.artifact-id }}
value: ${{ jobs.build-nugetlibrary.outputs.artifact-id }}

jobs:

Expand All @@ -20,8 +20,8 @@ jobs:
uses: ./.github/workflows/get-version-task.yml
secrets: inherit

build-library:
name: Build library project job
build-nugetlibrary:
name: Build NuGet library project job
runs-on: ubuntu-latest
outputs:
artifact-id: ${{ steps.artifact-upload-step.outputs.artifact-id }}
Expand All @@ -37,9 +37,9 @@ jobs:
- name: Checkout code step
uses: actions/checkout@v6

- name: Build library project step
- name: Build NuGet library project step
run: |
dotnet build ./Library/Library.csproj \
dotnet build ./NuGetLibrary/NuGetLibrary.csproj \
-property:OutputPath=${{ runner.temp }}/publish/ \
-property:PackageOutputPath=${{ runner.temp }}/publish/ \
--configuration ${{ github.ref_name == 'main' && 'Release' || 'Debug' }} \
Expand All @@ -58,11 +58,11 @@ jobs:
--skip-duplicate

- name: Zip output step
run: 7z a -t7z ${{ runner.temp }}/Library.7z ${{ runner.temp }}/publish/*
run: 7z a -t7z ${{ runner.temp }}/NuGetLibrary.7z ${{ runner.temp }}/publish/*

- name: Upload build artifacts step
id: artifact-upload-step
uses: actions/upload-artifact@v6
with:
name: library-build
path: ${{ runner.temp }}/Library.7z
name: nugetlibrary-build
path: ${{ runner.temp }}/NuGetLibrary.7z
12 changes: 6 additions & 6 deletions .github/workflows/build-release-task.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ jobs:
uses: ./.github/workflows/get-version-task.yml
secrets: inherit

build-library:
name: Build library job
uses: ./.github/workflows/build-library-task.yml
build-nugetlibrary:
name: Build NuGet library job
uses: ./.github/workflows/build-nugetlibrary-task.yml
secrets: inherit
with:
# Conditional push to NuGet.org
Expand All @@ -51,17 +51,17 @@ jobs:
name: Publish GitHub release job
if: ${{ inputs.github }}
runs-on: ubuntu-latest
needs: [get-version, build-library, build-executable, build-docker]
needs: [get-version, build-nugetlibrary, build-executable, build-docker]

steps:

- name: Checkout code step
uses: actions/checkout@v6

- name: Download library build artifacts job
- name: Download NuGet library build artifacts job
uses: actions/download-artifact@v7
with:
artifact-ids: ${{ needs.build-library.outputs.artifact-id }}
artifact-ids: ${{ needs.build-nugetlibrary.outputs.artifact-id }}
path: ./Publish

- name: Download executable build artifacts job
Expand Down
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ For comprehensive coding standards and detailed conventions, refer to [`.github/

### Project Structure

- **Library**: Core reusable library
- **NuGetLibrary**: Core reusable .NET NuGet library (published as `ptr727.ProjectTemplate.Library`)
- **Console**: CLI application using System.CommandLine
- **Tests**: xUnit with AwesomeAssertions (Arrange-Act-Assert pattern)
- **Benchmarks**: BenchmarkDotNet performance measurements
Expand Down
2 changes: 1 addition & 1 deletion Benchmarks/Benchmarks.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
<PackageReference Include="BenchmarkDotNet" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Library\Library.csproj" />
<ProjectReference Include="..\NuGetLibrary\NuGetLibrary.csproj" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Console/Console.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,6 @@
<PackageReference Include="System.CommandLine" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Library\Library.csproj" />
<ProjectReference Include="..\NuGetLibrary\NuGetLibrary.csproj" />
</ItemGroup>
</Project>
2 changes: 1 addition & 1 deletion Console/Program.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using ptr727.ProjectTemplate.Library;
using ptr727.ProjectTemplate.NuGetLibrary;

namespace ptr727.ProjectTemplate.Console;

Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion Library/Extensions.cs → NuGetLibrary/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
using System.Runtime.CompilerServices;

namespace ptr727.ProjectTemplate.Library;
namespace ptr727.ProjectTemplate.NuGetLibrary;

internal static partial class LogExtensions
{
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion Library/Library.cs → NuGetLibrary/Library.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace ptr727.ProjectTemplate.Library;
namespace ptr727.ProjectTemplate.NuGetLibrary;

/// <summary>
/// Provides the primary library functionality.
Expand Down
2 changes: 1 addition & 1 deletion Library/LogOptions.cs → NuGetLibrary/LogOptions.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace ptr727.ProjectTemplate.Library;
namespace ptr727.ProjectTemplate.NuGetLibrary;

/// <summary>
/// Provides global logging configuration for the library.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
<PackageVersion>1.0.0-pre</PackageVersion>
<PublishRepositoryUrl>true</PublishRepositoryUrl>
<RepositoryUrl>https://github.com/ptr727/ProjectTemplate</RepositoryUrl>
<RootNamespace>ptr727.ProjectTemplate.Library</RootNamespace>
<RootNamespace>ptr727.ProjectTemplate.NuGetLibrary</RootNamespace>
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
<Version>1.0.0.0</Version>
</PropertyGroup>
Expand Down
2 changes: 1 addition & 1 deletion Library/Options.cs → NuGetLibrary/Options.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace ptr727.ProjectTemplate.Library;
namespace ptr727.ProjectTemplate.NuGetLibrary;

/// <summary>
/// Options used to configure the library.
Expand Down
16 changes: 16 additions & 0 deletions ProjectTemplate.code-workspace
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
"accessibilities",
"Allman",
"apikey",
"astral",
"autoremove",
"buildcache",
"buildtransitive",
Expand All @@ -19,28 +20,40 @@
"datebadge",
"davidanson",
"debuglevel",
"devcontainer",
"dockerhub",
"dotnettools",
"dryrun",
"Emby",
"finalizers",
"gpgsign",
"gruntfuggly",
"hatchling",
"Jellyfin",
"Keychain",
"lastbuild",
"libsecret",
"LINQ",
"logfile",
"nameof",
"nbgv",
"nugetlibrary",
"nektos",
"Nerdbank",
"noninteractive",
"onCreateCommand",
"othercommand",
"Pieter",
"postCreateCommand",
"ProjectTemplate",
"pyproject",
"pypi",
"pypilibrary",
"pyright",
"quoteoftheday",
"resharper",
"Rubba",
"ruff",
"Serilog",
"settingsfile",
"signingkey",
Expand Down Expand Up @@ -87,6 +100,9 @@
"ms-dotnettools.csdevkit",
"streetsidesoftware.code-spell-checker",
"yzhang.markdown-all-in-one",
"ms-python.python",
"charliermarsh.ruff",
"ms-pyright.pyright",
]
}
}
10 changes: 5 additions & 5 deletions ProjectTemplate.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
<File Path=".github/workflows/build-datebadge-task.yml" />
<File Path=".github/workflows/build-docker-task.yml" />
<File Path=".github/workflows/build-executable-task.yml" />
<File Path=".github/workflows/build-library-task.yml" />
<File Path=".github/workflows/build-nugetlibrary-task.yml" />
<File Path=".github/workflows/build-release-task.yml" />
<File Path=".github/workflows/get-version-task.yml" />
<File Path=".github/workflows/merge-bot-pull-request.yml" />
Expand All @@ -24,14 +24,14 @@
<File Path="version.json" />
</Folder>
<Project Path="Benchmarks/Benchmarks.csproj">
<BuildDependency Project="Library/Library.csproj" />
<BuildDependency Project="NuGetLibrary/NuGetLibrary.csproj" />
</Project>
<Project Path="Console/Console.csproj">
<BuildDependency Project="Library/Library.csproj" />
<BuildDependency Project="NuGetLibrary/NuGetLibrary.csproj" />
</Project>
<Project Path="CodeGen/CodeGen.csproj" />
<Project Path="Library/Library.csproj" />
<Project Path="NuGetLibrary/NuGetLibrary.csproj" />
<Project Path="Tests/Tests.csproj">
<BuildDependency Project="Library/Library.csproj" />
<BuildDependency Project="NuGetLibrary/NuGetLibrary.csproj" />
</Project>
</Solution>
Loading
Loading