centralize guides and rails under mosaic with runtime compatibility links

This commit is contained in:
Jason Woltje
2026-02-17 11:39:52 -06:00
parent a1c2efef1c
commit 4eac2c76e6
85 changed files with 10785 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
# detect-platform.ps1 - Detect git platform (Gitea or GitHub) for current repo
# Usage: . .\detect-platform.ps1; Get-GitPlatform
# or: .\detect-platform.ps1 (prints platform name)
function Get-GitPlatform {
[CmdletBinding()]
param()
$remoteUrl = git remote get-url origin 2>$null
if ([string]::IsNullOrEmpty($remoteUrl)) {
Write-Error "Not a git repository or no origin remote"
return $null
}
# Check for GitHub
if ($remoteUrl -match "github\.com") {
return "github"
}
# Check for common Gitea indicators
# Gitea URLs typically don't contain github.com, gitlab.com, bitbucket.org
if ($remoteUrl -notmatch "gitlab\.com" -and $remoteUrl -notmatch "bitbucket\.org") {
# Assume Gitea for self-hosted repos
return "gitea"
}
return "unknown"
}
function Get-GitRepoInfo {
[CmdletBinding()]
param()
$remoteUrl = git remote get-url origin 2>$null
if ([string]::IsNullOrEmpty($remoteUrl)) {
Write-Error "Not a git repository or no origin remote"
return $null
}
# Extract owner/repo from URL
# Handles: git@host:owner/repo.git, https://host/owner/repo.git, https://host/owner/repo
$repoPath = $remoteUrl
if ($remoteUrl -match "^git@") {
$repoPath = ($remoteUrl -split ":")[1]
} else {
# Remove protocol and host
$repoPath = $remoteUrl -replace "^https?://[^/]+/", ""
}
# Remove .git suffix if present
$repoPath = $repoPath -replace "\.git$", ""
return $repoPath
}
function Get-GitRepoOwner {
[CmdletBinding()]
param()
$repoInfo = Get-GitRepoInfo
if ($repoInfo) {
return ($repoInfo -split "/")[0]
}
return $null
}
function Get-GitRepoName {
[CmdletBinding()]
param()
$repoInfo = Get-GitRepoInfo
if ($repoInfo) {
return ($repoInfo -split "/")[-1]
}
return $null
}
# If script is run directly (not dot-sourced), output the platform
if ($MyInvocation.InvocationName -ne ".") {
Get-GitPlatform
}

80
rails/git/detect-platform.sh Executable file
View File

@@ -0,0 +1,80 @@
#!/bin/bash
# detect-platform.sh - Detect git platform (Gitea or GitHub) for current repo
# Usage: source detect-platform.sh && detect_platform
# or: ./detect-platform.sh (prints platform name)
detect_platform() {
local remote_url
remote_url=$(git remote get-url origin 2>/dev/null)
if [[ -z "$remote_url" ]]; then
echo "error: not a git repository or no origin remote" >&2
return 1
fi
# Check for GitHub
if [[ "$remote_url" == *"github.com"* ]]; then
PLATFORM="github"
export PLATFORM
echo "github"
return 0
fi
# Check for common Gitea indicators
# Gitea URLs typically don't contain github.com, gitlab.com, bitbucket.org
if [[ "$remote_url" != *"gitlab.com"* ]] && \
[[ "$remote_url" != *"bitbucket.org"* ]]; then
# Assume Gitea for self-hosted repos
PLATFORM="gitea"
export PLATFORM
echo "gitea"
return 0
fi
PLATFORM="unknown"
export PLATFORM
echo "unknown"
return 1
}
get_repo_info() {
local remote_url
remote_url=$(git remote get-url origin 2>/dev/null)
if [[ -z "$remote_url" ]]; then
echo "error: not a git repository or no origin remote" >&2
return 1
fi
# Extract owner/repo from URL
# Handles: git@host:owner/repo.git, https://host/owner/repo.git, https://host/owner/repo
local repo_path
if [[ "$remote_url" == git@* ]]; then
repo_path="${remote_url#*:}"
else
repo_path="${remote_url#*://}"
repo_path="${repo_path#*/}"
fi
# Remove .git suffix if present
repo_path="${repo_path%.git}"
echo "$repo_path"
}
get_repo_owner() {
local repo_info
repo_info=$(get_repo_info)
echo "${repo_info%%/*}"
}
get_repo_name() {
local repo_info
repo_info=$(get_repo_info)
echo "${repo_info##*/}"
}
# If script is run directly (not sourced), output the platform
if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
detect_platform
fi

111
rails/git/issue-assign.ps1 Normal file
View File

@@ -0,0 +1,111 @@
# issue-assign.ps1 - Assign issues on Gitea or GitHub
# Usage: .\issue-assign.ps1 -Issue ISSUE_NUMBER [-Assignee assignee] [-Labels labels] [-Milestone milestone]
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Alias("i")]
[int]$Issue,
[Alias("a")]
[string]$Assignee,
[Alias("l")]
[string]$Labels,
[Alias("m")]
[string]$Milestone,
[Alias("r")]
[switch]$RemoveAssignee,
[Alias("h")]
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$ScriptDir\detect-platform.ps1"
function Show-Usage {
@"
Usage: issue-assign.ps1 [OPTIONS]
Assign or update an issue on the current repository (Gitea or GitHub).
Options:
-Issue, -i NUMBER Issue number (required)
-Assignee, -a USER Assign to user (use @me for self)
-Labels, -l LABELS Add comma-separated labels
-Milestone, -m NAME Set milestone
-RemoveAssignee, -r Remove current assignee
-Help, -h Show this help message
Examples:
.\issue-assign.ps1 -i 42 -a "username"
.\issue-assign.ps1 -i 42 -l "in-progress" -m "0.2.0"
.\issue-assign.ps1 -i 42 -a @me
"@
exit 1
}
if ($Help) {
Show-Usage
}
$platform = Get-GitPlatform
switch ($platform) {
"github" {
if ($Assignee) {
gh issue edit $Issue --add-assignee $Assignee
}
if ($RemoveAssignee) {
$current = gh issue view $Issue --json assignees -q '.assignees[].login' 2>$null
if ($current) {
$assignees = ($current -split "`n") -join ","
gh issue edit $Issue --remove-assignee $assignees
}
}
if ($Labels) {
gh issue edit $Issue --add-label $Labels
}
if ($Milestone) {
gh issue edit $Issue --milestone $Milestone
}
Write-Host "Issue #$Issue updated successfully"
}
"gitea" {
$needsEdit = $false
$cmd = @("tea", "issue", "edit", $Issue)
if ($Assignee) {
$cmd += @("--assignees", $Assignee)
$needsEdit = $true
}
if ($Labels) {
$cmd += @("--labels", $Labels)
$needsEdit = $true
}
if ($Milestone) {
$milestoneList = tea milestones list 2>$null
$milestoneId = ($milestoneList | Select-String "^\s*(\d+).*$Milestone" | ForEach-Object { $_.Matches.Groups[1].Value } | Select-Object -First 1)
if ($milestoneId) {
$cmd += @("--milestone", $milestoneId)
$needsEdit = $true
} else {
Write-Warning "Could not find milestone '$Milestone'"
}
}
if ($needsEdit) {
& $cmd[0] $cmd[1..($cmd.Length-1)]
Write-Host "Issue #$Issue updated successfully"
} else {
Write-Host "No changes specified"
}
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}

135
rails/git/issue-assign.sh Executable file
View File

@@ -0,0 +1,135 @@
#!/bin/bash
# issue-assign.sh - Assign issues on Gitea or GitHub
# Usage: issue-assign.sh -i ISSUE_NUMBER [-a assignee] [-l labels] [-m milestone]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
ISSUE=""
ASSIGNEE=""
LABELS=""
MILESTONE=""
REMOVE_ASSIGNEE=false
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Assign or update an issue on the current repository (Gitea or GitHub).
Options:
-i, --issue NUMBER Issue number (required)
-a, --assignee USER Assign to user (use @me for self)
-l, --labels LABELS Add comma-separated labels
-m, --milestone NAME Set milestone
-r, --remove-assignee Remove current assignee
-h, --help Show this help message
Examples:
$(basename "$0") -i 42 -a "username"
$(basename "$0") -i 42 -l "in-progress" -m "0.2.0"
$(basename "$0") -i 42 -a @me
EOF
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-i|--issue)
ISSUE="$2"
shift 2
;;
-a|--assignee)
ASSIGNEE="$2"
shift 2
;;
-l|--labels)
LABELS="$2"
shift 2
;;
-m|--milestone)
MILESTONE="$2"
shift 2
;;
-r|--remove-assignee)
REMOVE_ASSIGNEE=true
shift
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
if [[ -z "$ISSUE" ]]; then
echo "Error: Issue number is required (-i)" >&2
usage
fi
PLATFORM=$(detect_platform)
case "$PLATFORM" in
github)
if [[ -n "$ASSIGNEE" ]]; then
gh issue edit "$ISSUE" --add-assignee "$ASSIGNEE"
fi
if [[ "$REMOVE_ASSIGNEE" == true ]]; then
# Get current assignees and remove them
CURRENT=$(gh issue view "$ISSUE" --json assignees -q '.assignees[].login' 2>/dev/null | tr '\n' ',')
if [[ -n "$CURRENT" ]]; then
gh issue edit "$ISSUE" --remove-assignee "${CURRENT%,}"
fi
fi
if [[ -n "$LABELS" ]]; then
gh issue edit "$ISSUE" --add-label "$LABELS"
fi
if [[ -n "$MILESTONE" ]]; then
gh issue edit "$ISSUE" --milestone "$MILESTONE"
fi
echo "Issue #$ISSUE updated successfully"
;;
gitea)
# tea issue edit syntax
CMD="tea issue edit $ISSUE"
NEEDS_EDIT=false
if [[ -n "$ASSIGNEE" ]]; then
# tea uses --assignees flag
CMD="$CMD --assignees \"$ASSIGNEE\""
NEEDS_EDIT=true
fi
if [[ -n "$LABELS" ]]; then
# tea uses --labels flag (replaces existing)
CMD="$CMD --labels \"$LABELS\""
NEEDS_EDIT=true
fi
if [[ -n "$MILESTONE" ]]; then
MILESTONE_ID=$(tea milestones list 2>/dev/null | grep -E "^\s*[0-9]+" | grep "$MILESTONE" | awk '{print $1}' | head -1)
if [[ -n "$MILESTONE_ID" ]]; then
CMD="$CMD --milestone $MILESTONE_ID"
NEEDS_EDIT=true
else
echo "Warning: Could not find milestone '$MILESTONE'" >&2
fi
fi
if [[ "$NEEDS_EDIT" == true ]]; then
eval "$CMD"
echo "Issue #$ISSUE updated successfully"
else
echo "No changes specified"
fi
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac

