Skip to content

ci(python): build pygosqlx platform wheels and publish to PyPI - #851

Merged
ajitpratap0 merged 6 commits into
mainfrom
ci/pygosqlx-wheels-pypi
Oct 22, 2026
Merged

ajitpratap0 merged 6 commits into
mainfrom
ci/pygosqlx-wheels-pypi

Conversation

@ajitpratap0

@ajitpratap0 ajitpratap0 commented Oct 22, 2026 •

Copy link
Copy Markdown
Owner

Summary

Makes pygosqlx installable with pip install pygosqlx through prebuilt platform wheels that bundle libgosqlx, and adds a PyPI release pipeline. Builds on the 0.3.0 API (#850). The version stays at 0.3.0.

Packaging (python/)

  • pyproject.toml is now the only source of metadata: requires-python >=3.10, classifiers for 3.10–3.14 (3.8/3.9 dropped), SPDX license = "Apache-2.0" plus license-files (setuptools>=77). Development Status stays Alpha.
  • setup.py is now only a shim with no metadata. It declares the distribution non-pure (has_ext_modules) and tags the wheel py3-none-<platform>. Without it, a wheel that bundles a native .so/.dylib/.dll would be tagged py3-none-any. py3-none is correct because the library is loaded through ctypes and does not depend on the CPython ABI, so one wheel per OS/arch covers every Python version.
  • package-data bundles pygosqlx/lib/libgosqlx.*. python/LICENSE is a copy of the root license, because license-files cannot point outside the project dir.

New workflow .github/workflows/pygosqlx-release.yml

  • wheels uses cibuildwheel v4.3.0, pinned by SHA, with native runners only:
    • manylinux on x86_64 and aarch64 (ubuntu-24.04, ubuntu-24.04-arm). They are built in the manylinux_2_28 image and repaired with auditwheel repair --plat manylinux_2_17_{arch}, so both arches are tagged manylinux_2_17 (manylinux2014). Without the pin auditwheel tagged x86_64 manylinux_2_5, claiming untested glibc 2.5–2.16 distros. Go 1.26.10 is installed inside the container by python/scripts/install-go-linux.sh, from the official tarball checked against a pinned SHA-256.
    • macOS x86_64 and arm64 (macos-15-intel, macos-15) with deployment target 13.0. The cgo CFLAGS/LDFLAGS are pinned to the same minimum.
    • Windows AMD64 (windows-2025, runner MinGW gcc).
    • CIBW_BEFORE_BUILD builds libgosqlx with GOFLAGS=-trimpath (no absolute build paths in the binaries) into python/pygosqlx/lib. Each platform's single wheel is tested with pytest on CPython 3.10–3.14.
  • sdist fails if GO_VERSION in the workflow and install-go-linux.sh differ, checks that a pygosqlx-v* tag matches the pyproject.toml version, runs twine check --strict, and fails if the sdist contains a native binary.
  • Triggers:
    • pull_request on python/**, pkg/** (cbinding links the whole parser via pkg/gosqlx), go.mod, go.sum and the workflow only builds and tests.
    • Pushing a pygosqlx-v* tag builds, tests and publishes to PyPI. This is the only path to PyPI. The sdist job refuses a tag whose commit is not an ancestor of origin/main. The main v* tags never trigger the workflow.
    • workflow_dispatch builds and tests, then publishes to the target input: testpypi (default) or none. A dispatch can publish only from main. The TestPyPI upload uses skip-existing: true so repeated dry runs of the same version do not fail.
  • publish-pypi and publish-testpypi use environment: pypi / testpypi, permissions: id-token: write only, and pypa/gh-action-pypi-publish v1.14.2 pinned by SHA (Trusted Publishing, no token). The rest of the workflow has contents: read, and checkouts use persist-credentials: false.
  • The workflow header documents the one-time maintainer steps. None of them have been done: create the PyPI pending trusted publisher (owner ajitpratap0, repo GoSQLX, workflow pygosqlx-release.yml, environment pypi), create the pypi GitHub environment, and optionally the TestPyPI equivalents.

Keeping pygosqlx-v* tags out of the Go release (.github/workflows/release.yml)

  • GoReleaser OSS finds the previous tag with git describe --tags, so after the first pygosqlx-v* tag the next v1.x release would compute its changelog and compare link from the pygosqlx tag. A new step sets GORELEASER_CURRENT_TAG to the pushed tag and GORELEASER_PREVIOUS_TAG to git describe --tags --abbrev=0 --match 'v[0-9]*' "$TAG^". git.ignore_tags in .goreleaser.yml was not used because it is GoReleaser Pro-only.

Testing against the installed wheel

  • New tests/conftest.py. Setting PYGOSQLX_TEST_INSTALLED=1 keeps the checkout off sys.path; cibuildwheel also runs pytest with --import-mode=importlib. The per-file sys.path.insert hacks are removed. The _lib_available() skip checks now use the package's own core._get_lib_path(), so they also see a library bundled in an installed wheel.
  • New tests/test_installed_wheel.py, which runs only in installed mode. It fails (does not skip) if the checkout was imported, if GOSQLX_LIB_PATH is set, or if the wheel lacks a loadable bundled library. Without it, a wheel missing its library would pass CI with every library test skipped.
  • test_package_version.py no longer checks a setup.py version. It now asserts that setup.py carries no metadata.

Docs

  • python/README.md: pip install pygosqlx is the primary install, noting it works once the first pygosqlx-v* tag is published. Build from source comes second. Adds a supported-platforms table and release notes for maintainers.

Design decisions (conservative choices, recorded per brief)

  • Building from the sdist on a platform without a wheel prints a build-time WARNING when pygosqlx/lib/libgosqlx.* is missing, rather than failing the install (failing would also break pure-Python dev installs); the runtime FileNotFoundError now links the README build-from-source section.
  • Wheels are py3-none-<platform> rather than one cp3XX wheel per Python version. cibuildwheel builds once and reuses the wheel for the test runs on the other Pythons.
  • Real PyPI publishes only from a push of a pygosqlx-v* tag on a commit already on main (publish-pypi checks github.event_name == 'push', so a workflow_dispatch run on a tag ref cannot reach PyPI whatever target is). workflow_dispatch can only publish to TestPyPI (the default) or build only. This keeps the recommended pypi environment policy (tags pygosqlx-v* only) consistent, and every published version has a git tag.
  • Wheels are built for CPython 3.10–3.14 only: no musllinux, no free-threaded builds, no 3.15. The sdist installs the Python package without the native library (documented: build it and set GOSQLX_LIB_PATH).
  • The Linux aarch64 and macOS x86_64 wheels are built on native runners rather than under QEMU or by cross-compiling.
  • go.mod/go.sum were added to the PR path filter because they change what gets compiled into the library.
  • Actions are pinned to releases at least 2 weeks old: cibuildwheel v4.3.0 (not v4.3.3) and gh-action-pypi-publish v1.14.2 (not v1.14.3). upload/download-artifact reuse the SHAs already pinned in this repo.

Test Plan

  • bash pkg/cbinding/build.sh + python -m build (macOS arm64) gives pygosqlx-0.3.0-py3-none-macosx_<ver>_arm64.whl, with pygosqlx/lib/libgosqlx.dylib at the wheel root (platlib, Root-Is-Purelib: false). It is not py3-none-any.
  • Installed that wheel into a fresh venv. From a temp dir, PYGOSQLX_TEST_INSTALLED=1 python -m pytest --import-mode=importlib python/tests gave 187 passed, 0 skipped.
  • Review follow-up: the sdist now includes tests/conftest.py (recursive-include tests *.py). Added the Operating System :: Microsoft :: Windows classifier. Ran the Go-version check locally. git describe --match 'v[0-9]*' on this branch resolves to v1.15.0. actionlint is clean apart from its pre-existing unknown-label warning for macos-15-intel, a valid GitHub-hosted label that is newer than actionlint v1.7.7.
  • Source-tree mode is unchanged: pytest python/tests gave 184 passed, 3 skipped (the installed-only tests). Editable install pip install -e "python[dev]" works on Python 3.10.
  • twine check --strict passes on the sdist and wheel. actionlint is clean.
  • CI: pygosqlx Release built py3-none-manylinux…_x86_64, py3-none-manylinux…_aarch64, py3-none-macosx_13_0_{x86_64,arm64} and py3-none-win_amd64 wheels. Each was tested on CPython 3.10–3.14 against the installed wheel; cibuildwheel built once and reused the wheel for the other versions. The sdist job passes.
  • CI on head c76437c (run 39753781469): 47c4dc1 broke both Linux wheel jobs because cibuildwheel does not expand {arch} in the repair command. The arch now comes from the matrix (--plat manylinux_2_17_${{ matrix.arch }}). auditwheel produced pygosqlx-0.3.0-py3-none-manylinux2014_aarch64.manylinux_2_17_aarch64.whl and the x86_64 equivalent. All five wheel jobs and the sdist job pass.
  • Windows: the c-shared build works with the runner's MinGW toolchain. The only failure on the first push was a cross-drive os.path.commonpath bug in the new installed-wheel test, fixed in dc1fc88.
  • CI: the existing Python Bindings workflow still passes (ubuntu/macOS, Python 3.10/3.13).

Breaking Changes

  • pygosqlx now requires Python 3.10 or later; 3.8 and 3.9 support is dropped.
  • setup.py no longer carries package metadata. Anything that read the version from setup.py must read pyproject.toml instead.

Release note

### pygosqlx
- **Prebuilt wheels and PyPI release pipeline**: `pygosqlx` can be installed with `pip install pygosqlx` once the first `pygosqlx-v*` tag is published. Wheels bundle the native library for Linux x86_64/aarch64 (manylinux), macOS x86_64/arm64 (13+) and Windows AMD64, and are tested on Python 3.10–3.14. Releases are published from `pygosqlx-v*` tags via PyPI Trusted Publishing (`.github/workflows/pygosqlx-release.yml`).
- **Breaking**: pygosqlx now requires Python 3.10+ (3.8 and 3.9 dropped). Package metadata lives only in `pyproject.toml`.

🤖 Generated with Claude Code

https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

Make pygosqlx pip-installable with prebuilt wheels that bundle libgosqlx.

- pyproject.toml is the only metadata source; setup.py is reduced to a
  shim that marks the distribution non-pure and tags wheels
  py3-none-<platform>, so a wheel with a bundled native library is never
  tagged py3-none-any. requires-python >=3.10, classifiers 3.10-3.14,
  SPDX license metadata.
- New pygosqlx-release.yml: cibuildwheel builds and tests wheels for
  manylinux x86_64/aarch64 (Go installed in the container from a pinned,
  checksum-verified tarball), macOS x86_64/arm64 and Windows AMD64, plus
  an sdist. PRs build and test only; pygosqlx-v* tags publish to PyPI via
  Trusted Publishing; workflow_dispatch can publish to TestPyPI or PyPI.
- Tests can run against an installed wheel (PYGOSQLX_TEST_INSTALLED=1);
  test_installed_wheel.py fails if the checkout is imported or the wheel
  does not bundle a loadable library.
- README: pip install pygosqlx as primary install, supported platforms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@vercel

vercel Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

1 Skipped Deployment
Project Deployment Actions Updated
gosqlx-website Ignored Ignored Preview Oct 22, 2026 9:13am UTC

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 30s —— View job


Review of PR #851: pygosqlx wheels and PyPI pipeline

I read the workflow, setup.py, pyproject.toml, the Go install script and the new tests. I did not run any of it, and CI results aren't in yet. Overall the design is sound: py3-none-<platform> wheels, Trusted Publishing, SHA-pinned actions, least-privilege permissions, and a test that fails instead of skipping when the wheel has no library.

Likely bug (Windows CI)

  • python/tests/test_installed_wheel.py, test_imported_from_installed_package_not_checkout: os.path.commonpath([pkg_dir, _SOURCE_DIR]) raises ValueError: Paths don't have the same drive when the two paths are on different drives. On GitHub Windows runners the checkout is on D:\a\... and the cibuildwheel Python/venv is typically on C:\. That would fail the windows-amd64 job. Compare in a way that tolerates different drives, for example:
    pkg = os.path.realpath(pkg_dir); src = os.path.realpath(_SOURCE_DIR)
    try:
        inside = os.path.commonpath([pkg, src]) == src
    except ValueError:
        inside = False
    assert not inside, ...
    Using realpath also handles macOS /var → /private/var symlinks. Note that site-packages never lives under python/ unless the checkout was imported, so a simpler check is pkg_dir == os.path.join(src, "pygosqlx").

Smaller issues

  • Missing Windows classifier: the wheels ship for Windows, but pyproject.toml has no Operating System :: Microsoft :: Windows. Add it.
  • TestPyPI re-runs fail: publish-testpypi has no skip-existing: true. Version stays at 0.3.0, so the second dispatch fails with a 400 for the existing files. Setting skip-existing: true on that job only is safe.
  • Tag provenance: the tag/version check only runs in the sdist job, and nothing verifies that a pygosqlx-v* tag points at a commit on main. Anyone who can push tags can trigger a PyPI publish. The pypi environment's required reviewer and tag restriction is the real guard, so I'd make step 2 in the header mandatory rather than "recommended". An git merge-base --is-ancestor check against origin/main would add defense in depth.
  • Duplicated Go version: GO_VERSION lives in both the workflow and install-go-linux.sh, which will drift. A CI step that greps both and compares them would be cheap.
  • python/LICENSE copy: it can drift from the root LICENSE. A diff LICENSE python/LICENSE step in the sdist job would catch that.
  • Sdist installs without the library: pip install from the sdist (for example on musllinux or Python 3.15) builds a py3-none-<platform> wheel with no native library. The failure then shows up only at import time. A clear error message in core._get_lib_path() pointing at GOSQLX_LIB_PATH would help. The README documents this, so it's low priority.
  • Windows Go build: CIBW_BEFORE_BUILD_WINDOWS relies on the runner's MinGW gcc, which is on PATH today. If the image changes, it fails with an unclear cgo error. Consider an explicit gcc --version step before the build.

Looks good

  • has_ext_modules plus the get_tag override is the right way to get a platform-tagged py3-none wheel. setuptools>=77 also covers the bdist_wheel import path.
  • The Go tarball is checked against a SHA-256 and uses --proto '=https'.
  • persist-credentials: false, id-token: write only on the publish jobs, and the dispatch-from-main guard are all correct.
  • The sdist job's check that it contains no .so/.dylib/.dll is a good guard.
  • Removing the per-file sys.path hacks in favor of conftest.py is cleaner.

I made no code changes, since I can't modify files under .github/workflows and the main fix is in the tests. Please wait for the Windows wheel job before merging.

On Windows the installed package (C:) and the checkout (D:) are on
different drives, where os.path.commonpath raises ValueError.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 17s —— View job


Review of PR #851 (updated for the latest push)

I read the workflow and test_installed_wheel.py on the current branch head. I did not run anything, and CI results for the wheel jobs aren't in yet.

Resolved since the earlier review

  • The Windows cross-drive commonpath problem is already fixed by dc1fc88. test_imported_from_installed_package_not_checkout now catches ValueError.
  • One leftover: the paths still go through abspath rather than realpath. This is harmless in the wheel jobs, because site-packages is never under python/.

Remaining suggestions, most important first

  1. Tag provenance (pygosqlx-release.yml, publish-pypi)
    • A pygosqlx-v* tag on any commit can start a PyPI publish. The only guard is the pypi environment's reviewer and tag rule, and the header calls that "recommended".
    • Make it required in the header.
    • Optionally add a git merge-base --is-ancestor HEAD origin/main step to the sdist job. That needs fetch-depth: 0 on the checkout.
  2. TestPyPI re-runs (publish-testpypi)
    • The version stays at 0.3.0, so a second dispatch gets a 400 for files that already exist.
    • Add skip-existing: true to the TestPyPI publish step only.
  3. Windows classifier (python/pyproject.toml)
    • Wheels ship for Windows, but the classifiers lack Operating System :: Microsoft :: Windows. Add it.
  4. Drift guards (cheap CI checks in the sdist job)
    • diff LICENSE python/LICENSE.
    • Compare GO_VERSION in the workflow with the one in python/scripts/install-go-linux.sh.
  5. Windows toolchain (CIBW_BEFORE_BUILD_WINDOWS)
    • The build relies on the runner's MinGW gcc being on PATH. A gcc --version step before the build would give a clearer failure than a cgo error if the image changes.
  6. Sdist without the library
    • A pip install from the sdist, on musllinux or Python 3.15 for example, produces a package with no native library.
    • A clear error in core._get_lib_path() that points at GOSQLX_LIB_PATH would help. This is low priority, since the README documents it.

Looks good

  • py3-none-<platform> tagging through the setup.py shim.
  • SHA-pinned actions and least-privilege permissions. id-token: write is set only on the publish jobs, and persist-credentials: false is set on checkouts.
  • Dispatch publishing is limited to main, and the default target is testpypi.
  • The installed-wheel test fails instead of skipping when the library is missing.
  • The sdist job checks that no native binary is shipped.

I made no code changes. I can't edit .github/workflows, and the remaining items are suggestions. Please wait for the five wheel jobs and the sdist job to pass before merging.
· branch ci/pygosqlx-wheels-pypi

@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 19s —— View job


Review of PR #851 (updated after the latest push)

I re-read .github/workflows/pygosqlx-release.yml and python/tests/test_installed_wheel.py at the current head. I did not run anything, and I made no code changes. I can't edit workflow files, and the remaining items are small.

Resolved since the earlier review

  • The Windows cross-drive bug in test_imported_from_installed_package_not_checkout is fixed (test_installed_wheel.py:32-35). commonpath now catches ValueError and treats different drives as "not nested". One optional hardening: wrap both paths in os.path.realpath so symlinked temp dirs on macOS (/var → /private/var) compare correctly.

Still open (none blocks merge)

  1. skip-existing on TestPyPI. publish-testpypi (workflow line 260) will fail with a 400 on a second dispatch, because the version stays at 0.3.0. Add skip-existing: true under with: on that job only.
  2. Tag provenance. Nothing checks that a pygosqlx-v* tag points at a commit on main. The pypi environment's reviewer and tag restriction is the real guard, so I'd make step 2 of the header mandatory instead of "recommended". For defense in depth, add a step in sdist: git fetch origin main && git merge-base --is-ancestor HEAD origin/main (this needs fetch-depth: 0).
  3. Windows classifier. pyproject.toml lacks Operating System :: Microsoft :: Windows, though Windows wheels ship. Consider also adding the POSIX Linux and macOS classifiers.
  4. Duplicated GO_VERSION. It is defined in the workflow and in install-go-linux.sh, and only a comment keeps them in step. A one-line grep-and-compare CI step would stop them drifting.
  5. python/LICENSE drift. A diff LICENSE python/LICENSE step in the sdist job would catch it.
  6. Windows toolchain. CIBW_BEFORE_BUILD_WINDOWS relies on the runner's MinGW gcc. A gcc --version step before the build would give a clear failure if the image changes.
  7. Sdist without a library. An sdist install on an unsupported platform (musllinux, Python 3.15) fails only at import time. A clear message in core._get_lib_path() pointing at GOSQLX_LIB_PATH would help. The README already documents this, so it is low priority.

Looks good

  • py3-none-<platform> tagging through has_ext_modules plus the get_tag override.
  • SHA-pinned actions, persist-credentials: false, and id-token: write only on the publish jobs.
  • The dispatch-from-main guard.
  • The sdist no-native-binary check.
  • The installed-wheel tests fail instead of skipping, so a wheel without its library can't pass CI.

The real proof is the five wheel jobs and the sdist job, which haven't reported yet. Wait for the Windows and aarch64 jobs before merging.

- release.yml: pin GORELEASER_CURRENT_TAG/PREVIOUS_TAG to the v* series so
  pygosqlx-v* tags cannot truncate the Go release changelog
  (git.ignore_tags is GoReleaser Pro-only)
- PyPI publishes only from pygosqlx-v* tags; dispatch offers testpypi/none
- refuse to publish a tag whose commit is not on origin/main
- TestPyPI publish uses skip-existing for repeatable dry runs
- build c-shared libraries with -trimpath via GOFLAGS
- run the wheel build on pkg/** changes, not only pkg/cbinding/**
- fail if the workflow and install-go-linux.sh Go versions differ
- ship tests/conftest.py in the sdist; add Windows OS classifier

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 21s —— View job


Review of PR #851 (head c172b07)

I read the workflow, the release.yml change and the diff summary. I did not run anything, and I made no code changes. CI results for the wheel and sdist jobs are not in yet, so please wait for them before merging.

Earlier suggestions that are now addressed

  • skip-existing: true is set on the TestPyPI publish step only.
  • The sdist job checks that a tag commit is an ancestor of origin/main (with fetch-depth: 0) and that the tag matches the pyproject.toml version.
  • The GO_VERSION pins in the workflow and install-go-linux.sh are compared.
  • The workflow_dispatch pypi target is removed. PyPI is now reachable only from pygosqlx-v* tags.
  • release.yml pins GoReleaser's current and previous tag to the v* series, which stops pygosqlx tags from breaking the changelog.

Remaining points, none blocking

  1. Stale PR description. The body still says dispatch can publish to pypi. The workflow now offers only testpypi and none. Update the text.
  2. Tag trigger is stricter than the filter. The pygosqlx-v* glob also matches tags such as pygosqlx-vfoo. The version-match step rejects them, so this is safe, but it fails late, after the wheels are built. Moving the tag checks into an early job and having wheels depend on it would save runner time.
  3. Ancestor check timing. The check runs against origin/main as of the run. A tag pushed before the commit lands on main fails and needs a re-run. That is the desired behavior; just document it.
  4. Windows classifier. python/pyproject.toml still lacks Operating System :: Microsoft :: Windows, though Windows wheels ship. Linux and macOS classifiers would also be consistent.
  5. python/LICENSE drift. A diff LICENSE python/LICENSE step in the sdist job would catch it.
  6. Windows toolchain. CIBW_BEFORE_BUILD_WINDOWS relies on the runner's MinGW gcc. A gcc --version step would give a clearer failure than a cgo error if the image changes.
  7. Sdist without a library. Installing from the sdist on an unsupported platform fails only at import time. A clear error in core._get_lib_path() that points at GOSQLX_LIB_PATH would help. This is low priority because the README documents it.
  8. Required PyPI setup. The header calls the pypi environment's tag restriction and required reviewer "recommended". Since the environment is the main guard against a stray tag publishing, I'd make both mandatory in the docs.

Looks good

  • py3-none-<platform> tagging through the setup.py shim.
  • SHA-pinned actions, persist-credentials: false, and id-token: write only on the publish jobs.
  • Native runners only, and GOTOOLCHAIN=local with -trimpath for reproducible builds.
  • The installed-wheel tests fail instead of skipping, so a wheel without its library can't pass CI.
  • The sdist no-native-binary guard.

- publish-pypi now requires github.event_name == 'push'; a
  workflow_dispatch run on a pygosqlx-v* tag ref no longer uploads to
  PyPI regardless of the 'target' input.
- Linux wheels are repaired with --plat manylinux_2_17_{arch} so the
  x86_64 wheel no longer claims untested glibc 2.5-2.16 distros; README
  states the actual tag.
- setup.py warns at build time when the native library is missing, and
  the runtime FileNotFoundError points at the README build-from-source
  section.
- Drop an extra blank line in test_package_version.py (E303).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 25s —— View job


Review of PR #851 (head 47c4dc1)

I read the workflow, the release.yml change, setup.py, pyproject.toml and the core.py change. I ran nothing and made no code changes. I can't edit workflow files, and none of the findings below blocks merge. Please wait for the wheel and sdist jobs before merging.

Earlier review points that are now addressed

  • The Windows classifier is present, along with the macOS and Linux ones.
  • skip-existing: true is on the TestPyPI publish step only.
  • The sdist job checks that the tagged commit is an ancestor of origin/main, using fetch-depth: 0.
  • The sdist job checks that the tag matches the pyproject.toml version.
  • The sdist job checks that the two GO_VERSION pins agree.
  • core._get_lib_path() now has a clearer error message.
  • setup.py warns at build time when the native library is missing.
  • PyPI is reachable only from a tag push. The github.event_name == 'push' condition keeps a workflow_dispatch run on a tag ref off real PyPI.

Remaining points, most important first

  1. Tag checks run late. The pygosqlx-v* tag, version and ancestor checks live in sdist, but publish-pypi needs only [wheels, sdist].
    • A bad tag still burns all five wheel builds before failing, so the checks should move into an early job that wheels depends on.
    • Publishing is safe as it is, because sdist failing blocks publish-pypi.
  2. Required PyPI setup is still "recommended". The pypi environment's tag restriction and required reviewer are the real guard against a stray tag publishing. I'd make them mandatory in the header comment. The ancestor check only proves the commit is on main. It does not prove who pushed the tag.
  3. Ancestor check timing. A tag pushed before its commit reaches main fails and has to be re-run. That is the right behavior, so just document it in the header.
  4. Narrow glob. pygosqlx-v* also matches pygosqlx-vfoo. The version-match step rejects it, so this is safe.
  5. python/LICENSE drift. A diff LICENSE python/LICENSE step in the sdist job would catch the copy drifting from the root file.
  6. Windows toolchain. CIBW_BEFORE_BUILD_WINDOWS relies on the runner's MinGW gcc being on PATH. A gcc --version step would give a clearer failure than a cgo error if the image changes.
  7. Stale PR description. The description should say dispatch publishes only to testpypi or none. Check it against the current workflow.
  8. Sdist grep pattern. tar tzf ... | grep -E '\.(so|dylib|dll)$' misses versioned names such as libfoo.so.1. That is unlikely in this sdist and low priority.

Looks good

  • The py3-none-<platform> tagging through the setup.py shim (has_ext_modules plus the get_tag override).
  • SHA-pinned actions, persist-credentials: false, and id-token: write only on the publish jobs.
  • The Go tarball checked against a pinned SHA-256, with GOTOOLCHAIN=local and -trimpath.
  • The release.yml fix: pinning GORELEASER_CURRENT_TAG and GORELEASER_PREVIOUS_TAG to the v[0-9]* series keeps pygosqlx tags out of the Go changelog.
  • The installed-wheel tests fail rather than skip when the bundled library is missing.
    · branch ci/pygosqlx-wheels-pypi

cibuildwheel does not expand {arch} in CIBW_REPAIR_WHEEL_COMMAND_LINUX,
so auditwheel rejected the literal manylinux_2_17_{arch}. Take the
architecture from the matrix instead.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
@github-actions

github-actions Bot commented Oct 22, 2026 •

Copy link
Copy Markdown

Claude finished @ajitpratap0's task in 20s —— View job


Review of PR #851 (head c76437c)

I re-read .github/workflows/pygosqlx-release.yml at the current head. I ran nothing and made no code changes. I can't edit workflow files, and nothing below blocks merge. Please wait for the five wheel jobs and the sdist job to pass.

Resolved since the earlier reviews

  • The auditwheel --plat manylinux_2_17_${{ matrix.arch }} pin is in place. arch is set only on the Linux matrix entries, so the empty value on macOS and Windows is harmless.
  • publish-pypi requires github.event_name == 'push', so a dispatch on a tag ref can't reach PyPI.
  • skip-existing: true is on the TestPyPI step only.

Remaining points, most important first

  1. Tag checks run late (efficiency). The ancestor check and the tag/version check live in sdist, and wheels doesn't depend on it. A bad tag still burns five wheel builds before failing. Publishing is safe as it stands, because publish-pypi needs sdist. Moving the checks into a small early job that wheels depends on would save runner time.
  2. PyPI environment setup is still "recommended". The ancestor check shows the commit is on main. It doesn't show who pushed the tag. The pypi environment's tag policy and required reviewer are the real guard, so I'd mark steps 2 and the tag ruleset in the header as required.
  3. Document ancestor-check timing. A tag pushed before its commit reaches main fails and needs a re-run. That is the right behavior, so a one-line note in the header is enough.
  4. python/LICENSE drift. Add diff LICENSE python/LICENSE to the sdist job.
  5. Windows toolchain. CIBW_BEFORE_BUILD_WINDOWS relies on the runner's MinGW gcc. A gcc --version step before cibuildwheel would give a clear failure if the image changes. A cgo error would be harder to read.
  6. Sdist grep (minor). grep -E '\.(so|dylib|dll)$' misses versioned names such as libfoo.so.1. Use '\.(so(\.[0-9]+)*|dylib|dll)$'.
  7. Narrow glob (informational). pygosqlx-v* also matches pygosqlx-vfoo. The version-match step rejects it, so this is safe.

Looks good

  • py3-none-<platform> tagging through the setup.py shim.
  • SHA-pinned actions, persist-credentials: false, and id-token: write only on the publish jobs.
  • GOTOOLCHAIN=local, -trimpath, and the GO_VERSION agreement check.
  • The Go tarball checked against a pinned SHA-256.
  • The installed-wheel tests fail rather than skip when the bundled library is missing.
  • The release.yml change that keeps pygosqlx-v* tags out of the Go changelog.
    · branch ci/pygosqlx-wheels-pypi

@ajitpratap0
ajitpratap0 merged commit 7442049 into main Oct 22, 2026
42 checks passed
@ajitpratap0
ajitpratap0 deleted the ci/pygosqlx-wheels-pypi branch October 22, 2026 09:23
ajitpratap0 pushed a commit that referenced this pull request Oct 22, 2026
…uide

Record the pygosqlx 0.3.0 API and wheels, the gosqlx_version double free,
LSP serverInfo/CLI version reporting, the Python CI and release workflows and
the #848 docs. MIGRATION companion table lists pygosqlx 0.3.0, libgosqlx
exports and the LSP serverInfo version, with matching behaviour-change notes.
Regenerate the v1.16.0 blog page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9
ajitpratap0 added a commit that referenced this pull request Oct 22, 2026
* chore(parser): remove stray parser.go-e backup with conflict markers [vercel skip]

The sed backup file was committed by accident in #791. It is not compiled
but ships in the module zip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* chore(release): bump version to 1.16.0 [vercel skip]

gosqlx.Version and the CLI version were still 1.14.0 (v1.15.0 shipped with
them), so gosqlx --version, the MCP server info and /health reported 1.14.0.
Also bumps the VS Code extension, Claude Code plugin and marketplace, glama,
performance baseline label, llms.txt and the site's release badge. pygosqlx
__version__ now matches pyproject (0.2.0).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* docs(changelog): finalize 1.16.0 release notes [vercel skip]

Turns [Unreleased] into [1.16.0] - 2026-10-21, adds the missing entries for
#734, #735, #780, #786, #789, #790, #791, #826, #835, #836, #837, #840, #841,
#843 and #844, updates the MCP and composite-field entries amended by #841
and #843, adds PR refs, and adds the compare links. The VS Code extension
gets a 1.16.0 entry, and split-changelog.js generates the /changelog page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* docs: v1.15 to v1.16 migration guide and release doc fixes [vercel skip]

MIGRATION gains a v1.15.0 -> v1.16.0 section with a behaviour-change
checklist. ERROR_CODES documents E4001 dialect gating and the 11 dialect
names. CLI_GUIDE lists --dialect on format, parse, analyze and lint and all
11 dialects. SQL_COMPATIBILITY marks Oracle CONNECT BY/PRIOR and SQL Server
PIVOT as parsed. api/mcp.md matches the current Config and middleware API,
api/models.md drops the nonexistent Location.Offset and documents byte
columns, and HIGHLIGHTING notes ANSI control-character neutralization.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* chore(website): regenerate sample AST and changelog pages

The website build rewrote both files on main: sample-ast.json gains the
WithOrdinality and ColumnAliases fields from #843, and v1-9-1.md drops the
emoji the changelog splitter strips.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* docs(release): correct allocation claim, plugin history, E4001 and LoadConfig errors

Address review notes on #845: the lead paragraph understated the perf
audit's allocation cuts, the MIGRATION table listed a v1.15.0 plugin that
never shipped, E4001 also covers LIMIT under SQL Server, and LoadConfig
rejects more trusted-proxy misconfigurations than the API doc listed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* docs(release): make glama.json match the MCP server

List all 11 validate_sql dialects, describe lint_sql as the 10 rules it
runs (L001-L010; the CLI and SDK have 30), sync tool descriptions with
pkg/mcp/server.go, and drop the unsourced 1.38M ops/sec claim in favour
of a link to the benchmarks page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* docs(release): add #846-#851 to the v1.16.0 CHANGELOG and migration guide

Record the pygosqlx 0.3.0 API and wheels, the gosqlx_version double free,
LSP serverInfo/CLI version reporting, the Python CI and release workflows and
the #848 docs. MIGRATION companion table lists pygosqlx 0.3.0, libgosqlx
exports and the LSP serverInfo version, with matching behaviour-change notes.
Regenerate the v1.16.0 blog page.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* docs(release): address v1.16.0 release review; add #852

- Release date 2026-10-22 in CHANGELOG, MIGRATION, the extension changelog
  and the generated blog post (re-stamp at tag time if it slips).
- vscode-extension CHANGELOG: Fixed entry for the #846 version reporting.
- CHANGELOG: keep the Behavior changes list tight; name TranspileError and
  the LintResult/SecurityScanResult types in the pygosqlx 0.3.0 entry.
- MIGRATION: PyPI wheels row is conditional on the pygosqlx-v0.3.0 tag.
- Add #852 (sdist builds fail without libgosqlx; release tag lookup skips v1).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* build(release): replace deprecated goreleaser keys (formats, version_template)

goreleaser check (v2.12.7) flagged archives.format, format_overrides.format
and snapshot.name_template as deprecated; release.yml runs goreleaser
'latest'. Snapshot release dry-run builds all six archives.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* docs(release): add #853 to the v1.16.0 CHANGELOG

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

* feat(python): version pygosqlx in lockstep with GoSQLX (1.16.0)

pygosqlx wheels bundle libgosqlx built from the same commit, so its version
now matches the GoSQLX release. The first PyPI release is 1.16.0 (it was
0.2.0, never published); no older versions are backfilled.

- pygosqlx-release.yml also publishes on GoSQLX 'vX.Y.Z' tags (the floating
  'v1' tag does not match); 'pygosqlx-v*' stays for Python-only .postN
  releases. Both must match pyproject.toml and be on main.
- pyproject.toml / __version__ 1.16.0; the version test now asserts
  __version__ equals the bundled library's version().
- CHANGELOG, MIGRATION and python/README describe the lockstep scheme.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RkzVu3JY9Y6BRWfjesWts9

---------

Co-authored-by: Ajit Pratap Singh <ajitpratapsingh@Ajits-Mac-mini-2655.local>
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant