diff --git a/docs/specs/DEVX-182.md b/docs/specs/DEVX-182.md new file mode 100644 index 0000000..21e282d --- /dev/null +++ b/docs/specs/DEVX-182.md @@ -0,0 +1,49 @@ +# DEVX-182: feat(molecule): release lease emission (ships DEVX-181) + +- Task: DEVX-182 +- Status: draft + +## Problem + +DEVX-181 landed on master but was never released: the squash subject +came out `DEVX-181: ci: retrigger validation` because the branch's last +commit was an empty `ci:` retrigger. git-cliff found no bump-worthy +commit, so `v0.55.5` is still latest and the S08 lease producer is +unshipped. A `feat:` merge is needed to cut the release — and while +shipping, the emission log line is upgraded from a bare count to the +actual lease owner and UTC expiry, which is what an operator needs when +debugging a cleanup race. + +## Approach + +REQ-1: `start_docker.main()` computes `lease_env()` once and logs +`owner=` + ISO-8601 `until=` alongside the export confirmation. The +single call also removes a latent second-boundary inconsistency where +`emit_github_env` and the count message each re-derived `now`. + +REQ-2: Merge squash commit carries `feat(molecule):` so git-cliff cuts +the next minor release containing DEVX-181's emitter and this change. + +## Test Plan + +- Update `test_emits_lease_on_success` + `test_prints_and_exports` for + the new log format; keep 100 % coverage. +- `make pre-push` — full devx suite green. +- Post-merge: verify a `v*` tag > v0.55.5 exists and + `pip index versions devx` (Gitea PyPI) lists it. + +## Deploy Plan + +- Auto-merge; post-merge release job tags + publishes. +- Infra (OBL-INFRA-658) and GRM (GRM-174) consume the new pin. + +## Rollback Plan + +- Revert merge; the unreleased module remains dormant regardless. + +## Acceptance Criteria + +- [x] REQ-1: emission log includes owner and ISO-8601 expiry; lease env + computed once — covered by updated unit tests. +- [x] REQ-2: merge commit uses `feat(molecule):` so the release job + cuts a version bump. diff --git a/src/devx/molecule/start_docker.py b/src/devx/molecule/start_docker.py index 298d94c..ca859bc 100644 --- a/src/devx/molecule/start_docker.py +++ b/src/devx/molecule/start_docker.py @@ -31,11 +31,12 @@ import subprocess # nosec B404 import sys import tempfile import time +from datetime import UTC, datetime import click from devx.i18n import _ -from devx.molecule.lease import emit_github_env, lease_env +from devx.molecule.lease import LEASE_UNTIL_ENV, OWNER_ENV, emit_github_env, lease_env DEFAULT_TIMEOUT = 30 DOCKER_SOCK = "/var/run/docker.sock" @@ -388,8 +389,12 @@ def main(timeout: int) -> None: # Implements: REQ-2 (DEVX-181) — emit the S08 producer lease env so # molecule-created objects carry org.oblachno.lease-until/owner # labels that runner-cleanup.sh honors. - if emit_github_env(lease_env()): - click.echo(f"Exported {len(lease_env())} lease vars to GITHUB_ENV") + # Implements: REQ-1 (DEVX-182) — one lease_env() call; log the + # owner and UTC expiry an operator needs for cleanup debugging. + env = lease_env() + if emit_github_env(env): + until = datetime.fromtimestamp(int(env[LEASE_UNTIL_ENV]), tz=UTC).strftime("%Y-%m-%dT%H:%M:%SZ") + click.echo(f"Exported lease vars to GITHUB_ENV (owner={env[OWNER_ENV]}, until={until})") sys.exit(0) sys.exit(1) diff --git a/tests/unit/test_molecule_lease.py b/tests/unit/test_molecule_lease.py index 1b75840..f20f533 100644 --- a/tests/unit/test_molecule_lease.py +++ b/tests/unit/test_molecule_lease.py @@ -118,4 +118,6 @@ class TestStartDockerIntegration: ): result = runner.invoke(start_docker_main, ["--timeout", "1"]) assert result.exit_code == 0 - assert "Exported 2 lease vars" in result.output + assert "Exported lease vars to GITHUB_ENV" in result.output + assert "owner=run-7-job" in result.output + assert "until=" in result.output