Skip to content

Commit f6b9edf

Browse files
committed
ci: automate releases on merge to main
Add GitHub Actions to replace the manual 'just publish' flow: - ci.yml: run unit tests on every PR and push to main (py3.9 + 3.12). - release.yml: on merge to main, run python-semantic-release to compute the next version from Conventional Commit messages, bump pyproject.toml, tag, create a GitHub Release, and publish to PyPI via Trusted Publishing (OIDC). Also declare an explicit [build-system] (setuptools) which was missing. Versioning is anchored by a baseline v1.0.1 tag matching the current PyPI release; the 8 unreleased PRs on main will publish as 1.1.0 on first run.
1 parent 472e0f6 commit f6b9edf

3 files changed

Lines changed: 133 additions & 0 deletions

File tree

‎.github/workflows/ci.yml‎

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
push:
6+
branches: [main]
7+
8+
# Cancel superseded runs on the same ref to save CI minutes.
9+
concurrency:
10+
group: ci-${{ github.ref }}
11+
cancel-in-progress: true
12+
13+
jobs:
14+
test:
15+
name: Unit tests (py${{ matrix.python-version }})
16+
runs-on: ubuntu-latest
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
# Floor and a current version; bump as supported range changes.
21+
python-version: ["3.9", "3.12"]
22+
steps:
23+
- uses: actions/checkout@v4
24+
25+
- name: Install uv
26+
uses: astral-sh/setup-uv@v5
27+
with:
28+
python-version: ${{ matrix.python-version }}
29+
30+
- name: Install package + dev deps
31+
run: |
32+
uv venv
33+
uv pip install -e ".[dev]"
34+
35+
- name: Run unit tests
36+
# test_acceptance.py and test_query.py require a live Lightdash
37+
# instance + credentials, so they are excluded from CI.
38+
run: |
39+
uv run pytest tests/ \
40+
--ignore=tests/test_acceptance.py \
41+
--ignore=tests/test_query.py \
42+
-q

‎.github/workflows/release.yml‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
name: Release
2+
3+
# Publish on merge to main. python-semantic-release inspects the Conventional
4+
# Commit messages since the last "v*" tag, decides the next version (or that no
5+
# release is warranted), bumps pyproject.toml, tags, creates a GitHub Release,
6+
# and we then upload the built artifacts to PyPI.
7+
#
8+
# The version-bump commit it pushes back to main contains "[skip ci]" so this
9+
# workflow does not retrigger itself.
10+
on:
11+
push:
12+
branches: [main]
13+
14+
# Never run two releases concurrently.
15+
concurrency:
16+
group: release
17+
cancel-in-progress: false
18+
19+
jobs:
20+
test:
21+
name: Unit tests
22+
runs-on: ubuntu-latest
23+
steps:
24+
- uses: actions/checkout@v4
25+
- name: Install uv
26+
uses: astral-sh/setup-uv@v5
27+
with:
28+
python-version: "3.12"
29+
- name: Install package + dev deps
30+
run: |
31+
uv venv
32+
uv pip install -e ".[dev]"
33+
- name: Run unit tests
34+
run: |
35+
uv run pytest tests/ \
36+
--ignore=tests/test_acceptance.py \
37+
--ignore=tests/test_query.py \
38+
-q
39+
40+
release:
41+
name: Semantic Release
42+
runs-on: ubuntu-latest
43+
needs: test
44+
# Guard against forks: only the canonical repo should publish.
45+
if: github.repository == 'lightdash/python-sdk'
46+
permissions:
47+
contents: write # push the version bump/tag and create the GitHub Release
48+
id-token: write # PyPI Trusted Publishing (OIDC)
49+
steps:
50+
- name: Checkout
51+
uses: actions/checkout@v4
52+
with:
53+
fetch-depth: 0 # semantic-release needs full history + tags
54+
55+
- name: Python Semantic Release
56+
id: release
57+
uses: python-semantic-release/python-semantic-release@v9
58+
with:
59+
github_token: ${{ secrets.GITHUB_TOKEN }}
60+
61+
- name: Publish to PyPI
62+
if: steps.release.outputs.released == 'true'
63+
uses: pypa/gh-action-pypi-publish@release/v1
64+
65+
- name: Upload artifacts to the GitHub Release
66+
if: steps.release.outputs.released == 'true'
67+
uses: python-semantic-release/publish-action@v9
68+
with:
69+
github_token: ${{ secrets.GITHUB_TOKEN }}
70+
tag: ${{ steps.release.outputs.tag }}

‎pyproject.toml‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,24 @@ include = ["lightdash*"]
2828
testpaths = ["tests"]
2929
python_files = ["test_*.py"]
3030
log_cli_level = "DEBUG"
31+
32+
[build-system]
33+
requires = ["setuptools>=61.0"]
34+
build-backend = "setuptools.build_meta"
35+
36+
# Releases are automated by GitHub Actions (.github/workflows/release.yml).
37+
# python-semantic-release computes the next version from Conventional Commit
38+
# messages (feat: -> minor, fix: -> patch, BREAKING CHANGE -> major) since the
39+
# last "v*" tag, bumps the version below, tags, creates a GitHub Release, and
40+
# publishes to PyPI. Do not bump `version` by hand.
41+
[tool.semantic_release]
42+
version_toml = ["pyproject.toml:project.version"]
43+
build_command = "pip install build && python -m build"
44+
commit_message = "chore(release): v{version} [skip ci]"
45+
tag_format = "v{version}"
46+
47+
[tool.semantic_release.branches.main]
48+
match = "main"
49+
50+
[tool.semantic_release.changelog]
51+
exclude_commit_patterns = ['''chore\(release\):.*''']

0 commit comments

Comments
 (0)