diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..58c59cd --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,50 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this repository is + +This is Certego's shared org-level `.github` repository: a library of reusable GitHub Actions **workflows** and **composite actions**, plus canonical linter/formatter **configurations**, that other Certego projects consume via `git subtree`. It is not an application — there is no build step, no runtime, and (outside of the self-test fixtures) no product code. + +Consumers add this repo into their own project at `.github/` via: +```bash +git subtree add --squash --prefix .github https://github.com/certego/.github.git main && rm -rf .github/{.github,README.md} +``` +and update it later with `git subtree pull` (same flags). Keep this consumption model in mind when changing inputs/outputs of workflows or actions — they are a semi-public API for every Certego project, not internal implementation details. + +The trailing `rm -rf .github/{.github,README.md}` is not optional cleanup — it removes this repo's own nested self-test copy (`.github/.github/`, see below) and this repo's own `README.md`, neither of which belong in a consumer project. **Every time a project adds or updates (`subtree pull`) this CI, it must re-run that `rm -rf` step**, otherwise the consumer ends up with a stray nested `.github/.github` directory and a leftover `.github/README.md` from this repo. + +## Repository layout + +- `workflows/` — reusable (`workflow_call`) YAML workflows plus two trigger workflows: + - `pull_request_automation.yml` — entry point run on every PR to `master`/`main`/`develop`/`dev`. Calls `_detect_changes.yml` to see which of backend/frontend/infra changed, then conditionally calls `_python.yml`, `_node.yml`, `_opentofu.yml`. + - `release.yml` — entry point run on PR close / push to `test`/`opentofu`. Calls `_release_and_tag.yml`, which tags+releases on a numeric PR title (e.g. `1.2.3`) merged into a release branch, and optionally publishes to PyPI/TestPyPI/npm/Twitter/ECR. + - `_detect_changes.yml`, `_python.yml`, `_node.yml`, `_opentofu.yml`, `_release_and_tag.yml` — underscore-prefixed reusable workflows, each with many boolean `use_*`/`check_*` inputs that toggle individual linters/services/steps. See `workflows/README.md` for the full input/output reference and step-by-step breakdown of each workflow — update that README whenever inputs or steps change. +- `actions/` — composite actions invoked by the reusable workflows (e.g. `python_linter`, `node_linter`, `codeql`, `services` (spins up Postgres/Redis/RabbitMQ/Mongo/Elasticsearch/Memcached test containers), `push_on_ecr`, `apt_requirements/*` and `python_requirements/*` cache helpers). Each has an `action.yml` and usually a `README.md`. +- `configurations/` — canonical linter/formatter config files consumers point their tools at directly (e.g. `pylint --rcfile=.github/configurations/python_linters/.pylintrc`): + - `python_linters/` — `.pylintrc`, `.flake8`, `.black`, `.isort.cfg`, `.bandit.yaml`, `.ruff.toml`, `requirements-linters.txt`. + - `node_linters/` — `eslint.config.mjs`, `.prettierrc.json`, `.stylelintrc.json`, `packages-linters.txt`. +- `.github/test/` — the fixture projects (`python_test/` a minimal Django+Celery app, `node_test/` a minimal npm/React app) used to self-test the workflows in this repo. These are hard-linked (not symlinked, since GitHub can't store symlink-as-hardlink semantics) into `.github/.github/{workflows,actions,configurations}` so the reusable workflows can `uses: ./.github/workflows/_xxx.yml` against themselves. +- `.pre-commit-config.yaml`, `.husky-pre-commit` — reference pre-commit/husky configs consumers copy into their own repo; they point at the `configurations/` files above. +- `dependabot.yml`, `CHANGELOG.md` — reference configs/format for consumers. + +## The hardlink self-test setup (important, easy to get wrong) + +Because this repo's own CI (`pull_request_automation.yml`) exercises `./.github/workflows/_python.yml` etc. against the fixture projects, the root-level `workflows/`, `actions/`, `configurations/` directories must also exist as identical copies under `.github/.github/`. These are maintained as **hard links**, not a symlink or a second copy: + +```bash +.github/hooks/post-merge # runs: cp -rfl {workflows,actions,configurations} .github/ +``` + +Consequences when editing this repo: +- After checkout/merge, run `.github/hooks/post-merge` (or symlink it as `.git/hooks/post-merge`) to restore the hardlinks — see `README.dev.md`. +- If you add, move, or rename a file (not just edit its content in place), the hardlink is not automatically created/updated for the new path — re-run the post-merge script. +- When staging changes, stage **both** the root file and its `.github/.github/...` counterpart. +- Do not `rm -rf` and recreate `.github/.github` casually; it is regenerated by the script, but any unstaged edits made only under one of the two paths can be lost if you're not careful about which copy you edited. + +## Making changes + +- There is no build/lint/test command to run locally in the traditional sense — this repo is tested by its own GitHub Actions CI (`pull_request_automation.yml`) exercising the fixture projects in `.github/test/`. To validate a workflow/action change, open a PR (or push to a branch that triggers the workflow) and watch the run against `python_test`/`node_test`. +- When changing a reusable workflow's inputs, outputs, or steps, update the corresponding section of `workflows/README.md` to match (it's an intentionally detailed input/output/step reference, not generated). +- When changing a linter configuration, update the matching `configurations/*/README.md` if usage instructions change. +- PRs target `develop` (see `README.dev.md`); releases are cut by merging a PR whose title is a bare semver (e.g. `1.2.3`) into `master`/`main`/`prod`.