feat(scripts): Add hybrid workflow automation scripts#246
Conversation
🔍 PR Validation ResultsBuild Status: ❌ Failed This comment was automatically generated by the PR validation workflow. |
There was a problem hiding this comment.
Pull Request Overview
This PR adds two essential bash scripts to support hybrid workflow automation for seamless branch creation and repository protection setup.
- Introduces
claude-branch.shfor intelligent branch creation with automatic prefix detection and optional draft PR generation - Adds
apply-branch-protection.shfor configuring differentiated GitHub branch protection rules between main and dev branches
Reviewed Changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 7 comments.
| File | Description |
|---|---|
| scripts/claude-branch.sh | Smart branch creation script with prefix detection, configurable base branches, and GitHub CLI integration for draft PRs |
| scripts/apply-branch-protection.sh | Branch protection automation script with differentiated rules for main (strict) and dev (relaxed) branches |
| BRANCH_NAME="fix/${BRANCH_INPUT#fix-}" | ||
| elif [[ $BRANCH_INPUT == docs-* ]] || [[ $BRANCH_INPUT == *-docs ]]; then | ||
| BRANCH_NAME="docs/${BRANCH_INPUT#docs-}" | ||
| elif [[ $BRANCH_INPUT == test-* ]] || [[ $BRANCH_INPUT == *-test ]]; then | ||
| BRANCH_NAME="test/${BRANCH_INPUT#test-}" | ||
| elif [[ $BRANCH_INPUT == chore-* ]] || [[ $BRANCH_INPUT == *-chore ]]; then | ||
| BRANCH_NAME="chore/${BRANCH_INPUT#chore-}" |
There was a problem hiding this comment.
The branch name stripping logic is incorrect. For input 'fix-navigation-bug', this produces 'fix/navigation-bug' but for input 'navigation-fix', it produces 'fix/navigation-fix' (not stripping the suffix). The logic should handle both prefix and suffix cases consistently.
| BRANCH_NAME="fix/${BRANCH_INPUT#fix-}" | |
| elif [[ $BRANCH_INPUT == docs-* ]] || [[ $BRANCH_INPUT == *-docs ]]; then | |
| BRANCH_NAME="docs/${BRANCH_INPUT#docs-}" | |
| elif [[ $BRANCH_INPUT == test-* ]] || [[ $BRANCH_INPUT == *-test ]]; then | |
| BRANCH_NAME="test/${BRANCH_INPUT#test-}" | |
| elif [[ $BRANCH_INPUT == chore-* ]] || [[ $BRANCH_INPUT == *-chore ]]; then | |
| BRANCH_NAME="chore/${BRANCH_INPUT#chore-}" | |
| BRANCH_NAME="fix/${BRANCH_INPUT#fix-}" | |
| BRANCH_NAME="${BRANCH_NAME%-fix}" | |
| elif [[ $BRANCH_INPUT == docs-* ]] || [[ $BRANCH_INPUT == *-docs ]]; then | |
| BRANCH_NAME="docs/${BRANCH_INPUT#docs-}" | |
| BRANCH_NAME="${BRANCH_NAME%-docs}" | |
| elif [[ $BRANCH_INPUT == test-* ]] || [[ $BRANCH_INPUT == *-test ]]; then | |
| BRANCH_NAME="test/${BRANCH_INPUT#test-}" | |
| BRANCH_NAME="${BRANCH_NAME%-test}" | |
| elif [[ $BRANCH_INPUT == chore-* ]] || [[ $BRANCH_INPUT == *-chore ]]; then | |
| BRANCH_NAME="chore/${BRANCH_INPUT#chore-}" | |
| BRANCH_NAME="${BRANCH_NAME%-chore}" |
| if [[ $BRANCH_INPUT == fix-* ]] || [[ $BRANCH_INPUT == *-fix ]]; then | ||
| BRANCH_NAME="fix/${BRANCH_INPUT#fix-}" | ||
| elif [[ $BRANCH_INPUT == docs-* ]] || [[ $BRANCH_INPUT == *-docs ]]; then | ||
| BRANCH_NAME="docs/${BRANCH_INPUT#docs-}" |
There was a problem hiding this comment.
Same issue as with fix branches - the suffix stripping logic is inconsistent. For 'navigation-docs', this produces 'docs/navigation-docs' instead of 'docs/navigation'.
| BRANCH_NAME="docs/${BRANCH_INPUT#docs-}" | |
| BRANCH_NAME="docs/${BRANCH_INPUT#docs-}" | |
| BRANCH_NAME="${BRANCH_NAME%-docs}" |
| elif [[ $BRANCH_INPUT == docs-* ]] || [[ $BRANCH_INPUT == *-docs ]]; then | ||
| BRANCH_NAME="docs/${BRANCH_INPUT#docs-}" | ||
| elif [[ $BRANCH_INPUT == test-* ]] || [[ $BRANCH_INPUT == *-test ]]; then | ||
| BRANCH_NAME="test/${BRANCH_INPUT#test-}" |
There was a problem hiding this comment.
Same suffix stripping issue affects test branches. The logic should properly handle both 'test-feature' and 'feature-test' patterns.
| BRANCH_NAME="test/${BRANCH_INPUT#test-}" | |
| BRANCH_NAME="test/${BRANCH_INPUT#test-}" | |
| BRANCH_NAME="${BRANCH_NAME%-test}" |
| elif [[ $BRANCH_INPUT == test-* ]] || [[ $BRANCH_INPUT == *-test ]]; then | ||
| BRANCH_NAME="test/${BRANCH_INPUT#test-}" | ||
| elif [[ $BRANCH_INPUT == chore-* ]] || [[ $BRANCH_INPUT == *-chore ]]; then | ||
| BRANCH_NAME="chore/${BRANCH_INPUT#chore-}" |
There was a problem hiding this comment.
Same suffix stripping issue affects chore branches. The logic should properly handle both 'chore-task' and 'task-chore' patterns.
| BRANCH_NAME="chore/${BRANCH_INPUT#chore-}" | |
| BRANCH_NAME="chore/${BRANCH_INPUT#chore-}" | |
| BRANCH_NAME="${BRANCH_NAME%-chore}" |
| # Check for required tools | ||
| if ! command -v jq &> /dev/null; then | ||
| echo -e "${RED}❌ Error: jq is required but not installed${NC}" | ||
| echo "Install with: brew install jq" | ||
| exit 1 | ||
| fi | ||
|
|
||
| if ! command -v curl &> /dev/null; then | ||
| echo -e "${RED}❌ Error: curl is required but not installed${NC}" | ||
| exit 1 | ||
| fi | ||
|
|
||
| # Run main function | ||
| main "$@" No newline at end of file |
There was a problem hiding this comment.
The dependency checks should be moved to the beginning of the main() function or before it's called. Currently, if users run with --help, they'll see the error about missing jq even though they just want to see usage information.
| # Check for required tools | |
| if ! command -v jq &> /dev/null; then | |
| echo -e "${RED}❌ Error: jq is required but not installed${NC}" | |
| echo "Install with: brew install jq" | |
| exit 1 | |
| fi | |
| if ! command -v curl &> /dev/null; then | |
| echo -e "${RED}❌ Error: curl is required but not installed${NC}" | |
| exit 1 | |
| fi | |
| # Run main function | |
| main "$@" | |
| # Run main function | |
| main "$@" | |
| # Check for required tools (moved into main function) |
| local response=$(curl -s -X PUT \ | ||
| -H "Authorization: token $TOKEN" \ | ||
| -H "Accept: application/vnd.github.v3+json" \ | ||
| -H "Content-Type: application/json" \ | ||
| -d "$settings" \ | ||
| "$GITHUB_API/repos/$OWNER/$REPO/branches/$branch/protection") | ||
|
|
||
| # Check if successful | ||
| if [[ $(echo "$response" | jq -r '.url // empty') ]]; then |
There was a problem hiding this comment.
This condition checks if the URL field exists, but GitHub API errors also return JSON with different fields. This could incorrectly report success when the API returns an error. Should check for specific success indicators or HTTP status codes.
| local response=$(curl -s -X PUT \ | |
| -H "Authorization: token $TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$settings" \ | |
| "$GITHUB_API/repos/$OWNER/$REPO/branches/$branch/protection") | |
| # Check if successful | |
| if [[ $(echo "$response" | jq -r '.url // empty') ]]; then | |
| local response | |
| local http_status | |
| response=$(curl -s -w "%{http_code}" -o /tmp/response_body -X PUT \ | |
| -H "Authorization: token $TOKEN" \ | |
| -H "Accept: application/vnd.github.v3+json" \ | |
| -H "Content-Type: application/json" \ | |
| -d "$settings" \ | |
| "$GITHUB_API/repos/$OWNER/$REPO/branches/$branch/protection") | |
| http_status=$(tail -n1 <<< "$response") | |
| response=$(cat /tmp/response_body) | |
| # Check if successful | |
| if [[ "$http_status" -eq 200 || "$http_status" -eq 204 ]]; then |
| else | ||
| echo -e "${YELLOW}⚠️ GitHub CLI (gh) not found. Install it to auto-create PRs.${NC}" | ||
| echo -e "${BLUE}Push complete. Create PR manually at:${NC}" | ||
| echo "https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/pull/new/$branch_name" |
There was a problem hiding this comment.
This sed command duplicates the regex logic from get_repo_info() in the other script. Consider extracting a shared function or using a more robust URL parsing approach that's consistent between scripts.
| echo "https://github.com/$(git remote get-url origin | sed 's/.*github.com[:/]\(.*\)\.git/\1/')/pull/new/$branch_name" | |
| repo_name=$(get_repo_name) | |
| echo "https://github.com/$repo_name/pull/new/$branch_name" |
Add two essential scripts for the hybrid workflow: 1. claude-branch.sh - Streamlined branch creation - Automatic branch prefix detection (feat/, fix/, docs/, etc.) - Base branch configuration (defaults to dev) - Optional draft PR creation with template - Clear next-steps guidance - Integration with commit size limits 2. apply-branch-protection.sh - GitHub branch protection setup - Different rules for main (strict) vs dev (relaxed) - Main: requires reviews, up-to-date branches, no force push - Dev: no reviews required, allows force push for rebasing - Dry-run mode for testing - Auto-detects repository from git remote These scripts reduce manual setup and ensure consistent workflow adoption. Part 3 of the hybrid workflow implementation. Co-authored-by: Claude <claude@anthropic.com>
8315cb8 to
5deb615
Compare
🔍 PR Validation ResultsBuild Status: ✅ Passed This comment was automatically generated by the PR validation workflow. |
🛠️ Workflow Automation Scripts
This PR adds essential scripts to support the hybrid workflow model with automation tools.
Scripts added:
1. claude-branch.sh - Smart branch creation
devbut can targetmainwhen needed--prflag creates draft PR with templateghfor seamless PR creation2. apply-branch-protection.sh - Branch protection setup
main, relaxed fordevUsage examples:
Why these scripts matter:
This is Part 3 of 5 of the hybrid workflow implementation.
These scripts make it easier for both Claude and human developers to follow the hybrid workflow conventions.