Skip to content

GitHub Actions Script API Practical Implementation Guide

This article is a follow-up to the morning article

Morning article: GitHub Actions Self-Healing Workflows Implementation Guide

Target Audience

  • Advanced users looking to leverage GitHub Actions Script API in production environments

Goals

  • Master REST/GraphQL API selection strategies
  • Implement authentication, permissions, and rate limiting solutions
  • Establish error handling and logging best practices

Architecture Overview

GitHub Actions Script API operates in three execution contexts:

Workflow Context → Script Action → GitHub API
     ↓               ↓              ↓
  - GITHUB_TOKEN   - octokit/rest  - Rate Limits
  - Repository     - context obj   - Permissions
  - Event payload  - Error handling - Response format

Implementation Steps

Step 1: API Selection Strategy and Context Configuration

Understand REST vs GraphQL characteristics and use them appropriately.

- name: Smart API Usage Pattern
  uses: actions/github-script@v7
  with:
    github-token: ${{ secrets.PAT_TOKEN }}
    script: |
      // REST: Simple CRUD operations
      const { data: issues } = await github.rest.issues.listForRepo({
        owner: context.repo.owner,
        repo: context.repo.repo,
        state: 'open',
        labels: 'bug'
      });

      // GraphQL: Complex queries and related data fetching
      const query = `
        query($owner: String!, $repo: String!) {
          repository(owner: $owner, name: $repo) {
            pullRequests(first: 10, states: OPEN) {
              nodes {
                number
                title
                author { login }
                reviews(first: 5) {
                  nodes { state author { login } }
                }
              }
            }
          }
        }
      `;

      const gqlResult = await github.graphql(query, {
        owner: context.repo.owner,
        repo: context.repo.repo
      });

Step 2: Permission Escalation and Token Management

Implement differentiation between Personal Access Tokens (PAT) and GITHUB_TOKEN.

- name: Permission-aware API Operations
  uses: actions/github-script@v7
  env:
    ADMIN_TOKEN: ${{ secrets.ADMIN_PAT }}
  with:
    script: |
      // Permission check function
      async function checkPermissions(requiredScope) {
        try {
          const { data: user } = await github.rest.users.getAuthenticated();
          const { data: perms } = await github.rest.repos.getCollaboratorPermissionLevel({
            owner: context.repo.owner,
            repo: context.repo.repo,
            username: user.login
          });

          const hasPermission = perms.permission === 'admin' || 
                               perms.permission === requiredScope;

          if (!hasPermission) {
            // Fallback: Use Admin PAT
            const adminOctokit = github.getOctokit(process.env.ADMIN_TOKEN);
            return adminOctokit;
          }
          return github;
        } catch (error) {
          core.setFailed(`Permission check failed: ${error.message}`);
        }
      }

      // Example usage: Branch Protection settings
      const apiClient = await checkPermissions('admin');
      await apiClient.rest.repos.updateBranchProtection({
        owner: context.repo.owner,
        repo: context.repo.repo,
        branch: 'main',
        required_status_checks: {
          strict: true,
          contexts: ['build', 'test']
        },
        enforce_admins: false
      });

Step 3: Rate Limiting and Batch Processing Optimization

Implement progressive backoff strategies for API limits.

- name: Rate-limit Resilient Processing
  uses: actions/github-script@v7
  with:
    script: |
      class RateLimitHandler {
        constructor(octokit, options = {}) {
          this.github = octokit;
          this.maxRetries = options.maxRetries || 3;
          this.baseDelay = options.baseDelay || 1000;
        }

        async executeWithRetry(apiCall, retryCount = 0) {
          try {
            const result = await apiCall();

            // Log rate limit information
            const remaining = result.headers['x-ratelimit-remaining'];
            if (remaining && parseInt(remaining) < 100) {
              const resetTime = new Date(result.headers['x-ratelimit-reset'] * 1000);
              console.log(`⚠️  Rate limit low: ${remaining} remaining, resets at ${resetTime}`);
            }

            return result;
          } catch (error) {
            if (error.status === 403 && error.message.includes('rate limit')) {
              if (retryCount < this.maxRetries) {
                const delay = this.baseDelay * Math.pow(2, retryCount);
                console.log(`Rate limited. Retrying in ${delay}ms... (${retryCount + 1}/${this.maxRetries})`);

                await new Promise(resolve => setTimeout(resolve, delay));
                return this.executeWithRetry(apiCall, retryCount + 1);
              }
            }
            throw error;
          }
        }
      }

      // Usage example: Bulk issue processing
      const handler = new RateLimitHandler(github);
      const issues = await handler.executeWithRetry(async () => {
        return github.rest.issues.listForRepo({
          owner: context.repo.owner,
          repo: context.repo.repo,
          per_page: 100,
          state: 'all'
        });
      });

Performance Comparison

API TypeProcessing SpeedRate LimitComplex QueriesRecommended Use
REST APIHigh5000req/hourCRUD operations
GraphQL APIMedium5000points/hourRelated data fetching
GitHub AppHighest15000req/hourLarge-scale processing

Common Failure Patterns and Solutions

SymptomCauseSolution
403 Permission deniedInsufficient GITHUB_TOKEN permissionsUse PAT or App authentication
404 Not FoundPrivate repository accessAdd repo scope permissions
Rate limit exceededExcessive API callsImplement batching and progressive backoff
Invalid GraphQL queryQuery syntax errorsUse schema validation tools

Automation Extension Ideas

  • API Usage Monitoring: Set up rate limit alerts with CloudWatch/DataDog
  • Caching Strategy: Store frequently accessed data with Redis/Memcached
  • Log Aggregation: Analyze API execution history with ELK stack
  • Test Automation: Mock API calls and regression testing
  • Permission Auditing: Periodic token permission checks and automatic renewal

Next Steps