-
Notifications
You must be signed in to change notification settings - Fork 0
feat(scripts): Add hybrid workflow automation scripts #246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,294 @@ | ||||||||||||||||||||||||||||||||||||||
| #!/bin/bash | ||||||||||||||||||||||||||||||||||||||
| # Apply Branch Protection Rules | ||||||||||||||||||||||||||||||||||||||
| # Configures GitHub branch protection for the hybrid workflow | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| set -euo pipefail | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Color codes for output | ||||||||||||||||||||||||||||||||||||||
| GREEN='\033[0;32m' | ||||||||||||||||||||||||||||||||||||||
| YELLOW='\033[0;33m' | ||||||||||||||||||||||||||||||||||||||
| RED='\033[0;31m' | ||||||||||||||||||||||||||||||||||||||
| BLUE='\033[0;34m' | ||||||||||||||||||||||||||||||||||||||
| NC='\033[0m' # No Color | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Configuration | ||||||||||||||||||||||||||||||||||||||
| GITHUB_API="https://api.github.com" | ||||||||||||||||||||||||||||||||||||||
| REQUIRED_CHECKS=( | ||||||||||||||||||||||||||||||||||||||
| "build" | ||||||||||||||||||||||||||||||||||||||
| "test" | ||||||||||||||||||||||||||||||||||||||
| "claude-standards" | ||||||||||||||||||||||||||||||||||||||
| ) | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to display usage | ||||||||||||||||||||||||||||||||||||||
| usage() { | ||||||||||||||||||||||||||||||||||||||
| echo "Usage: $0 [options]" | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| echo "Applies branch protection rules for the hybrid workflow." | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| echo "Options:" | ||||||||||||||||||||||||||||||||||||||
| echo " --token TOKEN GitHub personal access token (or set GITHUB_TOKEN env var)" | ||||||||||||||||||||||||||||||||||||||
| echo " --owner OWNER Repository owner (default: detected from git remote)" | ||||||||||||||||||||||||||||||||||||||
| echo " --repo REPO Repository name (default: detected from git remote)" | ||||||||||||||||||||||||||||||||||||||
| echo " --dry-run Show what would be done without making changes" | ||||||||||||||||||||||||||||||||||||||
| echo " --help Show this help message" | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| echo "Requirements:" | ||||||||||||||||||||||||||||||||||||||
| echo " - GitHub personal access token with repo permissions" | ||||||||||||||||||||||||||||||||||||||
| echo " - gh CLI tool installed (or provide --token)" | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to get repository info from git remote | ||||||||||||||||||||||||||||||||||||||
| get_repo_info() { | ||||||||||||||||||||||||||||||||||||||
| local remote_url=$(git remote get-url origin 2>/dev/null || echo "") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if [[ -z "$remote_url" ]]; then | ||||||||||||||||||||||||||||||||||||||
| echo -e "${RED}❌ Error: No git remote found${NC}" | ||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Extract owner and repo from URL | ||||||||||||||||||||||||||||||||||||||
| # Works with both HTTPS and SSH URLs | ||||||||||||||||||||||||||||||||||||||
| if [[ "$remote_url" =~ github\.com[:/]([^/]+)/([^/.]+)(\.git)?$ ]]; then | ||||||||||||||||||||||||||||||||||||||
| OWNER="${BASH_REMATCH[1]}" | ||||||||||||||||||||||||||||||||||||||
| REPO="${BASH_REMATCH[2]}" | ||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||
| echo -e "${RED}❌ Error: Could not parse GitHub repository from remote URL${NC}" | ||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to get GitHub token | ||||||||||||||||||||||||||||||||||||||
| get_github_token() { | ||||||||||||||||||||||||||||||||||||||
| if [[ -n "${GITHUB_TOKEN:-}" ]]; then | ||||||||||||||||||||||||||||||||||||||
| TOKEN="$GITHUB_TOKEN" | ||||||||||||||||||||||||||||||||||||||
| elif command -v gh &> /dev/null && gh auth status &>/dev/null; then | ||||||||||||||||||||||||||||||||||||||
| TOKEN=$(gh auth token) | ||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||
| echo -e "${RED}❌ Error: No GitHub token found${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo "Please provide --token or set GITHUB_TOKEN environment variable" | ||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to apply protection to a branch | ||||||||||||||||||||||||||||||||||||||
| apply_branch_protection() { | ||||||||||||||||||||||||||||||||||||||
| local branch=$1 | ||||||||||||||||||||||||||||||||||||||
| local settings=$2 | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| echo -e "${BLUE}🔒 Configuring protection for $branch branch...${NC}" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if [[ "$DRY_RUN" == "true" ]]; then | ||||||||||||||||||||||||||||||||||||||
| echo -e "${YELLOW}[DRY RUN] Would apply these settings:${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo "$settings" | jq '.' | ||||||||||||||||||||||||||||||||||||||
| return | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Apply protection rules | ||||||||||||||||||||||||||||||||||||||
| 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 | ||||||||||||||||||||||||||||||||||||||
| echo -e "${GREEN}✅ Successfully protected $branch branch${NC}" | ||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||
| echo -e "${RED}❌ Failed to protect $branch branch${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo "$response" | jq '.' | ||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to create main branch protection settings | ||||||||||||||||||||||||||||||||||||||
| create_main_protection() { | ||||||||||||||||||||||||||||||||||||||
| cat <<EOF | ||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||
| "required_status_checks": { | ||||||||||||||||||||||||||||||||||||||
| "strict": true, | ||||||||||||||||||||||||||||||||||||||
| "contexts": $(printf '%s\n' "${REQUIRED_CHECKS[@]}" | jq -R . | jq -s .) | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| "enforce_admins": false, | ||||||||||||||||||||||||||||||||||||||
| "required_pull_request_reviews": { | ||||||||||||||||||||||||||||||||||||||
| "dismissal_restrictions": {}, | ||||||||||||||||||||||||||||||||||||||
| "dismiss_stale_reviews": true, | ||||||||||||||||||||||||||||||||||||||
| "require_code_owner_reviews": false, | ||||||||||||||||||||||||||||||||||||||
| "required_approving_review_count": 1, | ||||||||||||||||||||||||||||||||||||||
| "require_last_push_approval": false | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| "restrictions": null, | ||||||||||||||||||||||||||||||||||||||
| "allow_force_pushes": false, | ||||||||||||||||||||||||||||||||||||||
| "allow_deletions": false, | ||||||||||||||||||||||||||||||||||||||
| "block_creations": false, | ||||||||||||||||||||||||||||||||||||||
| "required_conversation_resolution": true, | ||||||||||||||||||||||||||||||||||||||
| "lock_branch": false, | ||||||||||||||||||||||||||||||||||||||
| "allow_fork_syncing": true | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to create dev branch protection settings | ||||||||||||||||||||||||||||||||||||||
| create_dev_protection() { | ||||||||||||||||||||||||||||||||||||||
| cat <<EOF | ||||||||||||||||||||||||||||||||||||||
| { | ||||||||||||||||||||||||||||||||||||||
| "required_status_checks": { | ||||||||||||||||||||||||||||||||||||||
| "strict": false, | ||||||||||||||||||||||||||||||||||||||
| "contexts": $(printf '%s\n' "${REQUIRED_CHECKS[@]}" | jq -R . | jq -s .) | ||||||||||||||||||||||||||||||||||||||
| }, | ||||||||||||||||||||||||||||||||||||||
| "enforce_admins": false, | ||||||||||||||||||||||||||||||||||||||
| "required_pull_request_reviews": null, | ||||||||||||||||||||||||||||||||||||||
| "restrictions": null, | ||||||||||||||||||||||||||||||||||||||
| "allow_force_pushes": true, | ||||||||||||||||||||||||||||||||||||||
| "allow_deletions": false, | ||||||||||||||||||||||||||||||||||||||
| "block_creations": false, | ||||||||||||||||||||||||||||||||||||||
| "required_conversation_resolution": false, | ||||||||||||||||||||||||||||||||||||||
| "lock_branch": false, | ||||||||||||||||||||||||||||||||||||||
| "allow_fork_syncing": true | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
| EOF | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to check current protection status | ||||||||||||||||||||||||||||||||||||||
| check_protection_status() { | ||||||||||||||||||||||||||||||||||||||
| local branch=$1 | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| echo -e "${BLUE}🔍 Checking current protection for $branch...${NC}" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| local response=$(curl -s \ | ||||||||||||||||||||||||||||||||||||||
| -H "Authorization: token $TOKEN" \ | ||||||||||||||||||||||||||||||||||||||
| -H "Accept: application/vnd.github.v3+json" \ | ||||||||||||||||||||||||||||||||||||||
| "$GITHUB_API/repos/$OWNER/$REPO/branches/$branch/protection") | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| if [[ $(echo "$response" | jq -r '.message // empty') == "Branch not protected" ]]; then | ||||||||||||||||||||||||||||||||||||||
| echo -e "${YELLOW}⚠️ Branch $branch is not protected${NC}" | ||||||||||||||||||||||||||||||||||||||
| return 1 | ||||||||||||||||||||||||||||||||||||||
| else | ||||||||||||||||||||||||||||||||||||||
| echo -e "${GREEN}✓ Branch $branch is already protected${NC}" | ||||||||||||||||||||||||||||||||||||||
| if [[ "$VERBOSE" == "true" ]]; then | ||||||||||||||||||||||||||||||||||||||
| echo "$response" | jq '.' | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| return 0 | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Function to show summary | ||||||||||||||||||||||||||||||||||||||
| show_summary() { | ||||||||||||||||||||||||||||||||||||||
| echo -e "\n${GREEN}📊 Branch Protection Summary${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo -e "Repository: ${YELLOW}$OWNER/$REPO${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo -e "${BLUE}━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| echo -e "${GREEN}Main Branch Protection:${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo " ✓ Requires PR reviews (1 approval)" | ||||||||||||||||||||||||||||||||||||||
| echo " ✓ Dismisses stale reviews" | ||||||||||||||||||||||||||||||||||||||
| echo " ✓ Requires status checks to pass" | ||||||||||||||||||||||||||||||||||||||
| echo " ✓ Requires branches to be up to date" | ||||||||||||||||||||||||||||||||||||||
| echo " ✓ Requires conversation resolution" | ||||||||||||||||||||||||||||||||||||||
| echo " ✗ No force pushes allowed" | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| echo -e "${GREEN}Dev Branch Protection:${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo " ✗ No PR reviews required" | ||||||||||||||||||||||||||||||||||||||
| echo " ✓ Requires status checks to pass" | ||||||||||||||||||||||||||||||||||||||
| echo " ✗ Branches don't need to be up to date" | ||||||||||||||||||||||||||||||||||||||
| echo " ✗ No conversation resolution required" | ||||||||||||||||||||||||||||||||||||||
| echo " ✓ Force pushes allowed (for rebasing)" | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Main script | ||||||||||||||||||||||||||||||||||||||
| main() { | ||||||||||||||||||||||||||||||||||||||
| # Parse arguments | ||||||||||||||||||||||||||||||||||||||
| DRY_RUN=false | ||||||||||||||||||||||||||||||||||||||
| VERBOSE=false | ||||||||||||||||||||||||||||||||||||||
| TOKEN="" | ||||||||||||||||||||||||||||||||||||||
| OWNER="" | ||||||||||||||||||||||||||||||||||||||
| REPO="" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| while [[ $# -gt 0 ]]; do | ||||||||||||||||||||||||||||||||||||||
| case $1 in | ||||||||||||||||||||||||||||||||||||||
| --token) | ||||||||||||||||||||||||||||||||||||||
| TOKEN="$2" | ||||||||||||||||||||||||||||||||||||||
| shift 2 | ||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||
| --owner) | ||||||||||||||||||||||||||||||||||||||
| OWNER="$2" | ||||||||||||||||||||||||||||||||||||||
| shift 2 | ||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||
| --repo) | ||||||||||||||||||||||||||||||||||||||
| REPO="$2" | ||||||||||||||||||||||||||||||||||||||
| shift 2 | ||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||
| --dry-run) | ||||||||||||||||||||||||||||||||||||||
| DRY_RUN=true | ||||||||||||||||||||||||||||||||||||||
| shift | ||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||
| --verbose) | ||||||||||||||||||||||||||||||||||||||
| VERBOSE=true | ||||||||||||||||||||||||||||||||||||||
| shift | ||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||
| --help) | ||||||||||||||||||||||||||||||||||||||
| usage | ||||||||||||||||||||||||||||||||||||||
| exit 0 | ||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||
| *) | ||||||||||||||||||||||||||||||||||||||
| echo -e "${RED}❌ Unknown option: $1${NC}" | ||||||||||||||||||||||||||||||||||||||
| usage | ||||||||||||||||||||||||||||||||||||||
| exit 1 | ||||||||||||||||||||||||||||||||||||||
| ;; | ||||||||||||||||||||||||||||||||||||||
| esac | ||||||||||||||||||||||||||||||||||||||
| done | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Get repository info if not provided | ||||||||||||||||||||||||||||||||||||||
| if [[ -z "$OWNER" ]] || [[ -z "$REPO" ]]; then | ||||||||||||||||||||||||||||||||||||||
| get_repo_info | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| echo -e "${BLUE}🚀 Applying branch protection rules${NC}" | ||||||||||||||||||||||||||||||||||||||
| echo -e "Repository: ${YELLOW}$OWNER/$REPO${NC}" | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Get GitHub token if not provided | ||||||||||||||||||||||||||||||||||||||
| if [[ -z "$TOKEN" ]]; then | ||||||||||||||||||||||||||||||||||||||
| get_github_token | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Check if dry run | ||||||||||||||||||||||||||||||||||||||
| if [[ "$DRY_RUN" == "true" ]]; then | ||||||||||||||||||||||||||||||||||||||
| echo -e "${YELLOW}🔍 DRY RUN MODE - No changes will be made${NC}" | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Apply protection to main branch | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| if ! check_protection_status "main" || [[ "$DRY_RUN" == "true" ]]; then | ||||||||||||||||||||||||||||||||||||||
| apply_branch_protection "main" "$(create_main_protection)" | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Apply protection to dev branch | ||||||||||||||||||||||||||||||||||||||
| echo "" | ||||||||||||||||||||||||||||||||||||||
| if ! check_protection_status "dev" || [[ "$DRY_RUN" == "true" ]]; then | ||||||||||||||||||||||||||||||||||||||
| apply_branch_protection "dev" "$(create_dev_protection)" | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # Show summary | ||||||||||||||||||||||||||||||||||||||
| if [[ "$DRY_RUN" != "true" ]]; then | ||||||||||||||||||||||||||||||||||||||
| show_summary | ||||||||||||||||||||||||||||||||||||||
| fi | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| echo -e "\n${GREEN}✅ Branch protection configuration complete!${NC}" | ||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||
| # 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 "$@" | ||||||||||||||||||||||||||||||||||||||
|
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 "$@" | |
| # Run main function | |
| main "$@" | |
| # Check for required tools (moved into main function) |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
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.