Repository navigation
Expand file tree
/
Copy pathMakefile
More file actions
140 lines (122 loc) · 6.52 KB
/
Copy pathMakefile
File metadata and controls
140 lines (122 loc) · 6.52 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
# Makefile for git-template
#
# Provides one-command setup for this repository's shared git configuration
# and pre-commit hooks.
#
# Usage:
# make # same as `make help`
# make help # list available targets
# make setup # create .venv + configure the repo's git config and hooks
# make ci # run the full CI check suite (the command pipelines invoke)
# make lint # run all pre-commit hooks against all files
# make clean # remove the local virtualenv
#
# make rulesets-apply # rebuild this repo's GitHub branch protection
# make rulesets-diff # check live branch protection against the repo
# make rulesets-export # save live branch protection into the repo
#
# Requirements:
# - GNU make, git, and a POSIX shell (on Windows: Git Bash or WSL).
# - A Python interpreter >= $(MIN_PYTHON) reachable as `python3`. It is used
# ONLY to create the virtualenv, so it can be any install you already have
# (system, Homebrew, pyenv, ...). Point make at a specific one with:
# make setup PYTHON=/path/to/python3.12
#
# Nothing is installed globally and no exact global Python version is
# required: `make setup` creates a repo-local virtualenv in .venv/ and
# installs the pinned `pre-commit` from requirements-dev.txt into it.
#
# How it works:
# `make setup` does two things:
# 1. Builds .venv/ and installs the pinned tooling into it.
# 2. Runs `git config --local include.path ../.gitconfig`, which makes this
# repo's local config include the committed `.gitconfig`. That in turn
# sets `core.hooksPath = .githooks/`, activating the committed hook
# scripts (pre-commit and commit-msg) without needing `pre-commit
# install`. Those scripts run .venv's `pre-commit`, never PATH's.
.DEFAULT_GOAL := help
# ---------------------------------------------------------------------------
# REPO-LOCAL VIRTUALENV
# ---------------------------------------------------------------------------
# The interpreter used only to *create* .venv. Override on the command line
# (e.g. `make setup PYTHON=python3.12`) to build the venv from a specific one.
PYTHON ?= python3
# Minimum version for the interpreter above: some hooks (commitizen,
# sync-pre-commit-deps) are `language: python` and require >= 3.10. Because
# their manifests say `language_version: python3`, pre-commit builds them with
# whichever interpreter is running pre-commit itself — i.e. .venv's.
MIN_PYTHON := 3.10
VENV := .venv
ifeq ($(OS),Windows_NT)
VENV_BIN := $(VENV)/Scripts
else
VENV_BIN := $(VENV)/bin
endif
PRE_COMMIT := $(VENV_BIN)/pre-commit
# Marker file recording that requirements-dev.txt has been installed into
# .venv; makes `venv` a no-op until the requirements change.
VENV_STAMP := $(VENV)/.requirements-installed
RULESETS := ./scripts/github-rulesets.sh
.PHONY: setup venv ci lint clean check-python help \
rulesets-apply rulesets-diff rulesets-export
help: ## Show available targets
@grep -E '^[a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf " \033[36m%-18s\033[0m %s\n", $$1, $$2}'
setup: venv ## Create the local virtualenv and configure the repo's git config + hooks
git config --local include.path ../.gitconfig
$(PRE_COMMIT) install-hooks
venv: $(VENV_STAMP) ## Create/update the repo-local virtualenv (.venv) with the pinned tooling
$(VENV_STAMP): requirements-dev.txt
@$(MAKE) --no-print-directory check-python
$(PYTHON) -m venv $(VENV)
$(VENV_BIN)/python -m pip install --disable-pip-version-check --upgrade pip
$(VENV_BIN)/python -m pip install --disable-pip-version-check --require-virtualenv -r requirements-dev.txt
@touch $@
# ---------------------------------------------------------------------------
# CI ENTRYPOINT
# ---------------------------------------------------------------------------
# `make ci` is the SINGLE command CI/CD pipelines invoke. Both the GitHub
# Actions workflow (.github/workflows/ci.yml) and the Azure DevOps pipeline
# (azure-pipelines.yml) do nothing more than: check out the code, provide a
# Python interpreter, and run `make ci`. All actual logic lives here, in-repo,
# so it runs identically on a developer laptop and on every CI platform.
#
# Projects built from this template extend `ci` by adding their own build/test
# steps (e.g. `dotnet test`, `npm test`) as dependencies or extra recipe lines.
ci: lint ## Run the full CI check suite (what pipelines invoke)
lint: venv ## Run all pre-commit hooks against all files (same hooks as the git hooks)
$(PRE_COMMIT) run --all-files --show-diff-on-failure
clean: ## Remove the local virtualenv (rebuild it with `make setup`)
rm -rf $(VENV)
# ---------------------------------------------------------------------------
# GITHUB RULESETS (branch protection as code)
# ---------------------------------------------------------------------------
# Branch protection lives in .github/rulesets/*.json and is reconciled by name,
# so `make rulesets-apply` rebuilds it in any repo created from this template.
# See scripts/github-rulesets.sh for the details.
#
# These targets are deliberately NOT dependencies of `ci`: rulesets are admin
# API surface, and a workflow's default GITHUB_TOKEN cannot read them. Making
# `ci` depend on them would fail for reasons unrelated to the code under test,
# and would break the rule that `make ci` runs identically on a laptop.
#
# Requires the GitHub CLI (`gh`), authenticated — unlike the targets above, this
# is not covered by `make setup`. Target another repo with REPO=owner/name.
rulesets-apply: ## Create/update this repo's GitHub rulesets from .github/rulesets/
$(RULESETS) apply
rulesets-diff: ## Report drift between .github/rulesets/ and the live rulesets
$(RULESETS) diff
rulesets-export: ## Overwrite .github/rulesets/ with the live rulesets
$(RULESETS) export
check-python: ## Verify the interpreter used to build .venv is new enough
@command -v $(PYTHON) > /dev/null 2>&1 || { \
echo 'Error: `$(PYTHON)` was not found on your PATH.' 1>&2; \
echo ' Install any Python >= $(MIN_PYTHON), or point make at one you have:' 1>&2; \
echo ' make setup PYTHON=/path/to/python3' 1>&2; \
exit 1; \
}
@$(PYTHON) -c 'import sys; req = tuple(int(p) for p in "$(MIN_PYTHON)".split(".")); raise SystemExit(sys.version_info[:len(req)] < req)' || { \
echo "Error: $(PYTHON) is $$($(PYTHON) -V 2>&1 | cut -d" " -f2), but >= $(MIN_PYTHON) is required to build $(VENV)." 1>&2; \
echo ' Any interpreter >= $(MIN_PYTHON) will do; it need not be your default python3:' 1>&2; \
echo ' make setup PYTHON=python3.12' 1>&2; \
exit 1; \
}