ptr727.ProjectTemplate.Library
1.0.54
See the version list below for details.
dotnet add package ptr727.ProjectTemplate.Library --version 1.0.54
NuGet\Install-Package ptr727.ProjectTemplate.Library -Version 1.0.54
<PackageReference Include="ptr727.ProjectTemplate.Library" Version="1.0.54" />
<PackageVersion Include="ptr727.ProjectTemplate.Library" Version="1.0.54" />
<PackageReference Include="ptr727.ProjectTemplate.Library" />
paket add ptr727.ProjectTemplate.Library --version 1.0.54
#r "nuget: ptr727.ProjectTemplate.Library, 1.0.54"
#:package ptr727.ProjectTemplate.Library@1.0.54
#addin nuget:?package=ptr727.ProjectTemplate.Library&version=1.0.54
#tool nuget:?package=ptr727.ProjectTemplate.Library&version=1.0.54
ProjectTemplate
C# .NET project template.
Build and Distribution
- Source Code: GitHub - Source code, issues, discussions, and CI/CD pipelines.
- Versioned Releases: GitHub Releases - Version tagged source code and build artifacts.
- Docker Images: Docker Hub - Container images with all tools pre-installed.
- NuGet Packages: NuGet Packages - .NET libraries published to NuGet.org.
- PyPI Packages: PyPI Packages - Python library published to PyPI.org.
Build Status
Releases
Release Notes
Version: 1.0:
Summary:
- Something.
- And something else.
⚠️ Breaking Changes:
- Something.
- And something else.
See Release History for complete release notes and older versions.
Getting Started
Get started with ProjectTemplate in three easy steps:
⚠️ Important: Some important warning.
ℹ️ Note: Some interesting note.
Install ProjectTemplate:
- Do something.
Configure ProjectTemplate:
- Then something else.
Run ProjectTemplate:
Console --loglevel=Debug
See Installation for detailed setup instructions.
Table of Contents
- Build and Distribution
- Getting Started
- Table of Contents
- Use Cases
- Installation
- Configuration
- Usage
- Questions or Issues
- Development Environment Setup
- 3rd Party Tools
- License
- Template Project Setup
Use Cases
ℹ️ TL;DR: This widget is special because it does something special.
- It does something special.
- And it does something else special.
Installation
Choose an installation method based on your platform and requirements:
- Method 1 (Recommended): Easiest and most up-to-date option.
- ✅ Some good reason.
- ⚠️ Some not so good reason.
- ❌ Strong reason to avoid.
- Best for: Linux, NAS devices, servers, cross-platform deployments.
- Method 2: Custom configuration options.
- ✅ Some good reason.
- ⚠️ Some not so good reason.
- ❌ Strong reason to avoid.
- Best for: Specialized devices.
Configuration
⚠️ Important: The spinner setting must be configured before first use.
Required configuration:
- Set
footo something. - Set
barto something else.
Optional configuration:
- Set
advancedtospecial. - Some other custom option.
Usage
Console [global options] <command> [command options]
Command Quick Reference
| Command | Description | Notes |
|---|---|---|
| default | Default action when no command is specified | First time setup |
test |
Do something else useful | Some note |
--help |
Show help output | Use <command> --help for command specific help |
--version |
Show version output |
Use the --help option to get a list of all commands and global options.
To get help for a specific command run Console <command> --help.
Global Options
Global options apply to all commands:
| Option | Description | Default |
|---|---|---|
--logfile |
Debug log file | Optional |
--loglevel |
Debug log level | Default is Information |
--logfile-clear |
Clear log file at startup | Default is false |
General help:
>.\Console\bin\Debug\net10.0\Console --help
Description:
C# .NET console project
Usage:
Console [command] [options]
Options:
-l, --loglevel <Debug|Error|Fatal|Information|Verbose|Warning> Set the log level (default: Information). [default: Information]
-f, --logfile <logfile> Write logs to the specified file (optional).
-c, --logfile-clear Clear the log file before writing (default: false).
-?, -h, --help Show help and usage information
--version Show version information
Commands:
test Test command
Test Command
Test command options:
| Option | Description | Default |
|---|---|---|
--test |
Test options | Optional |
Test command help:
>.\Console\bin\Debug\net10.0\Console test --help
Description:
Test command
Usage:
Console test [options]
Options:
-t, --test <test> Test command option (optional).
-?, -h, --help Show help and usage information
-l, --loglevel <Debug|Error|Fatal|Information|Verbose|Warning> Set the log level (default: Information). [default: Information]
-f, --logfile <logfile> Write logs to the specified file (optional).
-c, --logfile-clear Clear the log file before writing (default: false).
Questions or Issues
For General Questions:
- Use the Discussions forum for general questions.
For Bug Reports:
- Ask in the Discussions forum if you are not sure if it is a bug.
- Check the existing Issues tracker for known problems.
- If the issue is unique and a bug, file it in Issues, and include all pertinent steps to reproduce the issue.
Development Environment Setup
The recommended setup is one of the per-language Dev Containers under .devcontainer/:
.devcontainer/dotnet/— .NET 10 SDK + GitHub CLI. Pair withDotNet.code-workspace..devcontainer/python/— Python 3.14 +uv+ GitHub CLI. Pair withPython.code-workspace.
Each container bind-mounts your SSH public key, allowed-signers file, and gh config from the host so commits sign correctly. gh is pre-authenticated when the host token is file-backed; macOS Keychain and Linux libsecret-backed tokens require an in-container gh auth login — see the credential-store nuance section.
Windows note: Python work is intentionally not supported on the Windows host. The Python extension caches the Linux-layout
PyPiLibrary/.venv/bin/pythonagainst a venv whose actual Windows path isPyPiLibrary\.venv\Scripts\python.exe, breaking Ruff. Use the python devcontainer.
Recommended (devcontainer):
- Complete host setup once per machine (git identity, SSH key, allowed_signers,
gh auth login, SSH commit signing). - Clone the repo, open the matching workspace (
DotNet.code-workspaceorPython.code-workspace) in VS Code with the Dev Containers extension, and run Reopen in Container — pick the language flavor. - The
postCreateCommandrunsdotnet tool restore(.NET container) or installsuvand runsuv sync(Python container). No git hooks are installed by default — see "Optional: enable git hooks locally" below.
Alternative (host install):
Install Developer Tools:
Install .NET SDK:
# Windows winget install Microsoft.DotNet.SDK.10 # Linux apt install dotnet-sdk-10.0Install Visual Studio Code:
# Windows winget install Microsoft.VisualStudioCodeInstall Visual Studio:
# Windows winget install Microsoft.VisualStudio.Community
Clone and Configure Project:
Clone the repository and initialize tools:
# Clone from CLI (or clone from VSCode) git clone -b main https://github.com/ptr727/[Project].git ./[Project] # Initialize dotnet tools cd ./[Project] dotnet tool restoreOpen
DotNet.code-workspace(orPython.code-workspace) in Visual Studio Code.Open
[Project].slnxin Visual Studio.
Optional: enable git hooks locally:
Hooks are not shipped with the template — CI is the lint backstop. Opt in per language if you want pre-commit checks locally.
For .NET work — install Husky.Net:
dotnet new tool-manifest # if no tool manifest exists yet dotnet tool install Husky dotnet husky install dotnet husky add pre-commit -c "dotnet csharpier check . && dotnet format style --verify-no-changes --severity=info"For Python work — install pre-commit:
uv tool install pre-commit pre-commit installSample
.pre-commit-config.yaml(the hooks shell intoPyPiLibrary/because the uv project — and therefore ruff/pyright and their configs — lives there, not at the repo root):repos: - repo: local hooks: - id: ruff-check name: ruff check entry: uv run --directory PyPiLibrary ruff check language: system files: ^PyPiLibrary/.*\.py$ pass_filenames: false - id: ruff-format name: ruff format entry: uv run --directory PyPiLibrary ruff format --check language: system files: ^PyPiLibrary/.*\.py$ pass_filenames: false - id: pyright name: pyright entry: uv run --directory PyPiLibrary pyright language: system files: ^PyPiLibrary/.*\.py$ pass_filenames: false
CI runs these same checks on every PR, so hooks are purely a local convenience.
3rd Party Tools
3rd Party tools used in this project:
- API Ninjas
- AwesomeAssertions
- Bring Your Own Badge
- Create Pull Request
- CSharpier
- GH Release
- Git Auto Commit
- GitHub Actions
- GitHub Dependabot
- Nerdbank.GitVersioning
- Serilog
- xUnit.Net
License
Licensed under the MIT License
Template Project Setup
Template - TODO List
- Configure git for SSH signing and SSH forwarding in dev containers — see docs/host-setup.md, docs/ssh-signing.md, and docs/devcontainer.md.
- Decide whether your project needs the .NET (
NuGetLibrary/) side, the Python (PyPiLibrary/) side, or both. Delete the unused folder and remove its references fromProjectTemplate.slnx,.github/dependabot.yml, and the corresponding.github/workflows/build-*-task.yml. - Start on Linux to avoid file permission issues when moving from Windows.
- Configure the Developer Environment.
- Open the project directory (not the workspace) in Visual Studio Code, and rename (Ctrl-Shift-H) all instances of
ProjectTemplateto[NewProject]in code. - Rename
DotNet.code-workspaceto[NewProject].code-workspaceandPython.code-workspaceto[NewProject]-Python.code-workspace, or delete the workspace for the language you don't need. RenameProjectTemplate.slnxto[NewProject].slnx. - Open the workspace file for the language you kept (
[NewProject].code-workspaceand/or[NewProject]-Python.code-workspace) in Visual Studio Code. - Delete any projects and associated actions that will not be used, update dependencies in actions to remove deleted actions.
- Rename projects to match the naming, update
.slnxand.csprojfiles, and update actions to match the naming. - Update the
namespacein.csand.csprojfiles to match the naming. - Update all ref-links in
README.mdto point to the naming. - Publish to GitHub from VSCode to create a new empty GitHub repository.
- Commit and push the
first-branch. - Edit and iterate only in
first-branchuntil ready to start with git history. - Setup
mainas the first permanent branch when ready. - Configure GitHub for the new repository.
- Follow the Branching Workflow.
- Delete the
Project Template Setupsection fromREADME.md.
Template - Developer Environment Setup
Template - Git Setup
⚠️ Prerequisites:
- Configure git for SSH signing — see SSH commit signing.
- Configure host prerequisites (SSH key,
allowed_signers,ghauth) — see host setup. - Configure SSH forwarding for dev containers — see devcontainer setup.
Setup new project from template:
# Clone the template project git clone -b main https://github.com/ptr727/ProjectTemplate.git ./[NewProject] # Reset git to start a new repo rm -r ./[NewProject]/.git cd ./[NewProject] git init -b first-branch # Init dotnet tools dotnet tool restore # Update dotnet tools dotnet tool update --all dotnet outdated --upgrade:promptSetup new project from scratch:
⚠️ Linux: Start configuration on Linux to avoid file permission issues.
# Init git mkdir ./[NewProject] cd ./[NewProject] git init -b first-branch # Init dotnet tools dotnet new tool-manifest dotnet tool install csharpier dotnet tool install dotnet-outdated-toolUse
first-branchfor all the initial project setup and testing.When ready, only when ready, create
mainbranch fromfirst-branchwith no history:# Create main branch with no history git checkout --orphan main git commit --allow-empty -m "temp" # Squash merge changes git merge --squash first-branch git commit -m "Initial import (squashed)" # Drop the temporary commit git reset --hard HEAD~1 # Delete first-branch git branch -D first-branch
Template - GitHub Setup
GitHub secrets setup:
Create a NuGet API Key.
- Save the Key as
NUGET_API_KEYin:- GitHub project security Settings / Secrets / Actions.
- GitHub project security Settings / Secrets / Dependabot.
- GitHub Local Actions Settings / Secrets.
- Save the Key as
Create a Docker Hub Personal Access Token.
- Save the PAT as
DOCKER_HUB_ACCESS_TOKENandDOCKER_HUB_USERNAMEin:- GitHub project security Settings / Secrets / Actions.
- GitHub project security Settings / Secrets / Dependabot.
- Save the PAT as
Create a GitHub App for the codegen and merge-bot workflows.
- App name:
ptr727-codegen. Bot user:ptr727-codegen[bot]. - Permissions required (repository scope):
- Contents: Read & write — push commits to the
codegenbranch and merge bot PRs. - Pull requests: Read & write — open, update, and merge pull requests.
- Metadata: Read-only (auto-required).
- Contents: Read & write — push commits to the
- Note the App ID from the app's settings page; generate a private key (downloads a
.pemfile). - Install the app on your account and grant it access to the repository. The app must be both created and installed — creating it alone is not sufficient (
actions/create-github-app-tokenfails withNot Foundif the app isn't installed on the repository). - Save the App ID as
CODEGEN_APP_IDand the private key contents asCODEGEN_APP_PRIVATE_KEYin both of:- GitHub project security Settings / Secrets / Actions — for the codegen workflow and the codegen merge job.
- GitHub project security Settings / Secrets / Dependabot — required because Dependabot-triggered
pull_requestworkflow runs use a separate, restricted secret context that doesn't see Actions secrets. Without the App secrets in the Dependabot store, themerge-dependabotjob inmerge-bot-pull-request.ymlcan't mint an App token and the PR will never auto-merge.
- If the codegen workflows require additional secrets (e.g. third-party API keys), register them in the Actions store; if a Dependabot-triggered workflow ever needs them, register them in the Dependabot store too.
- The App token is used by both the codegen workflow (
run-codegen-pull-request-task.yml) and every job inmerge-bot-pull-request.yml. App-authored pushes/PRs trigger downstreampull_requestandpushworkflow events directly — unlikeGITHUB_TOKEN-authored events, which are blocked by GitHub's recursion guard. This is whypublish-release.ymlfires on the merge commit after Dependabot or codegen auto-merge, and why the codegen workflow no longer needs the legacy close/reopen dance to trigger auto-merge. - The codegen auto-merge condition in
merge-bot-pull-request.yml(merge-codegenjob) requires:- Event is
openedorreopened— auto-merge is enabled once per PR at open time; subsequentsynchronizeevents do not re-enable. This is what lets thedisable-auto-merge-on-maintainer-pushsafeguard (below) stick. github.event.pull_request.user.login == 'ptr727-codegen[bot]'— PR was opened by the App.github.event.pull_request.head.repo.full_name == github.repository— PR is from this repo (not a fork).- Strict head/base pairing —
(head.ref == 'codegen-main' && base.ref == 'main') || (head.ref == 'codegen-develop' && base.ref == 'develop'). Codegen runs as a matrix opening one PR per branch; this pairing prevents a misconfigured workflow from sneaking acodegen-developbranch intomainor vice versa.
- Event is
- The
disable-auto-merge-on-maintainer-pushjob inmerge-bot-pull-request.ymlruns onsynchronizeevents against bot-authored PRs (Dependabot or codegen) when the event actor is NOT the same bot — i.e. a maintainer pushed commits. It callsgh pr merge --disable-autoso the maintainer's commits don't auto-merge along with the bot's content. Re-enable auto-merge manually (gh pr merge --auto <PR>or the GitHub UI) when ready.
Codegen targets
mainANDdevelopin parallel (matrix inrun-codegen-pull-request-task.yml), so generated content lands on both branches independently without any back-merging. See AGENTS.md "Branching Model" for why this dual-target pattern beats develop-only-with-flow-through.- App name:
Codegen workflow schedule:
run-periodic-codegen-pull-request.ymlruns every Monday at 02:00 UTC, plus on-demand viaworkflow_dispatch. It uses the App token (CODEGEN_APP_ID+CODEGEN_APP_PRIVATE_KEY) to commit, open the PR asptr727-codegen[bot], and let the merge-bot auto-merge once CI passes. No PAT, no close/reopen dance.
GitHub project settings:
- General:
- Default branch:
main - Pull requests — both merge methods enabled at the repo level so each branch ruleset can pick the right one (develop =
Squash, main =Merge):Allow merge commits✓ (required for develop → main releases)Allow squash merging✓ (required for feature → develop merges)Allow rebase merging— disabled (no flow uses it; the develop ruleset forbids it anyway)Always suggest updating pull request branchesAllow auto-merge
- Default branch:
- Rules / Rulesets — separate rulesets per branch. Develop and main intentionally diverge on three rules — allowed merge methods,
Require linear history, andRequire branches to be up to date before merging; everything else is shared.- "Develop":
- Target branches:
develop. - Allowed merge methods:
Squash Require linear history(develop is kept linear; main carries merge commits by design, so this setting belongs to develop only)Require status checks to pass→Require branches to be up to date before merging✓ (feature branches must rebase or merge develop before merging back — standard hygiene)- Plus shared settings (below).
- Target branches:
- "Main":
- Target branches:
main. - Allowed merge methods:
Merge Require status checks to pass→Require branches to be up to date before mergingintentionally OFF. This rule is incompatible with the forward-only develop model. GitHub's "up to date" check is graph-based: it asks whether main's tip commit is reachable from develop. After any develop → main release, main's new tip is a brand-new merge commit that develop's history doesn't contain. Forward-only develop never adds it (no back-merge of main into develop, no rebase of develop onto main), so the check fails permanently on every subsequent release. Leaving the rule on would force every release through an admin bypass. See AGENTS.md "Branching Model" for the full reasoning.- Plus shared settings (below).
- Target branches:
- Shared settings (apply to both rulesets):
Restrict deletionsRequire signed commitsRequire a pull request before mergingDismiss stale pull request approvals when new commits are pushedRequire conversation resolution before merging
Require status checks to pass- Status checks that are required:
Check pull request workflow status
- Status checks that are required:
Block force pushesAutomatically request Copilot code reviewReview new pushesReview draft pull requests
- "Develop":
- Actions / General:
Allow GitHub Actions to create and approve pull requests
Template - Branching Workflow
See AGENTS.md "Branching Model" for the authoritative definition. Summary:
- Persistent
mainanddevelopbranches, each with its own ruleset (above). Both must always be building error free. - Feature branches off
develop. Only commit on feature branches, never directly todevelopormain. - Feature →
develop: squash-merge (develop ruleset enforces this; develop is kept linear). develop→main: merge-commit (preserves develop's commit list as a real second-parent reference on main; main ruleset enforces this).developis forward-only. Nomain → developback-merges. The develop squash-only ruleset physically blocks merge commits.- Bots open parallel PRs against both branches.
.github/dependabot.ymlduplicates each ecosystem entry per branch, and.github/workflows/run-codegen-pull-request-task.ymlruns as a matrix (branch namescodegen-mainandcodegen-develop). Each branch absorbs its own bot PRs independently — neither falls behind, no back-merges needed.
Template - Release Distribution Model: Push vs. Pull
This template ships with a push-on-merge release model — every commit on main triggers .github/workflows/publish-release.yml which publishes a GitHub release, NuGet/PyPI uploads, Docker tags, and platform executables. With the dual-target bot model (Dependabot/codegen targeting both branches), this means every Dependabot bump that lands on main produces a new release. That's the right default for projects whose consumers pull at their own cadence (Docker pulls, NuGet/PyPI installs, manual binary downloads) — releases are cheap and frequent, consumers update on their own schedule.
For projects whose consumers are pushed updates (HACS for Home Assistant, package managers that auto-update integrations, Linux distros that vendor from main), every release is a forced update to all users. Frequent bot-driven releases become noise. To switch to a manual main-release model while keeping the rest of the dual-target dual-channel flow:
Edit
.github/workflows/publish-release.ymland change the trigger:on: - push: - branches: [ main, develop ] - workflow_dispatch: + push: + branches: [ develop ] + workflow_dispatch:Result:
developpushes still publish dev releases automatically (PEP 440.dev0to PyPI, NBGV-prerelease tags on NuGet, prerelease GitHub releases).mainpushes no longer auto-publish; you trigger the release manually via the GitHub Actions UI (workflow_dispatch) when a real release is wanted.(Optional) narrow what flows into
mainautomatically. If a sea of Dependabot PRs onmainis noisy without auto-release, either:- Drop the
main-target Dependabot entries from.github/dependabot.yml(so deps update ondeveloponly, and reachmainthrough the next develop → main release the maintainer triggers — closer to a pure develop-only flow with manual cadence), or - Keep dual-target Dependabot and let the merge-bot auto-merge them silently into
main; main always has fresh code, but ships only when the maintainer dispatches a release.
- Drop the
For an example of the manual-release model in production, see homeassistant-purpleair — that integration ships through HACS (push distribution) and uses workflow_dispatch for actual releases.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Microsoft.Extensions.Logging.Abstractions (>= 10.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.0.57 | 37 | 5/18/2026 |
| 1.0.55 | 35 | 5/13/2026 |
| 1.0.55-gbd3876e3dc | 33 | 5/18/2026 |
| 1.0.54 | 85 | 5/12/2026 |
| 1.0.54-ga03ad12524 | 38 | 5/13/2026 |
| 1.0.53-gd450626890 | 75 | 5/12/2026 |
| 1.0.52 | 79 | 5/12/2026 |
| 1.0.52-gbb66475387 | 77 | 5/12/2026 |
| 1.0.51-g1b1df869b1 | 94 | 5/11/2026 |
| 1.0.50-g5ce95cf23d | 94 | 5/11/2026 |
| 1.0.49 | 86 | 5/11/2026 |
| 1.0.49-ge72324d780 | 88 | 5/11/2026 |
| 1.0.48-gffb9e64d9e | 85 | 5/11/2026 |
| 1.0.47 | 85 | 5/11/2026 |
| 1.0.47-g2a27067c66 | 89 | 5/11/2026 |
| 1.0.46-gb67737eab3 | 91 | 5/11/2026 |
| 1.0.45-g4ddc6b9a5e | 86 | 5/11/2026 |
| 1.0.44 | 82 | 5/11/2026 |
| 1.0.44-gf154b783a4 | 92 | 5/11/2026 |
| 1.0.43-g79b34e0148 | 87 | 5/11/2026 |