Feature: Add GitHub Repository Transfer Capability - #23
Conversation
- Added gh-repo-transfer.sh script to transfer GitHub repositories
- Implements POST /repos/{owner}/{repo}/transfer API endpoint
- Supports transfer to new owner (user or organization)
- Uses secure curl configuration with HTTPS and TLS 1.2
- Includes parameter validation and error handling
- Loads GITHUB_TOKEN from auth.sh or environment variable
- Follows project architecture with BASE_DIR sourcing pattern
- Outputs JSON response via jq for consistent formatting
This extends GitHub API coverage with repository transfer capabilities:
- Enables programmatic ownership transfer
- Follows same security and error handling patterns as existing scripts
- Allows migration between organizations or to other users
There was a problem hiding this comment.
Code Review
This pull request introduces a new Bash script, gh-repo-transfer.sh, to transfer GitHub repositories to a new owner using the GitHub REST API. The review feedback highlights several critical improvements: ensuring GITHUB_TOKEN is validated before execution, redirecting usage errors to stderr while fixing a typo, safely constructing the JSON payload using jq to prevent injection vulnerabilities, and removing the -f flag from curl to allow proper error handling and reporting of API error messages.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| response=$(curl --proto "=https" --tlsv1.2 -sSf -L -X POST "$endpoint" \ | ||
| -H "Accept: application/vnd.github+json" \ | ||
| -H "Authorization: Bearer $GITHUB_TOKEN" \ | ||
| -H "X-GitHub-Api-Version: 2026-03-10" \ | ||
| -d "$payload") | ||
|
|
||
| # Displays the response message or the repository name upon success. | ||
| echo "$response" | jq -r '.message // .name' | ||
|
|
||
| return 0 |
There was a problem hiding this comment.
Using curl -f (or --fail) with set -e causes the script to exit immediately on HTTP errors (like 404 or 422) without printing the API's JSON error response, which contradicts the described behavior in the PR description. Removing -f and checking for .message in the JSON response allows the error message to be printed while still exiting with a non-zero status on failure.
| response=$(curl --proto "=https" --tlsv1.2 -sSf -L -X POST "$endpoint" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer $GITHUB_TOKEN" \ | |
| -H "X-GitHub-Api-Version: 2026-03-10" \ | |
| -d "$payload") | |
| # Displays the response message or the repository name upon success. | |
| echo "$response" | jq -r '.message // .name' | |
| return 0 | |
| response=$(curl --proto "=https" --tlsv1.2 -sS -L -X POST "$endpoint" \ | |
| -H "Accept: application/vnd.github+json" \ | |
| -H "Authorization: Bearer $GITHUB_TOKEN" \ | |
| -H "X-GitHub-Api-Version: 2026-03-10" \ | |
| -d "$payload") | |
| # Displays the response message or the repository name upon success. | |
| echo "$response" | jq -r '.message // .name' | |
| # Exit with error if the response contains an error message | |
| if echo "$response" | jq -e '.message' >/dev/null; then | |
| return 1 | |
| fi | |
| return 0 |
| if [[ -z "${GITHUB_TOKEN:-}" ]]; then | ||
| if [[ -f "${BASE_DIR}/utils/auth.sh" ]]; then | ||
| source "${BASE_DIR}/utils/auth.sh" | ||
| fi | ||
| fi |
There was a problem hiding this comment.
If GITHUB_TOKEN is still unset after attempting to load auth.sh, the script will proceed and fail during the API call. Adding an explicit check and exiting early with a clear error message improves the user experience and script robustness.
| if [[ -z "${GITHUB_TOKEN:-}" ]]; then | |
| if [[ -f "${BASE_DIR}/utils/auth.sh" ]]; then | |
| source "${BASE_DIR}/utils/auth.sh" | |
| fi | |
| fi | |
| if [[ -z "${GITHUB_TOKEN:-}" ]]; then | |
| if [[ -f "${BASE_DIR}/utils/auth.sh" ]]; then | |
| source "${BASE_DIR}/utils/auth.sh" | |
| fi | |
| fi | |
| if [[ -z "${GITHUB_TOKEN:-}" ]]; then | |
| echo "Error: GITHUB_TOKEN is not set." >&2 | |
| exit 1 | |
| fi |
| if [[ -z "$target_repo" || -z "$new_owner" ]]; then | ||
| echo "Usage: $0 <owner/repo> <novo_owner>" | ||
| exit 1 | ||
| fi |
There was a problem hiding this comment.
The usage message is currently printed to standard output instead of standard error. Additionally, there is a typo in the placeholder (<novo_owner> instead of <new_owner>). Redirecting usage/error messages to stderr is standard practice.
| if [[ -z "$target_repo" || -z "$new_owner" ]]; then | |
| echo "Usage: $0 <owner/repo> <novo_owner>" | |
| exit 1 | |
| fi | |
| if [[ -z "$target_repo" || -z "$new_owner" ]]; then | |
| echo "Usage: $0 <owner/repo> <new_owner>" >&2 | |
| exit 1 | |
| fi |
| endpoint="https://api.github.com/repos/$target_repo/transfer" | ||
|
|
||
| # Creation of the JSON payload for the transfer | ||
| payload=$(printf '{"new_owner":"%s"}' "$new_owner") |
There was a problem hiding this comment.
Constructing JSON payloads using string interpolation or printf can lead to malformed JSON or injection vulnerabilities if the variable contains special characters (like quotes or backslashes). Since jq is already a dependency of this script, use it to safely encode the payload.
| payload=$(printf '{"new_owner":"%s"}' "$new_owner") | |
| payload=$(jq -n --arg new_owner "$new_owner" '{"new_owner": $new_owner}') |
This pull request introduces a new script,
gh-repo-transfer.sh, to enable programmatic repository transfers between owners (users or organizations) via the GitHub API. This extends the project's GitHub API coverage with additional repository management functionality and establishes improved error handling patterns for the codebase.Changes Implemented:
src/github/gh-repo-transfer.sh: New script implementing repository transfer functionality:POST /repos/{owner}/{repo}/transfer--proto "=https" --tlsv1.2)BASE_DIRsourcing patternGITHUB_TOKENfrom auth utilities or environment variablesError Handling Enhancement: Establishes robust
set -eo pipefailconfigurationset -euo pipefailStandalone Execution Support: Robust authentication loading pattern
settings.shfor base configurationauth.shloading if token not presentTechnical Details:
Error Handling Philosophy
Before (Pattern in Other Scripts):
set -euo pipefail-e: Exit on any error-u: Treat unset variables as errors (causes early exit with no error message)-o pipefail: Pipeline failures propagateAfter (Enhanced Pattern in This Script):
set -eo pipefail-e: Exit on any error-o pipefail: Pipeline failures propagate-u: Prevents premature exits without clear error messagesWhy This Matters:
set -ucan cause scripts to exit silently with no meaningful error message-uallows scripts to fail with clear error output viaecho >&2Authentication Loading Pattern
Advantages:
Script Features
gh-repo-transfer.sh <owner/repo> <new_owner>POST /repos/{owner}/{repo}/transferGITHUB_TOKENjqBenefits:
1. Improved Error Handling
2. Enhanced Architecture
3. Extended API Coverage
gh-repo-list.sh,gh-repo-delete.sh, andgh-search-repo.sh4. Automation Enablement
5. Security Standards
Usage Examples:
Basic Transfer
Bulk Transfer from File
Integration with Other Commands
Error Handling Example
Technical Differences from Existing Scripts:
Error Handling Comparison
set -eset -uset -o pipefailArchitecture Comparison
Motivation:
This addition addresses a gap in the project's GitHub API coverage:
Testing & Validation:
The script has been validated to ensure:
jqworks as expected--proto,--tlsv1.2) are applied correctlyDependencies:
None additional - the script leverages:
curl: Already used in all GitHub scriptsjq: Already used for JSON parsingauth.sh: Consistent with project patternsThis script establishes a new standard for error handling in the GitNap project, improving developer experience and debugging capabilities across the codebase.