64
rails/git/issue-close.sh Executable file
View File

@@ -0,0 +1,64 @@
#!/bin/bash
# issue-close.sh - Close an issue on GitHub or Gitea
# Usage: issue-close.sh -i <issue_number> [-c <comment>]
set -e
# Source platform detection
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
ISSUE_NUMBER=""
COMMENT=""
while [[ $# -gt 0 ]]; do
case $1 in
-i|--issue)
ISSUE_NUMBER="$2"
shift 2
;;
-c|--comment)
COMMENT="$2"
shift 2
;;
-h|--help)
echo "Usage: issue-close.sh -i <issue_number> [-c <comment>]"
echo ""
echo "Options:"
echo " -i, --issue Issue number (required)"
echo " -c, --comment Comment to add before closing (optional)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$ISSUE_NUMBER" ]]; then
echo "Error: Issue number is required (-i)"
exit 1
fi
# Detect platform and close issue
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
if [[ -n "$COMMENT" ]]; then
gh issue comment "$ISSUE_NUMBER" --body "$COMMENT"
fi
gh issue close "$ISSUE_NUMBER"
echo "Closed GitHub issue #$ISSUE_NUMBER"
elif [[ "$PLATFORM" == "gitea" ]]; then
if [[ -n "$COMMENT" ]]; then
tea issue comment "$ISSUE_NUMBER" "$COMMENT"
fi
tea issue close "$ISSUE_NUMBER"
echo "Closed Gitea issue #$ISSUE_NUMBER"
else
echo "Error: Unknown platform"
exit 1
fi

61
rails/git/issue-comment.sh Executable file
View File

@@ -0,0 +1,61 @@
#!/bin/bash
# issue-comment.sh - Add a comment to an issue on GitHub or Gitea
# Usage: issue-comment.sh -i <issue_number> -c <comment>
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
ISSUE_NUMBER=""
COMMENT=""
while [[ $# -gt 0 ]]; do
case $1 in
-i|--issue)
ISSUE_NUMBER="$2"
shift 2
;;
-c|--comment)
COMMENT="$2"
shift 2
;;
-h|--help)
echo "Usage: issue-comment.sh -i <issue_number> -c <comment>"
echo ""
echo "Options:"
echo " -i, --issue Issue number (required)"
echo " -c, --comment Comment text (required)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$ISSUE_NUMBER" ]]; then
echo "Error: Issue number is required (-i)"
exit 1
fi
if [[ -z "$COMMENT" ]]; then
echo "Error: Comment is required (-c)"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
gh issue comment "$ISSUE_NUMBER" --body "$COMMENT"
echo "Added comment to GitHub issue #$ISSUE_NUMBER"
elif [[ "$PLATFORM" == "gitea" ]]; then
tea issue comment "$ISSUE_NUMBER" "$COMMENT"
echo "Added comment to Gitea issue #$ISSUE_NUMBER"
else
echo "Error: Unknown platform"
exit 1
fi

View File

