Skip to content

Unify local and GitHub release preflight validation - #34

Merged
JovaniPink merged 1 commit into
masterfrom
agent/unify-release-preflight
Jul 30, 2026
Merged

Unify local and GitHub release preflight validation#34
JovaniPink merged 1 commit into
masterfrom
agent/unify-release-preflight

Conversation

@JovaniPink

@JovaniPink JovaniPink commented Jul 29, 2026

Copy link
Copy Markdown
Owner

Summary

Make scripts/release_preflight.py the single implementation for release validation in both local development and GitHub Actions.

The GitHub Release workflow now delegates its complete validation phase to the existing script, and a new manual workflow provides a safe v0.7.0 dry run against master. Repository contract tests ensure the workflows continue to invoke the script instead of reintroducing copied gate commands.

Why

The release workflow previously duplicated the script's tag/version checks, target-commit verification, test commands, static analysis, package build, and installed-wheel validation. That created two independently maintained release paths: local preflight could pass while GitHub ran a stale or different command set.

This change makes the Python script authoritative. GitHub Actions owns only environment setup, credential checks, delegation to the script, and, only in the published-release workflow, the final upload.

Scope

  • Replace duplicated validation steps in .github/workflows/release.yaml with one call to scripts/release_preflight.py.
  • Preserve the existing release-tag argument and explicit comparison with origin/master.
  • Add .github/workflows/release_preflight.yaml with workflow_dispatch:
    • checks out master with full history and recursive submodules;
    • defaults the expected tag to v0.7.0;
    • runs the shared script against HEAD and origin/master;
    • performs no publish step and requires no PyPI token.
  • Add workflow-contract tests that assert both workflows delegate exactly once to the shared script and do not duplicate script-owned quality-gate commands.
  • Document the shared/manual path in README and CHANGELOG.

Non-scope

  • No changes to runtime statechart behavior, SCXML execution, public Python APIs, dependencies, or package metadata.
  • No change to scripts/release_preflight.py gate selection or ordering.
  • No change to the pull-request workflow.
  • No tag creation, GitHub Release creation, PyPI upload, secret mutation, or other release-side effect.
  • No change to the PYPI_TOKEN guard or poetry publish command in the actual release workflow.

Behavior and release boundary

The manual workflow is validation-only. It always checks out master, verifies the supplied expected tag against pyproject.toml, confirms HEAD matches origin/master, runs the complete preflight, builds artifacts, and validates the wheel without publishing.

The existing GitHub Release workflow remains the only publishing path. It still requires a non-draft, non-prerelease published GitHub Release and a configured PYPI_TOKEN; only after the shared preflight succeeds does it execute poetry publish.

Merging this PR changes repository workflows, contract tests, and supporting documentation only. It does not create a tag, publish 0.7.0, or mutate PyPI.

Validation evidence

Executed locally on branch head 8930bb5dda23:

poetry run python scripts/release_preflight.py v0.7.0 \
  --target-ref HEAD \
  --master-ref HEAD

Release target verified: v0.7.0 (HEAD -> 8930bb5dda23) matches HEAD.
poetry check --lock: passed
415 primary tests passed
54 SCXML CI tests passed
Ruff format: 67 files already formatted
Ruff lint: passed
MyPy: no issues in 22 source files
sdist and wheel built
isolated installed-wheel smoke: passed

Using HEAD for both refs is intentional for pre-merge branch validation: it exercises every shared gate against the proposed commit without pretending the branch is already origin/master. The merged manual and publish workflows retain the real origin/master comparison.

Additional focused evidence:

poetry run python -m pytest tests/test_release_workflows.py -q
2 passed

ruby -e 'require "yaml"; ARGV.each { |path| YAML.parse_file(path) }' \
  .github/workflows/release.yaml \
  .github/workflows/release_preflight.yaml
passed

git diff --check origin/master...HEAD
passed

GitHub Actions Run tests and code quality run #53 also passed on the exact head commit.

Consistency guarantee

tests/test_release_workflows.py participates in the primary suite that the preflight script itself runs. It checks that:

  • each release workflow invokes scripts/release_preflight.py exactly once;
  • the publish workflow supplies the GitHub Release tag as both the expected tag and target ref;
  • the manual workflow defaults to v0.7.0, checks out master, and validates HEAD against origin/master;
  • neither workflow duplicates metadata, pytest, SCXML, Ruff, MyPy, build, or distribution-validation commands;
  • only the actual release workflow contains poetry publish.

Risks and mitigations

  • GitHub Actions quoting/ref behavior: The publish workflow passes the release tag through an environment variable; the manual workflow passes the typed dispatch input. Contract tests pin both command shapes, while the script performs the authoritative Git resolution.
  • Manual workflow uses a version-specific default: v0.7.0 is intentional for this release. A future version bump must update the workflow default and corresponding contract expectation explicitly.
  • Textual workflow contract checks: These tests intentionally protect ownership and command delegation without adding a runtime YAML dependency. GitHub remains the final validator of Actions-specific schema.
  • Full checkout cost: Both workflows retain fetch-depth: 0 because the script must resolve and compare release/master refs; recursive submodules remain required for the SCXML suite.

Rollback

Revert commit 8930bb5. That restores the prior inline release validation, removes the manual preflight workflow and contract tests, and removes the accompanying documentation. No package or data rollback is required because this PR has no runtime or publishing side effects by itself.

Review focus

  1. Confirm the published-release invocation resolves the release tag and origin/master exactly as the script expects.
  2. Confirm the manual workflow is strictly dry-run and always checks out master.
  3. Confirm the PYPI_TOKEN check and publish boundary remain unchanged.
  4. Confirm the contract tests prevent duplicated release gates without coupling to harmless YAML formatting.

Diff-size justification

The net change is 114 insertions and 50 deletions across five files. Most additions are the explicit manual workflow and focused contract tests; the release workflow itself becomes substantially smaller by deleting duplicated Python and shell commands. Keeping workflow, test, and documentation changes together makes the ownership boundary reviewable in one PR.

Unresolved decisions

None for v0.7.0. The next release should intentionally update the manual workflow's default expected tag and its contract test.

@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@JovaniPink
JovaniPink marked this pull request as ready for review July 30, 2026 01:00
@gemini-code-assist

Copy link
Copy Markdown

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@JovaniPink
JovaniPink merged commit ef7fbc7 into master Jul 30, 2026
4 checks passed
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