Use one copy per release, copy into a pull request and check each box as steps are completed.
Optional: version referenced below as X.Y[.Z] - replace with the real version throughout.
- Create / fast-forward release branch:
releases/X.Yoffmainif major/minor release. If patch release, fast-forward currentreleases/X.Ybranch. - Bump
__version__inscenedetect/__init__.py - Bump
docs/LATEST_VERSIONif needed (stable major/minor releases only) - Regular release: No
-devsuffix or other, pre-release: has suffix-dev0,-dev1, ...
- Docstrings / API docs reflect any signature changes (
cd docs/ && make htmlbuilds clean). -
docs/api/migration_guide.rstupdated if any public API changed. - Docstring examples all run correctly, nothing references removed or deprecated symbols.
- Changelog has release notes for major/minor release, all features, breaking changes, bug fixes, and known issues are documented.
-
website/pages/download.mdupdated with the new version / installer link / release date. -
website/pages/changelog.md: move the release changes from the Development section at the bottom to the top. -
website/pages/index.md: Latest release version and date updated.
- Static analysis passing (ruff + pyright).
- Unit tests green locally and in CI:
pytest -vv(should collect-m 'not release'by default). - Release test suite green: manually trigger or make a release candidate tag, all 4 jobs (
static,release-tests,install-matrix,long-stress) green across the OS and Python version matrix. -
pip-auditclean (or exceptions documented in the changelog).
- Update
packaging/windows/requirements.txtand bump bundled ffmpeg version inappveyor.yml - Run Appyeyor build on release branch, ensure resulting portable distribution and MSI installer are correct
GUI required for structural changes.
scripts/update_installer.pycovers routine version bumps and--sync-filescovers dependency-driven file-list changes, but anything that touches the project structure of the .aip still needs the AdvancedInstaller GUI. Examples:
- Moving the .aip or its source tree (the build's
SourcePathreferences are stored relative to the .aip and aren't rewritten by/NewSync.- Adding/removing build configurations, features, or prerequisites.
- Install directory layout (
APPDIRlocation), or per-component attributes.- Editing dialog layouts, branding bitmaps, install sequences, custom actions, file associations, or shortcuts.
- Final commit on
releases/X.Y: "Release vX.Y[.Z]". - Tag
vX.Y[.Z]-releaseon that commit and push. Wait for all tests/builds to pass. - Approve code signing request on SignPath, download
scenedetect-signed.zip - Finalize Windows artifacts locally (CI can't do this - signing happens after the AppVeyor build, so the post-signing steps must run locally):
- Create
dist/signed/and dropscenedetect-signed.zip(from SignPath) into it. No other inputs needed - the portable .zip is rebuilt from the signed .msi viamsiexec /a, eliminating the AppVeyor download. - Run
python scripts/finalize_windows_dist.py. This extracts the signed.msifrom the bundle, runsmsiexec /ato recover the installed file tree, repacks it as the portable.zipwith 7-Zip, writesPySceneDetect-X.Y.Z-win64.manifest.json+SHA256SUMS, and then runsscripts/validate_release.pyto verify filenames, hashes, Authenticode signatures, MSI/zip parity, and frozen.exesmoke tests.
- Create
- Draft release on Github using the tagged commit: include full changelog & release notes, signed portable .ZIP, signed .MSI installer, Python .whl/.tar.gz packages, and checksum manifests (
PySceneDetect-X.Y.Z-win64.manifest.json+SHA256SUMS) - Verify all artifacts uploaded to Github release are valid and named correctly
- Smoke-test all release artifacts
- Publish Github release
- Upload to PyPI:
publish-pypi.ymlmust be manually triggered on a release tag. Specifytestpypifirst, and make sure everything goes okay on the test instance. When verified and smoke tested, specifypypias the environment, and publish the production package. - Verify both projects: https://pypi.org/project/scenedetect/ and https://pypi.org/project/scenedetect-headless/.
- Deploy website:
generate-website.yml - Deploy docs:
generate-docs.yml - Merge release branch back into
main, verifydocs/LATEST_VERSIONis correct - Manually dispatch
generate-docs.ymlagainstreleases/X.Yto update www.scenedetect.com/docs/latest - Smoke-test PyPI release: in a fresh venv,
pip install scenedetect==X.Y.Z; CLI launches andscenedetect --versionlooks correct. - Verify download links on website are correct, PyPI project page is up to date and correct.
- Clear / archive release-scoped tracking files (
tracking.md, any release-specific TODOs). - Announce: project site, relevant issues / discussions closed and linked to the release.
- Branching model: work spans multiple commits on
releases/X.Y; the final one gets thevX.Y[.Z]-releasetag which gates the release-test workflow. A passing release-test is a hard prerequisite for publishing. - Version consistency is enforced in two places (
__init__.py,PySceneDetect.aip). Thestaticjob ofrelease-test.ymlchecks__init__.pyagainst the tag and verifies the changelog has a matching## PySceneDetect X.Yheading; the installer parity is checked byscripts/pre_release.py --release. - Changelog convention: the in-development section lives at the bottom of
website/pages/changelog.mdunder the "Development" heading - don't move it to the top.