@@ -0,0 +1,80 @@
# issue-create.ps1 - Create issues on Gitea or GitHub
# Usage: .\issue-create.ps1 -Title "Title" [-Body "Body"] [-Labels "label1,label2"] [-Milestone "milestone"]
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Alias("t")]
[string]$Title,
[Alias("b")]
[string]$Body,
[Alias("l")]
[string]$Labels,
[Alias("m")]
[string]$Milestone,
[Alias("h")]
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$ScriptDir\detect-platform.ps1"
function Show-Usage {
@"
Usage: issue-create.ps1 [OPTIONS]
Create an issue on the current repository (Gitea or GitHub).
Options:
-Title, -t TITLE Issue title (required)
-Body, -b BODY Issue body/description
-Labels, -l LABELS Comma-separated labels (e.g., "bug,feature")
-Milestone, -m NAME Milestone name to assign
-Help, -h Show this help message
Examples:
.\issue-create.ps1 -Title "Fix login bug" -Labels "bug,priority-high"
.\issue-create.ps1 -t "Add dark mode" -b "Implement theme switching" -m "0.2.0"
"@
exit 1
}
if ($Help) {
Show-Usage
}
$platform = Get-GitPlatform
switch ($platform) {
"github" {
$cmd = @("gh", "issue", "create", "--title", $Title)
if ($Body) { $cmd += @("--body", $Body) }
if ($Labels) { $cmd += @("--label", $Labels) }
if ($Milestone) { $cmd += @("--milestone", $Milestone) }
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
"gitea" {
$cmd = @("tea", "issue", "create", "--title", $Title)
if ($Body) { $cmd += @("--description", $Body) }
if ($Labels) { $cmd += @("--labels", $Labels) }
if ($Milestone) {
# Try to get milestone ID by name
$milestoneList = tea milestones list 2>$null
$milestoneId = ($milestoneList | Select-String "^\s*(\d+).*$Milestone" | ForEach-Object { $_.Matches.Groups[1].Value } | Select-Object -First 1)
if ($milestoneId) {
$cmd += @("--milestone", $milestoneId)
} else {
Write-Warning "Could not find milestone '$Milestone', creating without milestone"
}
}
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}

92
rails/git/issue-create.sh Executable file
View File

@@ -0,0 +1,92 @@
#!/bin/bash
# issue-create.sh - Create issues on Gitea or GitHub
# Usage: issue-create.sh -t "Title" [-b "Body"] [-l "label1,label2"] [-m "milestone"]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
TITLE=""
BODY=""
LABELS=""
MILESTONE=""
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Create an issue on the current repository (Gitea or GitHub).
Options:
-t, --title TITLE Issue title (required)
-b, --body BODY Issue body/description
-l, --labels LABELS Comma-separated labels (e.g., "bug,feature")
-m, --milestone NAME Milestone name to assign
-h, --help Show this help message
Examples:
$(basename "$0") -t "Fix login bug" -l "bug,priority-high"
$(basename "$0") -t "Add dark mode" -b "Implement theme switching" -m "0.2.0"
EOF
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-t|--title)
TITLE="$2"
shift 2
;;
-b|--body)
BODY="$2"
shift 2
;;
-l|--labels)
LABELS="$2"
shift 2
;;
-m|--milestone)
MILESTONE="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
if [[ -z "$TITLE" ]]; then
echo "Error: Title is required (-t)" >&2
usage
fi
PLATFORM=$(detect_platform)
case "$PLATFORM" in
github)
CMD="gh issue create --title \"$TITLE\""
[[ -n "$BODY" ]] && CMD="$CMD --body \"$BODY\""
[[ -n "$LABELS" ]] && CMD="$CMD --label \"$LABELS\""
[[ -n "$MILESTONE" ]] && CMD="$CMD --milestone \"$MILESTONE\""
eval "$CMD"
;;
gitea)
CMD="tea issue create --title \"$TITLE\""
[[ -n "$BODY" ]] && CMD="$CMD --description \"$BODY\""
[[ -n "$LABELS" ]] && CMD="$CMD --labels \"$LABELS\""
# tea accepts milestone by name directly (verified 2026-02-05)
[[ -n "$MILESTONE" ]] && CMD="$CMD --milestone \"$MILESTONE\""
eval "$CMD"
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac

84
rails/git/issue-edit.sh Executable file
View File

@@ -0,0 +1,84 @@
#!/bin/bash
# issue-edit.sh - Edit an issue on GitHub or Gitea
# Usage: issue-edit.sh -i <issue_number> [-t <title>] [-b <body>] [-l <labels>] [-m <milestone>]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
ISSUE_NUMBER=""
TITLE=""
BODY=""
LABELS=""
MILESTONE=""
while [[ $# -gt 0 ]]; do
case $1 in
-i|--issue)
ISSUE_NUMBER="$2"
shift 2
;;
-t|--title)
TITLE="$2"
shift 2
;;
-b|--body)
BODY="$2"
shift 2
;;
-l|--labels)
LABELS="$2"
shift 2
;;
-m|--milestone)
MILESTONE="$2"
shift 2
;;
-h|--help)
echo "Usage: issue-edit.sh -i <issue_number> [-t <title>] [-b <body>] [-l <labels>] [-m <milestone>]"
echo ""
echo "Options:"
echo " -i, --issue Issue number (required)"
echo " -t, --title New title"
echo " -b, --body New body/description"
echo " -l, --labels Labels (comma-separated, replaces existing)"
echo " -m, --milestone Milestone name"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$ISSUE_NUMBER" ]]; then
echo "Error: Issue number is required (-i)"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
CMD="gh issue edit $ISSUE_NUMBER"
[[ -n "$TITLE" ]] && CMD="$CMD --title \"$TITLE\""
[[ -n "$BODY" ]] && CMD="$CMD --body \"$BODY\""
[[ -n "$LABELS" ]] && CMD="$CMD --add-label \"$LABELS\""
[[ -n "$MILESTONE" ]] && CMD="$CMD --milestone \"$MILESTONE\""
eval $CMD
echo "Updated GitHub issue #$ISSUE_NUMBER"
elif [[ "$PLATFORM" == "gitea" ]]; then
CMD="tea issue edit $ISSUE_NUMBER"
[[ -n "$TITLE" ]] && CMD="$CMD --title \"$TITLE\""
[[ -n "$BODY" ]] && CMD="$CMD --description \"$BODY\""
[[ -n "$LABELS" ]] && CMD="$CMD --add-labels \"$LABELS\""
[[ -n "$MILESTONE" ]] && CMD="$CMD --milestone \"$MILESTONE\""
eval $CMD
echo "Updated Gitea issue #$ISSUE_NUMBER"
else
echo "Error: Unknown platform"
exit 1
fi

78
rails/git/issue-list.ps1 Normal file
View File

@@ -0,0 +1,78 @@
# issue-list.ps1 - List issues on Gitea or GitHub
# Usage: .\issue-list.ps1 [-State state] [-Label label] [-Milestone milestone] [-Assignee assignee]
[CmdletBinding()]
param(
[Alias("s")]
[ValidateSet("open", "closed", "all")]
[string]$State = "open",
[Alias("l")]
[string]$Label,
[Alias("m")]
[string]$Milestone,
[Alias("a")]
[string]$Assignee,
[Alias("n")]
[int]$Limit = 100,
[Alias("h")]
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$ScriptDir\detect-platform.ps1"
function Show-Usage {
@"
Usage: issue-list.ps1 [OPTIONS]
List issues from the current repository (Gitea or GitHub).
Options:
-State, -s STATE Filter by state: open, closed, all (default: open)
-Label, -l LABEL Filter by label
-Milestone, -m NAME Filter by milestone name
-Assignee, -a USER Filter by assignee
-Limit, -n N Maximum issues to show (default: 100)
-Help, -h Show this help message
Examples:
.\issue-list.ps1 # List open issues
.\issue-list.ps1 -s all -l bug # All issues with 'bug' label
.\issue-list.ps1 -m "0.2.0" # Issues in milestone 0.2.0
"@
exit 1
}
if ($Help) {
Show-Usage
}
$platform = Get-GitPlatform
switch ($platform) {
"github" {
$cmd = @("gh", "issue", "list", "--state", $State, "--limit", $Limit)
if ($Label) { $cmd += @("--label", $Label) }
if ($Milestone) { $cmd += @("--milestone", $Milestone) }
if ($Assignee) { $cmd += @("--assignee", $Assignee) }
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
"gitea" {
$cmd = @("tea", "issues", "list", "--state", $State, "--limit", $Limit)
if ($Label) { $cmd += @("--labels", $Label) }
if ($Milestone) { $cmd += @("--milestones", $Milestone) }
& $cmd[0] $cmd[1..($cmd.Length-1)]
if ($Assignee) {
Write-Warning "Assignee filtering may require manual review for Gitea"
}
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}

96
rails/git/issue-list.sh Executable file
View File

@@ -0,0 +1,96 @@
#!/bin/bash
# issue-list.sh - List issues on Gitea or GitHub
# Usage: issue-list.sh [-s state] [-l label] [-m milestone] [-a assignee]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
STATE="open"
LABEL=""
MILESTONE=""
ASSIGNEE=""
LIMIT=100
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
List issues from the current repository (Gitea or GitHub).
Options:
-s, --state STATE Filter by state: open, closed, all (default: open)
-l, --label LABEL Filter by label
-m, --milestone NAME Filter by milestone name
-a, --assignee USER Filter by assignee
-n, --limit N Maximum issues to show (default: 100)
-h, --help Show this help message
Examples:
$(basename "$0") # List open issues
$(basename "$0") -s all -l bug # All issues with 'bug' label
$(basename "$0") -m "0.2.0" # Issues in milestone 0.2.0
EOF
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-s|--state)
STATE="$2"
shift 2
;;
-l|--label)
LABEL="$2"
shift 2
;;
-m|--milestone)
MILESTONE="$2"
shift 2
;;
-a|--assignee)
ASSIGNEE="$2"
shift 2
;;
-n|--limit)
LIMIT="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
PLATFORM=$(detect_platform)
case "$PLATFORM" in
github)
CMD="gh issue list --state $STATE --limit $LIMIT"
[[ -n "$LABEL" ]] && CMD="$CMD --label \"$LABEL\""
[[ -n "$MILESTONE" ]] && CMD="$CMD --milestone \"$MILESTONE\""
[[ -n "$ASSIGNEE" ]] && CMD="$CMD --assignee \"$ASSIGNEE\""
eval "$CMD"
;;
gitea)
CMD="tea issues list --state $STATE --limit $LIMIT"
[[ -n "$LABEL" ]] && CMD="$CMD --labels \"$LABEL\""
[[ -n "$MILESTONE" ]] && CMD="$CMD --milestones \"$MILESTONE\""
# Note: tea may not support assignee filter directly
eval "$CMD"
if [[ -n "$ASSIGNEE" ]]; then
echo "Note: Assignee filtering may require manual review for Gitea" >&2
fi
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac

