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:
- Merge the reviewed changes through all required checks. Follow the root release checklist, including both changelogs and the local mutation gate. Update current installation examples and capability descriptions in both root READMEs, each package README and the maintained guides; preserve historical release records. Use absolute documentation links in package READMEs so they also work on PyPI.
- Build all five wheels and sdists. Run
twine check --stricton 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. - 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.
- Confirm the publishing identity for all five projects: owner
sunbos, repositorysqlseed, workflow filepublish.yml, GitHub environmentpypi. All five existing projects must authorize that same Trusted Publisher. GitHub Pages uses its separategithub-pagesenvironment. See PyPI's setup instructions for existing projects. - 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:
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:
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.
Maintain GitHub release notes¶
Use v<version> as the release title and keep its reviewed body in
.github/release-notes/v<version>.md. Copy the
bilingual template
and remove unused subsections in both languages. The order is English, Chinese,
then shared links. Within each language, use Added, Changed, Fixed, Removed,
Compatibility and Verification only when applicable. Both languages describe
the same changes. Link changelogs and source to the exact version tag; keep
historical verification evidence and upgrade limits with their own version.
The full CI/development environment includes the Markdown parser. For standalone release-note maintenance, activate a separate virtualenv and install its small hash-locked dependency set from the repository root; no sqlseed package is needed:
python -m pip install --require-hashes --only-binary :all: -r .github/requirements-release-notes.txt
Installation is a separate preparation step; --check still runs entirely offline.
Check the notes before committing. After approval, push the release commit and tag,
then create the release with the reviewed notes. --verify-tag stops if the tag is
missing from the remote repository:
python scripts/sync_release_notes.py --check
gh release create v<version> --verify-tag --title "v<version>" --notes-file .github/release-notes/v<version>.md
For existing releases, preview the differences, then apply the reviewed files:
python scripts/sync_release_notes.py
python scripts/sync_release_notes.py --apply --backup-name release-notes-20261012
Online commands require GitHub CLI access to api.github.com; applying requires
repository write access (Contents: write for fine-grained or GitHub App tokens).
For historical targets that change .github/workflows/ relative to the default
branch, GitHub additionally requires the classic PAT/OAuth workflow scope or
fine-grained/GitHub App Workflows: write permission; otherwise it may return
404 or 403. Authorize these permissions in the token or app settings, or refresh
an OAuth CLI login with gh auth refresh -h github.com -s workflow. That command
does not change a PAT supplied through the environment. The built-in Actions
GITHUB_TOKEN cannot satisfy this extra workflow permission. See
GitHub's release-update permission rules.
The default command only previews. Applying saves all original records under
.release-backups/<name>/ in the checkout before changing titles or bodies.
Choose a new name using only ASCII letters, digits, hyphens and underscores;
arbitrary paths, symlink backup roots and existing names are rejected. This
directory is ignored by Git; retain or copy it before removing the checkout.
The script checks versioned links against each note's filename, checks for
concurrent edits even when a release initially matches, and verifies each result.
It waits at least one second between mutations and preserves tags, release
state and assets. Run one synchronization at a time and avoid other release edits
until it finishes: the pre-update read and PATCH are separate API calls, so the
check cannot prevent an edit made between them. If an update fails partway through, retain the backup, inspect
the reported versions and preview again before retrying with a new backup
name. Updating an existing release's text does not trigger this repository's
release: published PyPI workflow. These commands do not create missing releases
or republish packages. See the
notes maintenance instructions.
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.6
Replace 0.2.6 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.
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.