Skip to content

Repository Backup

Repository Backup #11

Workflow file for this run

name: Repository Backup
on:
schedule:
# Run weekly on Sunday at 2 AM UTC
- cron: '0 2 * * 0'
workflow_dispatch:
inputs:
organization:
description: 'GitHub organization to backup'
required: false
default: 'quantecon'
force:
description: 'Force backup even if already exists today'
required: false
default: false
type: boolean
jobs:
backup:
runs-on: ubuntu-latest
permissions:
id-token: write # Required for OIDC authentication
contents: read
issues: write # Required for creating/updating issues
steps:
- name: Checkout repository
uses: actions/checkout@v4
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
cache: 'pip'
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -r requirements.txt
# Recommended: Use OIDC authentication (no long-lived credentials)
# Requires AWS IAM Identity Provider and Role configured for GitHub Actions
# See README.md for setup instructions
- name: Configure AWS credentials (OIDC)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ${{ vars.AWS_REGION || 'us-east-1' }}
- name: Run backup
env:
GITHUB_TOKEN: ${{ secrets.REPO_BACKUP_TOKEN || secrets.GITHUB_TOKEN }}
run: |
if [ "${{ github.event.inputs.force }}" = "true" ]; then
python -m src.main --config config.yml --task backup --force
else
python -m src.main --config config.yml --task backup
fi
- name: Generate backup report
id: report
if: always()
env:
GITHUB_TOKEN: ${{ secrets.REPO_BACKUP_TOKEN || secrets.GITHUB_TOKEN }}
run: |
python -m src.main --config config.yml --task report 2>&1 | tee /tmp/report.txt
echo "report<<EOF" >> $GITHUB_OUTPUT
cat /tmp/report.txt >> $GITHUB_OUTPUT
echo "EOF" >> $GITHUB_OUTPUT
- name: Create or update backup report issue
if: always()
uses: actions/github-script@v7
with:
script: |
const runUrl = `${process.env.GITHUB_SERVER_URL}/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`;
const date = new Date().toISOString().split('T')[0];
const jobStatus = '${{ job.status }}';
const isFailure = jobStatus === 'failure';
// Build issue body
let body = `## Backup Run: ${date}\n\n`;
body += `**Status:** ${jobStatus === 'success' ? '✅ Success' : '❌ Failed'}\n`;
body += `**Workflow Run:** [View Details](${runUrl})\n\n`;
body += `### Report Output\n\n`;
body += '```\n';
body += `${{ steps.report.outputs.report }}`;
body += '\n```\n\n';
if (isFailure) {
body += `\n---\n⚠️ **Attention Required** @mmcky\n`;
}
body += `\n---\n*Last updated: ${new Date().toISOString()}*`;
// Find existing issue with title "Weekly Backup Report"
const issues = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'open',
labels: 'backup-report'
});
const existingIssue = issues.data.find(i => i.title === 'Weekly Backup Report');
if (existingIssue) {
// Update existing issue
await github.rest.issues.update({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
body: body
});
// Add comment for this run
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: existingIssue.number,
body: `### Run ${date} - ${jobStatus === 'success' ? '✅ Success' : '❌ Failed'}\n\n[View workflow run](${runUrl})${isFailure ? '\n\n@mmcky - backup failed, please investigate.' : ''}`
});
console.log(`Updated issue #${existingIssue.number}`);
} else {
// Create new issue
const newIssue = await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: 'Weekly Backup Report',
body: body,
labels: ['backup-report']
});
console.log(`Created issue #${newIssue.data.number}`);
}