Skip to content

feat: write a release manifest, stop apps removed from the desired set - #154

Merged
ineedjet merged 1 commit into
mainfrom
release-manifest-and-orphan-stop
Aug 24, 2026
Merged

feat: write a release manifest, stop apps removed from the desired set#154
ineedjet merged 1 commit into
mainfrom
release-manifest-and-orphan-stop

Conversation

@ineedjet

Copy link
Copy Markdown
Collaborator

Summary

Implements #109. Design was worked out in the issue's comment thread first (final manifest shape landed on there, deliberately smaller than the original proposal - no target field, release stays a timestamp not a semver tag, ref entries are resolved not requested).

  • Every release gets a manifest.json at its root: schema_version, release timestamp, resolved app_refs/env_refs (the actual tag pulled, never @latest), and the sorted apps list. No secrets.
  • resolve.download_ref now returns (path, resolved_ref) instead of just path, so callers can capture what was actually resolved.
  • deploy_to_host reads the previous release's manifest.json off current before switching it, diffs against the new desired app set, and docker compose downs anything no longer wanted - using the old current path (last-known compose file/.env still intact there) rather than depending on the new release tree also happening to still contain that app's files (which it does, since build_release copies the whole catalog every time, but the old path is the more directly-correct source for "stop what was actually running").
  • release_name moved from per-host (generated fresh inside deploy_to_host for every host in a multi-host target) to once per deploy in main(), so a multi-host target's manifest is identical across all its hosts for the same logical deploy.

Test plan

  • deploy/tests/ + encrypt-env/tests/ + load-yaml-matrix/tests/ (70 tests, new manifest/orphan-stop tests added) pass
  • pre-commit (pymarkdown, ruff) passes
  • Next deploy to heimdall produces a manifest.json and (once an app is actually removed from a target) correctly stops it

Every release now gets a manifest.json at its root: schema_version,
release timestamp, resolved app_refs/env_refs (the actual tag
resolve.py pulled, never @latest), and the desired apps list. No
secrets, no target identifier - whoever's reading it already knows
which host they're on.

resolve.download_ref now returns (path, resolved_ref) instead of just
path, so build_release/resolve_app_envs can capture what was actually
resolved, not just what was requested.

deploy_to_host reads the previous release's manifest.json off current
before switching it, diffs its apps against the new desired set, and
docker compose downs anything no longer wanted - using current's own
path so that app's last-known compose file/.env are still there. This
works even though the new release's own tree also still contains that
app's compose file (build_release always copies the whole catalog,
not just a target's desired subset) - using the old release avoids
depending on that incidentally, and keeps the stop grounded in the
last environment that app actually ran with.

release_name moves from being generated once per host inside
deploy_to_host to once per deploy in main() - keeps a multi-host
target's manifest.json identical across every host of the same
logical deploy, and deploy_to_host takes it as a parameter now.

Closes #109

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@ineedjet
ineedjet merged commit 4b75d1d into main Aug 24, 2026
5 checks passed
@ineedjet
ineedjet deleted the release-manifest-and-orphan-stop branch August 24, 2026 22:20
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