diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..6a22387 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,41 @@ +name: CI + +on: + pull_request: + push: + branches: [main] + +# Cancel superseded runs on the same ref to save CI minutes. +concurrency: + group: ci-${{ github.ref }} + cancel-in-progress: true + +jobs: + test: + name: Unit tests (py${{ matrix.python-version }}) + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + # Floor and a current version; bump as supported range changes. + python-version: ["3.9", "3.12"] + steps: + - uses: actions/checkout@v4 + + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: ${{ matrix.python-version }} + + - name: Install package + dev deps + # setup-uv already created .venv and set VIRTUAL_ENV. + run: uv pip install -e ".[dev]" + + - name: Run unit tests + # test_acceptance.py and test_query.py require a live Lightdash + # instance + credentials, so they are excluded from CI. + run: | + uv run pytest tests/ \ + --ignore=tests/test_acceptance.py \ + --ignore=tests/test_query.py \ + -q diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..7c83171 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,69 @@ +name: Release + +# Publish on merge to main. python-semantic-release inspects the Conventional +# Commit messages since the last "v*" tag, decides the next version (or that no +# release is warranted), bumps pyproject.toml, tags, creates a GitHub Release, +# and we then upload the built artifacts to PyPI. +# +# The version-bump commit it pushes back to main contains "[skip ci]" so this +# workflow does not retrigger itself. +on: + push: + branches: [main] + +# Never run two releases concurrently. +concurrency: + group: release + cancel-in-progress: false + +jobs: + test: + name: Unit tests + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Install uv + uses: astral-sh/setup-uv@v5 + with: + python-version: "3.12" + - name: Install package + dev deps + # setup-uv already created .venv and set VIRTUAL_ENV. + run: uv pip install -e ".[dev]" + - name: Run unit tests + run: | + uv run pytest tests/ \ + --ignore=tests/test_acceptance.py \ + --ignore=tests/test_query.py \ + -q + + release: + name: Semantic Release + runs-on: ubuntu-latest + needs: test + # Guard against forks: only the canonical repo should publish. + if: github.repository == 'lightdash/python-sdk' + permissions: + contents: write # push the version bump/tag and create the GitHub Release + id-token: write # PyPI Trusted Publishing (OIDC) + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # semantic-release needs full history + tags + + - name: Python Semantic Release + id: release + uses: python-semantic-release/python-semantic-release@v9 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Publish to PyPI + if: steps.release.outputs.released == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + + - name: Upload artifacts to the GitHub Release + if: steps.release.outputs.released == 'true' + uses: python-semantic-release/publish-action@v9 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + tag: ${{ steps.release.outputs.tag }} diff --git a/pyproject.toml b/pyproject.toml index abeac22..8128a5b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,3 +28,24 @@ include = ["lightdash*"] testpaths = ["tests"] python_files = ["test_*.py"] log_cli_level = "DEBUG" + +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +# Releases are automated by GitHub Actions (.github/workflows/release.yml). +# python-semantic-release computes the next version from Conventional Commit +# messages (feat: -> minor, fix: -> patch, BREAKING CHANGE -> major) since the +# last "v*" tag, bumps the version below, tags, creates a GitHub Release, and +# publishes to PyPI. Do not bump `version` by hand. +[tool.semantic_release] +version_toml = ["pyproject.toml:project.version"] +build_command = "pip install build && python -m build" +commit_message = "chore(release): v{version} [skip ci]" +tag_format = "v{version}" + +[tool.semantic_release.branches.main] +match = "main" + +[tool.semantic_release.changelog] +exclude_commit_patterns = ['''chore\(release\):.*''']