Skip to content

Release v2.0 - #281

Merged
Breakthrough merged 5 commits into
mainfrom
releases/2.0
Nov 9, 2026
Merged

Breakthrough merged 5 commits into
mainfrom
releases/2.0

Conversation

@Breakthrough

@Breakthrough Breakthrough commented Nov 8, 2026 •

Copy link
Copy Markdown
Owner

DVR-Scan Release Checklist

Each release gets its own branch releases/2.0[.Z] and a pull request Release v2.0 into
main. Copy this checklist into the PR description and check off each item. Replace 2.0
throughout with the version.

0. Release branch

git checkout -b releases/2.0 main
git push -u origin releases/2.0
gh pr create --draft --base main --head releases/2.0 --title "Release v2.0" --body-file RELEASE-PLAN.md
  • releases/2.0 exists and the draft PR is open with this checklist as its body.

All release work (optional rehearsal, the release commit, the tag) happens on this branch; it
is merged into main in section 6 and then stays as the hotfix line for 2.0.Z patches.

1. Pre-release

Dependency Roll

Where applicable (mark as complete if nothing to update):

  • dist/requirements_windows.txt
  • pyproject.toml
  • uv lock --upgrade.
  • update ffmpeg pin (ffmpeg_version, GyanD/codexffmpeg release name) across all builders
  • Python version
  • Advanced Installer OSS license still valid (appveyor.yml resolves the installed
    Advanced Installer version dynamically, so no path to update)

