|
| 1 | +# Use Makefiles for CI Commands |
| 2 | + |
| 3 | +## Context |
| 4 | + |
| 5 | +Continuous Integration (CI) workflows often contain multiple commands for building, testing, linting, and deploying |
| 6 | +software. These commands can be written directly inside the CI workflow definitions (e.g., GitHub Actions YAML), or they |
| 7 | +can be placed in separate scripts where the CI workflows can call them. |
| 8 | + |
| 9 | +However, both approaches have drawbacks: |
| 10 | + |
| 11 | +* **CI workflows only**: Developers cannot easily run the exact same steps locally without re-creating the workflow |
| 12 | + environment or copy-pasting commands from YAML files. |
| 13 | +* **Separate scripts**: While more reusable than inline commands (different CI environments and local dev), scripts can |
| 14 | + accumulate and require remembering how they are named, where they live, and in which order they should be run. |
| 15 | + |
| 16 | +Makefiles provide a consistent and discoverable interface to common tasks across local development and CI/CD pipelines. |
| 17 | + |
| 18 | +## Options |
| 19 | + |
| 20 | +1. **Write commands directly in CI workflows** |
| 21 | + * Keeps everything in one YAML file |
| 22 | + * Limited reusability CI when using another CI system |
| 23 | + * Harder for developers to replicate the same flow locally |
| 24 | + |
| 25 | +2. **Use separate shell/Python scripts** |
| 26 | + * Allows reusing logic in CI and locally |
| 27 | + * Requires remembering file names and arguments or investing significant effort for developing a strict framework |
| 28 | + * Can fragment into multiple small scripts which require knowledge about how to chain them together |
| 29 | + |
| 30 | +3. **Define commands in Makefile** |
| 31 | + * Provides a single entry point (`make <target>`) for all build/test/deploy tasks |
| 32 | + * Easy for developers to run the same commands locally that CI runs |
| 33 | + * Commands are grouped and discoverable (`make help`), and can programmatically chained together |
| 34 | + * CI workflows stay minimal, calling only the required Make targets |
| 35 | + * Avoids duplication between CI YAML and local dev scripts |
| 36 | + |
| 37 | +## Decision |
| 38 | + |
| 39 | +> Adopt **Makefiles** as the canonical place for defining project build, test, and deployment commands. |
| 40 | +> CI workflows will invoke `make` targets rather than duplicating or hardcoding commands. |
| 41 | +
|
| 42 | +### Justification |
| 43 | + |
| 44 | +* **Ease of local execution**: Developers can run `make lint` or `make apply` locally, without digging into CI YAML. |
| 45 | +* **Consistency**: The exact same Make targets are run in CI and locally, avoiding drift. |
| 46 | +* **Discoverability**: A `Makefile` serves as self-documentation of available project tasks. |
| 47 | +* **Simplicity**: No need to remember how multiple scripts tie together. |
| 48 | + |
| 49 | +## Consequences |
| 50 | + |
| 51 | +* The toolchain requires developers to have GNU Make installed (which is available by default on most UNIX-like |
| 52 | + systems). |
| 53 | +* Some CI steps may still require lightweight shell wrapping (e.g. secrets handling), but the majority of commands live |
| 54 | + in the `Makefile`. |
| 55 | +* CI workflows become shorter and easier to maintain, but the Makefile may grow in complexity if too many |
| 56 | + responsibilities are centralised. |
0 commit comments