push-repo-sync #811
This file contains hidden or 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
| name: Repo Sync | |
| # HashiCorp Docs has two repositories: hashicorp/web-unified-docs (public) and hashicorp/web-unified-docs-internal (private). | |
| # This GitHub Actions workflow keeps the `main` branch of those two repos in sync. | |
| on: | |
| workflow_dispatch: | |
| repository_dispatch: | |
| types: [push-repo-sync] | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| concurrency: | |
| group: repo-sync-${{ github.repository }} | |
| # we don't want to cancel an in progress run | |
| # as it could leave a repo in an inconsistent state | |
| cancel-in-progress: false | |
| jobs: | |
| repo-sync: | |
| if: github.repository == 'hashicorp/web-unified-docs-internal' || github.repository == 'hashicorp/web-unified-docs' | |
| name: Repo Sync | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Report the commit that triggered the sync | |
| if: github.event_name == 'repository_dispatch' | |
| run: | | |
| echo "## Repo Sync Triggered" >> $GITHUB_STEP_SUMMARY | |
| echo "Syncing from repository: **${{ github.event.client_payload.repository }}**" >> $GITHUB_STEP_SUMMARY | |
| echo "Source commit: [\`${{ github.event.client_payload.commit }}\`](https://github.com/${{ github.event.client_payload.repository }}/commit/${{ github.event.client_payload.commit }})" >> $GITHUB_STEP_SUMMARY | |
| - name: Check out repo | |
| uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 2024-10-28 | |
| - name: Sync repo to branch | |
| uses: repo-sync/github-sync@3832fe8e2be32372e1b3970bbae8e7079edeec88 # v2.3.0 2023-07-13 | |
| with: | |
| source_repo: https://${{ secrets.CI_GITHUB_TOKEN }}@github.com/hashicorp/${{ github.repository == 'hashicorp/web-unified-docs-internal' && 'web-unified-docs' || 'web-unified-docs-internal' }}.git | |
| source_branch: main | |
| destination_branch: repo-sync | |
| github_token: ${{ secrets.CI_GITHUB_TOKEN }} | |
| - name: Ship pull request | |
| uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 2023-11-20 | |
| with: | |
| github-token: ${{ secrets.CI_GITHUB_TOKEN }} | |
| result-encoding: string | |
| script: | | |
| const { owner, repo } = context.repo | |
| const head = 'hashicorp: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.compareCommitsWithBasehead({ | |
| owner, | |
| repo, | |
| basehead: `${base}...${head}`, | |
| }) | |
| 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 unified docs repos. | |
| 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('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) | |
| await closePullRequest(pull_number) | |
| 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') |