Combining Multiple Repositories into a Single GitHub Action: A Step-by-Step Guide

Kolluru PawanKolluru Pawan
5 min read

GitHub Actions is a powerful automation tool that lets you build, test, and deploy code directly from your repository. But what if your project depends on multiple repositories? For example, you might have a microservices architecture or shared libraries stored in separate repos. In this blog post, we’ll walk through how to combine workflows across different repositories into a single GitHub Action.

Why Combine Repositories in a GitHub Action?

Here are common scenarios where this approach shines:

  1. Microservices: Trigger a unified test suite when changes occur in any linked service.

  2. Shared Libraries: Rebuild a core library and update dependent projects automatically.

  3. Monorepo Alternatives: Coordinate workflows across repos without consolidating codebases.

Prerequisites

  • Basic familiarity with GitHub Actions and YAML.

  • Access to the repositories you want to integrate.

  • A GitHub Personal Access Token (PAT) with appropriate permissions.

Step 1: Set Up the Base Workflow

Start by creating a workflow file (e.g., .github/workflows/combined.yml) in your primary repository. This will house the logic to interact with other repos.

name: Combined Repo Workflow
on:
  push:
    branches: [main]
  workflow_dispatch:

Step 2: Access Other Repositories

To interact with external repositories, use the actions/checkout action with a PAT. Here’s how:

Generate a PAT

  1. Go to GitHub Settings > Developer Settings > Personal Access Tokens.

  2. Create a token with repo scope (to access private repos if needed).

  3. Add the token as a secret (e.g., REPO_TOKEN) in your primary repository’s settings.

Checkout External Repos

Add steps to fetch code from other repositories:

jobs:
  fetch-dependencies:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Primary Repo
        uses: actions/checkout@v4

      - name: Checkout External Repo A
        uses: actions/checkout@v4
        with:
          repository: org/repo-a
          token: ${{ secrets.REPO_TOKEN }}
          path: repo-a

      - name: Checkout External Repo B
        uses: actions/checkout@v4
        with:
          repository: org/repo-b
          token: ${{ secrets.REPO_TOKEN }}
          path: repo-b

Step 3: Combine Workflows

Now that you’ve cloned the repos, run commands or trigger their workflows. For example:

  build-and-test:
    runs-on: ubuntu-latest
    needs: fetch-dependencies  # Wait for dependencies to fetch
    steps:
      - name: Build Repo A
        run: |
          cd repo-a
          npm install
          npm run build

      - name: Test Repo B
        run: |
          cd repo-b
          pip install -r requirements.txt
          pytest tests/

Step 4: Share Artifacts or Trigger Follow-Up Actions

To pass data between jobs or repos, use GitHub’s upload-artifact and download-artifact actions. For instance:

      - name: Upload Build Output
        uses: actions/upload-artifact@v3
        with:
          name: repo-a-build
          path: repo-a/dist/

  deploy:
    needs: build-and-test
    runs-on: ubuntu-latest
    steps:
      - name: Download Artifact
        uses: actions/download-artifact@v3
        with:
          name: repo-a-build

1. Clone Multiple Repositories in a Single Workflow

Use the actions/checkout action multiple times to clone other repositories into your workflow workspace.
Use Case: Aggregate code/files from multiple repositories for processing, testing, or deployment.

Example:

jobs:
  combine-repos:
    runs-on: ubuntu-latest
    steps:
      # Checkout the current repository
      - name: Checkout Current Repo
        uses: actions/checkout@v4

      # Checkout another repository (Repo A)
      - name: Checkout Repo A
        uses: actions/checkout@v4
        with:
          repository: your-username/repo-a
          token: ${{ secrets.PAT }}  # GitHub Personal Access Token (PAT)
          path: repo-a  # Clone into a subdirectory

      # Checkout another repository (Repo B)
      - name: Checkout Repo B
        uses: actions/checkout@v4
        with:
          repository: your-username/repo-b
          token: ${{ secrets.PAT }}
          path: repo-b

      # Example: Copy files from Repo A/B to the current repo
      - name: Merge Files
        run: |
          cp -r repo-a/src ./combined-src/
          cp -r repo-b/config ./combined-config/

Requirements:


2. Trigger Workflows Across Repositories

Use repository_dispatch or workflow triggers to chain workflows across repositories.
Use Case: Run a workflow in Repository B when an event occurs in Repository A.

Example (Triggering Repo B from Repo A):

Repo A Workflow:

jobs:
  trigger-repo-b:
    runs-on: ubuntu-latest
    steps:
      - name: Trigger Repo B Workflow
        uses: peter-evans/repository-dispatch@v2
        with:
          token: ${{ secrets.PAT }}
          repository: your-username/repo-b
          event-type: repo-a-trigger

Repo B Workflow (in .github/workflows/repo-b.yml):

on:
  repository_dispatch:
    types: [repo-a-trigger]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - run: echo "Triggered by Repo A!"

3. Mirror Changes Between Repositories

Push changes from one repository to another automatically.
Use Case: Sync code between a public and private repository.

jobs:
  mirror-repo:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout Source Repo
        uses: actions/checkout@v4
        with:
          fetch-depth: 0  # Fetch all history

      - name: Push to Target Repo
        run: |
          git remote add target https://${{ secrets.PAT }}@github.com/your-username/target-repo.git
          git push target HEAD:main

4. Aggregate Data/Artifacts from Multiple Repos

Download artifacts or data from other repositories into a central workflow.
Use Case: Combine test results or reports from multiple repositories.

jobs:
  aggregate-reports:
    runs-on: ubuntu-latest
    steps:
      - name: Download Artifact from Repo A
        uses: actions/download-artifact@v4
        with:
          repository: your-username/repo-a
          workflow: tests.yml
          name: test-results
          token: ${{ secrets.PAT }}
          path: repo-a-results

      - name: Process Reports
        run: |
          cat repo-a-results/results.txt >> combined-report.txt

Key Details

  1. repository: Specify the target repo in owner/repo-name format.

  2. path: Each repo is cloned into a subdirectory to avoid conflicts.

  3. token: Uses the PAT stored as a secret to authenticate access.


Handling Public Repositories

If the repositories are public, you can skip the token parameter:

- name: Clone Public Repo
  uses: actions/checkout@v4
  with:
    repository: your-org/public-repo
    path: public-repo

Best Practices

  1. Reuse PATs Securely: Never hardcode tokens in workflows—use GitHub Secrets.

  2. Parallelize Cloning: Use a matrix strategy to clone repos in parallel:

     strategy:
       matrix:
         repo:
           - your-org/repo-a
           - your-org/repo-b
     steps:
       - name: Clone ${{ matrix.repo }}
         uses: actions/checkout@v4
         with:
           repository: ${{ matrix.repo }}
           path: ${{ matrix.repo }}
    
  3. Cache Dependencies: Speed up workflows by caching tools (e.g., npm, pip):

     - name: Cache Node Modules
       uses: actions/cache@v3
       with:
         path: repo-a/node_modules
         key: repo-a-${{ hashFiles('repo-a/package-lock.json') }}
    
  4. Shallow Clone: Reduce clone time with fetch-depth for large repos:

     - uses: actions/checkout@v4
       with:
         repository: your-org/large-repo
         fetch-depth: 1 # Only fetch the latest commit
    

Example Use Case: Multi-Repo Testing

Clone a frontend and backend repo, then run tests:

- name: Test Frontend
  run: |
    cd frontend-repo
    npm install
    npm test

- name: Test Backend
  run: |
    cd backend-repo
    pip install -r requirements.txt
    pytest tests/

Limitations

  • Permissions: The PAT must have access to all repositories involved.

  • Workflow Complexity: Cloning many repos can slow down job execution.


By following this approach, you can seamlessly integrate code from multiple repositories into a single workflow for testing, building, or deployment.

0
Subscribe to my newsletter

Read articles from Kolluru Pawan directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Kolluru Pawan
Kolluru Pawan