62
rails/git/issue-reopen.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/bash
# issue-reopen.sh - Reopen a closed issue on GitHub or Gitea
# Usage: issue-reopen.sh -i <issue_number> [-c <comment>]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
ISSUE_NUMBER=""
COMMENT=""
while [[ $# -gt 0 ]]; do
case $1 in
-i|--issue)
ISSUE_NUMBER="$2"
shift 2
;;
-c|--comment)
COMMENT="$2"
shift 2
;;
-h|--help)
echo "Usage: issue-reopen.sh -i <issue_number> [-c <comment>]"
echo ""
echo "Options:"
echo " -i, --issue Issue number (required)"
echo " -c, --comment Comment to add when reopening (optional)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$ISSUE_NUMBER" ]]; then
echo "Error: Issue number is required (-i)"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
if [[ -n "$COMMENT" ]]; then
gh issue comment "$ISSUE_NUMBER" --body "$COMMENT"
fi
gh issue reopen "$ISSUE_NUMBER"
echo "Reopened GitHub issue #$ISSUE_NUMBER"
elif [[ "$PLATFORM" == "gitea" ]]; then
if [[ -n "$COMMENT" ]]; then
tea issue comment "$ISSUE_NUMBER" "$COMMENT"
fi
tea issue reopen "$ISSUE_NUMBER"
echo "Reopened Gitea issue #$ISSUE_NUMBER"
else
echo "Error: Unknown platform"
exit 1
fi

48
rails/git/issue-view.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
# issue-view.sh - View issue details on GitHub or Gitea
# Usage: issue-view.sh -i <issue_number>
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
ISSUE_NUMBER=""
while [[ $# -gt 0 ]]; do
case $1 in
-i|--issue)
ISSUE_NUMBER="$2"
shift 2
;;
-h|--help)
echo "Usage: issue-view.sh -i <issue_number>"
echo ""
echo "Options:"
echo " -i, --issue Issue number (required)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$ISSUE_NUMBER" ]]; then
echo "Error: Issue number is required (-i)"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
gh issue view "$ISSUE_NUMBER"
elif [[ "$PLATFORM" == "gitea" ]]; then
tea issue "$ISSUE_NUMBER"
else
echo "Error: Unknown platform"
exit 1
fi

50
rails/git/milestone-close.sh Executable file
View File

@@ -0,0 +1,50 @@
#!/bin/bash
# milestone-close.sh - Close a milestone on GitHub or Gitea
# Usage: milestone-close.sh -t <title>
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
TITLE=""
while [[ $# -gt 0 ]]; do
case $1 in
-t|--title)
TITLE="$2"
shift 2
;;
-h|--help)
echo "Usage: milestone-close.sh -t <title>"
echo ""
echo "Options:"
echo " -t, --title Milestone title (required)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$TITLE" ]]; then
echo "Error: Milestone title is required (-t)"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
gh api -X PATCH "/repos/{owner}/{repo}/milestones/$(gh api "/repos/{owner}/{repo}/milestones" --jq ".[] | select(.title==\"$TITLE\") | .number")" -f state=closed
echo "Closed GitHub milestone: $TITLE"
elif [[ "$PLATFORM" == "gitea" ]]; then
tea milestone close "$TITLE"
echo "Closed Gitea milestone: $TITLE"
else
echo "Error: Unknown platform"
exit 1
fi

View File

@@ -0,0 +1,98 @@
# milestone-create.ps1 - Create milestones on Gitea or GitHub
# Usage: .\milestone-create.ps1 -Title "Title" [-Description "Description"] [-Due "YYYY-MM-DD"]
[CmdletBinding()]
param(
[Alias("t")]
[string]$Title,
[Alias("d")]
[string]$Description,
[string]$Due,
[switch]$List,
[Alias("h")]
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$ScriptDir\detect-platform.ps1"
function Show-Usage {
@"
Usage: milestone-create.ps1 [OPTIONS]
Create or list milestones on the current repository (Gitea or GitHub).
Versioning Convention:
- Features get dedicated milestones
- Pre-release: 0.X.0 for breaking changes, 0.X.Y for patches
- Post-release: X.0.0 for breaking changes
- MVP starts at 0.1.0
Options:
-Title, -t TITLE Milestone title/version (e.g., "0.2.0")
-Description, -d DESC Milestone description
-Due DATE Due date (YYYY-MM-DD format)
-List List existing milestones
-Help, -h Show this help message
Examples:
.\milestone-create.ps1 -List
.\milestone-create.ps1 -t "0.1.0" -d "MVP Release"
.\milestone-create.ps1 -t "0.2.0" -d "User Authentication Feature" -Due "2025-03-01"
"@
exit 1
}
if ($Help) {
Show-Usage
}
$platform = Get-GitPlatform
if ($List) {
switch ($platform) {
"github" {
gh api repos/:owner/:repo/milestones --jq '.[] | "\(.number)`t\(.title)`t\(.state)`t\(.open_issues)/\(.closed_issues) issues"'
}
"gitea" {
tea milestones list
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}
exit 0
}
if (-not $Title) {
Write-Error "Title is required (-t) for creating milestones"
Show-Usage
}
switch ($platform) {
"github" {
$payload = @{ title = $Title }
if ($Description) { $payload.description = $Description }
if ($Due) { $payload.due_on = "${Due}T00:00:00Z" }
$json = $payload | ConvertTo-Json -Compress
$json | gh api repos/:owner/:repo/milestones --method POST --input -
Write-Host "Milestone '$Title' created successfully"
}
"gitea" {
$cmd = @("tea", "milestones", "create", "--title", $Title)
if ($Description) { $cmd += @("--description", $Description) }
if ($Due) { $cmd += @("--deadline", $Due) }
& $cmd[0] $cmd[1..($cmd.Length-1)]
Write-Host "Milestone '$Title' created successfully"
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}

117
rails/git/milestone-create.sh Executable file
View File

@@ -0,0 +1,117 @@
#!/bin/bash
# milestone-create.sh - Create milestones on Gitea or GitHub
# Usage: milestone-create.sh -t "Title" [-d "Description"] [--due "YYYY-MM-DD"]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
TITLE=""
DESCRIPTION=""
DUE_DATE=""
LIST_ONLY=false
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Create or list milestones on the current repository (Gitea or GitHub).
Versioning Convention:
- Features get dedicated milestones
- Pre-release: 0.X.0 for breaking changes, 0.X.Y for patches
- Post-release: X.0.0 for breaking changes
- MVP starts at 0.1.0
Options:
-t, --title TITLE Milestone title/version (e.g., "0.2.0")
-d, --desc DESCRIPTION Milestone description
--due DATE Due date (YYYY-MM-DD format)
--list List existing milestones
-h, --help Show this help message
Examples:
$(basename "$0") --list
$(basename "$0") -t "0.1.0" -d "MVP Release"
$(basename "$0") -t "0.2.0" -d "User Authentication Feature" --due "2025-03-01"
EOF
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-t|--title)
TITLE="$2"
shift 2
;;
-d|--desc)
DESCRIPTION="$2"
shift 2
;;
--due)
DUE_DATE="$2"
shift 2
;;
--list)
LIST_ONLY=true
shift
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
PLATFORM=$(detect_platform)
if [[ "$LIST_ONLY" == true ]]; then
case "$PLATFORM" in
github)
gh api repos/:owner/:repo/milestones --jq '.[] | "\(.number)\t\(.title)\t\(.state)\t\(.open_issues)/\(.closed_issues) issues"'
;;
gitea)
tea milestones list
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac
exit 0
fi
if [[ -z "$TITLE" ]]; then
echo "Error: Title is required (-t) for creating milestones" >&2
usage
fi
case "$PLATFORM" in
github)
# GitHub uses the API for milestone creation
JSON_PAYLOAD="{\"title\":\"$TITLE\""
[[ -n "$DESCRIPTION" ]] && JSON_PAYLOAD="$JSON_PAYLOAD,\"description\":\"$DESCRIPTION\""
[[ -n "$DUE_DATE" ]] && JSON_PAYLOAD="$JSON_PAYLOAD,\"due_on\":\"${DUE_DATE}T00:00:00Z\""
JSON_PAYLOAD="$JSON_PAYLOAD}"
gh api repos/:owner/:repo/milestones --method POST --input - <<< "$JSON_PAYLOAD"
echo "Milestone '$TITLE' created successfully"
;;
gitea)
CMD="tea milestones create --title \"$TITLE\""
[[ -n "$DESCRIPTION" ]] && CMD="$CMD --description \"$DESCRIPTION\""
[[ -n "$DUE_DATE" ]] && CMD="$CMD --deadline \"$DUE_DATE\""
eval "$CMD"
echo "Milestone '$TITLE' created successfully"
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac

