Skip to content

Publishing and verifying a release

Source, documentation and PyPI are separate deliveries. A successful merge updates the repository; the Pages workflow deploys documentation after main CI succeeds. The PyPI description comes from each distribution's README metadata, so editing GitHub alone does not update a previously uploaded package. See the PyPA README guide.

Prepare the five packages

The five-package layout starts with 0.2.4. Release Core (sqlseed), CLI (sqlseed-cli), AI (sqlseed-ai), MCP (mcp-server-sqlseed) and Web (sqlseed-web) from the same reviewed commit and version tag. Do not combine 0.2.3 Core with the new plugins. The migration guide covers the changed entry points and compatibility limits.

Before publishing:

  1. Merge the reviewed changes through all required checks. Follow the root release checklist, including both changelogs and the local mutation gate.
  2. Build all five wheels and sdists. Run twine check --strict on all ten artifacts. Check that the package names and versions match, each archive includes the AGPL license text, and metadata contains the correct README, dependencies and Documentation URL.
  3. Install the artifact set in fresh environments and run the distribution checks below. Check the built documentation and README links, including their rendered presentation. A metadata check alone does not check layout.
  4. Confirm the publishing identity for all five projects: owner sunbos, repository sqlseed, workflow file publish.yml, GitHub environment pypi. All five existing projects must authorize that same Trusted Publisher. GitHub Pages uses its separate github-pages environment. See PyPI's setup instructions for existing projects.
  5. Select the release version and obtain the maintainer's release approval. Push the reviewed commit before its v<version> tag, then create the GitHub release. Publishing is a separate operation from documentation review.

The publish workflow tests Python 3.10, 3.12 and 3.13, requires a v tag, builds the five packages, checks their metadata and wheel versions, then publishes each project's wheel and sdist in its own Trusted Publishing job. Jobs can succeed independently; this is not an atomic five-package transaction. Keep the workflow run, commit, tag and artifact hashes with the release record. If a publish fails partway through, inspect which files reached PyPI before retrying the same release. Its skip-existing setting does not prove all five packages were uploaded successfully.

After changing a Trusted Publisher, verify the shared identity against an existing release before retiring its old environment:

gh workflow run publish.yml --ref main -f release_tag=v0.2.4 -F verify_existing_release=true

This mode first requires all ten rebuilt files to match the existing public filenames and SHA256 hashes, with no yanked files. It then disables Twine's existing-file shortcut so PyPI actually checks upload permission for each project. PyPI accepts identical existing files without replacing them. This verification mode does not generate new attestations; the existing files and attestations remain intact. Normal publication retains skip-existing and attestation generation. A missing or changed public file stops verification before any upload job can run. Public installation acceptance still runs after all five jobs succeed.

If the upload tool needs a compatibility fix, merge the workflow correction to main and dispatch it with the existing release tag:

gh workflow run publish.yml --ref main -f release_tag=v0.2.4

The workflow resolves that tag once to a commit, then tests, builds and runs public installation checks from that exact source. The workflow revision can therefore receive maintenance without moving a published tag. Keep metadata validation and attestations enabled. For example, Core Metadata 2.5 requires PyPA publish action v1.14.2 or newer; rerunning a workflow pinned to the older uploader will repeat its metadata error.

Validate installed artifacts before release

Use a fresh virtual environment outside the checkout. Install all five wheel paths in one pip install invocation, requesting the AI wheel's [mcp] extra to enable the independent AI MCP server. From outside the checkout, with PYTHONPATH unset, run the scripts from the reviewed repository:

python -m pip check
python /path/to/sqlseed/scripts/check_wheel_install.py
python /path/to/sqlseed/scripts/check_public_entrypoints.py 0.2.4

Replace 0.2.4 with the exact version under test. Repeat in a fresh environment containing only Core and Web, running check_wheel_install.py --without-optional-components. Also install the five sdists together in a third environment and repeat the full checks. Never present a development version or a local version override as an already published release.

Verify from public PyPI after publication

Run the following from the reviewed checkout after all five projects have the exact version. A Linux runner with Python 3.12 is a useful reference environment; the Bash script also supports macOS. Set PYTHON_BIN to the desired interpreter. After all five upload jobs succeed, the publish workflow runs this check on Linux with Python 3.12 and retains the public-pypi-acceptance artifact. Use the same command below to repeat it locally or on another supported platform.

PYTHON_BIN=python3.12 bash scripts/verify_pypi_release.sh 0.2.4

The script uses the production PyPI index, creates disposable environments, ignores local package paths and saves the package metadata and installation reports. It checks the exact public version and its wheel/sdist availability, then tests full wheel, minimal Core/Web and full sdist installations. Third-party dependencies may build from source when a platform wheel is unavailable; that requires the dependency's build toolchain.

The installed-package checks cover:

  • Imports from the environment's site-packages, matching package versions and the separation of the Core and CLI entry points.
  • Real SQLite generation through Core, CLI and the offline MCP server, including expected row counts and preservation of unrelated rows.
  • Web startup on a temporary port, assets, preview and generation through HTTP.
  • Discovery of the four tools from the separate AI MCP server. Discovery does not invoke a model or prove that an LLM backend is reachable.

Open all five PyPI project pages after upload. Check the selected version, rendered descriptions, Documentation links, license and downloadable files. Compare the uploaded file hashes with the retained build artifacts. Verify the Pages deployment uses the reviewed main commit and that the installation, migration and API pages load correctly.

Keep real PostgreSQL and real LLM acceptance evidence separate. The public installation script uses SQLite and does not claim either of those integrations has been tested. A failed public installation or broken entry point is a release failure even if the local wheel checks passed.