0.4 The Gate
Knowing the commands is one thing. Remembering them every time is another. An experienced craftsman does not go a day without checking - not because they are vigilant, but because checking long ago became part of the motion. The apprentice does it by force of will. Force of will is known for being unreliable.
What You Need
Five commands are known. But running them one by one, in the right order, every time - that is a burden people start ignoring. What is needed is a single entry point that checks everything at once and does not allow work to be called finished until it has passed through.
One more document is also needed: a description of how to get into the workshop at all.
A new developer who clones the repository should be able to run tq without asking questions.
The Ritual
Create a Makefile in the project root - next to Cargo.toml:
# ==================================================================================== #
# HELPERS
# ==================================================================================== #
## help: print this help message
.PHONY: help
help:
@echo 'Usage:'
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
# ==================================================================================== #
# DEVELOPMENT
# ==================================================================================== #
## run: run tq
.PHONY: run
run:
@cargo run
## build: build debug binary
.PHONY: build
build:
@cargo build
## check: cargo check + clippy
.PHONY: check
check:
@cargo check && cargo clippy
## fmt: format code
.PHONY: fmt
fmt:
@cargo fmt
## test: run tests
.PHONY: test
test:
@cargo test
# ==================================================================================== #
# QUALITY CONTROL
# ==================================================================================== #
## ci: full check - format, linting and tests
.PHONY: ci
ci:
@cargo fmt --check && cargo clippy -- -D warnings && cargo test
# ==================================================================================== #
# BUILD
# ==================================================================================== #
## clean: remove build artifacts
.PHONY: clean
clean:
@cargo clean
Important: indentation in a Makefile must be a tab character. Spaces will produce an error.
make ci is the gate. This command decides whether the work is done:
make ci
Compiling tq v0.1.0 (.../tq)
Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.38s
Running unittests src/main.rs (target/debug/deps/tq-...)
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
No tests yet - that changes by the end of the first milestone. make ci does not object to
an empty test suite. It objects to code that is unformatted, fails Clippy, or does not compile.
Now README.md. Create it next to the Makefile:
# tq
A task manager. Work in progress.
## Requirements
- [Rust](https://rustup.rs/) - latest stable version
- `make`
## Quick start
cargo run
# or
make run
## Development
make ci # format + clippy + tests
make fmt # format code
make check # cargo check + clippy
make test # tests
make clean # remove build artifacts
The Result
make ci passes. The gate stands - unfinished work does not get through.
The
tqcode did not change in this chapter - the gate was built around what already exists. For consistency it is still at0-the-workshop/04-the-gate/.
Lore: How the Makefile Works
make help does not read a separate description file - it parses the Makefile itself.
Comments of the form ## target: description are not just comments; they are data:
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'
${MAKEFILE_LIST} is a Make variable containing the names of all loaded files. Usually that
is just Makefile, but if one Makefile includes another, sed will walk both.
Three steps:
-
sed -n 's/^##//p'- finds lines starting with##, strips the prefix, and prints them. Everything else is ignored. -
column -t -s ':'- aligns the output into columns, splitting on:. This is whyrun: run tqandci: full check - format, linting and testsline up neatly, regardless of target name length. -
sed -e 's/^/ /'- adds an indent before each line.
.PHONY declares targets as phony: Make assumes a target is a filename by default and skips
the command if a file with that name already exists. run, build, ci are not files.
Without .PHONY, make build might stay silent if a build/ directory were present.
@ at the start of a command suppresses its echo to the terminal. Without it, make run
would print cargo run before running it. With it - only the command’s own output appears.
Lore: —check and Why ci Does Not Format
make fmt runs cargo fmt - the command that rewrites files in place. In make ci, the
command is cargo fmt --check: it only checks and exits with an error if the formatting does
not match what is expected.
The difference matters. If make ci runs automatically - on a server, in a pipeline - it
should not silently modify files. An error is visible; a silent fix is not. In local work:
run make fmt, then make ci again.