Changelog and docs

  • docs/changelog.md is up to date and accurate
  • docs/download.md is up to date and accurate
  • Verify all docs are up to date: README.md, docs/*.md, the dvr-scan.cfg config file
    template, dvr-scan --help output, CONTRIBUTING.md, etc.

Installer project (Windows releases)

  • python scripts/update_installer.py bumps dist/installer/DVR-Scan.aip from
    __version__: ProductVersion -> 2.0, new ProductCode GUID, PackageFileName ->
    dvr-scan-2.0-win64. Needs Advanced Installer installed locally (set ADVINST to the full
    path of AdvancedInstaller.com if it is not under C:\Program Files (x86)\Caphyon).
  • If bundled files changed (new Python/PyAV/OpenCV DLLs), run
    python scripts/update_installer.py --sync-files after the local frozen build below to
    re-sync APPDIR against dist/dvr-scan/. CI re-syncs on every build (--sync-only), so
    this only keeps the committed .aip representative. Structural changes (dialogs, features,
    prerequisites, shortcuts, install directory layout) still need the Advanced Installer GUI.

Local frozen build test

python dist/pre_release.py --release --use-local-images   # --release asserts the .aip ProductVersion matches __version__
pyinstaller dist/dvr-scan.spec
python dist/post_release.py
cp ffmpeg.exe dist/dvr-scan/          # the pinned GyanD full_build, not whatever is on PATH
git checkout -- dvr_scan/docs         # pre_release.py overwrites the docs, so we must restore it
  • dist/dvr-scan/_internal/av.libs/ exists with the PyAV FFmpeg DLLs.
  • From a directory/environment with no ffmpeg on PATH (e.g. a temp dir, where ffmpeg
    is empty), the following must succeed and produce an mp4 with audio:
    dvr-scan.exe --version, dvr-scan-app.exe --version,
    dvr-scan.exe -i <repo>/tests/resources/simple_movement.mp4 -et 5s -df 3
    (scripts/validate_release.py repeats these checks against the final artifacts)
  • dvr-scan-app.exe launches, wizard opens, and can perform a scan

Rehearsal (optional, recommended after changes to the build/sign/publish pipeline)

Exercises everything a tag triggers without publishing anything. On releases/2.0, commit the
release edits with __version__ = "2.0-rc1" (dates may still be placeholders), then:

git tag v2.0-rc1-release && git push origin v2.0-rc1-release
  • gh run list --branch v2.0-rc1-release: Release Tests (tag vs __version__; the
    changelog heading check is skipped for -rc/-dev tags), Python Distribution and
    Windows Distribution pass; Update Website is skipped (its job guard excludes
    -rc/-dev tags).
  • AppVeyor builds the tag: .aip re-sync, MSI named dvr-scan-2.0-win64.msi (the .aip
    carries the stable version, so rc builds produce the stable MSI name/version), SignPath
    request created.
  • Approve the SignPath request, download dvr-scan-signed.zip into dist/signed/, run
    python scripts/finalize_windows_dist.py (section 4).
  • Create a draft pre-release with the eight assets (section 5, add --prerelease), then
    gh workflow run release.yml -f tag=v2.0-rc1-release -f verify-only=true: installer
    fresh-install + upgrade test (test-installer.yml maps rc tags to the stable MSI version)
    and TestPyPI publish + pip smoke install.
  • Clean up: gh release delete v2.0-rc1-release --yes,
    git push origin :refs/tags/v2.0-rc1-release && git tag -d v2.0-rc1-release, delete the
    local dist/signed/* and downloaded artifacts. The rc commit stays in the branch history;
    the TestPyPI upload is harmless.

2. Release commit

On releases/2.0:

  • dvr_scan/__init__.py: __version__ = "2.0" (no -dev/-rc suffix).
  • docs/changelog.md: heading (In Development) -> (YYYY-MM-DD); the heading must be
    ### 2.0 (YYYY-MM-DD) (checked by release-test.yml).
  • README.md: ### Latest Release: v2.0 (Month D, YYYY).
  • docs/download.md: Python block and Windows blocks need updated version/date information
    and download links
  • docs/index.md and docs/index_docs.md: Latest Version: 2.0 (Month D, YYYY)
  • dist/installer/DVR-Scan.aip if not already committed above
  • Dates are the actual tag date, consistent across all five files
  • git status shows nothing else (dvr_scan/docs/ is clean)
git add README.md docs/changelog.md docs/download.md docs/index.md docs/index_docs.md \
        dvr_scan/__init__.py dist/installer/DVR-Scan.aip
git commit -m "[release] Release v2.0"

3. Tag

git push origin releases/2.0
git tag v2.0-release
git push origin v2.0-release
  • Tag points at the head of releases/2.0 (the release commit); the PR's CI is green.

The PR is merged in section 6 with a merge commit or fast-forward, never squash: the tagged
commit must become an ancestor of main.

4. CI artifacts and code signing

Pushing the tag triggers Python Distribution, Windows Distribution, Release Tests
(tag vs __version__, changelog heading, twine check, pip-audit), Update Website, and the
AppVeyor build (which re-syncs the .aip file list via scripts/update_installer.py --sync-only
before building the MSI and hands the result to SignPath).

  • gh run list --branch v2.0-release shows all GitHub workflows passing
  • AppVeyor build passes
  • SignPath: approve the signing request and download dvr-scan-signed.zip (signed
    dvr-scan.exe, dvr-scan-app.exe and MSI) into dist/signed/. No other inputs are
    needed: the portable zip is rebuilt from the signed MSI.
  • python scripts/finalize_windows_dist.py: verifies the Authenticode signatures, copies the
    MSI as dvr-scan-2.0-win64.msi, extracts its file tree with msiexec /a and repacks it as
    dvr-scan-2.0-win64.zip with 7-Zip, writes dvr-scan-2.0-win64.manifest.json +
    SHA256SUMS, then runs scripts/validate_release.py (filenames, hashes, signatures on the
    MSI and both EXEs inside the zip, MSI/zip parity, frozen-exe smoke tests with ffmpeg removed
    from PATH). Re-run the checks alone with python scripts/validate_release.py.
  • Portable zip: extract, run dvr-scan.exe --version and one scan (also covered by validate).

Installing the MSI on a clean machine (shortcut, dvr-scan --version from a prompt, upgrade over
the previous version, clean uninstall) is automated by test-installer.yml, run in section 6.

5. GitHub release (draft)

  • Zenodo: the GitHub switch for Breakthrough/DVR-Scan is ON before publishing, so the
    publish event mints a new DOI (the tag itself does not).
  • Download the Python artifacts from the tag's Python Distribution:
    gh run download <run-id> -n dvr-scan-dist -D release/
    (should be four files: dvr_scan-2.0 and dvr_scan_headless-2.0, .whl + .tar.gz).
  • Copy the finalized Windows artifacts from dist/signed/ into release/.
  • Release notes: verbatim to the corresponding the 2.0 changelog section, but with adjusted
    #### headings promoted to ## (#### Release Notes -> ## Release Notes) since the
    existing headers are chosen for the website
gh release create v2.0-release --draft --title "DVR-Scan v2.0" --notes-file release-notes.md \
    release/dvr-scan-2.0-win64.msi release/dvr-scan-2.0-win64.zip \
    release/dvr-scan-2.0-win64.manifest.json release/SHA256SUMS \
    release/dvr_scan-2.0-py3-none-any.whl release/dvr_scan-2.0.tar.gz \
    release/dvr_scan_headless-2.0-py3-none-any.whl release/dvr_scan_headless-2.0.tar.gz
  • Eight assets, Windows names exactly as linked from docs/download.md. Leave the release
    as a draft; the orchestrator publishes it.

6. Publish (release orchestrator)

release.yml verifies the draft release's artifacts and then publishes stage by stage:
test-installer.yml (fresh install + upgrade from the previous release on a clean
windows-latest runner) -> TestPyPI publish + pip smoke install -> GitHub release
(draft -> public, marked latest) -> PyPI publish + pip smoke install.

gh workflow run release.yml -f tag=v2.0-release -f verify-only=true   # optional: stop before anything goes public
gh workflow run release.yml -f tag=v2.0-release
gh run watch

publish-pypi.yml can still be dispatched by hand (-f tag=v2.0-release -f environment=testpypi|pypi);
for pypi it requires the tag's Python Distribution, Windows Distribution and
Release Tests runs to have succeeded.

python -m venv /tmp/dvr && . /tmp/dvr/bin/activate      # or .\Scripts\activate
pip install dvr-scan==2.0
dvr-scan --version
dvr-scan -i tests/resources/simple_movement.mp4 -so -df 4 -et 100
pip install --force-reinstall dvr-scan-headless==2.0 && dvr-scan --version
  • Mark the PR ready and merge it into main with a merge commit or fast-forward (not
    squash)
    so the tagged commit is an ancestor of main. Keep releases/2.0.

7. Website

update-site.yml runs automatically when the v2.0-release tag is pushed (and on
workflow_dispatch). Because that happens before section 6, the download links on the site
resolve only once the release is public; re-dispatch if the site needs rebuilding later:

gh workflow run update-site.yml --ref v2.0-release
  • https://www.dvr-scan.com/ shows Latest Version: 2.0, /download/ links resolve correctly,
    /changelog/ shows the new section at the top

8. Post-release

  • dvr_scan/__init__.py: __version__ = "X.(Y+1)-dev0", add ### X.(Y+1) (In Development)
    at the top of docs/changelog.md. Commit [dist] Prepare for vX.(Y+1) development
  • Close the roadmap issue and milestone:
    gh issue close <n> -c "Released in v2.0"; close milestone v2.0 on GitHub.
  • Close/comment issues fixed in this release that are still open.
  • CITATION.cff: add version: 2.0, date-released: YYYY-MM-DD, and (first time
    only) the concept doi:; add the DOI badge to README.md (snippet in NEXT.md).
  • Announce: Discord, GitHub Discussions, any issues that asked for the feature.

Automation Reference

Script/Workflow Description
scripts/common.py version normalization, artifact names, hashing, Authenticode check
scripts/update_installer.py .aip version/GUID/package-name bump; --sync-files / --sync-only [--dev] re-sync APPDIR
scripts/finalize_windows_dist.py signed bundle -> MSI + portable zip + manifest + SHA256SUMS, then validate
scripts/validate_release.py standalone artifact validation (--allow-unsigned for local dry runs)
dist/pre_release.py --release asserts the .aip ProductVersion matches __version__
release-test.yml tag vs __version__, changelog heading, build + twine check, pip-audit
test-installer.yml MSI fresh install / upgrade / uninstall on a clean runner
release.yml orchestrates installer test -> TestPyPI -> GitHub release -> PyPI (verify-only=true stops before anything goes public)
update-site.yml rebuilds www.dvr-scan.com on v*-release tags
appveyor.yml frozen build, .aip re-sync, MSI build, SignPath hand-off

@Breakthrough
Breakthrough force-pushed the releases/2.0 branch 2 times, most recently from b89350e to cb6fe16 Compare November 9, 2026 02:33
@Breakthrough
Breakthrough marked this pull request as ready for review November 9, 2026 04:17
@Breakthrough
Breakthrough merged commit b69b4f8 into main Nov 9, 2026
60 of 61 checks passed

This branch was successfully deployed

2 active deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant