86 lines
2.7 KiB
Python
86 lines
2.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Resolve and validate the git tag to deploy.
|
|
|
|
Shared between staging and production deployments. Ensures a concrete
|
|
git tag is used — never a moving branch ref — so deployments are
|
|
reproducible and rollback-friendly.
|
|
|
|
Usage in workflows::
|
|
|
|
# Production (tag required)
|
|
python -m devx.ci.validate_deploy_ref --tag "$TAG" --github-output
|
|
|
|
# Staging force-deploy (tag required)
|
|
python -m devx.ci.validate_deploy_ref --tag "$TAG" --github-output
|
|
|
|
# Staging PR-triggered (PR SHA is already concrete, no tag needed)
|
|
python -m devx.ci.validate_deploy_ref --allow-empty --github-output
|
|
|
|
Writes ``deploy-ref=<tag>`` to ``$GITHUB_OUTPUT`` when ``--github-output``
|
|
is passed, otherwise prints the ref to stdout.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import os
|
|
import subprocess # nosec B404
|
|
import sys
|
|
|
|
import click
|
|
|
|
from devx.i18n import _
|
|
|
|
|
|
@click.command()
|
|
@click.option("--tag", default="", help=_("Git tag to deploy (e.g. v0.28.1)."))
|
|
@click.option(
|
|
"--allow-empty",
|
|
is_flag=True,
|
|
help=_("Allow empty tag (PR mode where SHA is concrete)."),
|
|
)
|
|
@click.option(
|
|
"--github-output",
|
|
is_flag=True,
|
|
help=_("Write deploy-ref to $GITHUB_OUTPUT file."),
|
|
)
|
|
def main(tag: str, allow_empty: bool, github_output: bool) -> None:
|
|
"""Resolve and validate the deploy ref, exiting non-zero on failure."""
|
|
if not tag:
|
|
if not allow_empty:
|
|
click.echo(
|
|
"::error::No tag specified. Deployments require a concrete git tag "
|
|
"(e.g. v0.28.1). Use --allow-empty only for PR-triggered staging deploys "
|
|
"where the checkout SHA is already concrete.",
|
|
err=True,
|
|
)
|
|
sys.exit(1)
|
|
ref = ""
|
|
click.echo("No tag specified — using checkout ref (PR mode).")
|
|
else:
|
|
result = subprocess.run( # nosec B603, B607
|
|
["git", "rev-parse", "-q", "--verify", f"refs/tags/{tag}"],
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
if result.returncode != 0:
|
|
click.echo(f"::error::Tag '{tag}' does not exist in the repository.", err=True)
|
|
sys.exit(1)
|
|
ref = tag
|
|
commit = result.stdout.strip()[:8]
|
|
click.echo(f"Deploying tag: {tag} (commit {commit})")
|
|
|
|
if github_output:
|
|
github_output_path = os.environ.get("GITHUB_OUTPUT")
|
|
if not github_output_path:
|
|
click.echo("::error::GITHUB_OUTPUT environment variable not set.", err=True)
|
|
sys.exit(1)
|
|
with open(github_output_path, "a") as f:
|
|
f.write(f"deploy-ref={ref}\n")
|
|
else:
|
|
click.echo(ref)
|
|
|
|
|
|
if __name__ == "__main__": # pragma: no cover
|
|
main()
|