43
rails/git/milestone-list.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
# milestone-list.sh - List milestones on GitHub or Gitea
# Usage: milestone-list.sh [-s <state>]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
STATE="open"
while [[ $# -gt 0 ]]; do
case $1 in
-s|--state)
STATE="$2"
shift 2
;;
-h|--help)
echo "Usage: milestone-list.sh [-s <state>]"
echo ""
echo "Options:"
echo " -s, --state Filter by state: open, closed, all (default: open)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
gh api "/repos/{owner}/{repo}/milestones?state=$STATE" --jq '.[] | "\(.title) (\(.state)) - \(.open_issues) open, \(.closed_issues) closed"'
elif [[ "$PLATFORM" == "gitea" ]]; then
tea milestone list
else
echo "Error: Unknown platform"
exit 1
fi

62
rails/git/pr-close.sh Executable file
View File

@@ -0,0 +1,62 @@
#!/bin/bash
# pr-close.sh - Close a pull request without merging on GitHub or Gitea
# Usage: pr-close.sh -n <pr_number> [-c <comment>]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
PR_NUMBER=""
COMMENT=""
while [[ $# -gt 0 ]]; do
case $1 in
-n|--number)
PR_NUMBER="$2"
shift 2
;;
-c|--comment)
COMMENT="$2"
shift 2
;;
-h|--help)
echo "Usage: pr-close.sh -n <pr_number> [-c <comment>]"
echo ""
echo "Options:"
echo " -n, --number PR number (required)"
echo " -c, --comment Comment before closing (optional)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$PR_NUMBER" ]]; then
echo "Error: PR number is required (-n)"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
if [[ -n "$COMMENT" ]]; then
gh pr comment "$PR_NUMBER" --body "$COMMENT"
fi
gh pr close "$PR_NUMBER"
echo "Closed GitHub PR #$PR_NUMBER"
elif [[ "$PLATFORM" == "gitea" ]]; then
if [[ -n "$COMMENT" ]]; then
tea pr comment "$PR_NUMBER" "$COMMENT"
fi
tea pr close "$PR_NUMBER"
echo "Closed Gitea PR #$PR_NUMBER"
else
echo "Error: Unknown platform"
exit 1
fi

130
rails/git/pr-create.ps1 Normal file
View File

