diff --git a/.claude/skills/ci-test-review/open-cc-ci-pr.sh b/.claude/skills/ci-test-review/open-cc-ci-pr.sh new file mode 100755 index 0000000..0235961 --- /dev/null +++ b/.claude/skills/ci-test-review/open-cc-ci-pr.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash +# ci-test-review :: open/update a PR on recipe-maintainers/cc-ci from the current branch +# -------------------------------------------------------------------------------------- +# Run from a dedicated cc-ci clone on the branch you want to PR. +# Optional env: +# TITLE=... override PR title (defaults to latest commit subject) +# BODY=... PR body +# BODY_FILE=... read body from file instead of BODY +# BASE=main base branch (default: main) +# REVIEWERS=trav,notplants +set -o errexit -o nounset -o pipefail + +TESTENV="${TESTENV:-/srv/cc-ci/.testenv}" +set -a; . "$TESTENV"; set +a +: "${GITEA_USERNAME:?}" +: "${GITEA_PASSWORD:?}" +: "${GITEA_URL:?}" + +git rev-parse --is-inside-work-tree >/dev/null + +repo_root="$(git rev-parse --show-toplevel)" +cd "$repo_root" + +branch="$(git rev-parse --abbrev-ref HEAD)" +[ "$branch" != "HEAD" ] || { echo "ERROR: detached HEAD; check out a branch first" >&2; exit 1; } +[ "$branch" != "main" ] || { echo "ERROR: refuse to open PR from main; use a dedicated branch" >&2; exit 1; } + +base="${BASE:-main}" +title="${TITLE:-$(git log -1 --pretty=%s)}" +if [ -n "${BODY_FILE:-}" ]; then + body="$(<"${BODY_FILE}")" +else + body="${BODY:-}" +fi + +if [ -z "$body" ]; then + commits="$(git log --pretty='- %h %s' "origin/${base}..HEAD" 2>/dev/null || git log --pretty='- %h %s' -5)" + body="cc-ci test update PR.\n\nCommits on top of ${base}:\n\n${commits}\n\nNOT merged — for operator review." +fi + +IFS=',' read -r -a reviewers <<< "${REVIEWERS:-trav,notplants}" +reviewers_json="$(printf '%s\n' "${reviewers[@]}" | jq -R . | jq -s 'map(select(length > 0))')" + +api="https://${GITEA_URL}/api/v1" +auth=(-u "${GITEA_USERNAME}:${GITEA_PASSWORD}") +payload="$(jq -n \ + --arg title "$title" \ + --arg body "$body" \ + --arg head "$branch" \ + --arg base "$base" \ + --argjson reviewers "$reviewers_json" \ + '{title:$title, body:$body, head:$head, base:$base, reviewers:$reviewers}')" + +resp="$(mktemp)" +code="$({ curl -sS -o "$resp" -w "%{http_code}" "${auth[@]}" \ + -H "Content-Type: application/json" \ + -X POST "${api}/repos/recipe-maintainers/cc-ci/pulls" \ + -d "$payload"; } || true)" + +if [ "$code" = "201" ]; then + jq -r '"PR_URL=" + (.html_url // "") + "\nPR_NUMBER=" + ((.number // 0) | tostring)' "$resp" + rm -f "$resp" + exit 0 +fi + +if [ "$code" = "409" ] || grep -q "pull request already exists" "$resp" 2>/dev/null; then + existing="$(curl -sS "${auth[@]}" "${api}/repos/recipe-maintainers/cc-ci/pulls?state=open&head=recipe-maintainers:${branch}&base=${base}")" + url="$(printf '%s' "$existing" | jq -r '.[0].html_url // empty')" + num="$(printf '%s' "$existing" | jq -r '.[0].number // empty')" + if [ -n "$url" ]; then + printf 'PR_URL=%s\nPR_NUMBER=%s\n' "$url" "$num" + rm -f "$resp" + exit 0 + fi +fi + +echo "ERROR: PR creation failed on recipe-maintainers/cc-ci (HTTP ${code})" >&2 +cat "$resp" >&2 || true +rm -f "$resp" +exit 1 diff --git a/.claude/skills/recipe-upgrade/post-pr-comment.sh b/.claude/skills/recipe-upgrade/post-pr-comment.sh new file mode 100755 index 0000000..233ea1d --- /dev/null +++ b/.claude/skills/recipe-upgrade/post-pr-comment.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash +# recipe-upgrade :: post a comment on a Gitea PR/issue +# ---------------------------------------------------- +# Usage: +# BODY='text' post-pr-comment.sh +# BODY_FILE=/tmp/comment.md post-pr-comment.sh +set -o errexit -o nounset -o pipefail + +REPO="${1:?usage: post-pr-comment.sh }" +PRIDX="${2:?usage: post-pr-comment.sh }" +TESTENV="${TESTENV:-/srv/cc-ci/.testenv}" +set -a; . "$TESTENV"; set +a +: "${GITEA_USERNAME:?}" +: "${GITEA_PASSWORD:?}" +: "${GITEA_URL:?}" + +if [ -n "${BODY_FILE:-}" ]; then + BODY="$(<"${BODY_FILE}")" +else + : "${BODY:?set BODY or BODY_FILE}" +fi + +API="https://${GITEA_URL}/api/v1" +AUTH=(-u "${GITEA_USERNAME}:${GITEA_PASSWORD}") + +resp="$(mktemp)" +code="$({ curl -sS -o "$resp" -w "%{http_code}" "${AUTH[@]}" \ + -H "Content-Type: application/json" \ + -X POST "${API}/repos/${REPO}/issues/${PRIDX}/comments" \ + -d "$(jq -n --arg body "$BODY" '{body:$body}')"; } || true)" + +if [ "$code" != "201" ]; then + echo "ERROR: comment POST failed for ${REPO}#${PRIDX} (HTTP ${code})" >&2 + cat "$resp" >&2 || true + rm -f "$resp" + exit 1 +fi + +jq -r '"COMMENT_URL=" + (.html_url // "") + "\nCOMMENT_ID=" + ((.id // 0) | tostring)' "$resp" +rm -f "$resp"