fluxer/scripts/ci/ci_steps.py
2026-02-17 12:22:36 +00:00

216 lines
5.5 KiB
Python

#!/usr/bin/env python3
from __future__ import annotations
from dataclasses import dataclass
from datetime import datetime, timezone
from typing import Mapping
from ci_utils import write_github_output, write_github_summary
ADD_KNOWN_HOSTS_SCRIPT = """
set -euo pipefail
mkdir -p ~/.ssh
ssh-keyscan -H "${SERVER_IP}" >> ~/.ssh/known_hosts
"""
INSTALL_DOCKER_PUSSH_SCRIPT = """
set -euo pipefail
mkdir -p ~/.docker/cli-plugins
curl -fsSL https://raw.githubusercontent.com/psviderski/unregistry/v0.3.1/docker-pussh \
-o ~/.docker/cli-plugins/docker-pussh
chmod +x ~/.docker/cli-plugins/docker-pussh
"""
INSTALL_RCLONE_SCRIPT = """
set -euo pipefail
if ! command -v rclone >/dev/null 2>&1; then
curl -fsSL https://rclone.org/install.sh | sudo bash
fi
"""
def rclone_config_script(
*,
endpoint: str,
acl: str,
profile: str = "ovh",
env_auth: bool = True,
expand_vars: bool = False,
) -> str:
heredoc = "RCLONEEOF" if expand_vars else "'RCLONEEOF'"
env_auth_value = "true" if env_auth else "false"
lines = [
"set -euo pipefail",
"mkdir -p ~/.config/rclone",
f"cat > ~/.config/rclone/rclone.conf <<{heredoc}",
f"[{profile}]",
"type = s3",
"provider = Other",
f"env_auth = {env_auth_value}",
f"endpoint = {endpoint}",
f"acl = {acl}",
"RCLONEEOF",
]
return "\n".join(lines) + "\n"
def bot_user_id_script() -> str:
return (
"set -euo pipefail\n"
"echo \"user-id=$(gh api \"/users/${APP_SLUG}[bot]\" --jq .id)\" >> \"$GITHUB_OUTPUT\"\n"
)
def record_deploy_commit_script(*, include_env: bool, include_sentry: bool) -> str:
lines = [
"set -euo pipefail",
"sha=$(git rev-parse HEAD)",
"echo \"Deploying commit ${sha}\"",
]
if include_env:
lines.append("printf 'DEPLOY_SHA=%s\\n' \"$sha\" >> \"$GITHUB_ENV\"")
if include_sentry:
lines.extend(
[
"printf 'SENTRY_BUILD_SHA=%s\\n' \"$sha\" >> \"$GITHUB_ENV\"",
"printf 'SENTRY_BUILD_NUMBER=%s\\n' \"$GITHUB_RUN_NUMBER\" >> \"$GITHUB_ENV\"",
"printf 'SENTRY_BUILD_TIMESTAMP=%s\\n' \"$(date +%s)\" >> \"$GITHUB_ENV\"",
]
)
return "\n".join(lines) + "\n"
def set_build_timestamp_script(*, env_name: str = "BUILD_TIMESTAMP") -> str:
return (
"set -euo pipefail\n"
f"echo \"{env_name}=$(date -u +%s)\" >> \"$GITHUB_ENV\"\n"
)
@dataclass(frozen=True)
class ReleaseMetadata:
version: str
channel: str
source_ref: str
sha_short: str
timestamp: str
date_ymd: str
build_number: str
def build_release_metadata(
*,
version_input: str,
channel: str,
source_ref: str,
env: Mapping[str, str],
now: datetime | None = None,
) -> ReleaseMetadata:
run_number = env.get("GITHUB_RUN_NUMBER", "")
sha = env.get("GITHUB_SHA", "")
version = version_input or f"0.0.{run_number}"
instant = now or datetime.now(timezone.utc)
timestamp = instant.strftime("%Y-%m-%dT%H:%M:%SZ")
date_ymd = instant.strftime("%Y%m%d")
sha_short = sha[:7]
return ReleaseMetadata(
version=version,
channel=channel,
source_ref=source_ref,
sha_short=sha_short,
timestamp=timestamp,
date_ymd=date_ymd,
build_number=run_number,
)
def write_release_metadata(metadata: ReleaseMetadata) -> None:
write_github_output(
{
"version": metadata.version,
"channel": metadata.channel,
"source_ref": metadata.source_ref,
"sha_short": metadata.sha_short,
"timestamp": metadata.timestamp,
"date": metadata.date_ymd,
"build_number": metadata.build_number,
}
)
def build_release_summary(
*,
title: str,
channel: str,
version: str,
build_number: str,
sha: str,
sha_short: str,
timestamp: str,
source_ref: str,
build_result: str,
image_tags: str,
image_digest: str,
registry: str,
image_name: str,
date_ymd: str,
) -> str:
lines: list[str] = [
f"## {title}",
"",
f"channel: {channel}",
f"version: v{version}",
f"build: {build_number}",
f"sha: {sha} (short: {sha_short})",
f"time: {timestamp}",
f"source_ref: {source_ref}",
"",
f"build result: {build_result}",
"",
]
if build_result == "success":
lines.extend(
[
"tags:",
"```",
image_tags,
"```",
f"digest: `{image_digest}`",
"",
]
)
if channel == "nightly":
lines.extend(
[
"pull:",
"```bash",
f"docker pull {registry}/{image_name}:nightly",
f"docker pull {registry}/{image_name}:nightly-{date_ymd}",
f"docker pull {registry}/{image_name}:sha-{sha_short}",
"```",
]
)
else:
lines.extend(
[
"pull:",
"```bash",
f"docker pull {registry}/{image_name}:stable",
f"docker pull {registry}/{image_name}:latest",
f"docker pull {registry}/{image_name}:v{version}",
"```",
]
)
return "\n".join(lines) + "\n"
def write_release_summary(summary: str, *, build_result: str) -> None:
write_github_summary(summary)
if build_result == "failure":
raise SystemExit(1)