Automate Branch Creation & Commits to External Repositories with GitHub Apps
Introduction
In modern software development, automation plays a crucial role in enhancing both efficiency and reliability. One common scenario is automating the process of creating branches and committing changes from one repository to another. This is particularly useful when you need to synchronize configurations, back up data, or deploy code across multiple repositories.
In this tutorial, we will guide you through the automation of branch creation and commits to a target repository using GitHub Apps and GitHub Actions. By the end, you'll have a setup where GitHub Actions automates the process of authenticating with a GitHub App, checking for changes, creating branches, and committing changes only when necessary.
Prerequisites
Before we begin, make sure you have the following:
GitHub Account: Administrative access to create GitHub Apps and manage repository settings.
Familiarity with GitHub Actions: A basic understanding of workflows and YAML configuration.
Python Programming Knowledge: Familiarity with Python, especially working with REST APIs.
Overview
We will automate the following steps:
Create or Update a Branch: Create a branch in the target repository, or update it if it already exists.
Commit Changes: Commit changes to the branch only when new changes are detected.
GitHub App for Authentication: Use a GitHub App to authenticate and perform operations securely.
Automate via GitHub Actions: Set up GitHub Actions to handle the entire workflow.
By the end, you'll have a fully functional GitHub Actions workflow that:
Authenticates using a GitHub App.
Checks for changes in the source repository.
Creates or updates a branch in the target repository.
Commits changes when necessary, avoiding redundant commits.
Step 1: Setting Up the GitHub App
1.1 Create a New GitHub App
Navigate to GitHub Settings.
Click "New GitHub App".
1.2 Configure the GitHub App
App Name: Choose a unique name for the app.
Homepage URL: Enter your repository or organization URL.
Webhook URL: You can skip this for now unless you need webhooks.
Permissions:
- Set Repository Permissions for Contents to Read and Write.
Subscribe to Events: This is optional for this use case.
Installation Scope: Choose "Any account" unless you want to restrict it.
1.3 Generate App Credentials
After creating the app, go to the app's settings page.
Generate a Private Key:
- In the "Private keys" section, click "Generate a private key". A
.pem
file will be downloaded. Keep this secure.
- In the "Private keys" section, click "Generate a private key". A
Get the App ID: You'll need the App ID, which is visible on the app settings page.
Step 2: Granting Access to Repositories
2.1 Install the GitHub App
Click "Install App" on the app settings page.
Select the repositories where the app will be installed, both the source repository (where the workflow will run) and the target repository (where branches and commits will be created).
Step 3: Configuring GitHub Actions Workflow
Create a new workflow file in your source repository, for example: .github/workflows/backup.yml
.
name: Backup to Target Repo
on:
push:
branches:
- main # Trigger the workflow when changes are pushed to the main branch
jobs:
backup:
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v3
- name: Set up Python
uses: actions/setup-python@v4
with:
python-version: '3.x'
- name: Install Dependencies
run: |
pip install PyJWT cryptography requests
- name: Run Backup Script
env:
APP_ID: ${{ secrets.APP_ID }}
PRIVATE_KEY: ${{ secrets.PRIVATE_KEY }}
TARGET_REPO_OWNER: 'target-owner' # Replace with actual target repo owner
TARGET_REPO_NAME: 'target-repo' # Replace with actual target repo name
run: |
python backup_script.py
Environment Variables
APP_ID: GitHub App ID.
PRIVATE_KEY: The private key file (
.pem
), stored as a GitHub secret.TARGET_REPO_OWNER: The owner of the target repository.
TARGET_REPO_NAME: The target repository name.
Secure Secrets
Make sure to store sensitive information like APP_ID
and PRIVATE_KEY
in GitHub Actions Secrets:
Go to your repository’s Settings > Secrets and variables > Actions.
Add secrets such as
APP_ID
andPRIVATE_KEY
.
Step 4: Writing the Automation Script
Create a Python script called backup_
script.py
in the root of your repository. This script will handle branch creation, updates, and commits.
4.1 Import Necessary Libraries
import os
import jwt
import time
import requests
from cryptography.hazmat.primitives import serialization
4.2 Authenticate as a GitHub App and Installation
def get_jwt(app_id, private_key):
"""Generate a JWT for GitHub App authentication."""
payload = {
'iat': int(time.time()) - 60,
'exp': int(time.time()) + (10 * 60),
'iss': app_id
}
return jwt.encode(payload, private_key, algorithm='RS256')
def get_installation_access_token(jwt_token, installation_id):
"""Get an installation access token."""
url = f'https://api.github.com/app/installations/{installation_id}/access_tokens'
headers = {
'Authorization': f'Bearer {jwt_token}',
'Accept': 'application/vnd.github+json'
}
response = requests.post(url, headers=headers)
response.raise_for_status()
return response.json()['token']
4.3 Main Logic for Branch Creation and Commit
def main():
app_id = os.getenv('APP_ID')
private_key = os.getenv('PRIVATE_KEY')
owner = os.getenv('TARGET_REPO_OWNER')
repo = os.getenv('TARGET_REPO_NAME')
# Load private key
private_key = private_key.replace('\\n', '\n').encode()
private_key = serialization.load_pem_private_key(private_key, password=None)
# Generate JWT and get access token
jwt_token = get_jwt(app_id, private_key)
access_token = get_installation_access_token(jwt_token, installation_id)
4.4 Creating or Updating the Branch
branch_name = 'backup-branch' # Define the branch name
# Check if branch exists
branch_url = f'https://api.github.com/repos/{owner}/{repo}/git/ref/heads/{branch_name}'
branch_response = requests.get(branch_url, headers=headers)
if branch_response.status_code == 200:
sha_latest_commit = branch_response.json()['object']['sha']
print(f"Branch '{branch_name}' exists with SHA {sha_latest_commit}")
else:
main_branch_url = f'https://api.github.com/repos/{owner}/{repo}/git/ref/heads/main'
main_branch_response = requests.get(main_branch_url, headers=headers)
main_sha = main_branch_response.json()['object']['sha']
# Create new branch
create_branch_url = f'https://api.github.com/repos/{owner}/{repo}/git/refs'
data = {"ref": f"refs/heads/{branch_name}", "sha": main_sha}
create_branch_response = requests.post(create_branch_url, headers=headers, json=data)
create_branch_response.raise_for_status()
sha_latest_commit = main_sha
print(f"Branch '{branch_name}' created with SHA {sha_latest_commit}")
4.5 Committing Changes
# Prepare new tree for commit
content = "# Backup Repository\nThis is an automated backup."
blob_data = {"content": content, "encoding": "utf-8"}
blob_url = f'https://api.github.com/repos/{owner}/{repo}/git/blobs'
blob_response = requests.post(blob_url, headers=headers, json=blob_data)
blob_sha = blob_response.json()['sha']
# Commit the changes
tree_data = {"base_tree
": tree_sha, "tree": [{"path": "README.md", "mode": "100644", "type": "blob", "sha": blob_sha}]}
new_commit_sha = commit_and_update_branch(headers, tree_data, sha_latest_commit)
Step 5: Putting It All Together
With the workflow and script in place, any changes to the source repository will trigger the GitHub Actions workflow, authenticate with the GitHub App, create or update a branch in the target repository, and commit changes as needed.
Conclusion
Automation of branch creation and commits is an essential step in streamlining repository management across multiple projects. By integrating GitHub Apps and GitHub Actions, you can efficiently manage repositories, automate tasks, and improve development workflows.
We covered how to:
Set up a GitHub App with appropriate permissions.
Configure a GitHub Actions workflow for automation.
Write a Python script to manage branches and commits.
Feel free to extend this workflow to include more advanced operations like handling multiple files, dealing with merge conflicts, or adding additional checks for more complex scenarios.
Subscribe to my newsletter
Read articles from Swami Buddha Chaitanya directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by