Initial commit
This commit is contained in:
191
skills/pr/scripts/00-pr-workflow.sh
Executable file
191
skills/pr/scripts/00-pr-workflow.sh
Executable file
@@ -0,0 +1,191 @@
|
||||
#!/bin/bash
|
||||
# 00-pr-workflow.sh - Complete PR workflow (fork → modify → PR)
|
||||
# Usage: ./00-pr-workflow.sh <upstream_repo> <base_branch> <feature_branch> <pr_title> [work_dir] [depth]
|
||||
# Example: ./00-pr-workflow.sh stolostron/multicluster-global-hub release-1.6 fix/bug-123 "Fix bug in handler" ~/tmp/contribute 1
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored messages
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
step() { echo -e "${BLUE}[STEP]${NC} $*"; }
|
||||
|
||||
# Check arguments
|
||||
if [ $# -lt 4 ]; then
|
||||
error "Usage: $0 <upstream_repo> <base_branch> <feature_branch> <pr_title> [work_dir] [depth]"
|
||||
error "Example: $0 stolostron/multicluster-global-hub release-1.6 fix/bug-123 \"Fix bug\" ~/tmp/contribute 1"
|
||||
error ""
|
||||
error "Parameters:"
|
||||
error " upstream_repo - Repository to fork (owner/repo)"
|
||||
error " base_branch - Base branch for PR (e.g., main, release-1.6)"
|
||||
error " feature_branch - Your feature branch name"
|
||||
error " pr_title - Pull request title"
|
||||
error " work_dir - Working directory (default: ~/tmp/contribute)"
|
||||
error " depth - Git clone depth (default: 1 for fast shallow clone)"
|
||||
error " Use 'full' for complete history if needed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
UPSTREAM_REPO="$1"
|
||||
BASE_BRANCH="$2"
|
||||
FEATURE_BRANCH="$3"
|
||||
PR_TITLE="$4"
|
||||
WORK_DIR="${5:-$HOME/tmp/contribute}"
|
||||
CLONE_DEPTH="${6:-1}" # Default to shallow clone (depth=1) for speed
|
||||
REPO_NAME=$(basename "$UPSTREAM_REPO")
|
||||
|
||||
info "========================================="
|
||||
info "Contribution Workflow Started"
|
||||
info "========================================="
|
||||
info "Upstream repository: $UPSTREAM_REPO"
|
||||
info "Base branch: $BASE_BRANCH"
|
||||
info "Feature branch: $FEATURE_BRANCH"
|
||||
info "PR title: $PR_TITLE"
|
||||
info "Work directory: $WORK_DIR"
|
||||
if [ "$CLONE_DEPTH" = "1" ]; then
|
||||
info "Clone depth: 1 (shallow clone - faster)"
|
||||
elif [ -n "$CLONE_DEPTH" ]; then
|
||||
info "Clone depth: $CLONE_DEPTH"
|
||||
else
|
||||
info "Clone depth: full history"
|
||||
fi
|
||||
info "========================================="
|
||||
|
||||
# Check prerequisites
|
||||
step "1/7: Checking prerequisites..."
|
||||
if ! command -v gh &> /dev/null; then
|
||||
error "GitHub CLI (gh) is not installed. Please install it first:"
|
||||
error " brew install gh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! gh auth status &> /dev/null; then
|
||||
error "Not authenticated with GitHub CLI. Please run:"
|
||||
error " gh auth login"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
GH_USER=$(gh api user --jq '.login')
|
||||
info "GitHub username: $GH_USER"
|
||||
|
||||
# Step 1: Fork and setup
|
||||
step "2/7: Forking and setting up repository..."
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
if ! bash "$SCRIPT_DIR/01-fork-and-setup.sh" "$UPSTREAM_REPO" "$WORK_DIR" "$CLONE_DEPTH"; then
|
||||
error "Failed to fork and setup repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
REPO_PATH="$WORK_DIR/$REPO_NAME"
|
||||
cd "$REPO_PATH"
|
||||
|
||||
# Step 2: Check for contribution guidelines
|
||||
step "3/7: Checking for contribution guidelines..."
|
||||
if [ -f "CONTRIBUTING.md" ]; then
|
||||
info "Found CONTRIBUTING.md - Please review contribution guidelines:"
|
||||
head -20 CONTRIBUTING.md
|
||||
echo ""
|
||||
warn "Press Enter to continue after reviewing guidelines..."
|
||||
# For automation, we'll skip the wait
|
||||
# read -r
|
||||
fi
|
||||
|
||||
# Step 3: Create feature branch
|
||||
step "4/7: Creating feature branch from latest upstream..."
|
||||
git fetch upstream
|
||||
if git rev-parse --verify "$FEATURE_BRANCH" &> /dev/null; then
|
||||
warn "Branch '$FEATURE_BRANCH' already exists. Switching to it..."
|
||||
git checkout "$FEATURE_BRANCH"
|
||||
# Optionally rebase on latest upstream
|
||||
git rebase "upstream/$BASE_BRANCH" || {
|
||||
error "Failed to rebase. Please resolve conflicts manually."
|
||||
exit 1
|
||||
}
|
||||
else
|
||||
git checkout -b "$FEATURE_BRANCH" "upstream/$BASE_BRANCH"
|
||||
info "Created branch '$FEATURE_BRANCH' from 'upstream/$BASE_BRANCH'"
|
||||
fi
|
||||
|
||||
# Step 4: Pause for manual changes
|
||||
step "5/7: Ready for code changes..."
|
||||
info ""
|
||||
info "Repository path: $REPO_PATH"
|
||||
info "Current branch: $(git branch --show-current)"
|
||||
info ""
|
||||
info "Next steps:"
|
||||
info " 1. Make your code changes"
|
||||
info " 2. Commit your changes with: git commit -s -m \"message\""
|
||||
info " 3. Return here and we'll create the PR"
|
||||
info ""
|
||||
warn "This script will now pause. Press Enter when you're ready to create the PR..."
|
||||
# For automation in Claude, we'll skip this pause
|
||||
# read -r
|
||||
|
||||
# Step 5: Verify changes are committed
|
||||
step "6/7: Verifying changes are committed..."
|
||||
if git diff-index --quiet HEAD --; then
|
||||
# Check if there are any commits on this branch
|
||||
COMMITS_AHEAD=$(git rev-list --count "upstream/$BASE_BRANCH..$FEATURE_BRANCH")
|
||||
if [ "$COMMITS_AHEAD" -eq 0 ]; then
|
||||
error "No changes committed. Please make changes and commit them first."
|
||||
exit 1
|
||||
fi
|
||||
info "Found $COMMITS_AHEAD commit(s) ready to push"
|
||||
else
|
||||
error "You have uncommitted changes. Please commit or stash them first."
|
||||
info "Run: git status"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Step 6: Run checks (if applicable)
|
||||
step "7/7: Running pre-PR checks..."
|
||||
# Check for common files that indicate tests should be run
|
||||
if [ -f "Makefile" ]; then
|
||||
if grep -q "^test:" Makefile; then
|
||||
info "Found 'test' target in Makefile. Consider running: make test"
|
||||
fi
|
||||
if grep -q "^lint:" Makefile; then
|
||||
info "Found 'lint' target in Makefile. Consider running: make lint"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Step 7: Create PR
|
||||
info ""
|
||||
info "========================================="
|
||||
info "Creating Pull Request"
|
||||
info "========================================="
|
||||
|
||||
# Get commit messages for PR body
|
||||
COMMIT_MESSAGES=$(git log --pretty=format:"- %s" "upstream/$BASE_BRANCH..$FEATURE_BRANCH")
|
||||
PR_BODY="## Changes
|
||||
|
||||
$COMMIT_MESSAGES
|
||||
|
||||
## Checklist
|
||||
- [x] Code changes are committed with sign-off
|
||||
- [ ] Tests pass locally (if applicable)
|
||||
- [ ] Documentation updated (if needed)
|
||||
|
||||
---
|
||||
*Generated via contribute script*"
|
||||
|
||||
# Use the fixed create-pr script
|
||||
if bash "$SCRIPT_DIR/03-create-pr.sh" "$BASE_BRANCH" "$PR_TITLE" "$PR_BODY"; then
|
||||
info ""
|
||||
info "========================================="
|
||||
info "✅ Contribution workflow completed!"
|
||||
info "========================================="
|
||||
else
|
||||
error "Failed to create PR. You can create it manually with:"
|
||||
error " gh pr create --repo $UPSTREAM_REPO --base $BASE_BRANCH --head $GH_USER:$FEATURE_BRANCH"
|
||||
exit 1
|
||||
fi
|
||||
255
skills/pr/scripts/01-fork-and-setup.sh
Executable file
255
skills/pr/scripts/01-fork-and-setup.sh
Executable file
@@ -0,0 +1,255 @@
|
||||
#!/bin/bash
|
||||
# 01-fork-and-setup.sh - Fork repository and setup local environment
|
||||
# Usage: ./01-fork-and-setup.sh <upstream_repo> [work_dir] [depth] [base_branch] [feature_branch]
|
||||
# Example: ./01-fork-and-setup.sh stolostron/multicluster-global-hub ~/tmp/contribute 1 main fix/version
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored messages
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
# Check arguments
|
||||
if [ $# -lt 1 ]; then
|
||||
error "Usage: $0 <upstream_repo> [work_dir] [depth] [base_branch] [feature_branch]"
|
||||
error "Example: $0 stolostron/multicluster-global-hub ~/tmp/contribute 1 main fix/version"
|
||||
error "Example (current dir): cd /path/to/repo && $0 stolostron/multicluster-global-hub . 1 main fix/version"
|
||||
error ""
|
||||
error "Parameters:"
|
||||
error " upstream_repo - Repository to fork (owner/repo)"
|
||||
error " work_dir - Working directory (default: ~/tmp/contribute)"
|
||||
error " Use '.' to work in current directory (must be a git repo)"
|
||||
error " depth - Git clone depth (default: full history)"
|
||||
error " Use 1 for shallow clone (faster, less history)"
|
||||
error " base_branch - Base branch to branch from (optional)"
|
||||
error " feature_branch - Feature branch to create (optional, requires base_branch)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
UPSTREAM_REPO="$1"
|
||||
WORK_DIR="${2:-$HOME/tmp/contribute}"
|
||||
CLONE_DEPTH="${3:-}"
|
||||
BASE_BRANCH="${4:-}"
|
||||
FEATURE_BRANCH="${5:-}"
|
||||
REPO_NAME=$(basename "$UPSTREAM_REPO")
|
||||
|
||||
# Support current directory mode
|
||||
USE_CURRENT_DIR=false
|
||||
if [ "$WORK_DIR" = "." ]; then
|
||||
USE_CURRENT_DIR=true
|
||||
WORK_DIR="$(pwd)"
|
||||
info "Using current directory mode"
|
||||
fi
|
||||
|
||||
info "Upstream repository: $UPSTREAM_REPO"
|
||||
info "Work directory: $WORK_DIR"
|
||||
info "Repository name: $REPO_NAME"
|
||||
if [ -n "$CLONE_DEPTH" ]; then
|
||||
info "Clone depth: $CLONE_DEPTH (shallow clone for faster download)"
|
||||
else
|
||||
info "Clone depth: full history"
|
||||
fi
|
||||
if [ -n "$BASE_BRANCH" ] && [ -n "$FEATURE_BRANCH" ]; then
|
||||
info "Will create feature branch: $FEATURE_BRANCH from $BASE_BRANCH"
|
||||
fi
|
||||
|
||||
# Check if gh CLI is available
|
||||
if ! command -v gh &> /dev/null; then
|
||||
error "GitHub CLI (gh) is not installed. Please install it first:"
|
||||
error " brew install gh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if user is authenticated with gh
|
||||
if ! gh auth status &> /dev/null; then
|
||||
error "Not authenticated with GitHub CLI. Please run:"
|
||||
error " gh auth login"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current GitHub username
|
||||
GH_USER=$(gh api user --jq '.login')
|
||||
info "GitHub username: $GH_USER"
|
||||
|
||||
# Check if fork already exists (with possible different name)
|
||||
info "Checking if fork already exists..."
|
||||
FORK_EXISTS=false
|
||||
FORK_REPO_NAME=""
|
||||
|
||||
# First, try the expected name
|
||||
if gh repo view "$GH_USER/$REPO_NAME" &> /dev/null; then
|
||||
warn "Fork already exists: $GH_USER/$REPO_NAME"
|
||||
FORK_EXISTS=true
|
||||
FORK_REPO_NAME="$REPO_NAME"
|
||||
else
|
||||
# Check if there's a fork with a different name by querying the upstream repo
|
||||
info "Checking for fork with different name..."
|
||||
POTENTIAL_FORK=$(gh api "repos/$UPSTREAM_REPO/forks" --jq ".[] | select(.owner.login == \"$GH_USER\") | .name" 2>/dev/null | head -1)
|
||||
|
||||
if [ -n "$POTENTIAL_FORK" ]; then
|
||||
warn "Found existing fork with different name: $GH_USER/$POTENTIAL_FORK"
|
||||
warn "Original repo: $REPO_NAME, Fork name: $POTENTIAL_FORK"
|
||||
FORK_EXISTS=true
|
||||
FORK_REPO_NAME="$POTENTIAL_FORK"
|
||||
else
|
||||
info "Fork does not exist. Creating fork..."
|
||||
FORK_OUTPUT=$(gh repo fork "$UPSTREAM_REPO" --clone=false 2>&1)
|
||||
if [ $? -eq 0 ]; then
|
||||
# Extract the actual fork name from output or check again
|
||||
FORK_REPO_NAME=$(gh api "repos/$UPSTREAM_REPO/forks" --jq ".[] | select(.owner.login == \"$GH_USER\") | .name" 2>/dev/null | head -1)
|
||||
if [ -z "$FORK_REPO_NAME" ]; then
|
||||
FORK_REPO_NAME="$REPO_NAME" # Fallback to expected name
|
||||
fi
|
||||
info "Fork created successfully: $GH_USER/$FORK_REPO_NAME"
|
||||
FORK_EXISTS=true
|
||||
else
|
||||
error "Failed to create fork"
|
||||
error "$FORK_OUTPUT"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Use the actual fork name for subsequent operations
|
||||
if [ -n "$FORK_REPO_NAME" ]; then
|
||||
info "Using fork: $GH_USER/$FORK_REPO_NAME"
|
||||
else
|
||||
error "Could not determine fork repository name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Determine repository path
|
||||
if [ "$USE_CURRENT_DIR" = true ]; then
|
||||
# In current directory mode, check if we're already in a git repo
|
||||
if git rev-parse --git-dir &> /dev/null; then
|
||||
REPO_PATH="$WORK_DIR"
|
||||
info "Using current directory as repository: $REPO_PATH"
|
||||
else
|
||||
error "Current directory mode requires you to be in a git repository"
|
||||
error "Either cd to the repository or specify a different work_dir"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Create work directory if it doesn't exist
|
||||
mkdir -p "$WORK_DIR"
|
||||
REPO_PATH="$WORK_DIR/$REPO_NAME"
|
||||
fi
|
||||
|
||||
# Check if repository already cloned (using the original repo name for local directory)
|
||||
if [ -d "$REPO_PATH/.git" ]; then
|
||||
warn "Repository already exists at: $REPO_PATH"
|
||||
info "Checking remotes..."
|
||||
|
||||
cd "$REPO_PATH"
|
||||
|
||||
# Check current remotes
|
||||
if git remote get-url upstream &> /dev/null; then
|
||||
CURRENT_UPSTREAM=$(git remote get-url upstream)
|
||||
info "Current upstream: $CURRENT_UPSTREAM"
|
||||
else
|
||||
warn "No upstream remote found. Adding it..."
|
||||
git remote add upstream "https://github.com/$UPSTREAM_REPO.git"
|
||||
info "Added upstream: https://github.com/$UPSTREAM_REPO.git"
|
||||
fi
|
||||
|
||||
if git remote get-url origin &> /dev/null; then
|
||||
CURRENT_ORIGIN=$(git remote get-url origin)
|
||||
info "Current origin: $CURRENT_ORIGIN"
|
||||
else
|
||||
warn "No origin remote found. Adding it..."
|
||||
git remote add origin "git@github.com:$GH_USER/$FORK_REPO_NAME.git"
|
||||
info "Added origin: git@github.com:$GH_USER/$FORK_REPO_NAME.git"
|
||||
fi
|
||||
else
|
||||
if [ "$USE_CURRENT_DIR" = true ]; then
|
||||
error "Current directory is not a git repository and current directory mode is enabled"
|
||||
error "Either cd to the repository or use a different work_dir"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
info "Cloning fork to: $REPO_PATH"
|
||||
cd "$WORK_DIR"
|
||||
|
||||
# Clone the fork with optional depth
|
||||
CLONE_CMD="git clone"
|
||||
if [ -n "$CLONE_DEPTH" ]; then
|
||||
CLONE_CMD="$CLONE_CMD --depth $CLONE_DEPTH"
|
||||
info "Using shallow clone (depth=$CLONE_DEPTH) for faster download..."
|
||||
fi
|
||||
|
||||
# Clone using the actual fork name, but rename directory to original repo name
|
||||
if [ "$FORK_REPO_NAME" = "$REPO_NAME" ]; then
|
||||
# Fork name matches, no need to rename
|
||||
if $CLONE_CMD "git@github.com:$GH_USER/$FORK_REPO_NAME.git"; then
|
||||
info "Fork cloned successfully"
|
||||
cd "$REPO_NAME"
|
||||
|
||||
# Add upstream remote
|
||||
info "Adding upstream remote..."
|
||||
git remote add upstream "https://github.com/$UPSTREAM_REPO.git"
|
||||
info "Added upstream: https://github.com/$UPSTREAM_REPO.git"
|
||||
else
|
||||
error "Failed to clone fork"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
# Fork name differs, clone and rename
|
||||
if $CLONE_CMD "git@github.com:$GH_USER/$FORK_REPO_NAME.git" "$REPO_NAME"; then
|
||||
info "Fork cloned successfully (renamed from $FORK_REPO_NAME to $REPO_NAME)"
|
||||
cd "$REPO_NAME"
|
||||
|
||||
# Add upstream remote
|
||||
info "Adding upstream remote..."
|
||||
git remote add upstream "https://github.com/$UPSTREAM_REPO.git"
|
||||
info "Added upstream: https://github.com/$UPSTREAM_REPO.git"
|
||||
else
|
||||
error "Failed to clone fork"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
# Fetch latest from upstream
|
||||
info "Fetching latest from upstream..."
|
||||
if [ -n "$CLONE_DEPTH" ]; then
|
||||
# For shallow clones, also use depth when fetching
|
||||
git fetch --depth "$CLONE_DEPTH" upstream
|
||||
else
|
||||
git fetch upstream
|
||||
fi
|
||||
|
||||
# Create feature branch if specified
|
||||
if [ -n "$BASE_BRANCH" ] && [ -n "$FEATURE_BRANCH" ]; then
|
||||
info "Creating feature branch..."
|
||||
|
||||
# Check if feature branch already exists
|
||||
if git rev-parse --verify "$FEATURE_BRANCH" &> /dev/null; then
|
||||
warn "Branch '$FEATURE_BRANCH' already exists. Switching to it..."
|
||||
git checkout "$FEATURE_BRANCH"
|
||||
else
|
||||
info "Creating branch '$FEATURE_BRANCH' from 'upstream/$BASE_BRANCH'..."
|
||||
git checkout -b "$FEATURE_BRANCH" "upstream/$BASE_BRANCH"
|
||||
info "Created and switched to branch '$FEATURE_BRANCH'"
|
||||
fi
|
||||
fi
|
||||
|
||||
info "✅ Setup complete!"
|
||||
info ""
|
||||
info "Repository path: $REPO_PATH"
|
||||
info "Remotes configured:"
|
||||
git remote -v
|
||||
if [ -n "$FEATURE_BRANCH" ]; then
|
||||
info "Current branch: $(git branch --show-current)"
|
||||
fi
|
||||
info ""
|
||||
info "Next steps:"
|
||||
info " 1. cd $REPO_PATH"
|
||||
info " 2. Make your changes"
|
||||
info " 3. Run create-pr script to submit PR"
|
||||
153
skills/pr/scripts/02-check-guidelines.sh
Executable file
153
skills/pr/scripts/02-check-guidelines.sh
Executable file
@@ -0,0 +1,153 @@
|
||||
#!/bin/bash
|
||||
# 02-check-guidelines.sh - Check repository contribution guidelines and requirements
|
||||
# Usage: ./02-check-guidelines.sh [repo_path]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored messages
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
check() { echo -e "${BLUE}[CHECK]${NC} $*"; }
|
||||
|
||||
REPO_PATH="${1:-.}"
|
||||
cd "$REPO_PATH"
|
||||
|
||||
info "Checking contribution guidelines for repository: $(basename "$PWD")"
|
||||
echo ""
|
||||
|
||||
# Check for CONTRIBUTING.md
|
||||
check "Looking for CONTRIBUTING.md..."
|
||||
if [ -f "CONTRIBUTING.md" ]; then
|
||||
info "✅ Found CONTRIBUTING.md"
|
||||
echo ""
|
||||
echo "===== Contribution Guidelines (first 30 lines) ====="
|
||||
head -30 CONTRIBUTING.md
|
||||
echo "===== (see CONTRIBUTING.md for full details) ====="
|
||||
echo ""
|
||||
else
|
||||
warn "No CONTRIBUTING.md found"
|
||||
fi
|
||||
|
||||
# Check for CODE_OF_CONDUCT.md
|
||||
check "Looking for CODE_OF_CONDUCT.md..."
|
||||
if [ -f "CODE_OF_CONDUCT.md" ]; then
|
||||
info "✅ Found CODE_OF_CONDUCT.md - Please review community guidelines"
|
||||
else
|
||||
warn "No CODE_OF_CONDUCT.md found"
|
||||
fi
|
||||
|
||||
# Check for CLA
|
||||
check "Looking for CLA requirements..."
|
||||
CLA_FOUND=false
|
||||
for file in CONTRIBUTING.md README.md .github/CONTRIBUTING.md docs/CONTRIBUTING.md; do
|
||||
if [ -f "$file" ] && grep -qi "CLA\|contributor license agreement" "$file"; then
|
||||
warn "⚠️ CLA (Contributor License Agreement) may be required"
|
||||
warn " Check: $file"
|
||||
CLA_FOUND=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$CLA_FOUND" = false ]; then
|
||||
info "No CLA requirement detected"
|
||||
fi
|
||||
|
||||
# Check for DCO (Developer Certificate of Origin)
|
||||
check "Looking for DCO requirements..."
|
||||
DCO_FOUND=false
|
||||
for file in CONTRIBUTING.md README.md .github/CONTRIBUTING.md docs/CONTRIBUTING.md; do
|
||||
if [ -f "$file" ] && grep -qi "DCO\|sign-off\|signed-off-by" "$file"; then
|
||||
info "✅ DCO (Developer Certificate of Origin) required"
|
||||
info " Use: git commit -s"
|
||||
DCO_FOUND=true
|
||||
break
|
||||
fi
|
||||
done
|
||||
if [ "$DCO_FOUND" = false ]; then
|
||||
warn "No explicit DCO requirement found, but it's a best practice to use -s flag"
|
||||
fi
|
||||
|
||||
# Check for PR template
|
||||
check "Looking for PR template..."
|
||||
if [ -f ".github/PULL_REQUEST_TEMPLATE.md" ] || [ -f "PULL_REQUEST_TEMPLATE.md" ] || [ -f ".github/pull_request_template.md" ]; then
|
||||
info "✅ Found PR template - Your PR description should follow this format"
|
||||
if [ -f ".github/PULL_REQUEST_TEMPLATE.md" ]; then
|
||||
echo ""
|
||||
echo "===== PR Template ====="
|
||||
cat .github/PULL_REQUEST_TEMPLATE.md
|
||||
echo "===== (end of template) ====="
|
||||
echo ""
|
||||
fi
|
||||
else
|
||||
warn "No PR template found"
|
||||
fi
|
||||
|
||||
# Check for testing requirements
|
||||
check "Looking for testing requirements..."
|
||||
if [ -f "Makefile" ]; then
|
||||
info "✅ Found Makefile"
|
||||
if grep -q "^test:" Makefile; then
|
||||
info " → Run tests with: make test"
|
||||
fi
|
||||
if grep -q "^lint:" Makefile; then
|
||||
info " → Run linter with: make lint"
|
||||
fi
|
||||
if grep -q "^fmt:" Makefile; then
|
||||
info " → Format code with: make fmt"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check for CI configuration
|
||||
check "Looking for CI/CD configuration..."
|
||||
CI_FOUND=false
|
||||
if [ -d ".github/workflows" ]; then
|
||||
info "✅ Found GitHub Actions workflows:"
|
||||
for workflow in .github/workflows/*.{yml,yaml}; do
|
||||
if [ -f "$workflow" ]; then
|
||||
info " → $(basename "$workflow")"
|
||||
CI_FOUND=true
|
||||
fi
|
||||
done
|
||||
fi
|
||||
if [ -f ".travis.yml" ]; then
|
||||
info "✅ Found Travis CI configuration"
|
||||
CI_FOUND=true
|
||||
fi
|
||||
if [ -f ".circleci/config.yml" ]; then
|
||||
info "✅ Found CircleCI configuration"
|
||||
CI_FOUND=true
|
||||
fi
|
||||
if [ "$CI_FOUND" = false ]; then
|
||||
warn "No CI/CD configuration found"
|
||||
fi
|
||||
|
||||
# Check commit message conventions
|
||||
check "Looking for commit message conventions..."
|
||||
for file in CONTRIBUTING.md README.md .github/CONTRIBUTING.md docs/CONTRIBUTING.md; do
|
||||
if [ -f "$file" ]; then
|
||||
if grep -qi "conventional commits\|commit message\|commit format" "$file"; then
|
||||
info "✅ Commit message conventions found - Please review: $file"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
info "========================================="
|
||||
info "Summary"
|
||||
info "========================================="
|
||||
info "Before submitting your PR, ensure you:"
|
||||
info " 1. ✓ Read CONTRIBUTING.md (if exists)"
|
||||
info " 2. ✓ Sign commits with -s flag (DCO)"
|
||||
info " 3. ✓ Run tests locally (make test)"
|
||||
info " 4. ✓ Follow commit message conventions"
|
||||
info " 5. ✓ Fill out PR template (if exists)"
|
||||
info "========================================="
|
||||
124
skills/pr/scripts/03-create-pr.sh
Executable file
124
skills/pr/scripts/03-create-pr.sh
Executable file
@@ -0,0 +1,124 @@
|
||||
#!/bin/bash
|
||||
# 03-create-pr.sh - Add, commit, push changes and create PR to upstream
|
||||
# Usage: ./03-create-pr.sh <base_branch> <pr_title> [pr_body] [commit_message]
|
||||
# Example: ./03-create-pr.sh main "Fix bug in sync handler" "This PR fixes..." "fix: resolve bug"
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Function to print colored messages
|
||||
info() { echo -e "${GREEN}[INFO]${NC} $*"; }
|
||||
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
|
||||
error() { echo -e "${RED}[ERROR]${NC} $*" >&2; }
|
||||
|
||||
# Check arguments
|
||||
if [ $# -lt 2 ]; then
|
||||
error "Usage: $0 <base_branch> <pr_title> [pr_body] [commit_message]"
|
||||
error "Example: $0 main \"Fix bug in sync handler\" \"This PR fixes...\" \"fix: resolve bug\""
|
||||
exit 1
|
||||
fi
|
||||
|
||||
BASE_BRANCH="$1"
|
||||
PR_TITLE="$2"
|
||||
PR_BODY="${3:-}"
|
||||
COMMIT_MESSAGE="${4:-$PR_TITLE}"
|
||||
|
||||
# Check if gh CLI is available
|
||||
if ! command -v gh &> /dev/null; then
|
||||
error "GitHub CLI (gh) is not installed. Please install it first:"
|
||||
error " brew install gh"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if in a git repository
|
||||
if ! git rev-parse --git-dir &> /dev/null; then
|
||||
error "Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Get current branch
|
||||
CURRENT_BRANCH=$(git branch --show-current)
|
||||
info "Current branch: $CURRENT_BRANCH"
|
||||
|
||||
# Check if current branch is the base branch
|
||||
if [ "$CURRENT_BRANCH" = "$BASE_BRANCH" ]; then
|
||||
error "You are on the base branch ($BASE_BRANCH). Please create a feature branch first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for uncommitted changes and auto-commit if any
|
||||
if ! git diff-index --quiet HEAD --; then
|
||||
info "Found uncommitted changes. Auto-committing..."
|
||||
|
||||
# Add all modified/deleted files (not new untracked files)
|
||||
git add -u
|
||||
|
||||
# Commit with sign-off
|
||||
git commit -s -m "$COMMIT_MESSAGE"
|
||||
|
||||
info "Changes committed: $COMMIT_MESSAGE"
|
||||
fi
|
||||
|
||||
# Get upstream repo info
|
||||
if ! UPSTREAM_URL=$(git remote get-url upstream 2>/dev/null); then
|
||||
error "No upstream remote found. Please run 01-fork-and-setup.sh first."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract owner/repo from upstream URL
|
||||
UPSTREAM_REPO=$(echo "$UPSTREAM_URL" | sed -E 's|.*github\.com[:/](.*)\.git|\1|' | sed 's|\.git$||')
|
||||
info "Upstream repository: $UPSTREAM_REPO"
|
||||
|
||||
# Get origin repo info and extract username
|
||||
ORIGIN_URL=$(git remote get-url origin)
|
||||
ORIGIN_REPO=$(echo "$ORIGIN_URL" | sed -E 's|.*github\.com[:/](.*)\.git|\1|' | sed 's|\.git$||')
|
||||
ORIGIN_USER=$(echo "$ORIGIN_REPO" | cut -d'/' -f1)
|
||||
info "Origin repository: $ORIGIN_REPO"
|
||||
info "Origin user: $ORIGIN_USER"
|
||||
|
||||
# Push current branch to origin
|
||||
info "Pushing current branch to origin..."
|
||||
if git push -u origin "$CURRENT_BRANCH" 2>&1 | grep -q "Everything up-to-date"; then
|
||||
info "Branch already up-to-date on origin"
|
||||
else
|
||||
info "Branch pushed to origin"
|
||||
fi
|
||||
|
||||
# Check if PR already exists
|
||||
info "Checking if PR already exists..."
|
||||
EXISTING_PR=$(gh pr list --repo "$UPSTREAM_REPO" --head "$ORIGIN_USER:$CURRENT_BRANCH" --json number,title,url --jq '.[0]')
|
||||
|
||||
if [ -n "$EXISTING_PR" ] && [ "$EXISTING_PR" != "null" ]; then
|
||||
PR_NUMBER=$(echo "$EXISTING_PR" | jq -r '.number')
|
||||
PR_URL=$(echo "$EXISTING_PR" | jq -r '.url')
|
||||
EXISTING_TITLE=$(echo "$EXISTING_PR" | jq -r '.title')
|
||||
|
||||
warn "PR already exists!"
|
||||
info " PR #$PR_NUMBER: $EXISTING_TITLE"
|
||||
info " URL: $PR_URL"
|
||||
info ""
|
||||
info "Would you like to update the existing PR or create a new one?"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Create PR
|
||||
info "Creating PR to upstream..."
|
||||
if [ -n "$PR_BODY" ]; then
|
||||
PR_URL=$(gh pr create --repo "$UPSTREAM_REPO" --base "$BASE_BRANCH" --head "$ORIGIN_USER:$CURRENT_BRANCH" --title "$PR_TITLE" --body "$PR_BODY")
|
||||
else
|
||||
# Use interactive editor if no body provided
|
||||
PR_URL=$(gh pr create --repo "$UPSTREAM_REPO" --base "$BASE_BRANCH" --head "$ORIGIN_USER:$CURRENT_BRANCH" --title "$PR_TITLE")
|
||||
fi
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
info "✅ PR created successfully!"
|
||||
info " URL: $PR_URL"
|
||||
else
|
||||
error "Failed to create PR"
|
||||
exit 1
|
||||
fi
|
||||
Reference in New Issue
Block a user