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
21 changes: 21 additions & 0 deletions .codex/environments/swift-package.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copy to .codex/environments/swift-package.toml and adjust action names if needed.
version = 1
name = "swift-package"

[setup]
script = "swift package resolve"

[[actions]]
name = "resolve"
icon = "tool"
command = "swift package resolve"

[[actions]]
name = "build"
icon = "tool"
command = "swift build"

[[actions]]
name = "test"
icon = "tool"
command = "swift test"
1 change: 1 addition & 0 deletions .github/workflows/validate-repo-maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ jobs:
name: validate
runs-on: macos-26
steps:
# This is a validated floor, not a ceiling; update to newer stable official versions when validated.
- uses: actions/checkout@v6.0.2
- name: Report selected Xcode
run: xcode-select --print-path
Expand Down
44 changes: 44 additions & 0 deletions scripts/repo-maintenance/lib/common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,50 @@ positive_integer_or_default() {
esac
}

is_semver_prerelease_tag() {
tag_name="$1"
case "$tag_name" in
v[0-9]*.[0-9]*.[0-9]*-*)
return 0
;;
*)
return 1
;;
esac
}

expected_github_prerelease_value() {
tag_name="$1"
if is_semver_prerelease_tag "$tag_name"; then
printf '%s\n' "true"
else
printf '%s\n' "false"
fi
}

github_release_create_prerelease_flag() {
tag_name="$1"
if is_semver_prerelease_tag "$tag_name"; then
printf '%s\n' "--prerelease"
fi
}

verify_github_release_prerelease_metadata() {
tag_name="$1"
expected_value="$(expected_github_prerelease_value "$tag_name")"

actual_value="$(gh release view "$tag_name" --json isPrerelease --jq .isPrerelease 2>/dev/null || true)"
case "$actual_value" in
true|false)
;;
*)
die "GitHub release $tag_name exists, but its prerelease metadata was not readable. Confirm gh can read release JSON metadata before rerunning release.sh."
;;
esac

[ "$actual_value" = "$expected_value" ] || die "GitHub release $tag_name prerelease metadata mismatch: tag implies isPrerelease=$expected_value but GitHub reports isPrerelease=$actual_value. Update the release metadata or delete and recreate the release before rerunning release.sh."
}

