#!/bin/bash # pr-merge.sh - Merge pull requests on Gitea or GitHub # Usage: pr-merge.sh -n PR_NUMBER [-m squash] [-d] [--skip-queue-guard] [--dry-run] set -e SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" # shellcheck disable=SC1091 source "$SCRIPT_DIR/detect-platform.sh" # Default values PR_NUMBER="" MERGE_METHOD="squash" DELETE_BRANCH=false SKIP_QUEUE_GUARD=false DRY_RUN=false usage() { cat <&2 usage ;; esac done if [[ -z "$PR_NUMBER" ]]; then echo "Error: PR number is required (-n)" >&2 usage fi if [[ "$MERGE_METHOD" != "squash" ]]; then echo "Error: Mosaic policy enforces squash merge only. Received '$MERGE_METHOD'." >&2 exit 1 fi METADATA_JSON="$("$SCRIPT_DIR/pr-metadata.sh" -n "$PR_NUMBER")" BASE_BRANCH="$(printf '%s' "$METADATA_JSON" | python3 -c 'import json, sys; print((json.load(sys.stdin).get("baseRefName") or "").strip())')" if [[ "$BASE_BRANCH" != "main" ]]; then echo "Error: Mosaic policy allows merges only for PRs targeting 'main' (found '$BASE_BRANCH')." >&2 exit 1 fi if [[ "$SKIP_QUEUE_GUARD" != true ]]; then "$SCRIPT_DIR/ci-queue-wait.sh" \ --purpose merge \ -B "$BASE_BRANCH" \ -t "${MOSAIC_CI_QUEUE_TIMEOUT_SEC:-900}" \ -i "${MOSAIC_CI_QUEUE_POLL_SEC:-15}" fi PLATFORM=$(detect_platform) OWNER=$(get_repo_owner) REPO=$(get_repo_name) case "$PLATFORM" in github) if [[ "$DRY_RUN" == true ]]; then echo "Dry run: GitHub merge preflight OK for ${OWNER}/${REPO}#${PR_NUMBER} targeting ${BASE_BRANCH}" exit 0 fi CMD=(gh pr merge "$PR_NUMBER" --squash) [[ "$DELETE_BRANCH" == true ]] && CMD+=(--delete-branch) "${CMD[@]}" ;; gitea) HOST=$(get_remote_host) || { echo "Error: Cannot determine host from remote URL" >&2 exit 1 } TOKEN=$(get_gitea_token "$HOST") || { echo "Error: Could not resolve Gitea API token for ${HOST}" >&2 exit 1 } if [[ "$DRY_RUN" == true ]]; then echo "Dry run: Gitea merge preflight OK for ${OWNER}/${REPO}#${PR_NUMBER} targeting ${BASE_BRANCH} via ${HOST} API" exit 0 fi RESPONSE_FILE=$(mktemp) trap 'rm -f "$RESPONSE_FILE"' EXIT HTTP_CODE=$(curl -sS \ -X POST \ -H "Authorization: token $TOKEN" \ -H "Content-Type: application/json" \ -d '{"Do":"squash"}' \ -o "$RESPONSE_FILE" \ -w '%{http_code}' \ "https://${HOST}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}/merge") RESPONSE_BODY=$(cat "$RESPONSE_FILE") rm -f "$RESPONSE_FILE" trap - EXIT if [[ ! "$HTTP_CODE" =~ ^2 ]]; then echo "Error: Gitea PR merge failed for ${OWNER}/${REPO}#${PR_NUMBER} (HTTP ${HTTP_CODE})" >&2 if [[ -n "$RESPONSE_BODY" ]]; then printf '%s\n' "$RESPONSE_BODY" >&2 fi exit 1 fi # Delete branch after merge if requested if [[ "$DELETE_BRANCH" == true ]]; then echo "Note: Branch deletion after merge may need to be done separately with the Gitea API" >&2 fi ;; *) echo "Error: Could not detect git platform" >&2 exit 1 ;; esac echo "PR #$PR_NUMBER merged successfully"