From c8b074b65e32c76daafa03a024fb5b4df7838cfb Mon Sep 17 00:00:00 2001 From: Night Date: Sun, 25 Oct 2026 02:23:27 +1100 Subject: [PATCH 1/6] feat: projects ship a Makefile in place of run.sh * make build installs the locked dependencies and byte-compiles the package * make format and make format-dry-run run ruff format, and make test runs pytest * make release builds a wheel and an sdist into dist/ * breaking: generated projects no longer have run.sh --- template/Makefile.jinja | 22 ++++++++++++++++++ template/run.sh.jinja | 51 ----------------------------------------- 2 files changed, 22 insertions(+), 51 deletions(-) create mode 100644 template/Makefile.jinja delete mode 100755 template/run.sh.jinja diff --git a/template/Makefile.jinja b/template/Makefile.jinja new file mode 100644 index 0000000..8735163 --- /dev/null +++ b/template/Makefile.jinja @@ -0,0 +1,22 @@ +# Project tasks. CI runs format-dry-run, build, test and release. + +PACKAGE := {{ module_slug }} + +.PHONY: build format format-dry-run test release + +build: + uv sync --locked + uv run --locked python -m compileall -q $(PACKAGE) + +format: + uv run --locked ruff format . + +format-dry-run: + uv run --locked ruff format --check . + +test: + uv run --locked pytest + +release: + rm -rf dist + uv build --out-dir dist diff --git a/template/run.sh.jinja b/template/run.sh.jinja deleted file mode 100755 index 635fe91..0000000 --- a/template/run.sh.jinja +++ /dev/null @@ -1,51 +0,0 @@ -#!/usr/bin/env bash -# Project tasks. CI runs --format-dry-run, --build, --test and --release. - -set -euo pipefail -cd "$(dirname "$0")" - -package="{{ module_slug }}" - -usage() { - cat < - - --build install the locked dependencies and byte-compile the package - --format format the Python sources in place - --format-dry-run list unformatted Python sources and fail if there are any - --test run the tests - --release build the wheel and sdist into dist/ -USAGE -} - -build() { - uv sync --locked - uv run --locked python -m compileall -q "$package" -} - -format() { - uv run --locked ruff format . -} - -format_dry_run() { - uv run --locked ruff format --check . -} - -run_tests() { - uv run --locked pytest -} - -release() { - rm -rf dist - uv build --out-dir dist -} - -case "${1:-}" in - --build) build ;; - --format) format ;; - --format-dry-run) format_dry_run ;; - --test) run_tests ;; - --release) release ;; - -h|--help) usage ;; - *) usage >&2; exit 1 ;; -esac From efa5477ed1e931f7c405402d3fd4c9be97457395 Mon Sep 17 00:00:00 2001 From: Night Date: Sun, 25 Oct 2026 02:23:27 +1100 Subject: [PATCH 2/6] feat: the dev container includes make * make is installed alongside uv, so the Makefile targets run in the dev container and in CI --- template/Dockerfile | 1 + 1 file changed, 1 insertion(+) diff --git a/template/Dockerfile b/template/Dockerfile index 047cf0f..d86419a 100644 --- a/template/Dockerfile +++ b/template/Dockerfile @@ -9,6 +9,7 @@ RUN apt update && apt upgrade -y \ && apt install --no-install-recommends -y \ ca-certificates \ bash \ + make \ curl \ && apt clean \ && apt autoremove \ From 52b8aa49fbfd776eca66b34cd860886a34d78851 Mon Sep 17 00:00:00 2001 From: Night Date: Sun, 25 Oct 2026 02:23:27 +1100 Subject: [PATCH 3/6] feat: generated README shows the make commands * build, test, format and release sections use the Makefile targets --- template/README.md.jinja | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/template/README.md.jinja b/template/README.md.jinja index bd29787..678c197 100644 --- a/template/README.md.jinja +++ b/template/README.md.jinja @@ -15,7 +15,7 @@ ### Build ```bash -$ ./run.sh --build +$ make build ``` ### Run @@ -31,14 +31,14 @@ $ uv run main ### Run all tests ```bash -$ ./run.sh --test +$ make test ``` ### Formatting ```bash -$ ./run.sh --format # format in place -$ ./run.sh --format-dry-run # list files that need formatting +$ make format # format in place +$ make format-dry-run # list files that need formatting ``` @@ -52,7 +52,7 @@ $ ./run.sh --format-dry-run # list files that need formatting ## Release -`./run.sh --release` builds a wheel and an sdist into `dist/`. They install on any platform with Python 3.13. +`make release` builds a wheel and an sdist into `dist/`. They install on any platform with Python 3.13. From 6f19a9e50b39d9d48483bdec4d810d72381b7946 Mon Sep 17 00:00:00 2001 From: Night Date: Sun, 25 Oct 2026 02:24:52 +1100 Subject: [PATCH 4/6] chore: shared CI v2.0.0 * the shipped workflow runs make format-dry-run, make build, make test and make release instead of run.sh --- template/.github/.copier-ci-answers.yml | 2 +- template/.github/workflows/ci.yml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/template/.github/.copier-ci-answers.yml b/template/.github/.copier-ci-answers.yml index 4a3d4df..66b57a2 100644 --- a/template/.github/.copier-ci-answers.yml +++ b/template/.github/.copier-ci-answers.yml @@ -1,4 +1,4 @@ # .github/.copier-ci-answers.yml.jinja # Changes here will be overwritten by Copier; NEVER EDIT MANUALLY -_commit: v1.1.1 +_commit: v2.0.0 _src_path: gh:karshosphere/template-github-ci diff --git a/template/.github/workflows/ci.yml b/template/.github/workflows/ci.yml index 35a6097..afe7880 100644 --- a/template/.github/workflows/ci.yml +++ b/template/.github/workflows/ci.yml @@ -54,10 +54,10 @@ jobs: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - name: run.sh is present and executable + - name: Makefile is present run: | - [ -x run.sh ] || { - echo "::error file=run.sh::run.sh is missing or not executable" + [ -f Makefile ] || { + echo "::error::Makefile is missing from the project root" exit 1 } - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0 @@ -67,13 +67,13 @@ jobs: - name: Start the dev container run: devcontainer up --workspace-folder . - name: Format - run: devcontainer exec --workspace-folder . ./run.sh --format-dry-run + run: devcontainer exec --workspace-folder . make format-dry-run - name: Build - run: devcontainer exec --workspace-folder . ./run.sh --build + run: devcontainer exec --workspace-folder . make build - name: Test - run: devcontainer exec --workspace-folder . ./run.sh --test + run: devcontainer exec --workspace-folder . make test - name: Release build - run: devcontainer exec --workspace-folder . ./run.sh --release + run: devcontainer exec --workspace-folder . make release - if: github.event_name == 'push' uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: From f846b18cd34401d26388a041880c0ef373fee431 Mon Sep 17 00:00:00 2001 From: Night Date: Sun, 25 Oct 2026 02:24:52 +1100 Subject: [PATCH 5/6] chore: version v2.0.0 * major release, as generated projects use a Makefile in place of run.sh --- VERSION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/VERSION b/VERSION index 79127d8..46b105a 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v1.2.0 +v2.0.0 From a36dcd5eeec8c4bac790d418bf67572576b0bb5c Mon Sep 17 00:00:00 2001 From: Night Date: Sun, 25 Oct 2026 02:24:52 +1100 Subject: [PATCH 6/6] docs: readme and changelog for feature/makefile * README describes the Makefile targets generated projects get * changelog entry for this branch --- CHANGELOG.md | 1 + README.md | 12 ++++++------ 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 071bbd5..162f367 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,3 +7,4 @@ * fix/project-builds: generated projects install, start and build, with a uv.lock, the right colorlog package, a working FastAPI lifespan and a pinned uv in the dev container. * feature/run-script: generated projects ship a run.sh for building, formatting with ruff, testing with pytest and building a wheel and sdist, with starter tests and ruff-clean code. * feature/github-ci: generated projects ship the shared GitHub CI, a VERSION file and the shared Renovate settings, which copier update leaves alone. +* feature/makefile: generated projects ship a Makefile with build, format, format-dry-run, test and release targets in place of run.sh, with make in the dev container and the shared CI calling make. diff --git a/README.md b/README.md index adeab6e..d8cc428 100644 --- a/README.md +++ b/README.md @@ -54,16 +54,16 @@ The workflow is read-only apart from the tag job, which needs write access to cr ### Project Tasks -Every generated project has a `run.sh` at its root: -* `./run.sh --build` installs the locked dependencies and byte-compiles the package. -* `./run.sh --format` formats the Python sources with ruff; `--format-dry-run` lists unformatted files and fails if there are any. -* `./run.sh --test` runs the tests with pytest. -* `./run.sh --release` builds a wheel and an sdist into `dist/`. +Every generated project has a `Makefile` at its root: +* `make build` installs the locked dependencies and byte-compiles the package. +* `make format` formats the Python sources with ruff; `make format-dry-run` lists unformatted files and fails if there are any. +* `make test` runs the tests with pytest. +* `make release` builds a wheel and an sdist into `dist/`. ### GitHub CI -Generated projects ship with the shared workflow from [template-github-ci](https://github.com/karshosphere/template-github-ci), vendored into `template/.github/`. It expects the project's `run.sh` and `.devcontainer/`, requires a `VERSION` bump on every pull request, and publishes a GitHub release on each merge to main. +Generated projects ship with the shared workflow from [template-github-ci](https://github.com/karshosphere/template-github-ci), vendored into `template/.github/`. It expects the project's `Makefile` and `.devcontainer/`, requires a `VERSION` bump on every pull request, and publishes a GitHub release on each merge to main. To bring in a newer release of the workflow, from this repository's root: