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
18 changes: 5 additions & 13 deletions scripts/bring_up_to_date.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,15 +66,9 @@ compose_prompt() {

PROMPT="$(compose_prompt)"

# --- Open a URL in the default browser (best-effort, never fails the script)
open_url() {
local url="$1"
case "$(uname -s)" in
Darwin) open "$url" ;;
Linux) xdg-open "$url" ;;
MINGW*|MSYS*|CYGWIN*) cmd.exe /c start "$url" ;;
esac 2>/dev/null || true
}
# --- Shared PR prompt helpers ----------------------------------------------
# shellcheck source=lib/pr_prompt.sh
source "${SCRIPT_DIR}/lib/pr_prompt.sh"

# --- Allowed tools ----------------------------------------------------------
# Read/Edit/Write for file changes, Bash for just commands and git, WebFetch for fetching upstream
Expand All @@ -92,11 +86,9 @@ if [[ "$EXECUTE" == true ]]; then
--allowed-tools ${ALLOWED_TOOLS})"
echo "$OUTPUT"

# Try to extract a PR URL from the output and open it
PR_URL="$(echo "$OUTPUT" | grep -oE 'https://github\.com/[^ ]+/pull/[0-9]+' | head -1 || true)"
PR_URL="$(pr_prompt_extract_url "$OUTPUT")"
if [[ -n "$PR_URL" ]]; then
echo "Opening PR: ${PR_URL}"
open_url "$PR_URL"
pr_prompt_finalize "$PR_URL"
fi
else
echo "=== DRY RUN ==="
Expand Down
24 changes: 22 additions & 2 deletions scripts/bring_up_to_date_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOWNSTREAM_FILE="${SCRIPT_DIR}/downstream.txt"
BRING_UP="${SCRIPT_DIR}/bring_up_to_date.sh"

# shellcheck source=lib/pr_prompt.sh
source "${SCRIPT_DIR}/lib/pr_prompt.sh"
# Children must not prompt — only this driver does, once, at the end.
export PR_PROMPT_SUPPRESS=1

if [[ ! -f "$DOWNSTREAM_FILE" ]]; then
echo "Error: ${DOWNSTREAM_FILE} not found" >&2
exit 1
Expand All @@ -20,6 +25,7 @@ echo "Clone directory: ${WORK_DIR}"
PIDS=()
REPOS=()
CLONE_DIRS=()
LOG_FILES=()

while IFS= read -r repo_url; do
# Skip empty lines and comments
Expand All @@ -28,15 +34,19 @@ while IFS= read -r repo_url; do
# Derive repo name from URL (e.g. https://github.com/sksizer/rust-dir-aspect/ -> rust-dir-aspect)
REPO_NAME="$(basename "${repo_url%/}")"
CLONE_PATH="${WORK_DIR}/${REPO_NAME}"
LOG_FILE="${WORK_DIR}/${REPO_NAME}.log"

echo "Cloning: ${repo_url} -> ${CLONE_PATH}"
(
git clone --quiet "$repo_url" "$CLONE_PATH"
bash "$BRING_UP" ${ARGS[@]+"${ARGS[@]}"} "$CLONE_PATH"
{
git clone --quiet "$repo_url" "$CLONE_PATH"
bash "$BRING_UP" ${ARGS[@]+"${ARGS[@]}"} "$CLONE_PATH"
} 2>&1 | tee "$LOG_FILE"
) &
PIDS+=($!)
REPOS+=("$repo_url")
CLONE_DIRS+=("$CLONE_PATH")
LOG_FILES+=("$LOG_FILE")
done < "$DOWNSTREAM_FILE"

# Wait for all and report results
Expand All @@ -53,6 +63,16 @@ done
echo "---"
echo "Finished: $((${#PIDS[@]} - FAILED))/${#PIDS[@]} succeeded"

# Collect PR URLs from each per-repo log and prompt once at the end.
PR_URLS=()
for LOG_FILE in "${LOG_FILES[@]}"; do
[[ -f "$LOG_FILE" ]] || continue
URL="$(pr_prompt_extract_url "$(cat "$LOG_FILE")")"
[[ -n "$URL" ]] && PR_URLS+=("$URL")
done
unset PR_PROMPT_SUPPRESS
pr_prompt_finalize "${PR_URLS[@]}"

# Clean up clones
echo "Cleaning up: ${WORK_DIR}"
rm -rf "$WORK_DIR"
Expand Down
18 changes: 5 additions & 13 deletions scripts/cargo_update.sh
Original file line number Diff line number Diff line change
Expand Up @@ -74,15 +74,9 @@ compose_prompt() {

PROMPT="$(compose_prompt)"

# --- Open a URL in the default browser (best-effort, never fails the script)
open_url() {
local url="$1"
case "$(uname -s)" in
Darwin) open "$url" ;;
Linux) xdg-open "$url" ;;
MINGW*|MSYS*|CYGWIN*) cmd.exe /c start "$url" ;;
esac 2>/dev/null || true
}
# --- Shared PR prompt helpers ----------------------------------------------
# shellcheck source=lib/pr_prompt.sh
source "${SCRIPT_DIR}/lib/pr_prompt.sh"

# --- Allowed tools ----------------------------------------------------------
ALLOWED_TOOLS="Read Edit Write Bash"
Expand All @@ -105,12 +99,10 @@ if [[ "$EXECUTE" == true ]]; then
echo "$OUTPUT"
log "${C_DIM}──── end output ────${C_RESET}"

# Try to extract a PR URL from the output and open it
PR_URL="$(echo "$OUTPUT" | grep -oE 'https://github\.com/[^ ]+/pull/[0-9]+' | head -1 || true)"
PR_URL="$(pr_prompt_extract_url "$OUTPUT")"
if [[ -n "$PR_URL" ]]; then
log "${C_GREEN}✔ PR for ${C_MAGENTA}${LABEL}${C_GREEN}:${C_RESET} ${C_BOLD}${PR_URL}${C_RESET}"
log "Opening in browser…"
open_url "$PR_URL"
pr_prompt_finalize "$PR_URL"
else
log "${C_YELLOW}No PR URL detected in output for ${LABEL}${C_RESET}"
fi
Expand Down
18 changes: 18 additions & 0 deletions scripts/cargo_update_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOWNSTREAM_FILE="${SCRIPT_DIR}/downstream.txt"
CARGO_UPDATE="${SCRIPT_DIR}/cargo_update.sh"

# shellcheck source=lib/pr_prompt.sh
source "${SCRIPT_DIR}/lib/pr_prompt.sh"
# Children must not prompt — only this driver does, once, at the end.
export PR_PROMPT_SUPPRESS=1

# --- Colors (disabled when not a tty or NO_COLOR is set) --------------------
if [[ -t 1 && -z "${NO_COLOR:-}" ]]; then
C_RESET=$'\033[0m'
Expand Down Expand Up @@ -105,6 +110,19 @@ else
log "${C_YELLOW}$((${#PIDS[@]} - FAILED))/${#PIDS[@]} succeeded, ${C_RED}${FAILED} failed${C_RESET}"
fi

# Collect PR URLs from every per-repo log so we can prompt once at the end.
PR_URLS=()
for i in "${!PIDS[@]}"; do
LOG_FILE="${WORK_DIR}/${REPO_NAMES[$i]}.log"
[[ -f "$LOG_FILE" ]] || continue
URL="$(pr_prompt_extract_url "$(cat "$LOG_FILE")")"
[[ -n "$URL" ]] && PR_URLS+=("$URL")
done

# Unset suppression so the prompt actually fires for THIS (top-level) script.
unset PR_PROMPT_SUPPRESS
pr_prompt_finalize "${PR_URLS[@]}"

# Clean up clones
log "Cleaning up: ${C_DIM}${WORK_DIR}${C_RESET}"
rm -rf "$WORK_DIR"
Expand Down
58 changes: 58 additions & 0 deletions scripts/lib/pr_prompt.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
#!/usr/bin/env bash
# Shared helpers for collecting PR URLs and prompting the user whether to open
# them at the end of a script run. Source this file — don't execute it.
#
# Environment:
# PR_PROMPT_SUPPRESS=1 — disable the interactive prompt entirely. Parent
# drivers (e.g. *_all.sh) set this when invoking
# single-repo scripts so only the outermost script
# asks. Also honored by CI via: PR_PROMPT_SUPPRESS=1

# Open a URL in the default browser (best-effort, never fails the caller).
pr_prompt__open_url() {
local url="$1"
case "$(uname -s)" in
Darwin) open "$url" ;;
Linux) xdg-open "$url" ;;
MINGW*|MSYS*|CYGWIN*) cmd.exe /c start "$url" ;;
esac 2>/dev/null || true
}

# Extract the first GitHub PR URL from a blob of text. Prints nothing if none.
pr_prompt_extract_url() {
grep -oE 'https://github\.com/[^[:space:]]+/pull/[0-9]+' <<<"$1" | head -1 || true
}

# Given a list of PR URLs (one per argument), show them and — if stdin is a
# TTY and PR_PROMPT_SUPPRESS is unset — ask whether to open them all now.
# No-op if no URLs are passed.
pr_prompt_finalize() {
local urls=("$@")
[[ ${#urls[@]} -eq 0 ]] && return 0

echo
echo "PR URL(s):"
for url in "${urls[@]}"; do
echo " $url"
done

if [[ -n "${PR_PROMPT_SUPPRESS:-}" ]]; then
return 0
fi
if [[ ! -t 0 || ! -t 1 ]]; then
echo "(non-interactive; skipping open prompt)"
return 0
fi

echo
local reply=""
read -r -p "Open $( [[ ${#urls[@]} -gt 1 ]] && echo "all ${#urls[@]} PRs" || echo "PR" ) in browser now? [y/N] " reply || return 0
case "$reply" in
y|Y|yes|YES)
for url in "${urls[@]}"; do
pr_prompt__open_url "$url"
done
;;
*) ;;
esac
}
17 changes: 5 additions & 12 deletions scripts/template_backport.sh
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,9 @@ compose_prompt() {
}
PROMPT="$(compose_prompt)"

# --- Open a URL in the default browser (best-effort) -----------------------
open_url() {
local url="$1"
case "$(uname -s)" in
Darwin) open "$url" ;;
Linux) xdg-open "$url" ;;
MINGW*|MSYS*|CYGWIN*) cmd.exe /c start "$url" ;;
esac 2>/dev/null || true
}
# --- Shared PR prompt helpers ----------------------------------------------
# shellcheck source=lib/pr_prompt.sh
source "${SCRIPT_DIR}/lib/pr_prompt.sh"

# --- Allowed tools ----------------------------------------------------------
# Backport mode: Claude must edit files, run checks, and create a PR.
Expand All @@ -91,10 +85,9 @@ if [[ "$EXECUTE" == true ]]; then
--allowed-tools ${ALLOWED_TOOLS})"
echo "$OUTPUT"

PR_URL="$(echo "$OUTPUT" | grep -oE 'https://github\.com/[^ ]+/pull/[0-9]+' | head -1 || true)"
PR_URL="$(pr_prompt_extract_url "$OUTPUT")"
if [[ -n "$PR_URL" ]]; then
echo "Opening PR: ${PR_URL}"
open_url "$PR_URL"
pr_prompt_finalize "$PR_URL"
else
echo "No PR opened (no candidates, or run was a no-op)."
fi
Expand Down
16 changes: 16 additions & 0 deletions scripts/template_backport_all.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,11 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DOWNSTREAM_FILE="${SCRIPT_DIR}/downstream.txt"
TEMPLATE_BACKPORT="${SCRIPT_DIR}/template_backport.sh"

# shellcheck source=lib/pr_prompt.sh
source "${SCRIPT_DIR}/lib/pr_prompt.sh"
# Children must not prompt — only this driver does, once, at the end.
export PR_PROMPT_SUPPRESS=1

if [[ ! -f "$DOWNSTREAM_FILE" ]]; then
echo "Error: ${DOWNSTREAM_FILE} not found" >&2
exit 1
Expand Down Expand Up @@ -57,4 +62,15 @@ echo
echo "---"
echo "Finished: $((${#PIDS[@]} - FAILED))/${#PIDS[@]} succeeded"
echo "Work dir left at: ${WORK_DIR}"

# Collect PR URLs from each per-repo log and prompt once at the end.
PR_URLS=()
for LOG_FILE in "${LOG_FILES[@]}"; do
[[ -f "$LOG_FILE" ]] || continue
URL="$(pr_prompt_extract_url "$(cat "$LOG_FILE")")"
[[ -n "$URL" ]] && PR_URLS+=("$URL")
done
unset PR_PROMPT_SUPPRESS
pr_prompt_finalize "${PR_URLS[@]}"

exit $FAILED
Loading