Skip to content

Instantly share code, notes, and snippets.

@lcatlett
Created June 16, 2025 21:25
Show Gist options
  • Save lcatlett/dba23f8dcda6892e048ec4887df85258 to your computer and use it in GitHub Desktop.
Save lcatlett/dba23f8dcda6892e048ec4887df85258 to your computer and use it in GitHub Desktop.
GitHub API Rate Limiting Workaround for GitHub Actions

GitHub API Rate Limiting Workaround for GitHub Actions

This gist provides a comprehensive solution for handling GitHub API rate limiting in GitHub Actions workflows. It includes retry logic with exponential backoff and support for Personal Access Tokens (PAT) to increase rate limits.

🚨 Problem

GitHub Actions workflows often fail with rate limiting errors when making API calls:

HTTP request has failed with error "Maximum retry attempts reached"

This happens because:

  • The default GITHUB_TOKEN has a limit of 1,000 requests/hour
  • Multiple workflows or API calls can quickly exhaust this limit
  • No built-in retry mechanism for rate limit handling

✅ Solution

This solution provides:

  1. Higher Rate Limits: Use Personal Access Token (5,000 requests/hour vs 1,000)
  2. Automatic Retry: Exponential backoff when rate limits are hit
  3. Robust Error Handling: Proper handling of different HTTP status codes
  4. Reusable Script: Can be used across multiple workflows
  5. Fallback Support: Works with both PAT and default GITHUB_TOKEN

📁 Files Included

  • github-api-call.sh - Main script with rate limiting and retry logic
  • test-github-api.sh - Test script to verify functionality
  • sample-workflow.yml - Example GitHub Actions workflow
  • workflow-integration.sh - Sample integration script for workflows

🚀 Quick Start

1. Create Personal Access Token

  1. Go to GitHub Settings → Developer settings → Personal access tokens → Tokens (classic)
  2. Click "Generate new token (classic)"
  3. Select scopes: repo (for private repos) or public_repo (for public repos)
  4. Copy the generated token

2. Add Repository Secret

  1. Go to your repository → Settings → Secrets and variables → Actions
  2. Click "New repository secret"
  3. Name: GITHUB_PAT
  4. Value: Your generated PAT
  5. Click "Add secret"

3. Add Script to Your Repository

# Create directory (if it doesn't exist)
mkdir -p .ci/scripts

# Download the script
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh

# Make it executable
chmod +x .ci/scripts/github-api-call.sh

4. Use in Your Workflow

env:
  GITHUB_PAT: ${{ secrets.GITHUB_PAT }}

steps:
  - name: Make GitHub API call
    run: |
      # Use the script instead of direct curl
      .ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/pulls"

📊 Rate Limits Comparison

Token Type Requests/Hour Use Case
GITHUB_TOKEN 1,000 Default, basic workflows
Personal Access Token 5,000 Higher volume workflows
GitHub App 15,000 Enterprise applications

🔧 Configuration

The script supports several environment variables:

# Required (one of these)
export GITHUB_PAT="ghp_xxxxxxxxxxxx"     # Preferred
export GITHUB_TOKEN="ghs_xxxxxxxxxxxx"   # Fallback

# Optional configuration
export MAX_RETRIES=5        # Default: 5
export INITIAL_WAIT=1       # Default: 1 second

📖 Usage Examples

Basic Usage

./github-api-call.sh "https://api.github.com/repos/owner/repo/pulls"

Raw Output (no JSON formatting)

./github-api-call.sh "https://api.github.com/repos/owner/repo/issues" raw

Custom Retry Settings

MAX_RETRIES=10 INITIAL_WAIT=2 ./github-api-call.sh "https://api.github.com/rate_limit"

In Workflow Context

# Get PR number for current commit
if api_response=$(./github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/commits/${{ github.sha }}/pulls" raw); then
  PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number | select(.!=null)')
  echo "Found PR: $PR_NUMBER"
fi

🧪 Testing

Run the test script to verify everything works:

# Set your token
export GITHUB_PAT="your_token_here"

# Run tests
./test-github-api.sh

Expected output:

✅ Basic API call successful
✅ Rate limit check successful
✅ Invalid URL properly rejected
✅ Non-existent endpoint properly handled

🔍 Troubleshooting

Still Getting Rate Limited?

  1. Verify GITHUB_PAT secret is set correctly
  2. Check PAT has appropriate permissions
  3. Monitor rate limit status: ./github-api-call.sh "https://api.github.com/rate_limit"

Permission Errors?

chmod +x github-api-call.sh

Debug Mode

The script provides detailed logging. Check GitHub Actions logs for:

  • Retry attempts
  • HTTP status codes
  • Rate limit information
  • Error messages

🏗️ Integration Patterns

Pattern 1: Replace Direct curl Calls

# Before (prone to rate limiting)
curl -H "Authorization: token $GITHUB_TOKEN" \
  "https://api.github.com/repos/$REPO/pulls"

# After (with retry logic)
./github-api-call.sh "https://api.github.com/repos/$REPO/pulls"

Pattern 2: Conditional API Calls

if [ -z "$PR_NUMBER" ]; then
  if api_response=$(./github-api-call.sh "$API_URL" raw); then
    export PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number')
  else
    echo "Failed to fetch PR number, continuing without it"
  fi
fi

Pattern 3: Bulk Operations

for repo in $REPO_LIST; do
  echo "Processing $repo..."
  ./github-api-call.sh "https://api.github.com/repos/$repo/releases/latest"
  sleep 1  # Additional rate limiting
done

📝 License

MIT License - Feel free to use and modify as needed.

🤝 Contributing

Found an issue or have an improvement? Please share your feedback!


Note: This solution has been tested with GitHub Actions and various API endpoints. The exponential backoff strategy effectively handles temporary rate limits while the PAT provides higher baseline limits.

#!/bin/bash
# GitHub API call script with rate limiting and retry logic
# Usage: ./github-api-call.sh <url> [output_format]
#
# Arguments:
# url: The GitHub API URL to call
# output_format: Optional. 'json' (default) or 'raw'
#
# Environment variables:
# GITHUB_PAT: Personal Access Token (preferred)
# GITHUB_TOKEN: Fallback token
# MAX_RETRIES: Maximum number of retries (default: 5)
# INITIAL_WAIT: Initial wait time in seconds (default: 1)
set -euo pipefail
# Configuration
MAX_RETRIES="${MAX_RETRIES:-5}"
INITIAL_WAIT="${INITIAL_WAIT:-1}"
OUTPUT_FORMAT="${2:-json}"
# Validate arguments
if [ $# -lt 1 ]; then
echo "Usage: $0 <github_api_url> [output_format]" >&2
echo "Example: $0 'https://api.github.com/repos/owner/repo/pulls' json" >&2
exit 1
fi
URL="$1"
# Validate URL
if [[ ! "$URL" =~ ^https://api\.github\.com/ ]]; then
echo "Error: URL must be a GitHub API URL (https://api.github.com/...)" >&2
exit 1
fi
# Check for authentication token
AUTH_TOKEN="${GITHUB_PAT:-${GITHUB_TOKEN:-}}"
if [ -z "$AUTH_TOKEN" ]; then
echo "Error: Neither GITHUB_PAT nor GITHUB_TOKEN environment variable is set" >&2
exit 1
fi
# Function to make GitHub API call with retry logic
github_api_call() {
local url="$1"
local retry_count=0
local wait_time="$INITIAL_WAIT"
while [ $retry_count -lt $MAX_RETRIES ]; do
echo "Making API call to: $url (attempt $((retry_count + 1))/$MAX_RETRIES)" >&2
# Make the API call
response=$(curl -s -w "%{http_code}" \
-H "Authorization: token ${AUTH_TOKEN}" \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
-H "User-Agent: GitHub-Actions-Workflow" \
"$url")
# Extract HTTP status code and response body
http_code="${response: -3}"
response_body="${response%???}"
case "$http_code" in
200)
echo "API call successful" >&2
if [ "$OUTPUT_FORMAT" = "raw" ]; then
echo "$response_body"
else
echo "$response_body" | jq .
fi
return 0
;;
403)
# Check if it's a rate limit error
if echo "$response_body" | jq -e '.message | contains("rate limit")' >/dev/null 2>&1; then
echo "Rate limit exceeded (HTTP 403). Waiting ${wait_time}s before retry..." >&2
# Try to get reset time from headers if available
reset_time=$(echo "$response_body" | jq -r '.documentation_url // empty' 2>/dev/null || echo "")
if [ -n "$reset_time" ]; then
echo "Rate limit documentation: $reset_time" >&2
fi
else
echo "Access forbidden (HTTP 403). Check token permissions." >&2
echo "Response: $response_body" >&2
return 1
fi
;;
404)
echo "Resource not found (HTTP 404)" >&2
echo "Response: $response_body" >&2
return 1
;;
422)
echo "Unprocessable entity (HTTP 422)" >&2
echo "Response: $response_body" >&2
return 1
;;
*)
echo "API call failed with HTTP $http_code. Waiting ${wait_time}s before retry..." >&2
echo "Response: $response_body" >&2
;;
esac
# Wait before retry with exponential backoff
sleep $wait_time
wait_time=$((wait_time * 2))
retry_count=$((retry_count + 1))
done
echo "Max retries ($MAX_RETRIES) reached. API call failed." >&2
return 1
}
# Make the API call
github_api_call "$URL"

