From d20e827a5c5d3d7e7824d2dc80d6dbf74e3abfc9 Mon Sep 17 00:00:00 2001 From: lyn Date: Mon, 13 Apr 2026 13:49:23 +0000 Subject: [PATCH] Integrate create-repo/add-collaborators/list-projs/repo-config into repo script, remove originals, update git-ctrl and SKILL.md --- git-hangman-lab/SKILL.md | 6 +- git-hangman-lab/scripts/create-repo | 61 ----- git-hangman-lab/scripts/git-ctrl | 49 +--- git-hangman-lab/scripts/list-projs | 56 ---- git-hangman-lab/scripts/repo | 247 ++++++++++++++++-- .../scripts/repo-add-collaborators | 49 ---- git-hangman-lab/scripts/repo-config | 135 ---------- 7 files changed, 234 insertions(+), 369 deletions(-) delete mode 100755 git-hangman-lab/scripts/create-repo delete mode 100755 git-hangman-lab/scripts/list-projs delete mode 100755 git-hangman-lab/scripts/repo-add-collaborators delete mode 100755 git-hangman-lab/scripts/repo-config diff --git a/git-hangman-lab/SKILL.md b/git-hangman-lab/SKILL.md index 0c68e9f..f7124ee 100644 --- a/git-hangman-lab/SKILL.md +++ b/git-hangman-lab/SKILL.md @@ -35,16 +35,16 @@ Generate an access token for the current user. ### Repository Operations -Manage repositories on git.hangman-lab.top via the `repo` subcommand: +Manage repositories via `git-ctrl repo`: ```bash {baseDir}/scripts/git-ctrl repo create {baseDir}/scripts/git-ctrl repo add-collaborators --user --repo {baseDir}/scripts/git-ctrl repo list-all -{baseDir}/scripts/git-ctrl repo config --repo-path +{baseDir}/scripts/git-ctrl repo config --repo-path [--recursive] ``` -> **Note**: `create` creates the repo at `${AGENT_WORKSPACE}/${repo-name}` +> `create` creates the repo at `${AGENT_WORKSPACE}/${repo-name}` ### Pull Request Operations diff --git a/git-hangman-lab/scripts/create-repo b/git-hangman-lab/scripts/create-repo deleted file mode 100755 index 67d52fb..0000000 --- a/git-hangman-lab/scripts/create-repo +++ /dev/null @@ -1,61 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -# Get the directory where this script is located -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -if [[ -z "${AGENT_WORKSPACE:-}" ]]; then - echo "Error: script must be executed by pcexec" - exit 1 -fi - -usage() { - echo "Usage: $0 " - echo "" - echo "Create a new git repository on git.hangman-lab.top" - echo "" - echo "Arguments:" - echo " repo-name Name of the repository to create" - exit 2 -} - -if [[ $# -eq 0 ]]; then - usage -fi - -REPO_NAME="$1" - -# Validate repo name (alphanumeric, hyphens, underscores, dots) -if ! [[ "$REPO_NAME" =~ ^[a-zA-Z0-9_.-]+$ ]]; then - echo "Error: Invalid repository name '$REPO_NAME'" - echo "Only alphanumeric characters, hyphens, underscores, and dots are allowed." - exit 1 -fi - -REPO_DIR="${AGENT_WORKSPACE}/${REPO_NAME}" - -# Step 1: Create directory -echo "Creating directory: ${REPO_DIR}" -mkdir -p "${REPO_DIR}" - -# Step 2: cd to directory -cd "${REPO_DIR}" - -# Step 3: git init -echo "Initializing git repository..." -git init - -# Step 4: git remote add origin -echo "Adding remote origin..." -USERNAME="$(secret-mgr get-username --key git)" -REMOTE_URL="https://git.hangman-lab.top/${USERNAME}/${REPO_NAME}.git" -git remote add origin "${REMOTE_URL}" -echo " Remote: ${REMOTE_URL}" - -# Step 5: Run repo-config -echo "Configuring repository..." -"$SCRIPT_DIR/repo-config" --repo-path "${REPO_DIR}" - -echo "" -echo "Done! Repository created at: ${REPO_DIR}" -echo "Remote: ${REMOTE_URL}" diff --git a/git-hangman-lab/scripts/git-ctrl b/git-hangman-lab/scripts/git-ctrl index 8d5999a..86d5a7b 100755 --- a/git-hangman-lab/scripts/git-ctrl +++ b/git-hangman-lab/scripts/git-ctrl @@ -8,54 +8,25 @@ if [[ $# -eq 0 ]]; then echo "Commands:" echo " check-git-cred Verify git credentials" echo " create-git-account Create a new git account" - echo " create-repo Create a new repository" echo " pr Pull request operations (create/list/commits/merge/show)" echo " generate-access-token Generate access token for current user" echo " link-keycloak Link Keycloak account with Gitea" echo " repo Repository operations (create/add-collaborators/list-all/config)" echo " external-login-ctrl Enable/disable local login" - echo " list-projs List all visible repositories" echo " reset-password Reset user password" exit 1 fi -subcommand="$1" -shift +subcommand="$1"; shift case "$subcommand" in - check-git-cred) - "$SCRIPT_DIR/check-git-cred" "$@" - ;; - create-git-account) - "$SCRIPT_DIR/create-git-account" "$@" - ;; - create-repo) - "$SCRIPT_DIR/create-repo" "$@" - ;; - pr) - "$SCRIPT_DIR/pr" "$@" - ;; - generate-access-token) - "$SCRIPT_DIR/generate-access-token" "$@" - ;; - link-keycloak) - "$SCRIPT_DIR/link-keycloak" "$@" - ;; - repo) - "$SCRIPT_DIR/repo" "$@" - ;; - external-login-ctrl) - "$SCRIPT_DIR/external-login-ctrl" "$@" - ;; - list-projs) - "$SCRIPT_DIR/list-projs" "$@" - ;; - reset-password) - "$SCRIPT_DIR/reset-password" "$@" - ;; - *) - echo "Unknown command: $subcommand" - echo "Run '$0' for usage information" - exit 1 - ;; + check-git-cred) "$SCRIPT_DIR/check-git-cred" "$@" ;; + create-git-account) "$SCRIPT_DIR/create-git-account" "$@" ;; + pr) "$SCRIPT_DIR/pr" "$@" ;; + generate-access-token) "$SCRIPT_DIR/generate-access-token" "$@" ;; + link-keycloak) "$SCRIPT_DIR/link-keycloak" "$@" ;; + repo) "$SCRIPT_DIR/repo" "$@" ;; + external-login-ctrl) "$SCRIPT_DIR/external-login-ctrl" "$@" ;; + reset-password) "$SCRIPT_DIR/reset-password" "$@" ;; + *) echo "Unknown command: $subcommand"; exit 1 ;; esac \ No newline at end of file diff --git a/git-hangman-lab/scripts/list-projs b/git-hangman-lab/scripts/list-projs deleted file mode 100755 index a7d1324..0000000 --- a/git-hangman-lab/scripts/list-projs +++ /dev/null @@ -1,56 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -MYSQL_CONTAINER="git-kc-mysql" -MYSQL_USER="root" -MYSQL_DB="giteadb" -MYSQL_ROOT_PASS="K0DprNKJ^vAu3Mx32hMZ%LCzWKElFRfA" - -GIT_HOST="root@vps.git" - -USERNAME=$(ego-mgr get default-username) -if [[ -z "$USERNAME" ]]; then - echo "Error: cannot get username from ego-mgr" >&2 - exit 1 -fi - -QUERY=" -SELECT r.name, u.name as owner, r.is_private, - (r.owner_id = u.id AND r.owner_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci) as is_owner, - (r.owner_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci - OR r.is_private = 0 - OR a.user_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci - OR EXISTS (SELECT 1 FROM team_user tu WHERE tu.uid = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci)) as can_see, - COALESCE((r.owner_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci - OR a.user_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci - OR EXISTS (SELECT 1 FROM team_user tu JOIN team t ON t.id = tu.team_id - WHERE tu.uid = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci - AND (t.includes_all_repositories = 1 - OR EXISTS (SELECT 1 FROM team_repo tr WHERE tr.team_id = t.id AND tr.repo_id = r.id)))), 0) as can_write -FROM repository r -JOIN user u ON r.owner_id = u.id -LEFT JOIN access a ON a.repo_id = r.id AND a.user_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci -WHERE r.is_archived = 0 - AND (r.owner_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci - OR r.is_private = 0 - OR a.user_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci - OR EXISTS (SELECT 1 FROM team_user tu WHERE tu.uid = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci)) -ORDER BY r.name -" - -RESULT=$(ssh -o StrictHostKeyChecking=no "$GIT_HOST" \ - "docker exec $MYSQL_CONTAINER mysql -u $MYSQL_USER -p'$MYSQL_ROOT_PASS' -N -e \"$QUERY\" $MYSQL_DB" 2>/dev/null) - -if [[ -z "$RESULT" ]]; then - echo "| proj-name | owner | url | can-write |" - echo "|------------|-------|-----|-----------|" - exit 0 -fi - -echo "| proj-name | owner | url | can-write |" -echo "|------------|-------|-----|-----------|" - -echo "$RESULT" | while IFS=$'\t' read -r name owner is_private is_owner can_see can_write; do - can_write_val=$([[ "$can_write" == "1" ]] && echo "yes" || echo "no") - echo "| $name | $owner | https://git.hangman-lab.top/$owner/$name.git | $can_write_val |" -done \ No newline at end of file diff --git a/git-hangman-lab/scripts/repo b/git-hangman-lab/scripts/repo index 9f18e95..be0cd50 100755 --- a/git-hangman-lab/scripts/repo +++ b/git-hangman-lab/scripts/repo @@ -1,37 +1,232 @@ -#!/bin/bash +#!/usr/bin/env bash +set -euo pipefail +# Get the directory where this script is located SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" -if [[ $# -eq 0 ]]; then - echo "Usage: $0 [options]" +MYSQL_CONTAINER="git-kc-mysql" +MYSQL_USER="root" +MYSQL_DB="giteadb" +MYSQL_ROOT_PASS="K0DprNKJ^vAu3Mx32hMZ%LCzWKElFRfA" +GIT_HOST="root@vps.git" + +# ───────────────────────────────────────────── +# create +# ───────────────────────────────────────────── +do_create() { + if [[ $# -lt 1 ]]; then + echo "Usage: $0 create " + exit 1 + fi + + if [[ -z "${AGENT_WORKSPACE:-}" ]]; then + echo "Error: script must be executed by pcexec" + exit 1 + fi + + REPO_NAME="$1" + + # Validate repo name + if ! [[ "$REPO_NAME" =~ ^[a-zA-Z0-9_.-]+$ ]]; then + echo "Error: Invalid repository name '$REPO_NAME'" + echo "Only alphanumeric, hyphens, underscores, and dots are allowed." + exit 1 + fi + + REPO_DIR="${AGENT_WORKSPACE}/${REPO_NAME}" + + mkdir -p "${REPO_DIR}" + cd "${REPO_DIR}" + git init + + USERNAME="$(secret-mgr get-username --key git)" + REMOTE_URL="https://git.hangman-lab.top/${USERNAME}/${REPO_NAME}.git" + git remote add origin "${REMOTE_URL}" + + do_config --repo-path "${REPO_DIR}" + + echo "Done! Repository created at: ${REPO_DIR}" +} + +# ───────────────────────────────────────────── +# add-collaborators +# ───────────────────────────────────────────── +do_add_collaborators() { + local user="" repo="" + + while [[ $# -gt 0 ]]; do + case "$1" in + --user) user="$2"; shift 2 ;; + --repo) repo="$2"; shift 2 ;; + *) echo "Unknown option: $1"; exit 1 ;; + esac + done + + if [[ -z "$user" || -z "$repo" ]]; then + echo "Usage: $0 add-collaborators --user --repo " + exit 1 + fi + + if ! secret-mgr list | grep -q "git-access-token"; then + echo "Error: git-access-token not found. Generate one first." + exit 1 + fi + + owner=$(secret-mgr get-username --key git) + token=$(secret-mgr get-secret --key git-access-token) + + curl -s -X PUT \ + -H "Authorization: token $token" \ + -H "Content-Type: application/json" \ + -d '{"permission":"write"}' \ + "https://git.hangman-lab.top/api/v1/repos/$owner/$repo/collaborators/$user" +} + +# ───────────────────────────────────────────── +# list-all +# ───────────────────────────────────────────── +do_list_all() { + USERNAME=$(ego-mgr get default-username) + if [[ -z "$USERNAME" ]]; then + echo "Error: cannot get username from ego-mgr" >&2 + exit 1 + fi + + QUERY=" +SELECT r.name, u.name as owner, r.is_private, + COALESCE((r.owner_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci + OR a.user_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci + OR EXISTS (SELECT 1 FROM team_user tu JOIN team t ON t.id = tu.team_id + WHERE tu.uid = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci + AND (t.includes_all_repositories = 1 + OR EXISTS (SELECT 1 FROM team_repo tr WHERE tr.team_id = t.id AND tr.repo_id = r.id)))), 0) as can_write +FROM repository r +JOIN user u ON r.owner_id = u.id +LEFT JOIN access a ON a.repo_id = r.id AND a.user_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci +WHERE r.is_archived = 0 + AND (r.owner_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci + OR r.is_private = 0 + OR a.user_id = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci + OR EXISTS (SELECT 1 FROM team_user tu WHERE tu.uid = (SELECT id FROM user WHERE lower_name = LOWER('$USERNAME')) COLLATE utf8mb4_unicode_ci)) +ORDER BY r.name +" + + RESULT=$(ssh -o StrictHostKeyChecking=no "$GIT_HOST" \ + "docker exec $MYSQL_CONTAINER mysql -u $MYSQL_USER -p'$MYSQL_ROOT_PASS' -N -e \"$QUERY\" $MYSQL_DB" 2>/dev/null) + + echo "| proj-name | owner | url | can-write |" + echo "|------------|-------|-----|-----------|" + + [[ -z "$RESULT" ]] && exit 0 + + echo "$RESULT" | while IFS=$'\t' read -r name owner is_private can_write; do + can_write_val=$([[ "$can_write" == "1" ]] && echo "yes" || echo "no") + echo "| $name | $owner | https://git.hangman-lab.top/$owner/$name.git | $can_write_val |" + done +} + +# ───────────────────────────────────────────── +# config +# ───────────────────────────────────────────── +do_config() { + local REPO_PATH="" + local RECURSIVE=false + + while [[ $# -gt 0 ]]; do + case "$1" in + --repo-path) REPO_PATH="${2:-}"; shift 2 ;; + --recursive) RECURSIVE=true; shift ;; + *) echo "Usage: $0 config --repo-path [--recursive]"; exit 1 ;; + esac + done + + if [[ -z "$REPO_PATH" ]]; then + echo "Usage: $0 config --repo-path [--recursive]" + exit 1 + fi + + EMAIL=$(ego-mgr get email) + if [[ -z "$EMAIL" ]]; then + echo "Error: email not set in ego-mgr" + exit 1 + fi + + is_git_repo() { + if [[ -d "$1/.git" ]]; then return 0; fi + if [[ -f "$1/.git" ]]; then + gitdir=$(grep -m1 "gitdir:" "$1/.git" | cut -d' ' -f2 | tr -d ' ') + [[ -n "$gitdir" ]]; return 0 + fi + return 1 + } + + if ! is_git_repo "$REPO_PATH"; then + echo "Not a git repo: $REPO_PATH" + exit 1 + fi + + USER="$(secret-mgr get-username --key git)" + PASS="$(secret-mgr get-secret --key git)" + ENC_USER="$(U="$USER" python3 - <<'PY' +import os, urllib.parse +print(urllib.parse.quote(os.environ['U'], safe='')) +PY +)" + + configure_repo() { + local repo="$1" relative="${2:-}" + local name="${relative:-$repo}" + echo "Configuring: $name" + ( cd "$repo" && git config user.name "$USER" ) + ( cd "$repo" && git config user.email "$EMAIL" ) + local git_dir + git_dir="$(cd "$repo" && git rev-parse --absolute-git-dir)" + local cred_file="${git_dir}/credentials" + ( cd "$repo" && git config credential.helper "store --file ${cred_file}" ) + ( cd "$repo" && GIT_ASKPASS=true git credential-store --file "${cred_file}" store </dev/null | awk '{print $2}' || true) + for sm in $submodules; do + sm_path="$REPO_PATH/$sm" + if is_git_repo "$sm_path"; then + configure_repo "$sm_path" "$sm" + fi + done + fi + + echo "OK" +} + +# ───────────────────────────────────────────── +# Dispatch +# ───────────────────────────────────────────── +if [[ $# -lt 1 ]]; then + echo "Usage: $0 [args...]" echo "" echo "Commands:" - echo " create Create a new repository" - echo " add-collaborators Add collaborator to repository" - echo " list-all [args] List all visible repositories" - echo " config Configure repository" + echo " create Create a new repository" + echo " add-collaborators --user --repo Add collaborator" + echo " list-all List all visible repositories" + echo " config --repo-path [--recursive] Configure repo credentials" exit 1 fi -subcommand="$1" -shift +subcommand="$1"; shift case "$subcommand" in - create) - "$SCRIPT_DIR/create-repo" "$@" - ;; - add-collaborators) - "$SCRIPT_DIR/repo-add-collaborators" "$@" - ;; - list-all) - "$SCRIPT_DIR/list-projs" "$@" - ;; - config) - "$SCRIPT_DIR/repo-config" "$@" - ;; - *) - echo "Unknown command: $subcommand" - echo "Run '$0' for usage information" - exit 1 - ;; + create) do_create "$@" ;; + add-collaborators) do_add_collaborators "$@" ;; + list-all) do_list_all "$@" ;; + config) do_config "$@" ;; + *) echo "Unknown command: $subcommand"; exit 1 ;; esac \ No newline at end of file diff --git a/git-hangman-lab/scripts/repo-add-collaborators b/git-hangman-lab/scripts/repo-add-collaborators deleted file mode 100755 index d204c77..0000000 --- a/git-hangman-lab/scripts/repo-add-collaborators +++ /dev/null @@ -1,49 +0,0 @@ -#!/bin/bash - -# Get the directory where this script is located -SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" - -# Get username from ego-mgr -username=$(ego-mgr get default-username) - -# Check if username is provided -if [[ -z "$username" ]]; then - echo "Error: default-username not set in ego-mgr, please contact ard" - exit 1 -fi - -# Parse arguments -while [[ $# -gt 0 ]]; do - case $1 in - --repo) - repo="$2" - shift 2 - ;; - --user) - user="$2" - shift 2 - ;; - *) - echo "Unknown option: $1" - exit 1 - ;; - esac -done - -# Check if user and repo are provided -if [[ -z "$user" || -z "$repo" ]]; then - echo "Usage: $0 --user --repo " - exit 1 -fi - -# Check if git-access-token exists -if ! secret-mgr list | grep -q "git-access-token"; then - echo "generate your access token first" - exit 1 -fi - -owner=$(secret-mgr get-username --key git) -token=$(secret-mgr get-secret --key git-access-token) - -# Execute -curl -X PUT -H "Authorization: token $token" -H "Content-Type: application/json" -d '{"permission":"write"}' "https://git.hangman-lab.top/api/v1/repos/$owner/$repo/collaborators/$user" diff --git a/git-hangman-lab/scripts/repo-config b/git-hangman-lab/scripts/repo-config deleted file mode 100755 index 0d84492..0000000 --- a/git-hangman-lab/scripts/repo-config +++ /dev/null @@ -1,135 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -usage() { - echo "Usage: $0 --repo-path [--recursive]" - echo " --repo-path: Path to the git repository" - echo " --recursive: Also configure all submodules (recursive)" - exit 2 -} - -REPO_PATH="" -RECURSIVE=false - -while [[ $# -gt 0 ]]; do - case "$1" in - --repo-path) - REPO_PATH="${2:-}" - shift 2 - ;; - --recursive) - RECURSIVE=true - shift - ;; - *) - usage - ;; - esac -done - -if [[ -z "$REPO_PATH" ]]; then - usage -fi - -# Get email from ego-mgr -EMAIL=$(ego-mgr get email) - -# Check if email is provided -if [[ -z "$EMAIL" ]]; then - echo "Error: email not set in ego-mgr, please contact ard" - exit 1 -fi - -# Check if it's a git repo (either .git is a directory or a file with gitdir: reference) -is_git_repo() { - local repo="$1" - if [[ -d "$repo/.git" ]]; then - return 0 - elif [[ -f "$repo/.git" ]]; then - local gitdir - gitdir=$(grep -m1 "gitdir:" "$repo/.git" | cut -d' ' -f2 | tr -d ' ') - if [[ -n "$gitdir" ]]; then - return 0 - fi - fi - return 1 -} - -if ! is_git_repo "$REPO_PATH"; then - echo "Not a git repo: $REPO_PATH" - exit 1 -fi - -USER="$(secret-mgr get-username --key git)" -PASS="$(secret-mgr get-secret --key git)" - -if [[ -z "$USER" || -z "$PASS" ]]; then - echo "Missing credentials from secret-mgr (key: git)" - exit 2 -fi - -# URL-encode username for credential URL -ENC_USER="$(U="$USER" python3 - <<'PY' -import os, urllib.parse -print(urllib.parse.quote(os.environ['U'], safe='')) -PY -)" - -# Function to configure a single repo -configure_repo() { - local repo="$1" - local relative="${2:-}" - - # Get relative path name for display - local name="${relative:-$repo}" - - echo "Configuring: $name" - - # Set local user.name / user.email - ( cd "$repo" && git config user.name "$USER" ) - ( cd "$repo" && git config user.email "$EMAIL" ) - - # Resolve the real git dir (works for normal repos and submodules) - local git_dir - git_dir="$(cd "$repo" && git rev-parse --absolute-git-dir)" - local cred_file="${git_dir}/credentials" - - ( cd "$repo" && git config credential.helper "store --file ${cred_file}" ) - ( cd "$repo" && GIT_ASKPASS=true git credential-store --file "${cred_file}" store </dev/null | awk '{print $2}' || true) - - if [[ -z "$submodules" ]]; then - echo "No submodules found" - else - for sm in $submodules; do - sm_path="$REPO_PATH/$sm" - if is_git_repo "$sm_path"; then - configure_repo "$sm_path" "$sm" - fi - done - fi -fi - -echo "" -echo "OK"