@@ -0,0 +1,130 @@
# pr-create.ps1 - Create pull requests on Gitea or GitHub
# Usage: .\pr-create.ps1 -Title "Title" [-Body "Body"] [-Base base] [-Head head] [-Labels "labels"] [-Milestone "milestone"]
[CmdletBinding()]
param(
[Alias("t")]
[string]$Title,
[Alias("b")]
[string]$Body,
[Alias("B")]
[string]$Base,
[Alias("H")]
[string]$Head,
[Alias("l")]
[string]$Labels,
[Alias("m")]
[string]$Milestone,
[Alias("i")]
[int]$Issue,
[Alias("d")]
[switch]$Draft,
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$ScriptDir\detect-platform.ps1"
function Show-Usage {
@"
Usage: pr-create.ps1 [OPTIONS]
Create a pull request on the current repository (Gitea or GitHub).
Options:
-Title, -t TITLE PR title (required, or use -Issue)
-Body, -b BODY PR description/body
-Base, -B BRANCH Base branch to merge into (default: main/master)
-Head, -H BRANCH Head branch with changes (default: current branch)
-Labels, -l LABELS Comma-separated labels
-Milestone, -m NAME Milestone name
-Issue, -i NUMBER Link to issue (auto-generates title if not provided)
-Draft, -d Create as draft PR
-Help Show this help message
Examples:
.\pr-create.ps1 -Title "Add login feature" -Body "Implements user authentication"
.\pr-create.ps1 -t "Fix bug" -B main -H feature/fix-123
.\pr-create.ps1 -i 42 -b "Implements the feature described in #42"
.\pr-create.ps1 -t "WIP: New feature" -Draft
"@
exit 1
}
if ($Help) {
Show-Usage
}
# If no title but issue provided, generate title
if (-not $Title -and $Issue) {
$Title = "Fixes #$Issue"
}
if (-not $Title) {
Write-Error "Title is required (-t) or provide an issue (-i)"
Show-Usage
}
# Default head branch to current branch
if (-not $Head) {
$Head = git branch --show-current
}
# Add issue reference to body if provided
if ($Issue) {
if ($Body) {
$Body = "$Body`n`nFixes #$Issue"
} else {
$Body = "Fixes #$Issue"
}
}
$platform = Get-GitPlatform
switch ($platform) {
"github" {
$cmd = @("gh", "pr", "create", "--title", $Title)
if ($Body) { $cmd += @("--body", $Body) }
if ($Base) { $cmd += @("--base", $Base) }
if ($Head) { $cmd += @("--head", $Head) }
if ($Labels) { $cmd += @("--label", $Labels) }
if ($Milestone) { $cmd += @("--milestone", $Milestone) }
if ($Draft) { $cmd += "--draft" }
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
"gitea" {
$cmd = @("tea", "pr", "create", "--title", $Title)
if ($Body) { $cmd += @("--description", $Body) }
if ($Base) { $cmd += @("--base", $Base) }
if ($Head) { $cmd += @("--head", $Head) }
if ($Labels) { $cmd += @("--labels", $Labels) }
if ($Milestone) {
$milestoneList = tea milestones list 2>$null
$milestoneId = ($milestoneList | Select-String "^\s*(\d+).*$Milestone" | ForEach-Object { $_.Matches.Groups[1].Value } | Select-Object -First 1)
if ($milestoneId) {
$cmd += @("--milestone", $milestoneId)
} else {
Write-Warning "Could not find milestone '$Milestone', creating without milestone"
}
}
if ($Draft) {
Write-Warning "Draft PR may not be supported by your tea version"
}
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}

164
rails/git/pr-create.sh Executable file
View File

@@ -0,0 +1,164 @@
#!/bin/bash
# pr-create.sh - Create pull requests on Gitea or GitHub
# Usage: pr-create.sh -t "Title" [-b "Body"] [-B base] [-H head] [-l "labels"] [-m "milestone"]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
TITLE=""
BODY=""
BASE_BRANCH=""
HEAD_BRANCH=""
LABELS=""
MILESTONE=""
DRAFT=false
ISSUE=""
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Create a pull request on the current repository (Gitea or GitHub).
Options:
-t, --title TITLE PR title (required, or use --issue)
-b, --body BODY PR description/body
-B, --base BRANCH Base branch to merge into (default: main/master)
-H, --head BRANCH Head branch with changes (default: current branch)
-l, --labels LABELS Comma-separated labels
-m, --milestone NAME Milestone name
-i, --issue NUMBER Link to issue (auto-generates title if not provided)
-d, --draft Create as draft PR
-h, --help Show this help message
Examples:
$(basename "$0") -t "Add login feature" -b "Implements user authentication"
$(basename "$0") -t "Fix bug" -B main -H feature/fix-123
$(basename "$0") -i 42 -b "Implements the feature described in #42"
$(basename "$0") -t "WIP: New feature" --draft
EOF
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-t|--title)
TITLE="$2"
shift 2
;;
-b|--body)
BODY="$2"
shift 2
;;
-B|--base)
BASE_BRANCH="$2"
shift 2
;;
-H|--head)
HEAD_BRANCH="$2"
shift 2
;;
-l|--labels)
LABELS="$2"
shift 2
;;
-m|--milestone)
MILESTONE="$2"
shift 2
;;
-i|--issue)
ISSUE="$2"
shift 2
;;
-d|--draft)
DRAFT=true
shift
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
# If no title but issue provided, generate title
if [[ -z "$TITLE" ]] && [[ -n "$ISSUE" ]]; then
TITLE="Fixes #$ISSUE"
fi
if [[ -z "$TITLE" ]]; then
echo "Error: Title is required (-t) or provide an issue (-i)" >&2
usage
fi
# Default head branch to current branch
if [[ -z "$HEAD_BRANCH" ]]; then
HEAD_BRANCH=$(git branch --show-current)
fi
# Add issue reference to body if provided
if [[ -n "$ISSUE" ]]; then
if [[ -n "$BODY" ]]; then
BODY="$BODY
Fixes #$ISSUE"
else
BODY="Fixes #$ISSUE"
fi
fi
PLATFORM=$(detect_platform)
case "$PLATFORM" in
github)
CMD="gh pr create --title \"$TITLE\""
[[ -n "$BODY" ]] && CMD="$CMD --body \"$BODY\""
[[ -n "$BASE_BRANCH" ]] && CMD="$CMD --base \"$BASE_BRANCH\""
[[ -n "$HEAD_BRANCH" ]] && CMD="$CMD --head \"$HEAD_BRANCH\""
[[ -n "$LABELS" ]] && CMD="$CMD --label \"$LABELS\""
[[ -n "$MILESTONE" ]] && CMD="$CMD --milestone \"$MILESTONE\""
[[ "$DRAFT" == true ]] && CMD="$CMD --draft"
eval "$CMD"
;;
gitea)
# tea pull create syntax
CMD="tea pr create --title \"$TITLE\""
[[ -n "$BODY" ]] && CMD="$CMD --description \"$BODY\""
[[ -n "$BASE_BRANCH" ]] && CMD="$CMD --base \"$BASE_BRANCH\""
[[ -n "$HEAD_BRANCH" ]] && CMD="$CMD --head \"$HEAD_BRANCH\""
# Handle labels for tea
if [[ -n "$LABELS" ]]; then
# tea may use --labels flag
CMD="$CMD --labels \"$LABELS\""
fi
# Handle milestone for tea
if [[ -n "$MILESTONE" ]]; then
MILESTONE_ID=$(tea milestones list 2>/dev/null | grep -E "^\s*[0-9]+" | grep "$MILESTONE" | awk '{print $1}' | head -1)
if [[ -n "$MILESTONE_ID" ]]; then
CMD="$CMD --milestone $MILESTONE_ID"
else
echo "Warning: Could not find milestone '$MILESTONE', creating without milestone" >&2
fi
fi
# Note: tea may not support --draft flag in all versions
if [[ "$DRAFT" == true ]]; then
echo "Note: Draft PR may not be supported by your tea version" >&2
fi
eval "$CMD"
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac

88
rails/git/pr-diff.sh Executable file
View File

@@ -0,0 +1,88 @@
#!/bin/bash
# pr-diff.sh - Get the diff for a pull request on GitHub or Gitea
# Usage: pr-diff.sh -n <pr_number> [-o <output_file>]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
PR_NUMBER=""
OUTPUT_FILE=""
while [[ $# -gt 0 ]]; do
case $1 in
-n|--number)
PR_NUMBER="$2"
shift 2
;;
-o|--output)
OUTPUT_FILE="$2"
shift 2
;;
-h|--help)
echo "Usage: pr-diff.sh -n <pr_number> [-o <output_file>]"
echo ""
echo "Options:"
echo " -n, --number PR number (required)"
echo " -o, --output Output file (optional, prints to stdout if omitted)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$PR_NUMBER" ]]; then
echo "Error: PR number is required (-n)" >&2
exit 1
fi
detect_platform > /dev/null
if [[ "$PLATFORM" == "github" ]]; then
if [[ -n "$OUTPUT_FILE" ]]; then
gh pr diff "$PR_NUMBER" > "$OUTPUT_FILE"
else
gh pr diff "$PR_NUMBER"
fi
elif [[ "$PLATFORM" == "gitea" ]]; then
# tea doesn't have a direct diff command — use the API
OWNER=$(get_repo_owner)
REPO=$(get_repo_name)
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
# Extract host from remote URL
if [[ "$REMOTE_URL" == https://* ]]; then
HOST=$(echo "$REMOTE_URL" | sed -E 's|https://([^/]+)/.*|\1|')
elif [[ "$REMOTE_URL" == git@* ]]; then
HOST=$(echo "$REMOTE_URL" | sed -E 's|git@([^:]+):.*|\1|')
else
echo "Error: Cannot determine host from remote URL" >&2
exit 1
fi
DIFF_URL="https://${HOST}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}.diff"
# Use tea's auth token if available
TEA_TOKEN=$(tea login list 2>/dev/null | grep "$HOST" | awk '{print $NF}' || true)
if [[ -n "$TEA_TOKEN" ]]; then
DIFF_CONTENT=$(curl -sS -H "Authorization: token $TEA_TOKEN" "$DIFF_URL")
else
DIFF_CONTENT=$(curl -sS "$DIFF_URL")
fi
if [[ -n "$OUTPUT_FILE" ]]; then
echo "$DIFF_CONTENT" > "$OUTPUT_FILE"
else
echo "$DIFF_CONTENT"
fi
else
echo "Error: Unknown platform" >&2
exit 1
fi

76
rails/git/pr-list.ps1 Normal file
View File

@@ -0,0 +1,76 @@
# pr-list.ps1 - List pull requests on Gitea or GitHub
# Usage: .\pr-list.ps1 [-State state] [-Label label] [-Author author]
[CmdletBinding()]
param(
[Alias("s")]
[ValidateSet("open", "closed", "merged", "all")]
[string]$State = "open",
[Alias("l")]
[string]$Label,
[Alias("a")]
[string]$Author,
[Alias("n")]
[int]$Limit = 100,
[Alias("h")]
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$ScriptDir\detect-platform.ps1"
function Show-Usage {
@"
Usage: pr-list.ps1 [OPTIONS]
List pull requests from the current repository (Gitea or GitHub).
Options:
-State, -s STATE Filter by state: open, closed, merged, all (default: open)
-Label, -l LABEL Filter by label
-Author, -a USER Filter by author
-Limit, -n N Maximum PRs to show (default: 100)
-Help, -h Show this help message
Examples:
.\pr-list.ps1 # List open PRs
.\pr-list.ps1 -s all # All PRs
.\pr-list.ps1 -s merged -a username # Merged PRs by user
"@
exit 1
}
if ($Help) {
Show-Usage
}
$platform = Get-GitPlatform
switch ($platform) {
"github" {
$cmd = @("gh", "pr", "list", "--state", $State, "--limit", $Limit)
if ($Label) { $cmd += @("--label", $Label) }
if ($Author) { $cmd += @("--author", $Author) }
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
"gitea" {
$cmd = @("tea", "pr", "list", "--state", $State, "--limit", $Limit)
if ($Label) {
Write-Warning "Label filtering may require manual review for Gitea"
}
if ($Author) {
Write-Warning "Author filtering may require manual review for Gitea"
}
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}

93
rails/git/pr-list.sh Executable file
View File

@@ -0,0 +1,93 @@
#!/bin/bash
# pr-list.sh - List pull requests on Gitea or GitHub
# Usage: pr-list.sh [-s state] [-l label] [-a author]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
STATE="open"
LABEL=""
AUTHOR=""
LIMIT=100
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
List pull requests from the current repository (Gitea or GitHub).
Options:
-s, --state STATE Filter by state: open, closed, merged, all (default: open)
-l, --label LABEL Filter by label
-a, --author USER Filter by author
-n, --limit N Maximum PRs to show (default: 100)
-h, --help Show this help message
Examples:
$(basename "$0") # List open PRs
$(basename "$0") -s all # All PRs
$(basename "$0") -s merged -a username # Merged PRs by user
EOF
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-s|--state)
STATE="$2"
shift 2
;;
-l|--label)
LABEL="$2"
shift 2
;;
-a|--author)
AUTHOR="$2"
shift 2
;;
-n|--limit)
LIMIT="$2"
shift 2
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
PLATFORM=$(detect_platform)
case "$PLATFORM" in
github)
CMD="gh pr list --state $STATE --limit $LIMIT"
[[ -n "$LABEL" ]] && CMD="$CMD --label \"$LABEL\""
[[ -n "$AUTHOR" ]] && CMD="$CMD --author \"$AUTHOR\""
eval "$CMD"
;;
gitea)
# tea pr list - note: tea uses 'pulls' subcommand in some versions
CMD="tea pr list --state $STATE --limit $LIMIT"
# tea filtering may be limited
if [[ -n "$LABEL" ]]; then
echo "Note: Label filtering may require manual review for Gitea" >&2
fi
if [[ -n "$AUTHOR" ]]; then
echo "Note: Author filtering may require manual review for Gitea" >&2
fi
eval "$CMD"
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac

81
rails/git/pr-merge.ps1 Normal file
View File

@@ -0,0 +1,81 @@
# pr-merge.ps1 - Merge pull requests on Gitea or GitHub
# Usage: .\pr-merge.ps1 -Number PR_NUMBER [-Method method] [-DeleteBranch]
[CmdletBinding()]
param(
[Parameter(Mandatory=$true)]
[Alias("n")]
[int]$Number,
[Alias("m")]
[ValidateSet("merge", "squash", "rebase")]
[string]$Method = "merge",
[Alias("d")]
[switch]$DeleteBranch,
[Alias("h")]
[switch]$Help
)
$ScriptDir = Split-Path -Parent $MyInvocation.MyCommand.Path
. "$ScriptDir\detect-platform.ps1"
function Show-Usage {
@"
Usage: pr-merge.ps1 [OPTIONS]
Merge a pull request on the current repository (Gitea or GitHub).
Options:
-Number, -n NUMBER PR number to merge (required)
-Method, -m METHOD Merge method: merge, squash, rebase (default: merge)
-DeleteBranch, -d Delete the head branch after merge
-Help, -h Show this help message
Examples:
.\pr-merge.ps1 -n 42 # Merge PR #42
.\pr-merge.ps1 -n 42 -m squash # Squash merge
.\pr-merge.ps1 -n 42 -m rebase -d # Rebase and delete branch
"@
exit 1
}
if ($Help) {
Show-Usage
}
$platform = Get-GitPlatform
switch ($platform) {
"github" {
$cmd = @("gh", "pr", "merge", $Number)
switch ($Method) {
"merge" { $cmd += "--merge" }
"squash" { $cmd += "--squash" }
"rebase" { $cmd += "--rebase" }
}
if ($DeleteBranch) { $cmd += "--delete-branch" }
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
"gitea" {
$cmd = @("tea", "pr", "merge", $Number)
switch ($Method) {
"merge" { $cmd += @("--style", "merge") }
"squash" { $cmd += @("--style", "squash") }
"rebase" { $cmd += @("--style", "rebase") }
}
if ($DeleteBranch) {
Write-Warning "Branch deletion after merge may need to be done separately with tea"
}
& $cmd[0] $cmd[1..($cmd.Length-1)]
}
default {
Write-Error "Could not detect git platform"
exit 1
}
}
Write-Host "PR #$Number merged successfully"

110
rails/git/pr-merge.sh Executable file
View File

@@ -0,0 +1,110 @@
#!/bin/bash
# pr-merge.sh - Merge pull requests on Gitea or GitHub
# Usage: pr-merge.sh -n PR_NUMBER [-m method] [-d]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Default values
PR_NUMBER=""
MERGE_METHOD="merge" # merge, squash, rebase
DELETE_BRANCH=false
usage() {
cat <<EOF
Usage: $(basename "$0") [OPTIONS]
Merge a pull request on the current repository (Gitea or GitHub).
Options:
-n, --number NUMBER PR number to merge (required)
-m, --method METHOD Merge method: merge, squash, rebase (default: merge)
-d, --delete-branch Delete the head branch after merge
-h, --help Show this help message
Examples:
$(basename "$0") -n 42 # Merge PR #42
$(basename "$0") -n 42 -m squash # Squash merge
$(basename "$0") -n 42 -m rebase -d # Rebase and delete branch
EOF
exit 1
}
# Parse arguments
while [[ $# -gt 0 ]]; do
case $1 in
-n|--number)
PR_NUMBER="$2"
shift 2
;;
-m|--method)
MERGE_METHOD="$2"
shift 2
;;
-d|--delete-branch)
DELETE_BRANCH=true
shift
;;
-h|--help)
usage
;;
*)
echo "Unknown option: $1" >&2
usage
;;
esac
done
if [[ -z "$PR_NUMBER" ]]; then
echo "Error: PR number is required (-n)" >&2
usage
fi
PLATFORM=$(detect_platform)
case "$PLATFORM" in
github)
CMD="gh pr merge $PR_NUMBER"
case "$MERGE_METHOD" in
merge) CMD="$CMD --merge" ;;
squash) CMD="$CMD --squash" ;;
rebase) CMD="$CMD --rebase" ;;
*)
echo "Error: Invalid merge method '$MERGE_METHOD'" >&2
exit 1
;;
esac
[[ "$DELETE_BRANCH" == true ]] && CMD="$CMD --delete-branch"
eval "$CMD"
;;
gitea)
# tea pr merge syntax
CMD="tea pr merge $PR_NUMBER"
# tea merge style flags
case "$MERGE_METHOD" in
merge) CMD="$CMD --style merge" ;;
squash) CMD="$CMD --style squash" ;;
rebase) CMD="$CMD --style rebase" ;;
*)
echo "Error: Invalid merge method '$MERGE_METHOD'" >&2
exit 1
;;
esac
# Delete branch after merge if requested
if [[ "$DELETE_BRANCH" == true ]]; then
echo "Note: Branch deletion after merge may need to be done separately with tea" >&2
fi
eval "$CMD"
;;
*)
echo "Error: Could not detect git platform" >&2
exit 1
;;
esac
echo "PR #$PR_NUMBER merged successfully"

