Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 55 additions & 12 deletions .github/workflows/publish-pypi.yml
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
name: Publish to PyPi

# This will build a package with a version set by versioneer from the most recent tag matching v____
# It will publish to TestPyPi, and to real Pypi *if* run on master where head has a release tag
# For a live run, this should only need to be triggered by a newly published repo release.
# This can also be run manually for testing
# Builds the package, checks wheel structure, publishes to TestPyPI, runs smoke
# tests against TestPyPI, then publishes to real PyPI only if all prior steps pass.
on:
release:
types: [published]
Expand All @@ -13,31 +11,76 @@ on:
- 'v*.*.*'

jobs:
build-n-publish:
name: Build dist files for PyPi
build:
name: Build and check wheel
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-python@v5
with:
python-version: 3.13
python-version: '3.13'
- name: Build dist files
run: |
python -m pip install --upgrade pip
python -m pip install -e .[test] build
python -m build
git describe --tag --dirty --always

- name: Publish distribution 📦 to Test PyPI # always run
- name: Check wheel structure
run: python -m pytest test/test_packaging.py -m packaging -v
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/

publish-test-pypi:
name: Publish to Test PyPI
needs: build
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Publish to Test PyPI
uses: pypa/gh-action-pypi-publish@release/v1 # license BSD-2
with:
password: ${{ secrets.TEST_PYPI_API_TOKEN }}
repository_url: https://test.pypi.org/legacy/

- name: Publish distribution 📦 to PyPI
if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }}
skip_existing: true

smoke-test-pypi:
name: Smoke test from Test PyPI
needs: publish-test-pypi
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ['3.x']
runs-on: ${{ matrix.os }}
steps:
- uses: actions/setup-python@v5
with:
python-version: ${{ matrix.python-version }}
- name: Install from Test PyPI
run: |
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple/ tableauserverclient
- name: Smoke test
run: |
python -c "import tableauserverclient as TSC; server = TSC.Server('http://example.com', use_server_version=False)"

publish-pypi:
name: Publish to PyPI
needs: smoke-test-pypi
if: ${{ github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/v') }}
runs-on: ubuntu-latest
steps:
- uses: actions/download-artifact@v4
with:
name: dist
path: dist/
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1 # license BSD-2
with:
password: ${{ secrets.PYPI_API_TOKEN }}
2 changes: 2 additions & 0 deletions .github/workflows/pypi-smoke-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ name: Pypi smoke tests

on:
workflow_dispatch:
release:
types: [published]
schedule:
- cron: 0 11 * * * # Every day at 11AM UTC (7AM EST)

Expand Down
7 changes: 5 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ tableauserverclient = ["*"]

[tool.setuptools.packages.find]
where = ["."]
include = ["tableauserverclient*"]
exclude = ["test*", "samples*", "test_e2e*", "docs*", "dist*", "build*"]

[tool.setuptools.dynamic]
version = {attr = "versioneer.get_version"}
Expand All @@ -68,7 +68,10 @@ exclude = ['/bin/']
[tool.pytest.ini_options]
testpaths = ["test"]
addopts = "--junitxml=./test.junit.xml -n auto"
markers = ["e2e: mark test as end-to-end (requires a real Tableau server)"]
markers = [
"e2e: mark test as end-to-end (requires a real Tableau server)",
"packaging: mark test as requiring a built wheel in dist/",
]

[tool.versioneer]
VCS = "git"
Expand Down
19 changes: 19 additions & 0 deletions test/test_packaging.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import zipfile
from pathlib import Path
import pytest

pytestmark = pytest.mark.packaging


def _find_wheel():
wheels = list(Path("dist").glob("tableauserverclient-*.whl"))
if not wheels:
pytest.skip("No wheel in dist/ -- run 'python -m build --wheel' first")
return max(wheels, key=lambda p: p.stat().st_mtime)


def test_wheel_only_tableauserverclient_at_root():
with zipfile.ZipFile(_find_wheel()) as whl:
top_dirs = {n.split("/")[0] for n in whl.namelist() if "/" in n}
non_dist_info = {d for d in top_dirs if not d.endswith(".dist-info") and not d.endswith(".data")}
assert non_dist_info == {"tableauserverclient"}, f"Unexpected top-level entries: {non_dist_info}"
Loading