From b65260afa224261c0e4b9ca6b75624321931db44 Mon Sep 17 00:00:00 2001 From: Jens Troeger Date: Mon, 2 Jun 2025 19:07:49 +1000 Subject: [PATCH 1/6] feat: add a Makefile goal `simple-index` that generates a PEP-503 compatible Simple Index directory inside the dist --- Makefile | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Makefile b/Makefile index edfbc68b..2088db99 100644 --- a/Makefile +++ b/Makefile @@ -197,6 +197,18 @@ dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-docs-md.zip: docs-md dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-build-epoch.txt: echo $(SOURCE_DATE_EPOCH) > dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-build-epoch.txt +# Build a PEP-503 compatible Simple Repository compatible directory inside of dist/. +# For details on the layout of that directory, see: https://peps.python.org/pep-0503/ +# This directory can then be used to install (hashed) artifacts from using `pip` and +# its `--extra-index-url` argument: https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-extra-index-url +.PHONY: simple-index +simple-index: dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz + mkdir -p dist/simple-index/$(PACKAGE_NAME) + echo -e "\n$(PACKAGE_NAME)" > dist/simple-index/index.html + echo -e "\n$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz" > dist/simple-index/$(PACKAGE_NAME)/index.html + cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/simple-index/$(PACKAGE_NAME)/ + cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz dist/simple-index/$(PACKAGE_NAME)/ + # Build the HTML and Markdown documentation from the package's source. DOCS_SOURCE := $(shell git ls-files docs/source) .PHONY: docs docs-html docs-md From 8fe1d889eea873ae1dd6e86446a0f1b9b63d86c7 Mon Sep 17 00:00:00 2001 From: Jens Troeger Date: Mon, 2 Jun 2025 19:29:42 +1000 Subject: [PATCH 2/6] chore: gah, fixt typos --- Makefile | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index 2088db99..557a4d7b 100644 --- a/Makefile +++ b/Makefile @@ -197,9 +197,9 @@ dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-docs-md.zip: docs-md dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-build-epoch.txt: echo $(SOURCE_DATE_EPOCH) > dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-build-epoch.txt -# Build a PEP-503 compatible Simple Repository compatible directory inside of dist/. -# For details on the layout of that directory, see: https://peps.python.org/pep-0503/ -# This directory can then be used to install (hashed) artifacts from using `pip` and +# Build a PEP-503 compatible Simple Repository directory inside of dist/. For details on +# the layout of that directory, see: https://peps.python.org/pep-0503/ +# The directory can then be used to install (hashed) artifacts by using `pip` and # its `--extra-index-url` argument: https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-extra-index-url .PHONY: simple-index simple-index: dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz From a6b4a2a102b4622e608a17603463a206f85890f4 Mon Sep 17 00:00:00 2001 From: Jens Troeger Date: Wed, 4 Jun 2025 10:56:08 +1000 Subject: [PATCH 3/6] fix: normalize the Simple Repo project name from the package name as per PEP 503 --- Makefile | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index 557a4d7b..4dda6018 100644 --- a/Makefile +++ b/Makefile @@ -198,16 +198,17 @@ dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-build-epoch.txt: echo $(SOURCE_DATE_EPOCH) > dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-build-epoch.txt # Build a PEP-503 compatible Simple Repository directory inside of dist/. For details on -# the layout of that directory, see: https://peps.python.org/pep-0503/ +# the layout of that directory and the normalized project name, see: https://peps.python.org/pep-0503/ # The directory can then be used to install (hashed) artifacts by using `pip` and # its `--extra-index-url` argument: https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-extra-index-url +PROJECT_NAME := $(shell python -c $$'import re; print(re.sub(r"[-_.]+", "-", "$(PACKAGE_NAME)").lower());') .PHONY: simple-index simple-index: dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz - mkdir -p dist/simple-index/$(PACKAGE_NAME) + mkdir -p dist/simple-index/$(PROJECT_NAME) echo -e "\n$(PACKAGE_NAME)" > dist/simple-index/index.html - echo -e "\n$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz" > dist/simple-index/$(PACKAGE_NAME)/index.html - cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/simple-index/$(PACKAGE_NAME)/ - cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz dist/simple-index/$(PACKAGE_NAME)/ + echo -e "\n$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz" > dist/simple-index/$(PROJECT_NAME)/index.html + cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/simple-index/$(PROJECT_NAME)/ + cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz dist/simple-index/$(PROJECT_NAME)/ # Build the HTML and Markdown documentation from the package's source. DOCS_SOURCE := $(shell git ls-files docs/source) From 85132bbe1f5f9a4f6161cad6bb73af2748ef4296 Mon Sep 17 00:00:00 2001 From: Jens Troeger Date: Thu, 5 Jun 2025 10:00:19 -1000 Subject: [PATCH 4/6] chore: add hash fragments to package URLs --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 4dda6018..4c83722a 100644 --- a/Makefile +++ b/Makefile @@ -206,7 +206,7 @@ PROJECT_NAME := $(shell python -c $$'import re; print(re.sub(r"[-_.]+", "-", "$( simple-index: dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz mkdir -p dist/simple-index/$(PROJECT_NAME) echo -e "\n$(PACKAGE_NAME)" > dist/simple-index/index.html - echo -e "\n$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz" > dist/simple-index/$(PROJECT_NAME)/index.html + echo -e "\n$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz" > dist/simple-index/$(PROJECT_NAME)/index.html cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/simple-index/$(PROJECT_NAME)/ cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz dist/simple-index/$(PROJECT_NAME)/ From 9ac4aaff3687b16cc380455527ff000063805fd2 Mon Sep 17 00:00:00 2001 From: Jens Troeger Date: Thu, 5 Jun 2025 10:10:49 -1000 Subject: [PATCH 5/6] chore: validate generated index.html files --- Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 4c83722a..dbbf83bd 100644 --- a/Makefile +++ b/Makefile @@ -205,8 +205,8 @@ PROJECT_NAME := $(shell python -c $$'import re; print(re.sub(r"[-_.]+", "-", "$( .PHONY: simple-index simple-index: dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz mkdir -p dist/simple-index/$(PROJECT_NAME) - echo -e "\n$(PACKAGE_NAME)" > dist/simple-index/index.html - echo -e "\n$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz" > dist/simple-index/$(PROJECT_NAME)/index.html + echo -e "\nSimple Index$(PACKAGE_NAME)" > dist/simple-index/index.html + echo -e "\nSimple Index: $(PROJECT_NAME)$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz" > dist/simple-index/$(PROJECT_NAME)/index.html cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION)-py3-none-any.whl dist/simple-index/$(PROJECT_NAME)/ cp -f dist/$(PACKAGE_NAME)-$(PACKAGE_VERSION).tar.gz dist/simple-index/$(PROJECT_NAME)/ From a8d52b795267ea29f40943ff4698454b0cef1036 Mon Sep 17 00:00:00 2001 From: Jens Troeger Date: Wed, 8 Apr 2026 18:40:41 +1000 Subject: [PATCH 6/6] docs: mention in README --- README.md | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8add8a90..7d77de8c 100644 --- a/README.md +++ b/README.md @@ -21,8 +21,9 @@ This repository is intended to be a base template, a cookiecutter for a new Pyth [Testing](#testing) [Generating documentation](#generating-documentation) [Synchronizing with this template repo](#synchronizing-with-this-template-repo) -[Versioning, publishing and changelog](#versioning-publishing-and-changelog) +[Versioning, publishing and distributions](#versioning-publishing-and-distributions)  [Building from a source distribution package](#building-from-a-source-distribution-package) + [Using the Simple Index](#using-the-simple-index) [Build integrity using SLSA framework](#build-integrity-using-slsa-framework) [Cleaning up](#cleaning-up) [Frequently asked questions](#frequently-asked-questions) @@ -255,7 +256,7 @@ In addition to the default HTML, Sphinx also generates Markdown documentation co The [sync-with-upstream.yaml](https://github.com/jenstroeger/python-package-template/blob/main/.github/workflows/sync-with-upstream.yaml) GitHub Acions workflow checks this template repo daily and automatically creates a pull request in the downstream repo if there is a new release. Make sure to set up the GitHub username and email address in this workflow accordingly. -## Versioning, publishing and changelog +## Versioning, publishing and distributions To enable automation for [semantic versioning](https://semver.org/), package publishing, and changelog generation it is important to use meaningful [conventional commit messages](https://www.conventionalcommits.org/)! This package template already has a built-in semantic release support enabled which is set up to take care of all three of these aspects — every time changes are pushed to the `release` branch. @@ -299,6 +300,16 @@ SKIP=check-hooks-apply,check-useless-excludes,actionlint make dist Note that we skip Git hooks that are unnecessary when building from the source distribution. As above, this builds the source package and a binary distribution, and stores both in the `dist/` folder. And, as expected, setting the `SOURCE_DATE_EPOCH` environment variable to the build epoch value of the original sdist and wheel build results in the bit-exact same binary distribution package! +## Using the Simple Index + +Once source and/or binary distribution packages have been built, they can be served using a [PEP 503](https://peps.python.org/pep-0503/) compatible package repository. Simply call + +```bash +make simple-index +``` + +to create the package repository in the `dist/` folder, and then use it e.g. with [pip](https://pip.pypa.io/en/stable/cli/pip_install/#cmdoption-extra-index-url) and its `--extra-index-url` parameter. + ## Build integrity using SLSA framework The build process in this repository follows the requirements in the [SLSA framework](https://slsa.dev/) to be compliant at level 3. An important aspect of SLSA to improve the supply chain security posture is to generate a verifiable provenance for the build pipeline. Such a provenance can be used to verify the builder and let the consumers check the materials and configurations used while building an artifact. In this repository we use the [generic provenance generator reusable workflow](https://github.com/slsa-framework/slsa-github-generator) to generate a provenance that can attest to the following artifacts in every release: