.github/workflows/repo-sync.yml #6452
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Note this is almost fully copied from | |
# https://github.com/github/docs/blob/main/.github/workflows/repo-sync.yml | |
# with the exception of: | |
# - the `cron` schedule | |
# - the `if` condition to allow this to run only in `dev-portal-internal` | |
# - the `source_repo` has been updated to `dev-portal` | |
# - the PAT credentials are from our `hashibot-web` account. They're managed in | |
# the `dev-portal-internal` repository secrets. | |
on: | |
workflow_dispatch: | |
schedule: | |
- cron: '0 */2 * * *' # https://crontab.guru/every-2-hours | |
permissions: | |
contents: write | |
pull-requests: write | |
jobs: | |
repo-sync: | |
if: github.repository == 'hashicorp/dev-portal-internal' | |
name: Repo Sync | |
runs-on: ubuntu-latest | |
steps: | |
- name: Check out repo | |
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 | |
- name: Sync repo to branch | |
uses: repo-sync/github-sync@3832fe8e2be32372e1b3970bbae8e7079edeec88 | |
with: | |
source_repo: https://${{ secrets.PAT_HASHIBOT_WEB_DEV_PORTAL_INTERNAL_SYNC }}@github.com/hashicorp/dev-portal.git | |
source_branch: main | |
destination_branch: repo-sync | |
github_token: ${{ secrets.PAT_HASHIBOT_WEB_DEV_PORTAL_INTERNAL_SYNC }} | |
- name: Ship pull request | |
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea | |
with: | |
github-token: ${{ secrets.PAT_HASHIBOT_WEB_DEV_PORTAL_INTERNAL_SYNC }} | |
result-encoding: string | |
script: | | |
const { owner, repo } = context.repo | |
const head = 'repo-sync' | |
const base = 'main' | |
async function closePullRequest(prNumber) { | |
console.log('Closing pull request', prNumber) | |
await github.rest.pulls.update({ | |
owner, | |
repo, | |
pull_number: prNumber, | |
state: 'closed' | |
}) | |
// Error loud here, so no try/catch | |
console.log('Closed pull request', prNumber) | |
} | |
console.log('Closing any existing pull requests') | |
const { data: existingPulls } = await github.rest.pulls.list({ owner, repo, head, base }) | |
if (existingPulls.length) { | |
console.log('Found existing pull requests', existingPulls.map(pull => pull.number)) | |
for (const pull of existingPulls) { | |
await closePullRequest(pull.number) | |
} | |
console.log('Closed existing pull requests') | |
} | |
try { | |
const { data } = await github.rest.repos.compareCommits({ | |
owner, | |
repo, | |
head, | |
base, | |
}) | |
const { files } = data | |
console.log(`File changes between ${head} and ${base}:`, files) | |
if (!files.length) { | |
console.log('No files changed, bailing') | |
return | |
} | |
} catch (err) { | |
console.error(`Unable to compute the files difference between ${head} and ${base}`, err.message) | |
} | |
console.log('Creating a new pull request') | |
const body = ` | |
This is an automated pull request to sync changes between the public and private repos. | |
Our bot will merge this pull request automatically. | |
To preserve continuity across repos, _do not squash_ this pull request. | |
` | |
let pull, pull_number | |
try { | |
const response = await github.rest.pulls.create({ | |
owner, | |
repo, | |
head, | |
base, | |
title: 'Repo sync', | |
body, | |
}) | |
pull = response.data | |
pull_number = pull.number | |
console.log('Created pull request successfully', pull.html_url) | |
} catch (err) { | |
// Don't error/alert if there's no commits to sync | |
// Don't throw if > 100 pulls with same head_sha issue | |
if (err.message?.includes('No commits') || err.message?.includes('same head_sha')) { | |
console.log(err.message) | |
return | |
} | |
throw err | |
} | |
console.log('Locking conversations to prevent spam') | |
try { | |
await github.rest.issues.lock({ | |
...context.repo, | |
issue_number: pull_number, | |
lock_reason: 'spam' | |
}) | |
console.log('Locked the pull request to prevent spam') | |
} catch (error) { | |
console.error('Failed to lock the pull request.', error) | |
// Don't fail the workflow | |
} | |
console.log('Counting files changed') | |
const { data: prFiles } = await github.rest.pulls.listFiles({ owner, repo, pull_number }) | |
if (prFiles.length) { | |
console.log(prFiles.length, 'files have changed') | |
} else { | |
console.log('No files changed, closing') | |
await closePullRequest(pull_number) | |
return | |
} | |
console.log('Checking for merge conflicts') | |
if (pull.mergeable_state === 'dirty') { | |
console.log('Pull request has a conflict', pull.html_url) | |
throw new Error('Pull request has a conflict, please resolve manually') | |
} | |
console.log('No detected merge conflicts') | |
console.log('Merging the pull request') | |
// Admin merge pull request to avoid squash | |
await github.rest.pulls.merge({ | |
owner, | |
repo, | |
pull_number, | |
merge_method: 'merge', | |
}) | |
// Error loud here, so no try/catch | |
console.log('Merged the pull request successfully') |