Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 16 additions & 6 deletions .github/scripts/check-release-intent.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,16 @@ release_pattern='^((feat|fix|perf|refactor|revert)(\([a-z0-9][a-z0-9._/-]*\))?(!
release_pr_pattern='^chore\(release\): .+'

is_release_pr=false
if [[ "${subject}" =~ ${release_pr_pattern} && "${head_branch}" == release/* ]]; then
is_release_pr=true
is_generated_release_branch=false
case "${head_branch}" in
release/* | release-please--branches--*)
is_generated_release_branch=true
;;
esac
if [[ "${subject}" =~ ${release_pr_pattern} ]]; then
if [[ "${is_generated_release_branch}" == true || "${head_branch}" == "main" ]]; then
is_release_pr=true
fi
fi

package_versions_from_ref() {
Expand Down Expand Up @@ -113,8 +121,9 @@ Package and release-please manifest version bumps are release owned. Run the
Release workflow with prepare-release-pr and merge the generated release PR
instead of changing versions in a feature/fix PR.

Generated release PRs are allowed only from release/* branches and
when their title starts with chore(release):.
Generated release PRs are allowed only from generated release branches, and
their main merge commits are allowed only when the subject starts with
chore(release):.

Received:
${subject}
Expand Down Expand Up @@ -167,8 +176,9 @@ Use one of these Conventional Commit types in the PR title:
Breaking changes may use any type with !, for example:
chore!: remove a deprecated API

Generated release PRs are exempt only from release/* branches and when
their title starts with chore(release):.
Generated release PRs are exempt only from generated release branches, and
their main merge commits are exempt only when the subject starts with
chore(release):.

Docs, README, CI, tests, examples, xtask-only maintenance, source-checkout
scripts, and other repository-only changes can keep non-release types such as
Expand Down
5 changes: 5 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@ jobs:
- name: Set up Moon
uses: ./.github/actions/setup-moon

- name: Set up Rust
uses: ./.github/actions/setup-rust
with:
cache-save-if: "true"

- name: Validate release metadata
run: |
tools/release/release.py check
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1 @@
7496ad92c25f4d01d0cc3db01ca83c2841f5bdeb1dd8c45b152458dea6cb0bc3
7b87d6512c9f965d4147dd3027f20ead7b21b9dc34cc704583a1ce675df5d18e
48 changes: 48 additions & 0 deletions tools/release/sync_release_pr.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import argparse
import json
import re
import subprocess
import sys
import tomllib
from dataclasses import dataclass
Expand Down Expand Up @@ -35,6 +36,10 @@
TOML_TABLE_RE = re.compile(r"^\s*\[([A-Za-z0-9_.-]+)\]\s*(?:#.*)?$")
PNPM_NODE_DIRECT_KEY_RE = re.compile(r"^(\s*)'(@oliphaunt/node-direct-[^']+)':\s*$")
PNPM_SPECIFIER_RE = re.compile(r"^(\s*specifier:\s*)(\S+)(\s*)$")
ASSET_INPUT_FINGERPRINT_PATH = ROOT / "src/runtimes/liboliphaunt/wasix/assets/generated/asset-inputs.sha256"
ASSET_INPUT_FINGERPRINT_MISMATCH_RE = re.compile(
r"committed asset input fingerprint must be '([0-9a-f]+)', got '([0-9a-f]+)'"
)


@dataclass(frozen=True)
Expand Down Expand Up @@ -427,6 +432,48 @@ def sync_lockfiles(changes: list[Change], *, write: bool) -> None:
sync_lockfile(lockfile, versions, changes, write=write)


def read_optional_text(path: Path) -> str | None:
if not path.exists():
return None
return path.read_text(encoding="utf-8")


def command_output_for_error(result: subprocess.CompletedProcess[str]) -> str:
parts = [part.strip() for part in (result.stdout, result.stderr) if part.strip()]
return "\n".join(parts) or f"exit {result.returncode}"


def sync_asset_input_fingerprint(changes: list[Change], *, write: bool) -> None:
command = ["cargo", "run", "-p", "xtask", "--", "assets", "input-fingerprint"]
if write:
command.append("--write")

before = read_optional_text(ASSET_INPUT_FINGERPRINT_PATH)
result = subprocess.run(command, cwd=ROOT, text=True, capture_output=True, check=False)
output = command_output_for_error(result)

if result.returncode != 0:
mismatch = ASSET_INPUT_FINGERPRINT_MISMATCH_RE.search(output)
if not write and mismatch is not None:
changes.append(
Change(
ASSET_INPUT_FINGERPRINT_PATH,
f"{mismatch.group(1)} -> {mismatch.group(2)}",
)
)
return
fail(f"`{' '.join(command)}` failed:\n{output}")

if not write:
return

after = read_optional_text(ASSET_INPUT_FINGERPRINT_PATH)
if before != after:
old = before.strip() if before is not None else "<missing>"
new = after.strip() if after is not None else "<missing>"
changes.append(Change(ASSET_INPUT_FINGERPRINT_PATH, f"{old} -> {new}"))


def main() -> int:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--check", action="store_true", help="fail instead of writing updates")
Expand All @@ -439,6 +486,7 @@ def main() -> int:
sync_pnpm_node_direct_optional_specifiers(changes, write=write)
sync_cargo_path_dependency_pins(changes, write=write)
sync_lockfiles(changes, write=write)
sync_asset_input_fingerprint(changes, write=write)

if not changes:
print("release PR derived files are in sync")
Expand Down
Loading