Add Forgejo template variable expansion for automatic repo customization

Replace hardcoded TODO markers with Forgejo template variables (${REPO_NAME},
${REPO_OWNER}, etc.) so new repos created from this template are auto-customized.
Use Forgejo Actions context variables in build.yaml for dynamic FORGE_URL.
Hardcode forge.eblu.me as the Forgejo instance. Update CLAUDE.md and README.md
to reflect reduced manual setup steps.

Python class names kept as manual TODO (same as directory rename) since template
variables in Python code positions aren't valid syntax for linters.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Erich Blume 2026-03-03 20:28:15 -08:00
commit c86cdcf335
15 changed files with 48 additions and 46 deletions

View file

@ -1,6 +1,5 @@
[project]
# TODO: Rename to match your project (also rename the src/ directory)
name = "project-template-ci"
name = "${REPO_NAME}-ci"
version = "0.1.0"
requires-python = ">=3.13"
dependencies = ["dagger-io"]

View file

@ -1,4 +1,4 @@
# TODO: Update module docstring and class name to match your project
"""Project Template CI — Dagger build functions."""
"""${REPO_NAME_TITLE} CI — Dagger build functions."""
# TODO: Rename class to match your project (also rename the src/ directory)
from .main import ProjectTemplateCi as ProjectTemplateCi

View file

@ -2,7 +2,7 @@ import dagger
from dagger import dag, function, object_type
# TODO: Rename class to match your project (e.g. MyProjectCi)
# TODO: Rename class to match your project (also rename the src/ directory)
@object_type
class ProjectTemplateCi:
@function

View file

@ -42,8 +42,7 @@ jobs:
SPECIFIC_VERSION="${{ inputs.specific_version }}"
# Fetch latest release
# TODO: Update FORGE_URL to match your Forgejo instance and repo
FORGE_URL="https://forge.example.com/api/v1/repos/owner/repo"
FORGE_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
echo "Fetching latest release..."
LATEST=$(curl -s "${FORGE_URL}/releases/latest" | jq -r '.tag_name // empty' || true)
@ -152,8 +151,7 @@ jobs:
TARBALL="docs-${VERSION}.tar.gz"
CHANGELOG_UPDATED="${{ steps.changelog.outputs.changelog_updated }}"
# TODO: Update FORGE_URL to match your Forgejo instance and repo
FORGE_URL="https://forge.example.com/api/v1/repos/owner/repo"
FORGE_URL="${{ github.server_url }}/api/v1/repos/${{ github.repository }}"
echo "Creating release $VERSION..."
@ -221,9 +219,8 @@ jobs:
exit 0
fi
# TODO: Update git identity to match your Forgejo instance
git config user.name "Forgejo Actions"
git config user.email "actions@forge.example.com"
git config user.email "actions@forge.eblu.me"
git add CHANGELOG.md docs/changelog.d/

9
.gitea/template Normal file
View file

@ -0,0 +1,9 @@
CLAUDE.md
docs/index.md
dagger.json
.dagger/pyproject.toml
.dagger/src/**/*.py
docs/quartz.config.ts
docs/quartz.layout.ts
mise-tasks/pr-comments
mise-tasks/docs-mikado

View file

