recipe-maintainer: public snapshot (secrets + deployment plans removed, single commit)
Sanitized single-commit public mirror of recipe-maintainer. - Removed test-ssh/.testenv (live creds); added test-ssh/.testenv.example placeholders. - Removed plans/ and planned-updates/ (deployment-planning docs) so no client/ deployment domains appear in the public repo. - All other secret stores were already gitignored. - docs.coopcloud.tech retained as a submodule (public upstream).
This commit is contained in:
@@ -0,0 +1,191 @@
|
||||
---
|
||||
description: Push local recipe commits to git.autonomic.zone and open a PR against an upstream-synced main branch
|
||||
argument-hint: <recipe-name>
|
||||
allowed-tools: [Bash, Read]
|
||||
---
|
||||
|
||||
# Recipe Create PR
|
||||
|
||||
Take the local commits made to a recipe (e.g. during `/recipe-upgrade-apply`) and open a pull request on the Gitea instance at `git.autonomic.zone`. The Gitea repo's `main` branch is force-synced from the recipe's upstream `main` so the PR diff shows only the local changes.
|
||||
|
||||
The recipe name is: $ARGUMENTS
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Credentials are read from `test-ssh/.testenv`. The following variables must be set:
|
||||
|
||||
- `GITEA_USERNAME` — bot account on the Gitea instance
|
||||
- `GITEA_PASSWORD` — bot password
|
||||
- `GITEA_URL` — Gitea host (e.g. `git.autonomic.zone`)
|
||||
|
||||
Optional:
|
||||
|
||||
- `GITEA_NAMESPACE` — owner under which to create/find repos. Defaults to `recipe-maintainers` (the org whose `recipe-maintainers` team auto-grants access to all repos within it).
|
||||
|
||||
The recipe must be checked out at `~/.abra/recipes/$ARGUMENTS` with at least one commit beyond `origin/main`.
|
||||
|
||||
## Steps
|
||||
|
||||
Run the following script with the recipe name substituted in:
|
||||
|
||||
```bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
RECIPE="$ARGUMENTS"
|
||||
WORKSPACE="/workspace"
|
||||
RECIPE_DIR="${HOME}/.abra/recipes/${RECIPE}"
|
||||
TESTENV="${WORKSPACE}/test-ssh/.testenv"
|
||||
|
||||
# --- Load credentials ---
|
||||
[ -f "${TESTENV}" ] || { echo "ERROR: ${TESTENV} not found"; exit 1; }
|
||||
set -a; . "${TESTENV}"; set +a
|
||||
: "${GITEA_USERNAME:?missing in .testenv}"
|
||||
: "${GITEA_PASSWORD:?missing in .testenv}"
|
||||
: "${GITEA_URL:?missing in .testenv}"
|
||||
NAMESPACE="${GITEA_NAMESPACE:-recipe-maintainers}"
|
||||
|
||||
PASS_ENC=$(python3 -c "import urllib.parse,sys;print(urllib.parse.quote(sys.argv[1],safe=''))" "${GITEA_PASSWORD}")
|
||||
API="https://${GITEA_URL}/api/v1"
|
||||
AUTH=(-u "${GITEA_USERNAME}:${GITEA_PASSWORD}")
|
||||
|
||||
# --- Validate recipe checkout ---
|
||||
[ -d "${RECIPE_DIR}/.git" ] || { echo "ERROR: ${RECIPE_DIR} is not a git repo. Run 'abra recipe fetch ${RECIPE}' first."; exit 1; }
|
||||
cd "${RECIPE_DIR}"
|
||||
|
||||
# --- Fetch upstream main ---
|
||||
echo "→ Fetching upstream main from origin..."
|
||||
git fetch origin main
|
||||
|
||||
# --- Find diverged commits ---
|
||||
DIVERGED=$(git log --oneline origin/main..HEAD 2>/dev/null || true)
|
||||
if [ -z "${DIVERGED}" ]; then
|
||||
echo "ERROR: HEAD has no commits beyond origin/main. Nothing to PR."
|
||||
exit 1
|
||||
fi
|
||||
echo "→ Local commits to PR:"
|
||||
echo "${DIVERGED}" | sed 's/^/ /'
|
||||
|
||||
# --- Determine PR branch name from the most recent commit ---
|
||||
LATEST_MSG=$(git log -1 --pretty=%s HEAD)
|
||||
if echo "${LATEST_MSG}" | grep -qiE "upgrade to [0-9]"; then
|
||||
VERSION=$(echo "${LATEST_MSG}" | grep -oiE "upgrade to [0-9][^[:space:]]+" | awk '{print $NF}')
|
||||
BRANCH="upgrade-${VERSION}"
|
||||
else
|
||||
BRANCH="pr-$(date -u +%Y%m%d-%H%M%S)"
|
||||
fi
|
||||
echo "→ PR branch: ${BRANCH}"
|
||||
|
||||
# --- Check / create Gitea repo ---
|
||||
REPO_URL_API="${API}/repos/${NAMESPACE}/${RECIPE}"
|
||||
STATUS=$(curl -s -o /dev/null -w "%{http_code}" "${AUTH[@]}" "${REPO_URL_API}")
|
||||
|
||||
if [ "${STATUS}" = "404" ]; then
|
||||
echo "→ Repo ${NAMESPACE}/${RECIPE} does not exist; creating..."
|
||||
CREATE_BODY=$(python3 -c "import json;print(json.dumps({'name':'${RECIPE}','private':True,'default_branch':'main','auto_init':False}))")
|
||||
|
||||
# Try org namespace first
|
||||
CREATE_OUT=$(mktemp)
|
||||
CREATE_STATUS=$(curl -s -o "${CREATE_OUT}" -w "%{http_code}" "${AUTH[@]}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "${API}/orgs/${NAMESPACE}/repos" \
|
||||
-d "${CREATE_BODY}")
|
||||
|
||||
if [ "${CREATE_STATUS}" != "201" ]; then
|
||||
echo " ! create under org ${NAMESPACE} returned HTTP ${CREATE_STATUS} — falling back to user namespace ${GITEA_USERNAME}"
|
||||
cat "${CREATE_OUT}" >&2
|
||||
echo "" >&2
|
||||
CREATE_STATUS=$(curl -s -o "${CREATE_OUT}" -w "%{http_code}" "${AUTH[@]}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "${API}/user/repos" \
|
||||
-d "${CREATE_BODY}")
|
||||
if [ "${CREATE_STATUS}" != "201" ]; then
|
||||
echo "ERROR: failed to create repo (HTTP ${CREATE_STATUS}):"
|
||||
cat "${CREATE_OUT}"
|
||||
rm -f "${CREATE_OUT}"
|
||||
exit 1
|
||||
fi
|
||||
NAMESPACE="${GITEA_USERNAME}"
|
||||
fi
|
||||
rm -f "${CREATE_OUT}"
|
||||
echo " ✓ created ${NAMESPACE}/${RECIPE}"
|
||||
elif [ "${STATUS}" = "200" ]; then
|
||||
echo "→ Repo ${NAMESPACE}/${RECIPE} already exists"
|
||||
else
|
||||
echo "ERROR: unexpected HTTP ${STATUS} when checking ${REPO_URL_API}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# --- Set up the gitea remote with credentials embedded ---
|
||||
REMOTE_URL="https://${GITEA_USERNAME}:${PASS_ENC}@${GITEA_URL}/${NAMESPACE}/${RECIPE}.git"
|
||||
if git remote | grep -qx gitea; then
|
||||
git remote set-url gitea "${REMOTE_URL}"
|
||||
else
|
||||
git remote add gitea "${REMOTE_URL}"
|
||||
fi
|
||||
|
||||
# --- Force-sync Gitea main with origin/main so the PR diff is clean ---
|
||||
echo "→ Force-syncing gitea/main from origin/main..."
|
||||
git push --force gitea "refs/remotes/origin/main:refs/heads/main"
|
||||
|
||||
# --- Push local commits as the PR branch ---
|
||||
echo "→ Pushing local commits as branch '${BRANCH}'..."
|
||||
git push --force gitea "HEAD:refs/heads/${BRANCH}"
|
||||
|
||||
# --- Create the PR ---
|
||||
# NOTE: for an upgrade PR the body (passed in via RECIPE_PR_BODY) MUST link the upstream release notes
|
||||
# — one explicit line per upgraded image/service, e.g.
|
||||
# **Upstream release notes:** <service> <old>→<new>: <url>
|
||||
# pulling each URL from recipe-info/<recipe>/upstream.md (between the current → new version). These links
|
||||
# belong in the PR body itself, NOT only in a side report, so the reviewer sees what changed upstream.
|
||||
PR_TITLE="${LATEST_MSG}"
|
||||
if [ -n "${RECIPE_PR_BODY:-}" ]; then
|
||||
PR_BODY="${RECIPE_PR_BODY}"
|
||||
else
|
||||
PR_BODY=$(printf "Local commits on top of upstream main:\n\n%s\n" "$(git log origin/main..HEAD --pretty='- %h %s')")
|
||||
fi
|
||||
PR_BODY="${PR_BODY}
|
||||
|
||||
cc @trav @notplants"
|
||||
PR_PAYLOAD=$(python3 -c "
|
||||
import json, sys
|
||||
print(json.dumps({
|
||||
'title': sys.argv[1],
|
||||
'body': sys.argv[2],
|
||||
'head': sys.argv[3],
|
||||
'base': 'main',
|
||||
'reviewers': ['trav', 'notplants'],
|
||||
}))" "${PR_TITLE}" "${PR_BODY}" "${BRANCH}")
|
||||
|
||||
PR_RESPONSE=$(mktemp)
|
||||
PR_STATUS=$(curl -s -o "${PR_RESPONSE}" -w "%{http_code}" "${AUTH[@]}" \
|
||||
-H "Content-Type: application/json" \
|
||||
-X POST "${API}/repos/${NAMESPACE}/${RECIPE}/pulls" \
|
||||
-d "${PR_PAYLOAD}")
|
||||
|
||||
if [ "${PR_STATUS}" = "201" ]; then
|
||||
PR_URL=$(python3 -c "import json;print(json.load(open('${PR_RESPONSE}'))['html_url'])")
|
||||
echo ""
|
||||
echo "✓ PR created: ${PR_URL}"
|
||||
elif [ "${PR_STATUS}" = "409" ] || grep -q "pull request already exists" "${PR_RESPONSE}" 2>/dev/null; then
|
||||
echo ""
|
||||
echo "ℹ A PR for branch '${BRANCH}' already exists. See:"
|
||||
echo " https://${GITEA_URL}/${NAMESPACE}/${RECIPE}/pulls"
|
||||
else
|
||||
echo "ERROR: PR creation failed (HTTP ${PR_STATUS}):"
|
||||
cat "${PR_RESPONSE}"
|
||||
rm -f "${PR_RESPONSE}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
rm -f "${PR_RESPONSE}"
|
||||
```
|
||||
|
||||
After the script runs, report back the PR URL (or the existing-PR list URL if Gitea returned 409).
|
||||
|
||||
## Notes
|
||||
|
||||
- The `gitea` remote is created/updated in `~/.abra/recipes/<recipe>/.git/config` with the password embedded — this is acceptable here since `.testenv` already stores the password in plaintext, but be aware the remote URL is now stored in that local file.
|
||||
- Re-running the skill is safe: the script force-pushes both the synced `main` and the PR branch, and reports gracefully if a PR for that branch already exists.
|
||||
- The PR branch name is derived from the most recent commit message — if it matches `upgrade to <version>`, the branch becomes `upgrade-<version>`; otherwise a timestamped name is used.
|
||||
- **For upgrade PRs, `RECIPE_PR_BODY` must carry the upstream release-notes links** (one line per upgraded service: `**Upstream release notes:** <service> <old>→<new>: <url>`, sourced from `recipe-info/<recipe>/upstream.md`). `/recipe-upgrade-apply` composes the body with these links already; if you invoke this command directly for an upgrade, include them in `RECIPE_PR_BODY` yourself so the reviewer sees what changed upstream.
|
||||
Reference in New Issue
Block a user