Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 3cc99a6

Browse files
repo sync between public and internal repos for web-unifed-docs GHA (#236)
1 parent 5aa2eb7 commit 3cc99a6

File tree

1 file changed

+153
-0
lines changed

1 file changed

+153
-0
lines changed

.github/workflows/repo-sync.yml

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
name: Repo Sync
2+
3+
# **What it does**: HashiCorp Docs has two repositories: hashicorp/web-unified-docs (public) and hashicorp/web-unified-docs-internal (private).
4+
# This GitHub Actions workflow keeps the `main` branch of those two repos in sync.
5+
# **Why we have it**: To keep the open-source repository up-to-date
6+
# while still having an internal repository for sensitive work.
7+
# **Who does it impact**: Open-source.
8+
9+
on:
10+
workflow_dispatch:
11+
schedule:
12+
- cron: '0 */2 * * *' # Runs every 2 hours
13+
14+
permissions:
15+
contents: write
16+
pull-requests: write
17+
18+
jobs:
19+
repo-sync:
20+
if: github.repository == 'hashicorp/web-unified-docs-internal' || github.repository == 'hashicorp/web-unified-docs'
21+
name: Repo Sync
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: Check out repo
25+
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 2024-10-28
26+
27+
- name: Sync repo to branch
28+
uses: repo-sync/github-sync@3832fe8e2be32372e1b3970bbae8e7079edeec88 # v2.3.0 2023-07-13
29+
with:
30+
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
31+
source_branch: main
32+
destination_branch: repo-sync
33+
github_token: ${{ secrets.CI_GITHUB_TOKEN }}
34+
35+
- name: Ship pull request
36+
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7.0.1 2023-11-20
37+
with:
38+
github-token: ${{ secrets.CI_GITHUB_TOKEN }}
39+
result-encoding: string
40+
script: |
41+
const { owner, repo } = context.repo
42+
const head = 'github:repo-sync'
43+
const base = 'main'
44+
45+
async function closePullRequest(prNumber) {
46+
console.log('Closing pull request', prNumber)
47+
await github.rest.pulls.update({
48+
owner,
49+
repo,
50+
pull_number: prNumber,
51+
state: 'closed'
52+
})
53+
// Error loud here, so no try/catch
54+
console.log('Closed pull request', prNumber)
55+
}
56+
57+
console.log('Closing any existing pull requests')
58+
const { data: existingPulls } = await github.rest.pulls.list({ owner, repo, head, base })
59+
if (existingPulls.length) {
60+
console.log('Found existing pull requests', existingPulls.map(pull => pull.number))
61+
for (const pull of existingPulls) {
62+
await closePullRequest(pull.number)
63+
}
64+
console.log('Closed existing pull requests')
65+
}
66+
67+
try {
68+
const { data } = await github.rest.repos.compareCommits({
69+
owner,
70+
repo,
71+
head,
72+
base,
73+
})
74+
const { files } = data
75+
console.log(`File changes between ${head} and ${base}:`, files)
76+
if (!files.length) {
77+
console.log('No files changed, bailing')
78+
return
79+
}
80+
} catch (err) {
81+
console.error(`Unable to compute the files difference between ${head} and ${base}`, err.message)
82+
}
83+
84+
console.log('Creating a new pull request')
85+
const body = `
86+
This is an automated pull request to sync changes between the public and private unified docs repos.
87+
88+
To preserve continuity across repos, _do not squash_ this pull request.
89+
`
90+
let pull, pull_number
91+
try {
92+
const response = await github.rest.pulls.create({
93+
owner,
94+
repo,
95+
head,
96+
base,
97+
title: 'Repo sync',
98+
body,
99+
})
100+
pull = response.data
101+
pull_number = pull.number
102+
console.log('Created pull request successfully', pull.html_url)
103+
} catch (err) {
104+
// Don't error/alert if there's no commits to sync
105+
// Don't throw if > 100 pulls with same head_sha issue
106+
if (err.message?.includes('No commits') || err.message?.includes('same head_sha')) {
107+
console.log(err.message)
108+
return
109+
}
110+
throw err
111+
}
112+
113+
console.log('Locking conversations to prevent spam')
114+
try {
115+
await github.rest.issues.lock({
116+
...context.repo,
117+
issue_number: pull_number,
118+
lock_reason: 'spam'
119+
})
120+
console.log('Locked the pull request to prevent spam')
121+
} catch (error) {
122+
console.error('Failed to lock the pull request.', error)
123+
// Don't fail the workflow
124+
}
125+
126+
console.log('Counting files changed')
127+
const { data: prFiles } = await github.rest.pulls.listFiles({ owner, repo, pull_number })
128+
if (prFiles.length) {
129+
console.log(prFiles.length, 'files have changed')
130+
} else {
131+
console.log('No files changed, closing')
132+
await closePullRequest(pull_number)
133+
return
134+
}
135+
136+
console.log('Checking for merge conflicts')
137+
if (pull.mergeable_state === 'dirty') {
138+
console.log('Pull request has a conflict', pull.html_url)
139+
await closePullRequest(pull_number)
140+
throw new Error('Pull request has a conflict, please resolve manually')
141+
}
142+
console.log('No detected merge conflicts')
143+
144+
console.log('Merging the pull request')
145+
// Admin merge pull request to avoid squash
146+
await github.rest.pulls.merge({
147+
owner,
148+
repo,
149+
pull_number,
150+
merge_method: 'merge',
151+
})
152+
// Error loud here, so no try/catch
153+
console.log('Merged the pull request successfully')

0 commit comments

Comments
 (0)