From 1a2f8abd8bcee1bdf23739f9693eab9475aac32d Mon Sep 17 00:00:00 2001 From: lyn Date: Wed, 1 Apr 2026 15:40:08 +0000 Subject: [PATCH] feat(git-hangman-lab): rename create-pr to pr with subcommands - Replace single create-pr script with unified pr script - Add subcommands: create, list, commits, merge - Update git-ctrl and SKILL.md documentation --- git-hangman-lab/SKILL.md | 11 +- git-hangman-lab/scripts/create-pr | 95 ----------- git-hangman-lab/scripts/git-ctrl | 6 +- git-hangman-lab/scripts/pr | 263 ++++++++++++++++++++++++++++++ 4 files changed, 274 insertions(+), 101 deletions(-) delete mode 100755 git-hangman-lab/scripts/create-pr create mode 100755 git-hangman-lab/scripts/pr diff --git a/git-hangman-lab/SKILL.md b/git-hangman-lab/SKILL.md index ee29450..57e2c19 100644 --- a/git-hangman-lab/SKILL.md +++ b/git-hangman-lab/SKILL.md @@ -43,16 +43,21 @@ Create a new git repository on git.hangman-lab.top. > **Note**: The repository will be created at `${AGENT_WORKSPACE}/${repo-name}` (default: `/root/.openclaw/workspace/workspace-mentor`) -### Create Pull Request +### Pull Request Operations -Create a pull request on git.hangman-lab.top. +Manage pull requests on git.hangman-lab.top. ```bash -{baseDir}/scripts/git-ctrl create-pr [pr-title] [pr-body] +{baseDir}/scripts/git-ctrl pr create [pr-title] [pr-body] +{baseDir}/scripts/git-ctrl pr list +{baseDir}/scripts/git-ctrl pr commits +{baseDir}/scripts/git-ctrl pr merge [commit-id] [title] [message] ``` > **Note**: The access token will be automatically generated if not found. +> **``** can be: `merge`, `squash`, `rebase`, `manually-merged` + ### Link Keycloak Account Link Keycloak account with Gitea (for OAuth binding). diff --git a/git-hangman-lab/scripts/create-pr b/git-hangman-lab/scripts/create-pr deleted file mode 100755 index 6841682..0000000 --- a/git-hangman-lab/scripts/create-pr +++ /dev/null @@ -1,95 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Get the directory where this script is located -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -usage() { - echo "Usage: $0 [pr-title] [pr-body]" - echo "" - echo "Create a pull request on git.hangman-lab.top" - echo "" - echo "Arguments:" - echo " repo-local-path Local path to the git repository" - echo " head-branch Branch containing the changes" - echo " base-branch Branch to merge into (e.g., main)" - echo " pr-title Title of the pull request (optional, default: 'untitled pull request')" - echo " pr-body Body/description of the pull request (optional, default: '')" - exit 2 -} - -if [[ $# -lt 3 ]]; then - usage -fi - -REPO_LOCAL_PATH="$1" -HEAD_BRANCH="$2" -BASE_BRANCH="$3" -PR_TITLE="${4:-untitled pull request}" -PR_BODY="${5:-}" - -# Validate repo path -if [[ ! -d "$REPO_LOCAL_PATH/.git" ]]; then - echo "Error: Not a git repository: $REPO_LOCAL_PATH" - exit 1 -fi - -# Check if git-access-token exists, if not generate it -if ! secret-mgr list 2>/dev/null | grep -q "git-access-token"; then - echo "Access token not found, generating..." - "$SCRIPT_DIR/generate-access-token" -fi - -# Get the access token (extract actual token from "Access token was successfully created: ") -GIT_TOKEN="$(secret-mgr get-secret --key git-access-token | awk '{print $NF}')" - -if [[ -z "$GIT_TOKEN" ]]; then - echo "Error: Failed to get git-access-token" - exit 1 -fi - -# Get remote URL from .git -REMOTE_URL="$(git -C "$REPO_LOCAL_PATH" remote get-url origin)" - -# Match pattern: https://git.hangman-lab.top/${owner}/${repo-name}.git -if [[ "$REMOTE_URL" =~ https://git\.hangman-lab\.top/([^/]+)/([^/]+)\.git ]]; then - OWNER="${BASH_REMATCH[1]}" - REPO_NAME="${BASH_REMATCH[2]}" -else - echo "Error: Invalid remote URL format: $REMOTE_URL" - echo "Expected: https://git.hangman-lab.top/\${owner}/\${repo-name}.git" - exit 1 -fi - -echo "Creating PR: $OWNER/$REPO_NAME ($HEAD_BRANCH -> $BASE_BRANCH)" - -# Create PR via API -RESPONSE=$(curl -s -X POST "https://git.hangman-lab.top/api/v1/repos/${OWNER}/${REPO_NAME}/pulls" \ - -H 'accept: application/json' \ - -H 'Content-Type: application/json' \ - -H "Authorization: token ${GIT_TOKEN}" \ - -d "$(jq -n \ - --arg head "$HEAD_BRANCH" \ - --arg base "$BASE_BRANCH" \ - --arg title "$PR_TITLE" \ - --arg body "$PR_BODY" \ - '{head: $head, base: $base, title: $title, body: $body}')") - -# Check if response contains an error -if echo "$RESPONSE" | jq -e '.message' >/dev/null 2>&1; then - ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message') - echo "Error: $ERROR_MSG" - exit 1 -fi - -# Extract PR URL from response -PR_URL=$(echo "$RESPONSE" | jq -r '.html_url // empty') - -if [[ -n "$PR_URL" ]]; then - echo "Pull request created successfully!" - echo "URL: $PR_URL" -else - echo "Error: Failed to create pull request" - echo "Response: $RESPONSE" - exit 1 -fi diff --git a/git-hangman-lab/scripts/git-ctrl b/git-hangman-lab/scripts/git-ctrl index 251015f..4f301a2 100755 --- a/git-hangman-lab/scripts/git-ctrl +++ b/git-hangman-lab/scripts/git-ctrl @@ -11,7 +11,7 @@ if [[ $# -eq 0 ]]; then echo " check-git-cred Verify git credentials" echo " create-git-account Create a new git account" echo " create-repo Create a new repository" - echo " create-pr Create a pull request" + echo " pr Pull request operations (create/list/commits/merge)" echo " generate-access-token Generate access token for current user" echo " link-keycloak Link Keycloak account with Gitea" echo " repo-add-collaborators Add collaborator to repository" @@ -36,8 +36,8 @@ case "$subcommand" in create-repo) "$SCRIPT_DIR/create-repo" "$@" ;; - create-pr) - "$SCRIPT_DIR/create-pr" "$@" + pr) + "$SCRIPT_DIR/pr" "$@" ;; generate-access-token) "$SCRIPT_DIR/generate-access-token" "$@" diff --git a/git-hangman-lab/scripts/pr b/git-hangman-lab/scripts/pr new file mode 100755 index 0000000..0fc9c53 --- /dev/null +++ b/git-hangman-lab/scripts/pr @@ -0,0 +1,263 @@ +#!/usr/bin/env bash +set -euo pipefail + +# Get the directory where this script is located +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Ensure access token exists +ensure_token() { + # Check if git-access-token exists, if not generate it + if ! secret-mgr list 2>/dev/null | grep -q "git-access-token"; then + echo "Access token not found, generating..." + "$SCRIPT_DIR/generate-access-token" + fi + + # Get the access token (extract actual token from "Access token was successfully created: ") + GIT_TOKEN="$(secret-mgr get-secret --key git-access-token | awk '{print $NF}')" + + if [[ -z "$GIT_TOKEN" ]]; then + echo "Error: Failed to get git-access-token" + exit 1 + fi + + echo "$GIT_TOKEN" +} + +# Get owner and repo from local git repo +get_repo_info() { + local repo_path="$1" + + if [[ ! -d "$repo_path/.git" ]]; then + echo "Error: Not a git repository: $repo_path" + exit 1 + fi + + REMOTE_URL="$(git -C "$repo_path" remote get-url origin)" + + if [[ "$REMOTE_URL" =~ https://git\.hangman-lab\.top/([^/]+)/([^/]+)\.git ]]; then + OWNER="${BASH_REMATCH[1]}" + REPO_NAME="${BASH_REMATCH[2]}" + else + echo "Error: Invalid remote URL format: $REMOTE_URL" + echo "Expected: https://git.hangman-lab.top/\${owner}/\${repo-name}.git" + exit 1 + fi +} + +# Subcommand: create +cmd_create() { + local repo_path="$1" + local head_branch="$2" + local base_branch="$3" + local pr_title="${4:-untitled pull request}" + local pr_body="${5:-}" + + get_repo_info "$repo_path" + local token + token="$(ensure_token)" + + echo "Creating PR: $OWNER/$REPO_NAME ($head_branch -> $base_branch)" + + RESPONSE=$(curl -s -X POST "https://git.hangman-lab.top/api/v1/repos/${OWNER}/${REPO_NAME}/pulls" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H "Authorization: token ${token}" \ + -d "$(jq -n \ + --arg head "$head_branch" \ + --arg base "$base_branch" \ + --arg title "$pr_title" \ + --arg body "$pr_body" \ + '{head: $head, base: $base, title: $title, body: $body}')") + + if echo "$RESPONSE" | jq -e '.message' >/dev/null 2>&1; then + ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message') + echo "Error: $ERROR_MSG" + exit 1 + fi + + PR_URL=$(echo "$RESPONSE" | jq -r '.html_url // empty') + + if [[ -n "$PR_URL" ]]; then + echo "Pull request created successfully!" + echo "URL: $PR_URL" + else + echo "Error: Failed to create pull request" + echo "Response: $RESPONSE" + exit 1 + fi +} + +# Subcommand: list +cmd_list() { + local repo_path="$1" + + get_repo_info "$repo_path" + local token + token="$(ensure_token)" + + echo "Listing PRs for: $OWNER/$REPO_NAME" + + RESPONSE=$(curl -s -X GET "https://git.hangman-lab.top/api/v1/repos/${OWNER}/${REPO_NAME}/pulls/pinned" \ + -H 'accept: application/json' \ + -H "Authorization: token ${token}") + + if echo "$RESPONSE" | jq -e '.message' >/dev/null 2>&1; then + ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message') + echo "Error: $ERROR_MSG" + exit 1 + fi + + echo "$RESPONSE" | jq -r '.[] | "\(.number)\t\(.title)\t\(.state)\t\(.html_url)"' 2>/dev/null || echo "$RESPONSE" +} + +# Subcommand: commits +cmd_commits() { + local repo_path="$1" + local pr_index="$2" + + get_repo_info "$repo_path" + local token + token="$(ensure_token)" + + echo "Fetching commits for PR #$pr_index in: $OWNER/$REPO_NAME" + + RESPONSE=$(curl -s -X GET "https://git.hangman-lab.top/api/v1/repos/${OWNER}/${REPO_NAME}/pulls/${pr_index}/commits" \ + -H 'accept: application/json' \ + -H "Authorization: token ${token}") + + if echo "$RESPONSE" | jq -e '.message' >/dev/null 2>&1; then + ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message') + echo "Error: $ERROR_MSG" + exit 1 + fi + + echo "$RESPONSE" | jq -r '.[] | "\(.sha[0:7])\t\(.commit.message | split("\n")[0])"' 2>/dev/null || echo "$RESPONSE" +} + +# Subcommand: merge +cmd_merge() { + local repo_path="$1" + local pr_index="$2" + local do="$3" + local commit_id="${4:-}" + local title="${5:-}" + local message="${6:-}" + + get_repo_info "$repo_path" + local token + token="$(ensure_token)" + + echo "Merging PR #$pr_index in: $OWNER/$REPO_NAME (Do: $do)" + + # Get PR head sha first + PR_INFO=$(curl -s -X GET "https://git.hangman-lab.top/api/v1/repos/${OWNER}/${REPO_NAME}/pulls/${pr_index}" \ + -H 'accept: application/json' \ + -H "Authorization: token ${token}") + + HEAD_SHA=$(echo "$PR_INFO" | jq -r '.head.sha') + + if [[ -z "$HEAD_SHA" || "$HEAD_SHA" == "null" ]]; then + echo "Error: Failed to get PR head sha" + exit 1 + fi + + # Build JSON body + local json + json=$(jq -n \ + --arg do "$do" \ + --arg commit_id "$commit_id" \ + --arg title "$title" \ + --arg message "$message" \ + --arg head_sha "$HEAD_SHA" \ + '{ + Do: $do, + MergeCommitID: (if $commit_id != "" then $commit_id else null end), + MergeMessageField: (if $message != "" then $message else null end), + MergeTitleField: (if $title != "" then $title else null end), + delete_branch_after_merge: true, + force_merge: false, + head_commit_id: $head_sha, + merge_when_checks_succeed: true + }') + + RESPONSE=$(curl -s -X POST "https://git.hangman-lab.top/api/v1/repos/${OWNER}/${REPO_NAME}/pulls/${pr_index}/merge" \ + -H 'accept: application/json' \ + -H 'Content-Type: application/json' \ + -H "Authorization: token ${token}" \ + -d "$json") + + if echo "$RESPONSE" | jq -e '.message' >/dev/null 2>&1; then + ERROR_MSG=$(echo "$RESPONSE" | jq -r '.message') + echo "Error: $ERROR_MSG" + exit 1 + fi + + MERGED=$(echo "$RESPONSE" | jq -r '.merged') + + if [[ "$MERGED" == "true" ]]; then + echo "Pull request merged successfully!" + else + echo "Error: Failed to merge pull request" + echo "$RESPONSE" | jq '.' + exit 1 + fi +} + +# Usage +usage() { + echo "Usage: $0 [options]" + echo "" + echo "Commands:" + echo " create [pr-title] [pr-body]" + echo " Create a pull request" + echo " list List pull requests" + echo " commits List commits in a PR" + echo " merge [commit-id] [title] [message]" + echo " Merge a pull request" + echo "" + echo " can be: merge, squash, rebase, manually-merged" + exit 2 +} + +# Main +if [[ $# -lt 2 ]]; then + usage +fi + +COMMAND="$1" +shift + +case "$COMMAND" in + create) + if [[ $# -lt 3 ]]; then + echo "Error: create requires " + exit 2 + fi + cmd_create "$@" + ;; + list) + if [[ $# -lt 1 ]]; then + echo "Error: list requires " + exit 2 + fi + cmd_list "$@" + ;; + commits) + if [[ $# -lt 2 ]]; then + echo "Error: commits requires " + exit 2 + fi + cmd_commits "$@" + ;; + merge) + if [[ $# -lt 3 ]]; then + echo "Error: merge requires " + exit 2 + fi + cmd_merge "$@" + ;; + *) + echo "Error: Unknown command: $COMMAND" + usage + ;; +esac