Skip to content

feat(scripts): Add hybrid workflow automation scripts#246

Merged
DrunkOnJava merged 1 commit intomainfrom
feat/hybrid-workflow-scripts
Jul 31, 2025
Merged

feat(scripts): Add hybrid workflow automation scripts#246
DrunkOnJava merged 1 commit intomainfrom
feat/hybrid-workflow-scripts

Conversation

@DrunkOnJava
Copy link
Owner

🛠️ 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

  • Automatic prefix detection: Detects branch type from name (feat/, fix/, docs/, etc.)
  • Configurable base branch: Defaults to dev but can target main when needed
  • Draft PR creation: Optional --pr flag creates draft PR with template
  • Developer guidance: Shows next steps and commit size limits
  • GitHub CLI integration: Works with gh for seamless PR creation

2. apply-branch-protection.sh - Branch protection setup

  • Differentiated rules: Strict for main, relaxed for dev
  • Main branch protection:
    • Requires 1 review approval
    • Dismisses stale reviews
    • Requires up-to-date branches
    • Blocks force pushes
    • Requires conversation resolution
  • Dev branch protection:
    • No review requirements
    • Allows force pushes (for rebasing)
    • Status checks still required
  • Safety features: Dry-run mode, auto-detection of repo info

Usage examples:

# Create a feature branch
./scripts/claude-branch.sh add-search-feature

# Create a fix branch with draft PR
./scripts/claude-branch.sh fix-navigation --pr

# Create branch from main instead of dev
./scripts/claude-branch.sh critical-hotfix --base main --pr

# Apply branch protection (dry run)
./scripts/apply-branch-protection.sh --dry-run

# Apply branch protection
./scripts/apply-branch-protection.sh

Why these scripts matter:

  • Reduces friction in following the hybrid workflow
  • Ensures consistency in branch naming and PR creation
  • Automates protection setup for new repositories
  • Guides developers through best practices

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.

Copilot AI review requested due to automatic review settings July 31, 2025 22:21
@github-actions
Copy link

🔍 PR Validation Results

Build Status: ❌ Failed
SwiftLint: ⚠️ Issues found
Project Structure: ❌ Issues found
Compilation: ❌ Failed


This comment was automatically generated by the PR validation workflow.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.sh for intelligent branch creation with automatic prefix detection and optional draft PR generation
  • Adds apply-branch-protection.sh for 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

Comment on lines +218 to +224
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-}"
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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}"

Copilot uses AI. Check for mistakes.
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-}"
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same issue as with fix branches - the suffix stripping logic is inconsistent. For 'navigation-docs', this produces 'docs/navigation-docs' instead of 'docs/navigation'.

Suggested change
BRANCH_NAME="docs/${BRANCH_INPUT#docs-}"
BRANCH_NAME="docs/${BRANCH_INPUT#docs-}"
BRANCH_NAME="${BRANCH_NAME%-docs}"

Copilot uses AI. Check for mistakes.
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-}"
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same suffix stripping issue affects test branches. The logic should properly handle both 'test-feature' and 'feature-test' patterns.

Suggested change
BRANCH_NAME="test/${BRANCH_INPUT#test-}"
BRANCH_NAME="test/${BRANCH_INPUT#test-}"
BRANCH_NAME="${BRANCH_NAME%-test}"

Copilot uses AI. Check for mistakes.
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-}"
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same suffix stripping issue affects chore branches. The logic should properly handle both 'chore-task' and 'task-chore' patterns.

Suggested change
BRANCH_NAME="chore/${BRANCH_INPUT#chore-}"
BRANCH_NAME="chore/${BRANCH_INPUT#chore-}"
BRANCH_NAME="${BRANCH_NAME%-chore}"

Copilot uses AI. Check for mistakes.
Comment on lines +281 to +294
# 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
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
# 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)

Copilot uses AI. Check for mistakes.
Comment on lines +88 to +96
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
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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

Copilot uses AI. Check for mistakes.
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"
Copy link

Copilot AI Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Suggested change
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"

Copilot uses AI. Check for mistakes.
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>
@DrunkOnJava DrunkOnJava force-pushed the feat/hybrid-workflow-scripts branch from 8315cb8 to 5deb615 Compare July 31, 2025 23:10
@github-actions
Copy link

🔍 PR Validation Results

Build Status: ✅ Passed
SwiftLint: ⚠️ Issues found
Project Structure: ❌ Issues found
Compilation: ❌ Failed


This comment was automatically generated by the PR validation workflow.

@DrunkOnJava DrunkOnJava merged commit e7d5c85 into main Jul 31, 2025
2 of 4 checks passed
@DrunkOnJava DrunkOnJava deleted the feat/hybrid-workflow-scripts branch July 31, 2025 23:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants