|
| 1 | +# Contributing to the Bootc Operator |
| 2 | + |
| 3 | +The Bootc Operator is a Kubernetes operator for managing |
| 4 | +[bootc](https://github.com/bootc-dev/bootc) nodes. We welcome contributions of |
| 5 | +all kinds: bug reports, feature requests, documentation improvements, and code |
| 6 | +changes. |
| 7 | + |
| 8 | +## Table of Contents |
| 9 | + |
| 10 | +- [Prerequisites](#prerequisites) |
| 11 | +- [Development Environment](#development-environment) |
| 12 | +- [Building](#building) |
| 13 | +- [Testing](#testing) |
| 14 | +- [Investigating CI Failures](#investigating-ci-failures) |
| 15 | +- [Code Style](#code-style) |
| 16 | +- [Submitting Changes](#submitting-changes) |
| 17 | +- [AI Generated Code](#ai-generated-code) |
| 18 | +- [Community](#community) |
| 19 | +- [License](#license) |
| 20 | +- [Other Useful Documentation](#other-useful-documentation) |
| 21 | + |
| 22 | +## Prerequisites |
| 23 | + |
| 24 | +Before contributing, make sure you have the following installed: |
| 25 | + |
| 26 | +- **Go** (see `go.mod` for the required version) |
| 27 | +- **Make** |
| 28 | +- **Podman** |
| 29 | +- **kubectl** |
| 30 | + |
| 31 | +For end-to-end testing you will also need: |
| 32 | + |
| 33 | +- [bink](https://github.com/bootc-dev/bink) — lightweight Kubernetes clusters |
| 34 | + backed by bootc nodes |
| 35 | +- [skopeo](https://github.com/containers/skopeo) — container image inspection |
| 36 | + |
| 37 | +Tool dependencies like `controller-gen`, `kustomize`, `golangci-lint`, and |
| 38 | +`setup-envtest` are downloaded automatically to `./bin/` by the Makefile when |
| 39 | +needed. |
| 40 | + |
| 41 | +### Development Environment |
| 42 | + |
| 43 | +Most contributors work on a Linux host with Go and Podman available. Make sure |
| 44 | +the Podman socket is running — bink and the build system communicate with |
| 45 | +Podman through it: |
| 46 | + |
| 47 | +```shell |
| 48 | +systemctl --user start podman.socket |
| 49 | +``` |
| 50 | + |
| 51 | +Before diving into the code, familiarize yourself with the project from a user |
| 52 | +perspective by reading the [README](README.md) and the |
| 53 | +[Architecture](docs/ARCHITECTURE.md) document. We also recommend getting |
| 54 | +familiar with [bink](https://github.com/bootc-dev/bink), which is used to |
| 55 | +create lightweight Kubernetes clusters backed by bootc nodes for development |
| 56 | +and testing. |
| 57 | + |
| 58 | +You can create a bink cluster by running: |
| 59 | +```shell |
| 60 | +make deploy-bink |
| 61 | +``` |
| 62 | + |
| 63 | +To tear down the cluster when done: |
| 64 | + |
| 65 | +```shell |
| 66 | +make teardown-bink |
| 67 | +``` |
| 68 | + |
| 69 | +By default, `deploy-bink` and `e2e` share the same cluster named `e2e`. To use |
| 70 | +a separate development cluster: |
| 71 | + |
| 72 | +```shell |
| 73 | +make deploy-bink BINK_CLUSTER_NAME=dev |
| 74 | +``` |
| 75 | + |
| 76 | +## Building |
| 77 | + |
| 78 | +```shell |
| 79 | +make build # Build all binaries (manager + daemon) to ./bin/ |
| 80 | +make buildimg # Build the container image (default: bootc-operator:dev) |
| 81 | +``` |
| 82 | + |
| 83 | +The `bootc-operator` container image contains both the controller and daemon |
| 84 | +binaries. |
| 85 | + |
| 86 | +After modifying API types in `api/`, regenerate CRDs and code: |
| 87 | + |
| 88 | +```shell |
| 89 | +make manifests # Regenerate CRD and RBAC manifests |
| 90 | +make generate # Regenerate DeepCopy implementations |
| 91 | +``` |
| 92 | + |
| 93 | +## Testing |
| 94 | + |
| 95 | +### Running Unit Tests |
| 96 | + |
| 97 | +Unit tests live in `internal/controller/` and `internal/daemon/` alongside the |
| 98 | +code they test. They use the controller-runtime |
| 99 | +[envtest](https://book.kubebuilder.io/reference/envtest) framework, which |
| 100 | +provides a local control plane (etcd + API server) without a full cluster. The |
| 101 | +required binaries are downloaded automatically. |
| 102 | + |
| 103 | +```shell |
| 104 | +make unit # Run all unit tests |
| 105 | +make unit V=1 # Verbose output |
| 106 | +make unit RUN=Foo # Run tests matching "Foo" |
| 107 | +``` |
| 108 | + |
| 109 | +### Running End-to-End Tests |
| 110 | + |
| 111 | +E2E tests live in `test/e2e/` and run against a real |
| 112 | +[bink](https://github.com/bootc-dev/bink) cluster. The full workflow is: |
| 113 | + |
| 114 | +Each e2e test creates a dedicated worker node for the duration of the test and |
| 115 | +tears it down when the test completes. The freshly provisioned node ensures |
| 116 | +that each test starts from a clean state. |
| 117 | + |
| 118 | +```shell |
| 119 | +make buildimg # Build the operator container image |
| 120 | +make deploy-bink # Start a bink cluster and deploy the operator |
| 121 | +make e2e # Run the e2e test suite |
| 122 | +make e2e V=1 # Verbose streaming output |
| 123 | +make e2e RUN=Foo # Run tests matching "Foo" |
| 124 | +``` |
| 125 | + |
| 126 | +> [!NOTE] |
| 127 | +> The container image must be rebuilt and pushed to the bink registry after |
| 128 | +> every code change. Run `make buildimg` followed by `make deploy-bink` to |
| 129 | +> pick up your latest changes in the cluster. |
| 130 | +
|
| 131 | +### Internal Registry |
| 132 | + |
| 133 | +The bink cluster includes an internal container registry. From the host, push |
| 134 | +images to `localhost:5000`: |
| 135 | + |
| 136 | +```shell |
| 137 | +podman push --tls-verify=false localhost:5000/my-image:latest |
| 138 | +``` |
| 139 | + |
| 140 | +From inside the cluster, the same image is available at |
| 141 | +`registry.cluster.local:5000`: |
| 142 | + |
| 143 | +```yaml |
| 144 | +image: registry.cluster.local:5000/my-image:latest |
| 145 | +``` |
| 146 | +
|
| 147 | +### Finding Test Logs |
| 148 | +
|
| 149 | +Each e2e test automatically gathers diagnostic logs when it completes |
| 150 | +(regardless of pass or fail). Logs are written to `_output/logs/<test-name>/` |
| 151 | +and include: |
| 152 | + |
| 153 | +- Operator pod logs |
| 154 | +- Pod and deployment descriptions |
| 155 | +- BootcNodePool and BootcNode descriptions |
| 156 | +- Kubernetes events |
| 157 | +- Node descriptions and journal logs for each worker node |
| 158 | + |
| 159 | +You can also manually gather logs from a running cluster: |
| 160 | + |
| 161 | +```shell |
| 162 | +make gather-bink |
| 163 | +``` |
| 164 | + |
| 165 | +This collects the same diagnostics into `_output/logs/gather-bink/`. |
| 166 | + |
| 167 | +## Investigating CI Failures |
| 168 | + |
| 169 | +CI runs on [GitHub Actions](https://github.com/bootc-dev/bootc-operator/actions) |
| 170 | +and consists of three jobs: `unit`, `build-bink`, and `e2e`. When a run fails, |
| 171 | +you can inspect it using the `gh` CLI. |
| 172 | + |
| 173 | +View a run summary: |
| 174 | + |
| 175 | +```shell |
| 176 | +gh run view <run-id> --repo bootc-dev/bootc-operator |
| 177 | +``` |
| 178 | + |
| 179 | +### Downloading E2E Logs |
| 180 | + |
| 181 | +The e2e job uploads diagnostic logs as a GitHub Actions artifact named |
| 182 | +`e2e-logs`. These contain the same logs collected by `make gather-bink` |
| 183 | +(operator pod logs, node journals, event dumps, etc.). Download them with: |
| 184 | + |
| 185 | +```shell |
| 186 | +gh run download <run-id> --repo bootc-dev/bootc-operator |
| 187 | +``` |
| 188 | + |
| 189 | +This creates a local `e2e-logs/` directory with per-test subdirectories |
| 190 | +matching the structure described in [Finding Test Logs](#finding-test-logs). |
| 191 | + |
| 192 | +## Code Style |
| 193 | + |
| 194 | +### Go |
| 195 | + |
| 196 | +- Run `make fmt` and `make vet` before submitting. |
| 197 | +- Run `make lint` to check with |
| 198 | + [golangci-lint](https://golangci-lint.run/). Use `make lint-fix` to apply |
| 199 | + automatic fixes. |
| 200 | +- All Go files must include the SPDX license header: |
| 201 | + |
| 202 | + ```go |
| 203 | + // SPDX-License-Identifier: Apache-2.0 |
| 204 | + ``` |
| 205 | + |
| 206 | +## Submitting Changes |
| 207 | + |
| 208 | +### Before Writing a Big Patch |
| 209 | + |
| 210 | +If you are planning a large change, please **open an issue first** to discuss |
| 211 | +the approach. This avoids wasted effort and helps maintainers give early |
| 212 | +feedback. |
| 213 | + |
| 214 | +### Developer Certificate of Origin |
| 215 | + |
| 216 | +This project uses the [Developer Certificate of Origin](https://developercertificate.org/) |
| 217 | +(DCO). You must sign off each commit to certify that you have the right to |
| 218 | +submit it under the project's open source license. |
| 219 | + |
| 220 | +Add a sign-off line to your commits: |
| 221 | + |
| 222 | +``` |
| 223 | +Signed-off-by: Your Name <your.email@example.com> |
| 224 | +``` |
| 225 | + |
| 226 | +Use `git commit -s` to add this automatically. Your sign-off name must match |
| 227 | +your real name. |
| 228 | + |
| 229 | +### Commit Style |
| 230 | + |
| 231 | +Follow a commit style similar to the Linux kernel: |
| 232 | + |
| 233 | +1. **Subject line**: a short contextual prefix, imperative mood, under 72 |
| 234 | + characters, no trailing period. |
| 235 | +2. **Body**: separated by a blank line, wrapped at 72 characters. Explain |
| 236 | + *what* changed and *why*. |
| 237 | +3. Use `Closes: #<number>` or `Fixes: #<number>` to link to issues. |
| 238 | + |
| 239 | +### Pull Request Process |
| 240 | + |
| 241 | +1. Fork the repository and create a topic branch from `main`. |
| 242 | +2. Make your changes in small, focused commits. |
| 243 | +3. Ensure all checks pass locally: |
| 244 | + |
| 245 | + ```shell |
| 246 | + make fmt manifests generate |
| 247 | + make vet |
| 248 | + make lint |
| 249 | + make unit |
| 250 | + ``` |
| 251 | + |
| 252 | +4. Push your branch and open a pull request against `main`. |
| 253 | +5. Describe the change clearly in the PR description — what it does and why. |
| 254 | +6. Address review feedback. Maintainers may request changes before merging. |
| 255 | + |
| 256 | +### Code Review |
| 257 | + |
| 258 | +All submissions require review before merging. Reviewers look for: |
| 259 | + |
| 260 | +- Correctness and test coverage |
| 261 | +- Consistency with existing patterns |
| 262 | +- Clear commit messages |
| 263 | +- Generated files kept in sync |
| 264 | + |
| 265 | +## AI generated code |
| 266 | + |
| 267 | +For AI generated code, please refer the |
| 268 | +[AGENTS.md](https://github.com/bootc-dev/infra/blob/main/common/AGENTS.md) |
| 269 | +document. |
| 270 | + |
| 271 | +## Community |
| 272 | + |
| 273 | +- **Issues**: Use [GitHub Issues](https://github.com/bootc-dev/bootc-operator/issues) |
| 274 | + to report bugs or request features. |
| 275 | + |
| 276 | +## License |
| 277 | + |
| 278 | +By contributing, you agree that your contributions will be licensed under the |
| 279 | +[Apache License 2.0](LICENSE). |
| 280 | + |
| 281 | +## Other useful documentation |
| 282 | + |
| 283 | +Please, refer to these guides for further help: |
| 284 | +* [General bootc review guide](https://github.com/bootc-dev/infra/blob/main/common/REVIEW.md) |
| 285 | +* [Kubernetes contributing guide](https://github.com/kubernetes/community/tree/main/contributors/guide) |
| 286 | +* [Golang best-practise](https://go.dev/doc/effective_go) |
| 287 | +* [Kubernetes API conventions](https://github.com/kubernetes/community/blob/main/contributors/devel/sig-architecture/api-conventions.md) |
0 commit comments