From a8b377c3f8159d340f6f8b8c77df24d9629ee3cb Mon Sep 17 00:00:00 2001 From: Roberto Alfieri Date: Mon, 13 Apr 2026 17:04:10 +0200 Subject: [PATCH] [ci] Add AGENTS.md and CLAUDE.md for AI agent guidance Add structured documentation for AI coding agents working on this repository. AGENTS.md provides repo-wide context: variable naming rules, generated file warnings, testing commands, commit conventions, and repository layout. CLAUDE.md adds Claude-specific behavioral guidance and references AGENTS.md as the primary source of truth. Co-Authored-By: Claude Opus 4.6 Signed-off-by: Roberto Alfieri --- AGENTS.md | 297 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ CLAUDE.md | 3 + 2 files changed, 300 insertions(+) create mode 100644 AGENTS.md create mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..4b2b0dd4b --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,297 @@ +# AGENTS.md + +## What is this repository + +CI-Framework is an Ansible collection (`cifmw.general`) that bootstraps +development and CI environments for RHOSO (Red Hat OpenStack Services on +OpenShift). It is **not** intended for production or long-lived deployments. + +The upstream repository lives at +`https://github.com/openstack-k8s-operators/ci-framework`. + +## Tech stack + +- **Ansible** collection (requires `ansible-core >= 2.15`). +- **Python 3** modules and plugins under `plugins/`. +- **Molecule** + Podman for per-role testing. +- **ansible-test** for unit, sanity, and integration tests on plugins. +- **Sphinx** for documentation (hosted on ReadTheDocs). +- **Zuul**, **GitHub Actions**, and **Prow** for CI. + +## Repository layout + +| Path | Description | +|---|---| +| `roles/` | Ansible roles. Each has `defaults/`, `tasks/`, `molecule/`, `README.md`. | +| `playbooks/` | Domain-specific playbooks in subdirectories (`adoption/`, `ceph/`, `bgp/`, etc.). Legacy numbered-stage playbooks are deprecated -- orchestration is handled by the `cifmw_setup` role. | +| `plugins/` | Collection plugins: `action/`, `filter/`, `modules/`, `module_utils/`. Test with `ansible-test`, not Molecule. | +| `tests/` | `ansible-test` suites: `unit/` (pytest), `integration/targets/`, `sanity/ignore.txt`. | +| `ci/` | CI-only playbooks: content provider, EDPM, kuttl, architecture validation, doc build, log collection. | +| `scenarios/` | Scenario-oriented variable packs used by framework flows. | +| `scripts/` | Environment setup, Molecule runner, ansible-test runner, Zuul/Molecule generation, snippet checks. | +| `docs/` | Sphinx sources under `docs/source/`. | +| `hooks/` | Hook playbooks consumed by the framework. Some hooks have their own `roles/` subdirectory. | +| `custom/` | Local overrides (gitignored except `README.md`). Safe for local dev experiments, never committed. | +| `containerfiles/` | Podman images for CI (`Containerfile.ci`, `Containerfile.tests`). | +| `group_vars/` | Shared group variables (e.g., `all.yml`). Changes here affect every playbook run. | +| `zuul.d/` | Zuul job and project definitions. **Some files are generated -- see below.** | +| `_skeleton_role_/` | Template used by `ansible-galaxy role init` when creating new roles. | + +## Critical rules + +### Variable naming + +All Ansible role variables **must** match the pattern `^cifmw_[a-z_][a-z0-9_]*$` +where after the `cifmw_` prefix comes the role name, then the variable name +(e.g., `cifmw_my_role_some_setting`). +This is enforced by `ansible-lint` with `strict: true` and `profile: production`. + +### FQCN required + +All module calls must use fully-qualified collection names. +The following FQCN rules are enabled in `.ansible-lint`: +`fqcn-builtins`, `fqcn[action]`, `fqcn[action-core]`, `fqcn[canonical]`, `fqcn[deep]`. + +### Generated files -- do not hand-edit + +The following files are **generated** by `scripts/create_role_molecule.py`: + +- `zuul.d/molecule.yaml` +- `zuul.d/projects.yaml` (molecule section) + +To regenerate: `make role_molecule`. To verify consistency: `make check_zuul_files`. +If you hand-edit these files, CI will reject the change. + +### Read-only / generated paths + +Do **not** modify these paths directly: + +| Path | Reason | +|---|---| +| `zuul.d/molecule.yaml` | Generated by `scripts/create_role_molecule.py`. | +| `zuul.d/projects.yaml` | Generated (molecule section). | +| `custom/` | Gitignored. Local-only overrides, never committed. | +| `hooks/playbooks/roles/` | Excluded from ansible-lint. Owned by hook authors. | + +All other paths (`roles/`, `playbooks/`, `plugins/`, `group_vars/`, `scenarios/`, +`hooks/playbooks/`, `ci/`, `scripts/`, `docs/`) are safe to edit following the +conventions in this file. + +### Debugging patterns + +Use `block`/`rescue`/`always` for complex task sequences. Dump relevant +variables in the `rescue` block, then `ansible.builtin.fail` to stop +execution. This makes CI failures much easier to diagnose. + +### Do not be too verbose + +There is no need to provide explanation for each variable in each task file. +It is enough when the variable description is available in the role README +file. Add comments only to complex code. + +### Do not create too many variables + +Balance the amount of variables: there is no need to create additional +variables especially for static values that are only used once by another +module or role. In that case, fewer variables means more clarity. + +### Make tasks easier to debug + +Tasks should not do too many things in a single step -- on failure that +becomes difficult to debug. In some cases, adding more small, fast tasks +is better than one large task. Add debug messages only in very complex +places, not everywhere. + +## Playbooks + +Do not rely on the `playbooks/` directory as the primary orchestration layer. +The numbered-stage playbooks (`01-bootstrap.yml`, `02-infra.yml`, etc.) are +**deprecated** -- orchestration is now handled by the `cifmw_setup` role. + +The `playbooks/` directory still contains: +- **Subdirectories** (`adoption/`, `ceph/`, `bgp/`, `dcn/`, `multi-namespace/`) + with domain-specific flows. +- **Standalone playbooks** (`hooks.yml`, `update.yml`, `dcn.yml`, `nfs.yml`, + `switches_config.yml`, etc.) for specific operations. + +## Creating a new role + +Always use the Makefile: + +``` +make new_role ROLE_NAME=my_role +``` + +This generates the skeleton, Molecule config, and updates Zuul jobs. +Every new role must have: + +1. A `README.md` documenting its parameters. +2. Molecule test scenarios. +3. Documentation that builds cleanly (checked in CI). + +If the role cannot be tested via Molecule, remove the `molecule/` directory +and run `make role_molecule` to regenerate Zuul jobs. Add a note in the +role's `README.md` explaining why. + +## Testing + +### Commands + +| Command | What it does | +|---|---| +| `make pre_commit` | Runs pre-commit hooks (shellcheck, black, ansible-lint) with dependency install. | +| `make molecule` | Runs Molecule tests for all roles with dependency install. | +| `make ansible_test` | Runs ansible-test (units + sanity + integration) with dependency install. | +| `make tests` | Runs pre-commit + Molecule. | +| `make check_zuul_files` | Regenerates Zuul YAML and fails if it differs from committed files. | +| `make docs` | Builds Sphinx documentation under `docs/_build/html/`. | +| `make spelling` | Runs `pyspelling` on docs. | +| `make plugin-development-enable` | Rewrites import paths and sets `PYTHONPATH` for local plugin dev. | +| `make plugin-development-disable` | Reverts the changes made by `plugin-development-enable`. | + +### Container-based testing (requires Podman) + +| Command | What it does | +|---|---| +| `make run_ctx_pre_commit` | Pre-commit in a container. | +| `make run_ctx_molecule` | Molecule in a container. | +| `make run_ctx_ansible_test` | ansible-test in a container. | +| `make run_ctx_all_tests` | All of the above. | + +### Molecule specifics + +- Config: `.config/molecule/config_podman.yml` (host) or `config_local.yml` (container). +- Test a single role: `TEST_SINGLE_ROLE=my_role make molecule` or `make run_ctx_molecule`. +- Molecule scenarios live under `roles//molecule/`. + +### Validation priority + +When verifying a change, run checks in this order: + +1. `pre-commit run --all-files` — fast lint pass (ansible-lint, black, shellcheck). +2. `TEST_SINGLE_ROLE= make molecule` — targeted Molecule test. +3. `make ansible_test` — plugin unit/sanity/integration tests (only if plugins changed). +4. `make docs` — only if documentation was modified. + +### macOS limitations + +The Makefile test targets (`make tests`, `make molecule`, `make ansible_test`, +`make setup_tests`, `make setup_molecule`, and their `_nodeps` variants) **do not +work on macOS**. The underlying scripts use `readlink -f`, which is not available +on macOS. These targets are designed for Linux CI environments only. + +## Linting and code style + +- **ansible-lint**: `production` profile, `strict: true`. Config in `.ansible-lint`. +- **Python**: Formatted with `black`. +- **Shell**: Checked with `shellcheck` (severity=error, excludes SC2071). +- **Pre-commit**: Config in `.pre-commit-config.yaml`. Run with `make pre_commit` or `make run_ctx_pre_commit`. +- **Spelling**: `pyspelling` on docs. Run with `make spelling`. + +### Excluded from linting + +ansible-lint skips: `.github/`, `scripts/`, `docs/`, `containerfiles/`, `ci/`, +and the generated Zuul files (`zuul.d/projects.yaml`, `zuul.d/molecule.yaml`). + +## Commit conventions + +- **Title**: Must begin with the role name in brackets or parentheses: + `[my_role] Add feature X` or `(my_role) Fix bug Y`. + If changes span multiple roles, use `[multiple]` or `(multiple)`. + For cross-cutting changes use a category: `[ci]`, `[docs]`, `[Feature]`. +- **Body**: Must be longer than 10 characters and describe **why** the change + was made. +- **Sign-off**: Required (`git commit --signoff`). The sign-off certifies a + [DCO](https://developercertificate.org/). AI agents cannot sign off on behalf + of a human -- the committer must add it themselves or amend the commit. +- **AI attribution**: Use `Co-Authored-By:` for substantial AI-generated code, + `Assisted-By:` for minor AI help. Disclose the scope in the PR description. +- **Ticket references**: Link Jira cards in the commit message body: + `Closes: ANVIL-123` (resolves the ticket) or + `Related-Issue: #OSPRH-12345` (related but does not close). +- **Cross-repo dependencies**: When a change depends on an unmerged PR/MR in + another repository, add `Depends-On: ` in the PR/MR + description. Zuul uses this to test the changes together. + +### Commit strategy + +To keep a clean git history, prefer a single commit per feature or fix: + +1. Create the initial commit normally. +2. For subsequent changes on the same branch, amend the existing commit + (`git commit --amend`) instead of creating new ones. +3. After amending, use `git push --force` to update the remote branch. + +Never push directly to `main` — it is a protected branch. Always work on +a feature branch. Force pushing is only appropriate for **solo feature +branches**, never for `main` or shared branches. + +If a change is not directly related to the main goal of the pull request +but is required for it to work, add it as a **separate commit**. When +amending, be careful to edit only the commits that belong to the same +pull request. + +## Branch workflow + +- The default branch is `main`. +- Feature work happens on topic branches. +- PRs target `main` unless otherwise specified. +- Branch names should be descriptive (e.g., `fix-reproducer-pull-secret`, + `feature/OSPRH-12345-new-role`). + +## PR process + +- PRs are auto-set to draft on open. To undraft, push a non-`nit:` change. +- Minimum **2 approvals** required (excluding the author). +- Security-sensitive code requires additional maintainer review. +- Ownership is defined in `OWNERS` and `OWNERS_ALIASES`. + +## Relationship to ci-framework-jobs + +The `ci-framework-jobs` repository holds downstream Zuul job definitions that +consume this repository. Jobs in that repo declare +`required-projects: openstack-k8s-operators/ci-framework` and +`roles: zuul: openstack-k8s-operators/ci-framework` so Zuul checks out this +repo and exposes its roles during job execution. Uni jobs orchestrate this +repo's `reproducer.yml` playbook as their main entry point. + +When making changes here that affect CI behavior, coordinate with the +corresponding job definitions in `ci-framework-jobs`. + +## Plugin development + +To develop collection plugins locally without installing the collection: + +``` +make plugin-development-enable +``` + +This rewrites import paths and sets `PYTHONPATH`. Revert with: + +``` +make plugin-development-disable +``` + +Plugins are tested with `ansible-test`, not Molecule. + +## Documentation first + +Before searching the web or relying on general knowledge, check local +documentation: +- `docs/source/` — Sphinx sources for the ci-framework collection. +- Role-level `README.md` files under `roles//`. +- The downstream CI docs repository at + `https://gitlab.cee.redhat.com/ci-framework/docs` covers job types, + pipelines, troubleshooting, and glossary. + +## Confirm before acting + +Before performing expensive or broad-impact operations, confirm with the +user first: + +- Running full test suites (`make tests`, `make molecule`) — ask whether a + targeted run (`TEST_SINGLE_ROLE=`) is sufficient. +- Modifying `group_vars/all.yml` — changes here affect every playbook run. +- Editing roles used by multiple playbooks — flag the blast radius. +- Cross-repo changes that require coordinated updates in `ci-framework-jobs` + or `architecture`. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 000000000..f6aa6c026 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,3 @@ +# CLAUDE.md + +@AGENTS.md