114
rails/git/pr-metadata.sh Executable file
View File

@@ -0,0 +1,114 @@
#!/bin/bash
# pr-metadata.sh - Get PR metadata as JSON on GitHub or Gitea
# Usage: pr-metadata.sh -n <pr_number> [-o <output_file>]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
PR_NUMBER=""
OUTPUT_FILE=""
while [[ $# -gt 0 ]]; do
case $1 in
-n|--number)
PR_NUMBER="$2"
shift 2
;;
-o|--output)
OUTPUT_FILE="$2"
shift 2
;;
-h|--help)
echo "Usage: pr-metadata.sh -n <pr_number> [-o <output_file>]"
echo ""
echo "Options:"
echo " -n, --number PR number (required)"
echo " -o, --output Output file (optional, prints to stdout if omitted)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$PR_NUMBER" ]]; then
echo "Error: PR number is required (-n)" >&2
exit 1
fi
detect_platform > /dev/null
if [[ "$PLATFORM" == "github" ]]; then
METADATA=$(gh pr view "$PR_NUMBER" --json number,title,body,state,author,headRefName,baseRefName,files,labels,assignees,milestone,createdAt,updatedAt,url,isDraft)
if [[ -n "$OUTPUT_FILE" ]]; then
echo "$METADATA" > "$OUTPUT_FILE"
else
echo "$METADATA"
fi
elif [[ "$PLATFORM" == "gitea" ]]; then
OWNER=$(get_repo_owner)
REPO=$(get_repo_name)
REMOTE_URL=$(git remote get-url origin 2>/dev/null)
# Extract host from remote URL
if [[ "$REMOTE_URL" == https://* ]]; then
HOST=$(echo "$REMOTE_URL" | sed -E 's|https://([^/]+)/.*|\1|')
elif [[ "$REMOTE_URL" == git@* ]]; then
HOST=$(echo "$REMOTE_URL" | sed -E 's|git@([^:]+):.*|\1|')
else
echo "Error: Cannot determine host from remote URL" >&2
exit 1
fi
API_URL="https://${HOST}/api/v1/repos/${OWNER}/${REPO}/pulls/${PR_NUMBER}"
# Use tea's auth token if available
TEA_TOKEN=$(tea login list 2>/dev/null | grep "$HOST" | awk '{print $NF}' || true)
if [[ -n "$TEA_TOKEN" ]]; then
RAW=$(curl -sS -H "Authorization: token $TEA_TOKEN" "$API_URL")
else
RAW=$(curl -sS "$API_URL")
fi
# Normalize Gitea response to match our expected schema
METADATA=$(echo "$RAW" | python3 -c "
import json, sys
data = json.load(sys.stdin)
normalized = {
'number': data.get('number'),
'title': data.get('title'),
'body': data.get('body', ''),
'state': data.get('state'),
'author': data.get('user', {}).get('login', ''),
'headRefName': data.get('head', {}).get('ref', ''),
'baseRefName': data.get('base', {}).get('ref', ''),
'labels': [l.get('name', '') for l in data.get('labels', [])],
'assignees': [a.get('login', '') for a in data.get('assignees', [])],
'milestone': data.get('milestone', {}).get('title', '') if data.get('milestone') else '',
'createdAt': data.get('created_at', ''),
'updatedAt': data.get('updated_at', ''),
'url': data.get('html_url', ''),
'isDraft': data.get('draft', False),
'mergeable': data.get('mergeable'),
'diffUrl': data.get('diff_url', ''),
}
json.dump(normalized, sys.stdout, indent=2)
")
if [[ -n "$OUTPUT_FILE" ]]; then
echo "$METADATA" > "$OUTPUT_FILE"
else
echo "$METADATA"
fi
else
echo "Error: Unknown platform" >&2
exit 1
fi

115
rails/git/pr-review.sh Executable file
View File

@@ -0,0 +1,115 @@
#!/bin/bash
# pr-review.sh - Review a pull request on GitHub or Gitea
# Usage: pr-review.sh -n <pr_number> -a <action> [-c <comment>]
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
PR_NUMBER=""
ACTION=""
COMMENT=""
while [[ $# -gt 0 ]]; do
case $1 in
-n|--number)
PR_NUMBER="$2"
shift 2
;;
-a|--action)
ACTION="$2"
shift 2
;;
-c|--comment)
COMMENT="$2"
shift 2
;;
-h|--help)
echo "Usage: pr-review.sh -n <pr_number> -a <action> [-c <comment>]"
echo ""
echo "Options:"
echo " -n, --number PR number (required)"
echo " -a, --action Review action: approve, request-changes, comment (required)"
echo " -c, --comment Review comment (required for request-changes)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$PR_NUMBER" ]]; then
echo "Error: PR number is required (-n)"
exit 1
fi
if [[ -z "$ACTION" ]]; then
echo "Error: Action is required (-a): approve, request-changes, comment"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
case $ACTION in
approve)
gh pr review "$PR_NUMBER" --approve ${COMMENT:+--body "$COMMENT"}
echo "Approved GitHub PR #$PR_NUMBER"
;;
request-changes)
if [[ -z "$COMMENT" ]]; then
echo "Error: Comment required for request-changes"
exit 1
fi
gh pr review "$PR_NUMBER" --request-changes --body "$COMMENT"
echo "Requested changes on GitHub PR #$PR_NUMBER"
;;
comment)
if [[ -z "$COMMENT" ]]; then
echo "Error: Comment required"
exit 1
fi
gh pr review "$PR_NUMBER" --comment --body "$COMMENT"
echo "Added review comment to GitHub PR #$PR_NUMBER"
;;
*)
echo "Error: Unknown action: $ACTION"
exit 1
;;
esac
elif [[ "$PLATFORM" == "gitea" ]]; then
case $ACTION in
approve)
tea pr approve "$PR_NUMBER" ${COMMENT:+--comment "$COMMENT"}
echo "Approved Gitea PR #$PR_NUMBER"
;;
request-changes)
if [[ -z "$COMMENT" ]]; then
echo "Error: Comment required for request-changes"
exit 1
fi
tea pr reject "$PR_NUMBER" --comment "$COMMENT"
echo "Requested changes on Gitea PR #$PR_NUMBER"
;;
comment)
if [[ -z "$COMMENT" ]]; then
echo "Error: Comment required"
exit 1
fi
tea pr comment "$PR_NUMBER" "$COMMENT"
echo "Added comment to Gitea PR #$PR_NUMBER"
;;
*)
echo "Error: Unknown action: $ACTION"
exit 1
;;
esac
else
echo "Error: Unknown platform"
exit 1
fi

48
rails/git/pr-view.sh Executable file
View File

@@ -0,0 +1,48 @@
#!/bin/bash
# pr-view.sh - View pull request details on GitHub or Gitea
# Usage: pr-view.sh -n <pr_number>
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
source "$SCRIPT_DIR/detect-platform.sh"
# Parse arguments
PR_NUMBER=""
while [[ $# -gt 0 ]]; do
case $1 in
-n|--number)
PR_NUMBER="$2"
shift 2
;;
-h|--help)
echo "Usage: pr-view.sh -n <pr_number>"
echo ""
echo "Options:"
echo " -n, --number PR number (required)"
echo " -h, --help Show this help"
exit 0
;;
*)
echo "Unknown option: $1"
exit 1
;;
esac
done
if [[ -z "$PR_NUMBER" ]]; then
echo "Error: PR number is required (-n)"
exit 1
fi
detect_platform
if [[ "$PLATFORM" == "github" ]]; then
gh pr view "$PR_NUMBER"
elif [[ "$PLATFORM" == "gitea" ]]; then
tea pr "$PR_NUMBER"
else
echo "Error: Unknown platform"
exit 1
fi