@ -4,8 +4,7 @@ Guidance for Claude Code working in this repository. See also [[ai-assistance-gu
## Overview
<!-- TODO: Fill in project description when forking this template -->
**PROJECT_NAME** — description goes here.
**${REPO_NAME}** — ${REPO_DESCRIPTION}
**CRITICAL: Public repo — never commit secrets!**
@ -13,11 +12,13 @@ Guidance for Claude Code working in this repository. See also [[ai-assistance-gu
## First-Time Setup
This repository is a **project template**. All customization points are marked with `TODO` comments throughout the codebase. Before any other work, you should:
This repository is a **Forgejo template**. Most customization points are auto-resolved by Forgejo's template variable expansion when a new repo is created. The remaining manual steps are:
1. **Suggest resolving TODOs first.** Even if the user gives you a different task, check whether TODOs remain by searching for `TODO` across all files. If unresolved TODOs exist, inform the user that the template hasn't been fully customized yet and suggest resolving them first (the user may decline — that's fine, proceed with their request).
2. **To resolve TODOs:** search all files for `TODO`, update each value to match the new project, rename the `.dagger/src/project_template_ci/` directory, and verify nothing was missed.
3. **When all TODOs are resolved:** delete this "First-Time Setup" section entirely from `CLAUDE.md` — it is only needed once.
1. **Set `baseUrl`** in `docs/quartz.config.ts` — this is the hosted docs domain, not the repo URL
2. **Rename `.dagger/src/project_template_ci/`** directory to match your project, and update the class names inside
3. **Fill in project structure** in the `CLAUDE.md` Project Structure section
4. **Fill in license info** in `README.md`
5. **When all TODOs are resolved:** delete this "First-Time Setup" section entirely from `CLAUDE.md` — it is only needed once
## Rules

View file

@ -13,20 +13,17 @@ A personal project template with opinionated infrastructure for documentation, C
## Forking This Template
The template contains `TODO` markers at every point that needs customization. To set up a new project:
This is a **Forgejo template repository**. When you create a new repo from this template, Forgejo automatically expands variables like `${REPO_NAME}` and `${REPO_OWNER}` in key files — handling most customization automatically.
1. Fork or copy this repository
2. Search for `TODO` across all files — each one marks a value you need to update:
- Project name and description (`CLAUDE.md`, `docs/index.md`)
- Forgejo/forge instance URLs (`build.yaml`, `mise-tasks/docs-mikado`, `mise-tasks/pr-comments`)
- Dagger module name and class (`dagger.json`, `.dagger/`)
- Quartz site title and URLs (`docs/quartz.config.ts`, `docs/quartz.layout.ts`)
- CI git identity (`.forgejo/workflows/build.yaml`)
3. Rename the `.dagger/src/project_template_ci/` directory to match your new Dagger module name
4. Remove the "First-Time Setup" section from `CLAUDE.md` once all TODOs are resolved
5. Delete this "Forking This Template" section from `README.md` and write your own project description
After creating your repo, the remaining manual steps are:
If you use Claude Code, it will prompt you to resolve these TODOs at the start of your first session.
1. Set `baseUrl` in `docs/quartz.config.ts` to your docs site domain
2. Rename `.dagger/src/project_template_ci/` directory and update class names to match your project
3. Fill in the project structure section in `CLAUDE.md`
4. Add license information to `README.md`
5. Remove the "First-Time Setup" section from `CLAUDE.md` and this section from `README.md`
If you use Claude Code, it will prompt you to resolve remaining TODOs at the start of your first session.
## Getting Started

View file

@ -1,6 +1,5 @@
{
"_comment": "TODO: Rename 'project-template-ci' to match your project",
"name": "project-template-ci",
"name": "${REPO_NAME}-ci",
"engineVersion": "v0.19.11",
"sdk": {
"source": "python"

View file

@ -0,0 +1 @@
Add Forgejo template repository variable expansion — most TODO markers are now auto-resolved when creating a new repo from this template.

View file

@ -7,9 +7,7 @@ tags:
# Project Documentation
<!-- TODO: Fill in project description when forking this template -->
Welcome to the **PROJECT_NAME** documentation.
Welcome to the **${REPO_NAME}** documentation.
## Navigation

View file

@ -7,7 +7,7 @@ import * as Plugin from "./quartz/plugins"
*/
const config: QuartzConfig = {
configuration: {
pageTitle: "Project Docs", // TODO: Update to your project name
pageTitle: "${REPO_NAME_TITLE} Docs",
pageTitleSuffix: "",
enableSPA: true,
enablePopovers: true,

View file

@ -13,7 +13,7 @@ export const sharedPageComponents: SharedLayout = {
afterBody: [],
footer: Component.Footer({
links: {
"Repository": "https://CHANGEME.example.com/owner/repo", // TODO: Update to your repo URL
"Repository": "${REPO_LINK}",
},
}),
}

View file

@ -38,9 +38,8 @@ REPO_DIR = Path(__file__).parent.parent
C2_COMMIT_RE = re.compile(r"^C2\(([^)]+)\):\s+(plan|impl|close|finalize)\s+(.+)$")
# TODO: Update to match your Forgejo instance and repo
FORGE_API = "https://forge.example.com/api/v1"
FORGE_REPO = "owner/repo"
FORGE_API = "https://forge.eblu.me/api/v1"
FORGE_REPO = "${REPO_OWNER}/${REPO_NAME}"
def extract_frontmatter(file_path: Path) -> dict | None:

View file

@ -20,10 +20,9 @@ import httpx
from rich.console import Console
from rich.text import Text
# TODO: Update to match your Forgejo instance and repo
FORGE_API_BASE = "https://forge.example.com/api/v1"
REPO_OWNER = "owner"
REPO_NAME = "repo"
FORGE_API_BASE = "https://forge.eblu.me/api/v1"
REPO_OWNER = "${REPO_OWNER}"
REPO_NAME = "${REPO_NAME}"
def get_reviews(client: httpx.Client, pr_number: int) -> list[dict]:

View file

@ -63,7 +63,10 @@ hooks = [{ id = "shfmt", args = ["-i", "2", "-ci", "-bn"] }]
[[repos]]
repo = "https://github.com/ComPWA/taplo-pre-commit"
rev = "v0.9.3"
hooks = [{ id = "taplo-format" }, { id = "taplo-lint" }]
hooks = [
{ id = "taplo-format" },
{ id = "taplo-lint", exclude = '\.dagger/pyproject\.toml$' },
]
# JSON formatting (prettier for consistent style)
[[repos]]