github_wait_timeout() {
value="$1"
default_timeout="$(positive_integer_or_default "${REPO_MAINTENANCE_GH_WAIT_TIMEOUT_SECONDS:-120}" 120)"
Expand Down
21 changes: 13 additions & 8 deletions scripts/repo-maintenance/release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,15 @@ ensure_branch_release_context() {
run_version_bump() {
release_version="${RELEASE_TAG#v}"
version_bump_script="$SELF_DIR/version-bump.sh"
version_bump_subject="release: bump versions for $RELEASE_TAG"
head_subject="$(git -C "$REPO_ROOT" log -1 --format=%s 2>/dev/null || true)"

if [ "$skip_version_bump" = "true" ]; then
log "Skipping repo version bump because --skip-version-bump was requested."
return 0
fi

if git -C "$REPO_ROOT" log --format=%s "$base_branch"..HEAD | grep -Fxq "$version_bump_subject"; then
log "Version bump commit for $RELEASE_TAG is already on this branch; continuing the release resume path."
if [ "$head_subject" = "release: bump versions for $RELEASE_TAG" ]; then
log "Version bump commit for $RELEASE_TAG is already at HEAD; continuing the release resume path."
return 0
fi

Expand Down Expand Up @@ -287,8 +287,8 @@ wait_for_initial_pr_checks() {
log "Waiting up to ${timeout_seconds}s for GitHub to report initial checks on PR #$pr_number."

while :; do
last_state="$(gh pr view "$pr_number" --json statusCheckRollup --jq '[.statusCheckRollup[]? | .name + ":" + ((.status // .state // .conclusion // "") | ascii_downcase)] | join(", ")' 2>/dev/null || printf 'no checks reported')"
check_count="$(gh pr view "$pr_number" --json statusCheckRollup --jq '(.statusCheckRollup // []) | length' 2>/dev/null || printf '0')"
last_state="$(gh pr checks "$pr_number" --json name,state,workflow --jq 'map(.name + ":" + .state) | join(", ")' 2>/dev/null || printf 'no checks reported')"
check_count="$(gh pr checks "$pr_number" --json name,state,workflow --jq 'length' 2>/dev/null || printf '0')"
case "$check_count" in
''|*[!0-9]*)
check_count="0"
Expand Down Expand Up @@ -349,7 +349,7 @@ check_pr_comments() {
wait_for_pr_review_state "$pr_number"

review_decision="$(gh pr view "$pr_number" --json reviewDecision --jq '.reviewDecision // ""')"
comment_count="$(gh pr view "$pr_number" --json comments,reviews --jq '([.comments[]?, (.reviews[]? | select(.state == "COMMENTED" or ((.body // "") | length > 0)))] | length)')"
comment_count="$(gh pr view "$pr_number" --json comments,reviews --jq '([.comments[]?, (.reviews[]? | select(.state == "COMMENTED"))] | length)')"

if [ "$review_decision" = "CHANGES_REQUESTED" ]; then
gh pr view "$pr_number" --comments
Expand Down Expand Up @@ -398,18 +398,23 @@ create_github_release() {
fi

if [ "$REPO_MAINTENANCE_DRY_RUN" = "true" ]; then
log "Would create a GitHub release for $RELEASE_TAG with gh release create --verify-tag."
prerelease_flag="$(github_release_create_prerelease_flag "$RELEASE_TAG")"
log "Would create a GitHub release for $RELEASE_TAG with gh release create --verify-tag${prerelease_flag:+ $prerelease_flag}."
return 0
fi

if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
verify_github_release_prerelease_metadata "$RELEASE_TAG"
log "GitHub release $RELEASE_TAG already exists."
return 0
fi

gh release create "$RELEASE_TAG" --verify-tag --generate-notes
prerelease_flag="$(github_release_create_prerelease_flag "$RELEASE_TAG")"
# shellcheck disable=SC2086
gh release create "$RELEASE_TAG" --verify-tag --generate-notes $prerelease_flag
log "Created GitHub release $RELEASE_TAG."
wait_for_github_release "$RELEASE_TAG"
verify_github_release_prerelease_metadata "$RELEASE_TAG"
}

cleanup_merged_branches() {
Expand Down
9 changes: 7 additions & 2 deletions scripts/repo-maintenance/release/40-github-release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@ if ! command -v gh >/dev/null 2>&1; then
fi

if [ "${REPO_MAINTENANCE_DRY_RUN:-false}" = "true" ]; then
log "Would create a GitHub release for $RELEASE_TAG with gh release create --verify-tag."
prerelease_flag="$(github_release_create_prerelease_flag "$RELEASE_TAG")"
log "Would create a GitHub release for $RELEASE_TAG with gh release create --verify-tag${prerelease_flag:+ $prerelease_flag}."
exit 0
fi

if gh release view "$RELEASE_TAG" >/dev/null 2>&1; then
verify_github_release_prerelease_metadata "$RELEASE_TAG"
log "GitHub release $RELEASE_TAG already exists."
exit 0
fi

gh release create "$RELEASE_TAG" --verify-tag --generate-notes
prerelease_flag="$(github_release_create_prerelease_flag "$RELEASE_TAG")"
# shellcheck disable=SC2086
gh release create "$RELEASE_TAG" --verify-tag --generate-notes $prerelease_flag
log "Created GitHub release $RELEASE_TAG."
wait_for_github_release "$RELEASE_TAG"
verify_github_release_prerelease_metadata "$RELEASE_TAG"
Loading