Implementation Guide: GitHub API Rate Limiting Solution

This guide provides step-by-step instructions for implementing the GitHub API rate limiting workaround in your projects.

📋 Prerequisites

  • GitHub repository with Actions enabled
  • Basic knowledge of GitHub Actions workflows
  • Access to create repository secrets

🚀 Implementation Steps

Step 1: Create Personal Access Token

  1. Navigate to GitHub Settings

    • Go to GitHub.com → Settings → Developer settings → Personal access tokens → Tokens (classic)
  2. Generate New Token

    • Click "Generate new token (classic)"
    • Give it a descriptive name (e.g., "Actions Rate Limiting")
    • Set expiration (recommend 90 days or 1 year)
  3. Select Scopes

    • For public repositories: public_repo
    • For private repositories: repo
    • Optional: read:org if you need organization data
  4. Save the Token

    • Copy the generated token immediately (you won't see it again)

Step 2: Add Repository Secret

  1. Go to Repository Settings

    • Navigate to your repository → Settings → Secrets and variables → Actions
  2. Create New Secret

    • Click "New repository secret"
    • Name: GITHUB_PAT
    • Value: Paste your Personal Access Token
    • Click "Add secret"

Step 3: Download and Setup Scripts

Choose one of these methods:

Method A: Manual Download

# Create directory
mkdir -p .ci/scripts

# Download main script
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh

# Download test script
curl -o .ci/scripts/test-github-api.sh https://gist.githubusercontent.com/[GIST_ID]/test-github-api.sh

# Make executable
chmod +x .ci/scripts/*.sh

Method B: Using Integration Script

# Download integration script
curl -o setup-rate-limiting.sh https://gist.githubusercontent.com/[GIST_ID]/workflow-integration.sh
chmod +x setup-rate-limiting.sh

# Run setup
./setup-rate-limiting.sh setup

Step 4: Update Your Workflow

Basic Integration

name: Your Workflow

env:
  GITHUB_PAT: ${{ secrets.GITHUB_PAT }}

jobs:
  your_job:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      
      - name: Setup API script
        run: |
          chmod +x .ci/scripts/github-api-call.sh
      
      - name: Make API call
        run: |
          .ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/pulls"

Advanced Integration

- name: Get PR information with retry logic
  run: |
    if api_response=$(.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/commits/${{ github.sha }}/pulls" raw); then
      PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number | select(.!=null)')
      echo "PR_NUMBER=$PR_NUMBER" >> $GITHUB_ENV
    else
      echo "Failed to get PR info, continuing without it"
    fi

Step 5: Test the Implementation

  1. Local Testing (if you have the token):

    export GITHUB_PAT="your_token_here"
    .ci/scripts/test-github-api.sh
  2. Workflow Testing:

    • Push a commit or create a PR to trigger your workflow
    • Check the Actions logs for successful API calls
    • Look for retry messages if rate limits are hit

🔧 Migration from Existing Code

Replace Direct curl Calls

Before:

curl -u "${GITHUB_OWNER}:${GITHUB_TOKEN}" \
  -H "Accept: application/vnd.github.groot-preview+json" \
  "https://api.github.com/repos/${REPO}/commits/${SHA}/pulls"

After:

.ci/scripts/github-api-call.sh "https://api.github.com/repos/${REPO}/commits/${SHA}/pulls"

Update Environment Variable References

Before:

curl -H "Authorization: token ${GITHUB_TOKEN}" "$API_URL"

After:

.ci/scripts/github-api-call.sh "$API_URL"

Add Error Handling

Before:

PR_NUMBER=$(curl ... | jq -r '.[0].number')

After:

if api_response=$(.ci/scripts/github-api-call.sh "$API_URL" raw); then
  PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number | select(.!=null)')
else
  echo "Failed to get PR number, continuing without it"
fi

📊 Monitoring and Troubleshooting

Check Rate Limit Status

.ci/scripts/github-api-call.sh "https://api.github.com/rate_limit"

Common Issues and Solutions

  1. "Neither GITHUB_PAT nor GITHUB_TOKEN is set"

    • Verify the secret is created correctly
    • Check the secret name matches exactly: GITHUB_PAT
  2. "Access forbidden (HTTP 403)"

    • Check PAT permissions/scopes
    • Verify PAT hasn't expired
  3. Still getting rate limited

    • Verify PAT is being used (check logs)
    • Consider reducing API call frequency
    • Monitor rate limit status
  4. Script not found

    • Verify script path in workflow
    • Ensure script is executable: chmod +x

Debug Mode

Add this to your workflow for detailed logging:

- name: Debug API calls
  env:
    DEBUG: true
  run: |
    .ci/scripts/github-api-call.sh "https://api.github.com/rate_limit"

🎯 Best Practices

  1. Use PAT for Higher Limits

    • Always prefer GITHUB_PAT over GITHUB_TOKEN
    • Set appropriate expiration dates
  2. Implement Proper Error Handling

    • Don't fail workflows on non-critical API calls
    • Provide fallback behavior
  3. Monitor Rate Limits

    • Check rate limit status periodically
    • Log API usage in workflows
  4. Optimize API Usage

    • Cache responses when possible
    • Batch API calls when feasible
    • Use GraphQL for complex queries
  5. Security

    • Use repository secrets, not environment variables
    • Regularly rotate PATs
    • Use minimal required scopes

📈 Expected Results

After implementation, you should see:

  • ✅ Elimination of "Maximum retry attempts reached" errors
  • ✅ Automatic recovery from temporary rate limits
  • ✅ Higher API rate limits (5,000 vs 1,000 requests/hour)
  • ✅ Detailed logging for troubleshooting
  • ✅ Graceful handling of API failures

🔄 Maintenance

  • Monthly: Check PAT expiration dates
  • Quarterly: Review API usage patterns
  • As needed: Update scripts from gist
  • Before major releases: Test rate limiting behavior

Need Help? Check the troubleshooting section or review the sample workflow for complete examples.

name: Sample Workflow with GitHub API Rate Limiting
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main, develop ]
# Global environment variables
env:
GITHUB_PAT: ${{ secrets.GITHUB_PAT }} # Personal Access Token for higher rate limits
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Fallback token
jobs:
setup:
name: Setup and API calls
runs-on: ubuntu-latest
outputs:
pr_number: ${{ steps.get_pr.outputs.pr_number }}
pr_url: ${{ steps.get_pr.outputs.pr_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup GitHub API script
run: |
# Create scripts directory
mkdir -p .ci/scripts
# Download the rate limiting script (replace with your gist URL)
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh
# Make it executable
chmod +x .ci/scripts/github-api-call.sh
- name: Get PR information
id: get_pr
run: |
# Example: Get PR number and URL for current commit
if [ "${{ github.event_name }}" = "push" ] && [ "${{ github.ref }}" != "refs/heads/main" ]; then
echo "Fetching PR information for commit ${{ github.sha }}..."
# Use the rate-limiting script instead of direct curl
if api_response=$(.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/commits/${{ github.sha }}/pulls" raw); then
PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number | select(.!=null)')
PR_URL=$(echo "$api_response" | jq -r '.[0].html_url | select(.!=null)')
echo "Found PR #$PR_NUMBER: $PR_URL"
echo "pr_number=$PR_NUMBER" >> $GITHUB_OUTPUT
echo "pr_url=$PR_URL" >> $GITHUB_OUTPUT
else
echo "No PR found for this commit or API call failed"
fi
fi
- name: Check rate limit status
run: |
echo "Checking current rate limit status..."
.ci/scripts/github-api-call.sh "https://api.github.com/rate_limit"
api_operations:
name: API Operations with Rate Limiting
runs-on: ubuntu-latest
needs: setup
if: needs.setup.outputs.pr_number != ''
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup GitHub API script
run: |
mkdir -p .ci/scripts
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh
chmod +x .ci/scripts/github-api-call.sh
- name: Get PR details
run: |
PR_NUMBER="${{ needs.setup.outputs.pr_number }}"
echo "Getting details for PR #$PR_NUMBER..."
# Get PR details with rate limiting protection
.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER"
- name: Get PR files
run: |
PR_NUMBER="${{ needs.setup.outputs.pr_number }}"
echo "Getting files changed in PR #$PR_NUMBER..."
# Get PR files with rate limiting protection
if files_response=$(.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/pulls/$PR_NUMBER/files" raw); then
echo "Files changed:"
echo "$files_response" | jq -r '.[].filename'
fi
- name: Bulk API operations example
run: |
# Example of making multiple API calls with built-in rate limiting
echo "Performing bulk API operations..."
# Get recent releases
.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/releases"
# Get repository topics
.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/topics"
# Get repository languages
.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/languages"
test_script:
name: Test Rate Limiting Script
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup and test GitHub API script
run: |
# Download both the main script and test script
mkdir -p .ci/scripts
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh
curl -o .ci/scripts/test-github-api.sh https://gist.githubusercontent.com/[GIST_ID]/test-github-api.sh
# Make them executable
chmod +x .ci/scripts/github-api-call.sh
chmod +x .ci/scripts/test-github-api.sh
# Run the test suite
.ci/scripts/test-github-api.sh
custom_retry_example:
name: Custom Retry Configuration
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup GitHub API script
run: |
mkdir -p .ci/scripts
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh
chmod +x .ci/scripts/github-api-call.sh
- name: API call with custom retry settings
env:
MAX_RETRIES: 10 # Increase max retries
INITIAL_WAIT: 2 # Start with 2 second wait
run: |
echo "Making API call with custom retry settings..."
echo "Max retries: $MAX_RETRIES, Initial wait: $INITIAL_WAIT seconds"
# This will use the custom retry settings
.ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}"
error_handling_example:
name: Error Handling Example
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Setup GitHub API script
run: |
mkdir -p .ci/scripts
curl -o .ci/scripts/github-api-call.sh https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh
chmod +x .ci/scripts/github-api-call.sh
- name: API calls with error handling
run: |
# Example of proper error handling
echo "Making API calls with error handling..."
# Critical API call - fail if it doesn't work
if ! .ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}" > /dev/null; then
echo "Critical API call failed, stopping workflow"
exit 1
fi
# Optional API call - continue if it fails
if .ci/scripts/github-api-call.sh "https://api.github.com/repos/${{ github.repository }}/releases/latest" > /dev/null; then
echo "Latest release information retrieved"
else
echo "No releases found or API call failed, continuing..."
fi
echo "Workflow completed successfully"
#!/bin/bash
# Test script for github-api-call.sh
# This script tests the GitHub API functionality with rate limiting
set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
API_SCRIPT="$SCRIPT_DIR/github-api-call.sh"
echo "Testing GitHub API script..."
echo "================================"
# Check if the script exists and is executable
if [ ! -f "$API_SCRIPT" ]; then
echo "Error: github-api-call.sh not found at $API_SCRIPT"
exit 1
fi
if [ ! -x "$API_SCRIPT" ]; then
echo "Making github-api-call.sh executable..."
chmod +x "$API_SCRIPT"
fi
# Check for required environment variables
if [ -z "${GITHUB_PAT:-}" ] && [ -z "${GITHUB_TOKEN:-}" ]; then
echo "Error: Neither GITHUB_PAT nor GITHUB_TOKEN environment variable is set"
echo "Please set one of these variables before running the test"
exit 1
fi
# Test 1: Basic API call
echo "Test 1: Basic API call to get repository information"
echo "---------------------------------------------------"
if "$API_SCRIPT" "https://api.github.com/repos/${GITHUB_REPOSITORY:-octocat/Hello-World}" raw > /dev/null; then
echo "✅ Basic API call successful"
else
echo "❌ Basic API call failed"
exit 1
fi
# Test 2: Rate limit info
echo ""
echo "Test 2: Checking rate limit status"
echo "-----------------------------------"
if rate_limit_info=$("$API_SCRIPT" "https://api.github.com/rate_limit" raw); then
echo "✅ Rate limit check successful"
echo "Current rate limit status:"
echo "$rate_limit_info" | jq '.rate.remaining, .rate.limit, .rate.reset' 2>/dev/null || echo "$rate_limit_info"
else
echo "❌ Rate limit check failed"
fi
# Test 3: Invalid URL handling
echo ""
echo "Test 3: Testing invalid URL handling"
echo "------------------------------------"
if "$API_SCRIPT" "https://invalid-url.com/api" 2>/dev/null; then
echo "❌ Invalid URL test failed - should have rejected invalid URL"
else
echo "✅ Invalid URL properly rejected"
fi
# Test 4: Non-existent endpoint
echo ""
echo "Test 4: Testing non-existent endpoint"
echo "-------------------------------------"
if "$API_SCRIPT" "https://api.github.com/repos/nonexistent/repo" 2>/dev/null; then
echo "❌ Non-existent endpoint test unexpected success"
else
echo "✅ Non-existent endpoint properly handled"
fi
echo ""
echo "================================"
echo "GitHub API script tests completed"
echo ""
echo "If all tests passed, the script is ready for use in the workflow."
echo "Make sure to add the GITHUB_PAT secret to your repository settings."
#!/bin/bash
# Workflow Integration Script
# This script demonstrates how to integrate the GitHub API rate limiting solution
# into existing workflows and CI/CD pipelines
set -euo pipefail
# Configuration
SCRIPT_NAME="github-api-call.sh"
SCRIPT_URL="https://gist.githubusercontent.com/[GIST_ID]/github-api-call.sh"
SCRIPTS_DIR="${SCRIPTS_DIR:-.ci/scripts}"
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Logging functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# Function to setup the GitHub API script
setup_github_api_script() {
log_info "Setting up GitHub API rate limiting script..."
# Create scripts directory if it doesn't exist
if [ ! -d "$SCRIPTS_DIR" ]; then
log_info "Creating scripts directory: $SCRIPTS_DIR"
mkdir -p "$SCRIPTS_DIR"
fi
local script_path="$SCRIPTS_DIR/$SCRIPT_NAME"
# Download the script if it doesn't exist or if forced
if [ ! -f "$script_path" ] || [ "${FORCE_DOWNLOAD:-false}" = "true" ]; then
log_info "Downloading GitHub API script..."
if curl -s -o "$script_path" "$SCRIPT_URL"; then
log_success "Script downloaded successfully"
else
log_error "Failed to download script from $SCRIPT_URL"
return 1
fi
else
log_info "Script already exists at $script_path"
fi
# Make script executable
chmod +x "$script_path"
log_success "GitHub API script is ready at $script_path"
}
# Function to validate environment
validate_environment() {
log_info "Validating environment..."
# Check for required tools
local required_tools=("curl" "jq")
for tool in "${required_tools[@]}"; do
if ! command -v "$tool" &> /dev/null; then
log_error "Required tool '$tool' is not installed"
return 1
fi
done
# Check for authentication token
if [ -z "${GITHUB_PAT:-}" ] && [ -z "${GITHUB_TOKEN:-}" ]; then
log_warning "Neither GITHUB_PAT nor GITHUB_TOKEN is set"
log_warning "The script will fail without authentication"
return 1
fi
if [ -n "${GITHUB_PAT:-}" ]; then
log_success "GITHUB_PAT is available (recommended)"
else
log_warning "Using GITHUB_TOKEN (lower rate limits)"
fi
log_success "Environment validation passed"
}
# Function to test the GitHub API script
test_github_api_script() {
log_info "Testing GitHub API script..."
local script_path="$SCRIPTS_DIR/$SCRIPT_NAME"
if [ ! -f "$script_path" ]; then
log_error "Script not found at $script_path"
return 1
fi
# Test basic functionality
log_info "Testing basic API call..."
if "$script_path" "https://api.github.com/rate_limit" > /dev/null; then
log_success "Basic API call test passed"
else
log_error "Basic API call test failed"
return 1
fi
log_success "GitHub API script tests passed"
}
# Function to migrate existing curl calls
migrate_curl_calls() {
local file="$1"
local backup_file="${file}.backup"
log_info "Migrating curl calls in $file..."
# Create backup
cp "$file" "$backup_file"
log_info "Backup created: $backup_file"
# Replace curl calls with script calls
# This is a basic example - you may need to customize for your specific patterns
sed -i.tmp 's|curl -u "${GITHUB_OWNER}:${GITHUB_TOKEN}"|.ci/scripts/github-api-call.sh|g' "$file"
sed -i.tmp 's|curl -H "Authorization: token ${GITHUB_TOKEN}"|.ci/scripts/github-api-call.sh|g' "$file"
rm -f "${file}.tmp"
log_success "Migration completed for $file"
}
# Function to show usage examples
show_examples() {
cat << 'EOF'
=== Usage Examples ===
1. Basic API call:
./github-api-call.sh "https://api.github.com/repos/owner/repo/pulls"
2. Get raw response:
./github-api-call.sh "https://api.github.com/repos/owner/repo/issues" raw
3. Custom retry settings:
MAX_RETRIES=10 INITIAL_WAIT=2 ./github-api-call.sh "https://api.github.com/rate_limit"
4. In workflow context:
if api_response=$(./github-api-call.sh "$API_URL" raw); then
PR_NUMBER=$(echo "$api_response" | jq -r '.[0].number')
fi
5. Error handling:
if ! ./github-api-call.sh "$API_URL" > /dev/null; then
echo "Critical API call failed"
exit 1
fi
=== Environment Variables ===
Required (one of):
- GITHUB_PAT: Personal Access Token (recommended)
- GITHUB_TOKEN: Default GitHub token
Optional:
- MAX_RETRIES: Maximum retry attempts (default: 5)
- INITIAL_WAIT: Initial wait time in seconds (default: 1)
- SCRIPTS_DIR: Directory for scripts (default: .ci/scripts)
EOF
}
# Main function
main() {
local command="${1:-setup}"
case "$command" in
"setup")
validate_environment
setup_github_api_script
test_github_api_script
log_success "Setup completed successfully!"
;;
"test")
test_github_api_script
;;
"migrate")
if [ $# -lt 2 ]; then
log_error "Usage: $0 migrate <file_to_migrate>"
exit 1
fi
migrate_curl_calls "$2"
;;
"examples")
show_examples
;;
"validate")
validate_environment
;;
*)
echo "Usage: $0 {setup|test|migrate|examples|validate}"
echo ""
echo "Commands:"
echo " setup - Download and setup the GitHub API script"
echo " test - Test the GitHub API script functionality"
echo " migrate - Migrate existing curl calls in a file"
echo " examples - Show usage examples"
echo " validate - Validate environment setup"
exit 1
;;
esac
}
# Run main function with all arguments
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment