Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
297 changes: 297 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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.

Comment thread
danpawlik marked this conversation as resolved.
## 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/<name>/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=<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]`.
Comment thread
danpawlik marked this conversation as resolved.
- **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: <PR-or-MR-URL>` 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.
Comment thread
danpawlik marked this conversation as resolved.

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/<name>/`.
- 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=<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`.
3 changes: 3 additions & 0 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# CLAUDE.md

@AGENTS.md
Loading