chore(release): v0.19.1 - #465
Open
github-actions[bot] wants to merge 23 commits into
Open
Conversation
- Implement automatic draft GitHub release creation for new tags. - Extract release notes from `changelog.md` to populate draft releases. - Upgrade `astral-sh/setup-uv` action to `v8.2.0` across all workflows. - Update `actions/download-artifact` to `v8` in `draft-release.yml`. - Remove the `development.md` file. - Adjust `justfile` regex to match patch versions of GitHub Actions. Signed-off-by: aloksingh <alokmilenium@gmail.com>
Bump versions and enhance CI workflows
fix: add workflow_dispatch to publish-pypi for manual retry
chore: bump develop version to 0.20.0.dev0
Frappe v16 ships a Chrome-based PDF generator that renders without any
network requests, but it cannot start in the fm image because Chromium's
shared libraries are missing:
headless_shell: error while loading shared libraries: libnss3.so
Frappe downloads headless_shell into the bench itself via
find_or_download_chromium_executable(), so only the shared libraries are
needed here. The single-package shortcut other Frappe images use does not
port to our base: jammy has no chromium-headless-shell package, and
chromium-browser is a transitional stub for the chromium snap, which
cannot run in a container. The libraries are therefore listed explicitly.
Placed in the base stage so frappe, socketio, schedule and every worker
inherit them. Background jobs render PDFs for ticket email attachments, so
a frappe-only fix would leave those paths broken.
Refs: #452
…tions docs/changelog.md is cumulative but only ever committed to main, so develop's copy is a stale snapshot that stops at the last version released from develop. Right now develop holds only `## v0.19.0.dev0` while main also has `## v0.19.0`, a 422 line gap. Prepending onto that stale copy means the next release branch is generated without every section main has accumulated since, then conflicts with main at merge time. Resolving that conflict the wrong way silently deletes a released version's history from the changelog. Check the file out from main before git-cliff runs, so the release branch is main's changelog plus the new section. Nothing can be lost, there is nothing to resolve, and develop's copy no longer matters, which keeps main out of develop entirely.
The logic that pulls one version's section out of docs/changelog.md for the GitHub release body existed as an inline `python3 -c` block duplicated verbatim in draft-release.yml and tag-on-release-merge.yml, so a fix had to be applied twice and the two copies could drift apart unnoticed. Two behaviour changes over the inline version: - Fails loudly. The old code fell back to printing `Release <version>` when it found no matching heading, so a missing or mistyped section produced an empty-looking release with nothing in the logs to explain it. It now exits non-zero and reports which headings it did find. - Fixes a matching bug. The old pattern had no digit boundary, so asking for 0.19.1 also matched a `## v0.19.10` heading. In a newest-first changelog that heading appears earlier in the file, so the wrong notes would ship.
…he tag
frappe_manager/__about__.py is the single source of the package version
(hatchling reads it) and of the published image tag (bake-images.yml derives
`v${version}` from the same line). Getting it wrong publishes images under
the wrong name, and v0.20.0.dev0 already exists in ghcr as a result.
Until now it was a reviewer checkbox in the release PR body, which also
named the wrong file (pyproject.toml). Set it with the workflow instead and
verify the write took effect.
Also guard the value where it is consumed: draft-release.yml now refuses to
publish when the tag and __about__.py disagree, rather than building an
image under a tag nobody asked for.
Both workflows now call scripts/release_notes.py, so release-prepare fails
before opening a PR whose changelog git-cliff did not actually generate, and
draft-release no longer carries its own copy of the extraction logic.
… steps A tag pushed with the default GITHUB_TOKEN does not start new workflow runs. Both draft-release.yml and bake-images.yml trigger on `push: tags: v*`, so neither has ever fired for a tag created by this workflow. bake-images has exactly two push-triggered runs in its history, both from August 2025 for v0.18; every release since was built by hand via workflow_dispatch. The pytest gate in draft-release.yml was being skipped for the same reason. Push with RELEASE_PAT so the tag fans out to both, falling back to GITHUB_TOKEN with a warning that names the two workflows to run manually, so an unconfigured secret degrades visibly instead of silently. Removing the duplicated build, notes and `gh release create` steps is a prerequisite, not tidying: once the tag push actually triggers draft-release.yml, leaving them here would have two workflows racing to create the same release. draft-release.yml owns that, and it runs the tests first. Also refuse to tag when the branch version and __about__.py disagree, and drop the now-unused `actions: write` permission.
The self-hosted-arm64 leg had been cancelling on every nightly since at least 2026-07-24. Because the combine job needs both architectures, it was skipped every time, so the multi-arch manifest was never republished while the amd64 arch-specific tag kept moving. That would have blocked the next release outright: fm pins the manifest name, so a build producing only :amd64-vX.Y.Z leaves nothing for `fm update` to pull. arm64 hosted runners have been generally available since 2025-08-07 and are free, so ubuntu-24.04-arm replaces the self-hosted box and arm64 now builds natively rather than under emulation. The Dockerfile already maps uname -m for the wkhtmltopdf package, so nothing else had to change. While in the matrix: replace the 2x2x2 cross product plus two exclude rules with an explicit target list, so the valid pairs are declared rather than subtracted, and carry `arch` there so the basename call and two platform-comparison ternaries collapse to one field. Add fail-fast: false so one architecture cannot cancel the other mid-flight. Drop the self-hosted buildx prune step, hosted runners are ephemeral, and drop the single-value os axis from combine. Build cache was a single unversioned buildcache-<arch> ref written with mode=max, so every branch overwrote every other branch's cache and alternating builds thrashed it. Writes are now scoped by ref while reads fall back to develop's cache and then the legacy ref, so adopting this never forces a cold build. Tag and nightly builds share one `release` scope rather than leaving a dead cache ref per release, and the scope is sanitised because OCI tags cannot contain '/', which refs like dockerimage/1 and release/v0.19.1 would otherwise produce.
git-cliff generation only happened inside the Prepare Release workflow, so the only way to see what a release would produce was to dispatch it and read the resulting PR. Adds `just changelog` and `just changelog-for VERSION` to preview the generated section locally, and `just release-notes VERSION` to show what would be published as the release body. uvx resolves git-cliff, so no local install is required. The section comment states that docs/changelog.md is generated output rather than a file to hand-edit, which is the assumption the release workflow now depends on.
Without this, updating a bench to FM 0.19.1 leaves it on the v0.19.0 image, which has no Chromium libraries, so the release would ship and the PDF fix would never arrive. The cause is in MigrationBase._get_image_tag_for_migration(): on a stable FM release it returns the *migration's* version rather than the installed FM version. v0.19.0 was the only migration that existed, so a bench at 0.19.0.dev0 updating to FM 0.19.1 was discovered by that migration and re-tagged to v0.19.0. It only worked during development because a .dev0 FM takes the is_dev_environment branch and uses the installed version instead. So every release that changes the published images needs its own migration class, even when it changes nothing else. This one only re-tags compose images and pulls. Two deliberate differences from the v0.19.0 migration: - Iterates docker-compose*.yml rather than naming two files, so a compose file added later cannot be silently missed, and skips files carrying no fm images so admin-tools is not reformatted and given a spurious x-version. - Backs up the worker and admin-tools compose files. The parent only backs up docker-compose.yml, which leaves the rollback in migrate_benches() incomplete for any other compose file the migration rewrites. Refs: #452
…r-compose.yml bench_basic_backup() only backed up docker-compose.yml, but migrations routinely rewrite docker-compose.workers.yml too. The rollback in migrate_benches() restores whatever was backed up here, so a migration that failed after touching the worker compose left it modified with no way back. migrate_0_19_0 has been rewriting that file without a backup since it landed. The set is declared once, as MigrationBench.managed_compose_paths, next to the compose file managers that already model two of the three files. Consumers ask the bench rather than each rebuilding the list. Deliberately not a docker-compose*.yml glob. fm owns a closed set of three generated compose files, and a glob would also claim files it never created, such as a user's own docker-compose.override.yml, then back up and restore them as though fm managed them. The property filters to files present on disk, so a bench without workers or admin-tools needs no special casing. Also drops the bench_basic_backup override from the v0.19.1 migration, which was compensating for the gap one migration at a time, and its local glob helper.
… no migration
`fm migrate <bench>` only wrote bench_config.toml's migration_state when the
last applied migration's base version equalled the running fm version. A
release that ships no migration of its own therefore never stamped anything,
and neither did a run where the newest migration predates the release — the
case reached the moment 0.19.1's migration is the newest one and fm is already
on 0.20.0.dev0.
The bench then stays pinned to its old version, so every later command demands
a migration that has nothing left to do:
fm migrate alok.rt.gw -> Successfully migrated alok.rt.gw to v0.19.1
fm start alok.rt.gw -> Bench migration required (v0.19.0 -> v0.20.0.dev0)
Run: fm migrate alok.rt.gw
Reproduced on the migration test server going v0.19.0 -> fix/452.
`migrations.execute()` returning success already means every targeted bench is
at the running version, whether a migration touched it or not, so the stamp now
keys off the absence of a recorded exception. Benches no migration touched are
still reported as skipped, which is what they are.
This is the same assumption #452 fixed elsewhere: that each release always
carries a migration class named after it.
test_migrate_0_19_1.py pins what the migration is actually for: fm images in docker-compose.yml and docker-compose.workers.yml move to the new tag, redis and the admin-tools file are left alone, a second run pulls nothing, and a stable fm tags images with the migration's own version. That last one is the #452 regression — mutating the stable branch of _get_image_tag_for_migration() to v0.19.0 fails 4 of the 10 tests. test_migrate_bench_stamping.py covers the stamping rule: after a successful run every targeted bench that did not raise is written to the running fm version, including benches no migration touched. Reverting the stamp to the old base-version comparison fails 4 of its 6 tests.
- Update the v0.19.1 migration to automatically recreate running bench and worker containers after pulling new images to ensure they pick up the updated Chromium libraries. - Implement an Nginx race condition handler during container recreation to ensure the proxy service remains operational if the Frappe container restart causes a lookup failure. - Add comprehensive unit tests to verify that running benches are recreated, stopped benches remain inactive, and Nginx is recovered if it exits during the migration process. Signed-off-by: aloksingh <alokmilenium@gmail.com>
- Remove the "#452" issue reference from the Chromium dependency comment in the Dockerfile - Clean up documentation comments to maintain a professional codebase style Signed-off-by: aloksingh <alokmilenium@gmail.com>
Add Chromium libraries for PDF generation and improve CI workflows
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Release v0.19.1
Review the generated changelog entries below before merging.
Merging this PR creates the
v0.19.1tag, which triggers the draftrelease and the image build.
docs/changelog.mdis based on main's copy andfrappe_manager/__about__.pyhas been set to
0.19.1automatically.