Shared build, CI, release and editor setup for the Curiosus .NET libraries: Curiosus.Migrations, Curiosus.Utils, Curiosus.TelegramBot.
Files in sync/ are copied into the root of every repository by pull requests,
so local builds, AI agents and CI use exactly the same scripts and settings.
| Repository | Default branch | Pull requests | Coverage | NuGet |
|---|---|---|---|---|
| Curiosus.Migrations | ||||
| Curiosus.Utils | ||||
| Curiosus.TelegramBot |
Default branch is the last push: build, tests, publishing. Pull requests is the last pull request build.
| File | Purpose |
|---|---|
build/curiosus.cake |
Cake tasks: build, tests, coverage report, pack, nuget.org push, GitHub releases |
build/Curiosus.props |
Common MSBuild settings (deterministic CI builds, Source Link, symbol packages, package README, icon, authors, copyright) |
.config/dotnet-tools.json |
Cake and ReportGenerator versions |
.github/workflows/build.yml |
Pull request build, tests and coverage summary |
.github/workflows/release-packages.yml |
Publishing via NuGet Trusted Publishing + GitHub releases, coverage badge |
.github/dependabot.yml |
Security updates for all NuGet packages, monthly version updates for test-only packages |
nuget.config |
Restore from nuget.org only |
.editorconfig |
Code style |
.claude/curiosus.md |
Shared conventions (stack, commits, versioning, README, code style) for people and Claude Code, imported from the repository CLAUDE.md |
build.cake:
#load "build/curiosus.cake"
minLineCoverage = 70; // CoverageReport fails below it, %
// repository-specific tasks
RunTarget(target);Directory.Build.props:
<Project>
<Import Project="build/Curiosus.props" />
<!-- repository-specific settings -->
</Project>CLAUDE.md starts with @.claude/curiosus.md.
Coverage badges for README.md, for the repository and for a package:
[](https://github.com/curiosus-dev/<repository>/actions/workflows/release-packages.yml)
[](https://github.com/curiosus-dev/<repository>/actions/workflows/release-packages.yml)A package whose assembly is never loaded by tests shows "no tests".
Conventions the scripts rely on are described in .claude/curiosus.md.
Repositories with "docs": true in settings/repositories.json also get
sync-docs/: a Docusaurus website/ (theme, styles, logo) and
.github/workflows/docs.yml, which builds the site on pull requests and deploys it to GitHub Pages from main
at https://curiosus-dev.github.io/<repository>/.
The repository keeps only the content:
docs.jsonin the root:{ "title": "...", "tagline": "..." }.docs/— pages; the sidebar follows the directory structure,sidebar_positionfront matter and_category_.jsonfiles.- READMEs and CHANGELOGs are published by relative symlinks in
docs/, e.g.docs/packages/dal/curiosus-dal.md -> ../../../src/DAL/Curiosus.DAL/README.md. Symlinked files get no front matter (it would show on GitHub and nuget.org), their links must be absolute; Windows clones needcore.symlinks=true. - Sources are compiled as MDX: close HTML tags, no string
styleattributes, bare{/<in code spans. Broken links fail the build.
Search is a local index built with the site
(docusaurus-search-local). To switch a site to
Algolia DocSearch, apply there with the site URL. Algolia verifies the domain by
a meta tag: put its value to docs.json as algolia.siteVerification (the site keeps the local search), deploy, and
once approved add the search-only keys (they are public):
{
"title": "...", "tagline": "...",
"algolia": { "siteVerification": "...", "appId": "...", "apiKey": "...", "indexName": "..." }
}The footer cross-links the Curiosus libraries listed in libraries of sync-docs/website/docusaurus.config.mjs:
the documentation site when there is one, the repository otherwise.
A README links to the site with the status badge of the docs workflow:
[](https://curiosus-dev.github.io/<repository>/)Preview from a repository root: cd website && npm ci && npm start.
tests/docs-build.sh builds the site against tests/docs-fixture, tests/sync-test.sh checks
which repositories get sync-docs/; both run in the lint workflow. Dependabot updates the site dependencies in
sync-docs/website.
- Change files in
sync/and merge tomain. - Sync workflow opens a pull request in every repository (older sync pull requests are closed), CI of each repository validates the change.
- Review and merge the pull requests.
Files removed from sync/ are not removed from repositories, delete them there manually.
Preview locally from a repository root: SYNC_DRY_RUN=1 ../dotnet-tools/scripts/sync.sh.
Security and repository settings are described in settings/ and are the same for every repository
listed in settings/repositories.json:
| File | What |
|---|---|
repository.json |
Merge options, issues/wiki/projects, branch cleanup, secret scanning, push protection, Dependabot security updates |
actions.json |
Allowed actions (GitHub-owned + NuGet/login), SHA pinning required, read-only GITHUB_TOKEN, fork PR approval |
rulesets/protect-default-branch.json |
No force pushes or deletion of the default branch and release/*, no bypass |
rulesets/default-branch-pull-requests.json |
Changes of the default branch and release/* via pull requests with green required checks; repository admins can bypass |
rulesets/restrict-release-branches.json |
Only repository admins create release/* maintenance branches: they publish packages |
rulesets/protect-release-tags.json |
Tags can be created but never moved or deleted |
environments.json |
nuget environment for publishing (deploys from main and release/*) and github-pages for documentation sites (from main); used by the repositories listing them in repositories.json |
GitHub Pages (deployed by workflow) is enabled for repositories with "docs": true.
Dependabot alerts, Dependabot security updates, private vulnerability reporting and CodeQL default setup are enabled
by the same script. Community health files (SECURITY.md, CONTRIBUTING.md, issue and pull request templates)
come from curiosus-dev/.github.
scripts/repo-settings.py check # what differs from ./settings
scripts/repo-settings.py apply # make repositories match, needs repository admin rights
scripts/repo-settings.py apply dotnet-toolsSettings drift runs check weekly with the sync app token (read-only) and
fails when someone changed a setting by hand: either apply ./settings again or change ./settings.
Ruleset bypass actors are visible only to repository admins, so they are checked by a local check alone.
Actions are pinned to commit SHAs (sha_pinning_required is on). Dependabot updates the workflows of this repository;
synced workflows in sync/ are updated with:
scripts/pin-actions.sh # latest release within the same major version for every `uses:`Run it when Dependabot bumps an action here, then merge: the sync pull requests deliver the new pins.
- Create a GitHub App in the
curiosus-devorganization (Settings → Developer settings → GitHub Apps), without a webhook, with repository permissions:- Contents: read and write
- Pull requests: read and write
- Workflows: read and write (synced files include workflows)
- Administration: read (settings drift check)
- Code scanning alerts: read (settings drift check)
- Metadata: read
- Install the app on the Curiosus repositories, this one and
.github(the settings drift check reads all of them). - In this repository add the variable
SYNC_APP_CLIENT_ID(app Client ID) and the secretSYNC_APP_PRIVATE_KEY(generated private key).
- On nuget.org: profile → Trusted Publishing → add a policy owned by the packages owner:
repository owner
curiosus-dev, repository<name>, workflow filerelease-packages.yml, environmentnuget. The environment matters: a workflow file can be changed in any branch, thenugetenvironment deploys frommainand admin-createdrelease/*branches only, so tokens from other branches don't match the policy. - In the repository add the secret
NUGET_USER— nuget.org profile name, not an email. - After the first successful release remove old API key secrets and revoke the keys on nuget.org.
Add it to the matrix in .github/workflows/sync.yml, install the sync app on it,
add it to settings/repositories.json (with "environments": [ "nuget" ] for a library; with a documentation site
also "docs": true and the github-pages environment), run
scripts/repo-settings.py apply <name>, run the sync workflow manually and set up NuGet Trusted Publishing as above.
Add a library to libraries in sync-docs/website/docusaurus.config.mjs for the documentation footer.
The default branch must be main.