From 686feb0733b6877fb66a575b50232f50e4404cbe Mon Sep 17 00:00:00 2001 From: Kane Williams Date: Wed, 10 Jun 2026 11:22:38 +1200 Subject: [PATCH 1/3] ci: adopt release-please for automated releases --- .github/workflows/release-please.yml | 53 ++++++++++++++++++++++++ .github/workflows/release.yml | 62 ---------------------------- .release-please-manifest.json | 3 ++ release-please-config.json | 10 +++++ 4 files changed, 66 insertions(+), 62 deletions(-) create mode 100644 .github/workflows/release-please.yml delete mode 100644 .github/workflows/release.yml create mode 100644 .release-please-manifest.json create mode 100644 release-please-config.json diff --git a/.github/workflows/release-please.yml b/.github/workflows/release-please.yml new file mode 100644 index 0000000..9c561c8 --- /dev/null +++ b/.github/workflows/release-please.yml @@ -0,0 +1,53 @@ +name: Release Please + +on: + push: + branches: [main] + +permissions: + contents: write + pull-requests: write + +jobs: + release-please: + name: Release PR / tag + runs-on: ubuntu-latest + outputs: + release_created: ${{ steps.release.outputs.release_created }} + tag_name: ${{ steps.release.outputs.tag_name }} + steps: + - uses: googleapis/release-please-action@v4 + id: release + + publish: + name: Publish to PyPI + needs: release-please + if: ${{ needs.release-please.outputs.release_created == 'true' }} + runs-on: ubuntu-latest + environment: + name: pypi + url: https://pypi.org/p/datamasque-cli + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v4 + with: + ref: ${{ needs.release-please.outputs.tag_name }} + + - name: Set up uv + uses: astral-sh/setup-uv@v5 + with: + enable-cache: true + + - name: Set up Python + run: uv python install 3.12 + + - name: Build + run: uv build + + - name: Validate distributions + run: uvx twine check dist/* + + - name: Publish to PyPI + uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml deleted file mode 100644 index 947e861..0000000 --- a/.github/workflows/release.yml +++ /dev/null @@ -1,62 +0,0 @@ -name: Release - -on: - push: - tags: - - 'v*.*.*' - -jobs: - build: - name: Build sdist and wheel - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Set up uv - uses: astral-sh/setup-uv@v5 - with: - enable-cache: true - - - name: Set up Python - run: uv python install 3.12 - - - name: Verify tag matches package version - run: | - TAG_VERSION="${GITHUB_REF_NAME#v}" - PKG_VERSION="$(uv run python -c 'import tomllib,sys; print(tomllib.loads(open("pyproject.toml","rb").read().decode())["project"]["version"])')" - echo "Tag version: ${TAG_VERSION}" - echo "Package version: ${PKG_VERSION}" - if [ "${TAG_VERSION}" != "${PKG_VERSION}" ]; then - echo "::error::Tag ${GITHUB_REF_NAME} does not match pyproject.toml version ${PKG_VERSION}" - exit 1 - fi - - - name: Build - run: uv build - - - name: Upload distributions - uses: actions/upload-artifact@v4 - with: - name: dist - path: dist/ - retention-days: 7 - - publish: - name: Publish to PyPI - needs: build - runs-on: ubuntu-latest - environment: - name: pypi - url: https://pypi.org/p/datamasque-cli - permissions: - id-token: write - contents: read - steps: - - name: Download distributions - uses: actions/download-artifact@v4 - with: - name: dist - path: dist/ - - - name: Publish to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 diff --git a/.release-please-manifest.json b/.release-please-manifest.json new file mode 100644 index 0000000..96f1cd9 --- /dev/null +++ b/.release-please-manifest.json @@ -0,0 +1,3 @@ +{ + ".": "1.3.0" +} diff --git a/release-please-config.json b/release-please-config.json new file mode 100644 index 0000000..125236d --- /dev/null +++ b/release-please-config.json @@ -0,0 +1,10 @@ +{ + "$schema": "https://raw.githubusercontent.com/googleapis/release-please/main/schemas/config.json", + "include-component-in-tag": false, + "packages": { + ".": { + "release-type": "python", + "package-name": "datamasque-cli" + } + } +} From 7e7595a71ea19f6310552a3b51e98fa67ea2b383 Mon Sep 17 00:00:00 2001 From: Kane Williams Date: Wed, 10 Jun 2026 11:57:42 +1200 Subject: [PATCH 2/3] chore: remove superseded make-release targets and bump_version.py --- Makefile | 33 +-------------------------------- scripts/bump_version.py | 40 ---------------------------------------- 2 files changed, 1 insertion(+), 72 deletions(-) delete mode 100644 scripts/bump_version.py diff --git a/Makefile b/Makefile index 8664726..1a280cf 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: install lint format mypy test test-integration test-integration-local check build release-patch release-minor release-major +.PHONY: install lint format mypy test test-integration test-integration-local check build install: uv sync @@ -32,34 +32,3 @@ format-check: build: uv build - -# Bump version, commit, tag, push — CI publishes automatically. -# Usage: make release-patch (0.1.0 → 0.1.1) -# make release-minor (0.1.0 → 0.2.0) -# make release-major (0.1.0 → 1.0.0) -release-patch: check - $(eval VERSION := $(shell python3 scripts/bump_version.py patch)) - uv lock - git add pyproject.toml uv.lock - git commit -m "Release v$(VERSION)" - git tag "v$(VERSION)" - git push && git push --tags - @echo "Released v$(VERSION) — CI will publish to PyPI (https://pypi.org/p/datamasque-cli)" - -release-minor: check - $(eval VERSION := $(shell python3 scripts/bump_version.py minor)) - uv lock - git add pyproject.toml uv.lock - git commit -m "Release v$(VERSION)" - git tag "v$(VERSION)" - git push && git push --tags - @echo "Released v$(VERSION) — CI will publish to PyPI (https://pypi.org/p/datamasque-cli)" - -release-major: check - $(eval VERSION := $(shell python3 scripts/bump_version.py major)) - uv lock - git add pyproject.toml uv.lock - git commit -m "Release v$(VERSION)" - git tag "v$(VERSION)" - git push && git push --tags - @echo "Released v$(VERSION) — CI will publish to PyPI (https://pypi.org/p/datamasque-cli)" diff --git a/scripts/bump_version.py b/scripts/bump_version.py deleted file mode 100644 index b76fce4..0000000 --- a/scripts/bump_version.py +++ /dev/null @@ -1,40 +0,0 @@ -#!/usr/bin/env python3 -"""Bump the version in pyproject.toml and print the new version.""" - -from __future__ import annotations - -import re -import sys - -LEVEL = sys.argv[1] if len(sys.argv) > 1 else "patch" - -with open("pyproject.toml") as f: - content = f.read() - -match = re.search(r'version = "(\d+)\.(\d+)\.(\d+)"', content) -if not match: - print("Could not find version in pyproject.toml", file=sys.stderr) - sys.exit(1) - -major, minor, patch = int(match.group(1)), int(match.group(2)), int(match.group(3)) - -if LEVEL == "patch": - patch += 1 -elif LEVEL == "minor": - minor += 1 - patch = 0 -elif LEVEL == "major": - major += 1 - minor = 0 - patch = 0 -else: - print(f"Unknown level: {LEVEL}. Use patch, minor, or major.", file=sys.stderr) - sys.exit(1) - -new_version = f"{major}.{minor}.{patch}" -new_content = content.replace(match.group(0), f'version = "{new_version}"') - -with open("pyproject.toml", "w") as f: - f.write(new_content) - -print(new_version) From ffe33d2e0068094841810c193f15136b6e30f29c Mon Sep 17 00:00:00 2001 From: Kane Williams Date: Wed, 10 Jun 2026 11:57:42 +1200 Subject: [PATCH 3/3] docs(contributing): document the release-please flow --- CONTRIBUTING.md | 40 ++++++++++++++++++++++++---------------- 1 file changed, 24 insertions(+), 16 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83b3fa1..8e2aba7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -209,29 +209,37 @@ A few project-specific conventions on top of the generic style above: ## Commit messages -Use [Conventional Commits](https://www.conventionalcommits.org/) format where practical: +Use [Conventional Commits](https://www.conventionalcommits.org/) format: `feat: add dm run retry command`, `fix: handle 401 retry for multipart uploads`, `docs: clarify connections update semantics`, and so on. -## Releasing - -Releases are published automatically by CI when a version tag is pushed. - -```console -make release-patch # 0.1.0 → 0.1.1 — bug fixes -make release-minor # 0.1.0 → 0.2.0 — new features -make release-major # 0.1.0 → 1.0.0 — breaking changes -``` +The commit type drives the next release: +`fix:` bumps the patch version, +`feat:` the minor version, +and a `!` or `BREAKING CHANGE:` footer the major version. +The changelog is generated from these subjects, +so write them for whoever reads the release notes. +See [Releasing](#releasing). -Each target runs `make check`, -bumps the version in `pyproject.toml`, -refreshes `uv.lock`, -commits, tags, and pushes. -CI handles the publish to PyPI. +## Releasing -To smoke-test a release against TestPyPI without tagging, +Releases are automated with +[release-please](https://github.com/googleapis/release-please). +You do not bump the version or edit the changelog by hand. + +As Conventional Commits land on `main`, +release-please maintains an open release PR +that bumps the version in `pyproject.toml` +and updates `CHANGELOG.md` from the commit messages. +To cut a release, +review and merge that PR: +the merge tags the commit, +publishes the GitHub release, +and uploads to PyPI. + +To smoke-test a build against TestPyPI without releasing, trigger the `Release (TestPyPI)` workflow manually from the GitHub Actions tab. ## Toolchain