forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
265 lines (238 loc) · 11.2 KB
/
repo-sync.yml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
# The docs.github.com project has two repositories: github/docs (public) and github/docs-internal (private)
#
# This GitHub Actions workflow keeps the `main` branch of those two repos in sync.
#
# For more details, see https://github.com/repo-sync/repo-sync#how-it-works
name: Repo Sync
# **What it does**:
# - close-invalid-repo-sync: Close repo sync pull requests not created by Octomerger or a Hubber.
# - repo-sync: Syncs docs and docs-internal.
# **Why we have it**:
# - close-invalid-repo-sync: Another form of spam prevention for the open-source repository.
# - repo-sync: To keep the open-source repository up-to-date, while still having an internal
# repository for sensitive work.
# **Who does it impact**: Open-source.
on:
workflow_dispatch:
schedule:
- cron: '20,50 * * * *' # Run every hour at 20 and 50 minutes after
permissions:
contents: write
pull-requests: write
jobs:
close-invalid-repo-sync:
name: Close invalid Repo Sync PRs
runs-on: ubuntu-latest
steps:
- name: Find pull request
if: ${{ github.repository == 'github/docs' }}
uses: juliangruber/find-pull-request-action@3a4c7c62101755c3778d397dcb6a760a558992f1
id: find-pull-request
with:
github-token: ${{ secrets.DOCS_BOT_SPAM_VISION }}
branch: repo-sync
base: main
state: open
- name: Close pull request if unwanted
if: ${{ github.repository == 'github/docs' && steps.find-pull-request.outputs.number }}
uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
with:
github-token: ${{ secrets.DOCS_BOT_SPAM_VISION }}
script: |
const { owner, repo } = context.repo
const { data: pr } = await github.rest.pulls.get({
owner,
repo,
pull_number: parseInt(${{ steps.find-pull-request.outputs.number }})
})
const prCreator = pr.user.login
// If the PR creator is the expected account, stop now
if (prCreator === 'Octomerger') {
return
}
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'employees',
username: prCreator
})
// If the PR creator is a GitHub employee, stop now
return
} catch (err) {
// An error will be thrown if the user is not a GitHub employee.
// That said, we still want to proceed anyway!
}
// Close the PR and add the invalid label
await github.rest.issues.update({
owner,
repo,
issue_number: pr.number,
labels: ['invalid'],
state: 'closed'
})
// Comment on the PR
await github.rest.issues.createComment({
owner,
repo,
issue_number: pr.number,
body: "Please leave this `repo-sync` branch to the robots!\n\nI'm going to close this pull request now, but feel free to open a new issue or ask any questions in [discussions](https://github.com/github/docs/discussions)!"
})
repo-sync:
needs: close-invalid-repo-sync
if: github.repository == 'github/docs-internal' || github.repository == 'github/docs'
name: Repo Sync
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8
# Set up npm and run npm ci to get custom husky githooks error
# messages if they exist. We could also remove these steps
# because currently we have no hooks with customer error messages.
# See pull #32064 where they were removed.
- name: Setup Node.js
uses: actions/setup-node@8c91899e586c5b171469028077307d293428b516
with:
node-version-file: 'package.json'
cache: npm
- name: Install dependencies
run: npm ci
- name: Sync repo to branch
uses: repo-sync/github-sync@3832fe8e2be32372e1b3970bbae8e7079edeec88
env:
GITHUB_TOKEN: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
with:
source_repo: ${{ secrets.SOURCE_REPO }} # https://${access_token}@github.com/github/the-other-repo.git
source_branch: main
destination_branch: repo-sync
github_token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
- name: Create pull request
uses: repo-sync/pull-request@65785d95a5a466e46a9d0708933a3bd51bbf9dde
env:
GITHUB_TOKEN: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
with:
source_branch: repo-sync
destination_branch: main
pr_title: 'repo sync'
pr_body: "This is an automated pull request to sync changes between the public and private repos.\n\n:robot: This pull request should be merged (not squashed) to preserve continuity across repos, so please let a bot do the merging!"
pr_label: automated-reposync-pr
github_token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
# This will exit 0 if there's no difference between `repo-sync`
# and `main`. And if so, no PR will be created.
pr_allow_empty: false
- name: Find pull request
uses: juliangruber/find-pull-request-action@3a4c7c62101755c3778d397dcb6a760a558992f1
id: find-pull-request
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
branch: repo-sync
base: main
author: Octomerger
state: open
# Because we get far too much spam ;_;
- name: Lock conversations
if: ${{ github.repository == 'github/docs' && steps.find-pull-request.outputs.number }}
uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
with:
script: |
try {
await github.rest.issues.lock({
...context.repo,
issue_number: parseInt(${{ steps.find-pull-request.outputs.number }}),
lock_reason: 'spam'
})
console.log('Locked the pull request to prevent spam!')
} catch (error) {
// Log the error but don't fail the workflow
console.error(`Failed to lock the pull request. Error: ${error}`)
}
# There are cases where the branch becomes out-of-date in between the time this workflow began and when the pull request is created/updated
- name: Update branch
if: ${{ steps.find-pull-request.outputs.number }}
uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
with:
github-token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
script: |
const mainHeadSha = await github.rest.git.getRef({
...context.repo,
ref: 'heads/main'
})
console.log(`heads/main sha: ${mainHeadSha.data.object.sha}`)
const pull = await github.rest.pulls.get({
...context.repo,
pull_number: parseInt(${{ steps.find-pull-request.outputs.number }})
})
console.log(`Pull request base sha: ${pull.data.base.sha}`)
if (mainHeadSha.data.object.sha !== pull.data.base.sha || pull.data.mergeable_state === 'behind') {
try {
const updateBranch = await github.rest.pulls.updateBranch({
...context.repo,
pull_number: parseInt(${{ steps.find-pull-request.outputs.number }})
})
console.log(updateBranch.data.message)
} catch (error) {
// When the head branch is modified an error with status 422 is thrown
// We should retry one more time to update the branch
if (error.status === 422) {
try {
const updateBranch = await github.rest.pulls.updateBranch({
...context.repo,
pull_number: parseInt(${{ steps.find-pull-request.outputs.number }})
})
console.log(updateBranch.data.message)
} catch (error) {
// Only retry once. We'll rely on the update branch workflow to update
// this PR in the case of a second failure.
console.log(`Retried updating the branch, but an error occurred: ${error}`)
}
} else {
// A failed branch update shouldn't fail this worklow.
console.log(`An error occurred when updating the branch: ${error}`)
}
}
} else {
console.log(`Branch is already up-to-date`)
}
- name: Check pull request file count after updating
if: ${{ steps.find-pull-request.outputs.number }}
uses: actions/github-script@98814c53be79b1d30f795b907e553d8679345975
id: pr-files
env:
PR_NUMBER: ${{ steps.find-pull-request.outputs.number }}
with:
github-token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
result-encoding: string
script: |
const { data: prFiles } = await github.rest.pulls.listFiles({
...context.repo,
pull_number: process.env.PR_NUMBER,
})
core.setOutput('count', (prFiles && prFiles.length || 0).toString())
# Sometimes after updating the branch, there aren't any remaining files changed.
# If not, we should close the PR instead of merging it and triggering deployments.
- name: Close the pull request if no files remain
if: ${{ steps.find-pull-request.outputs.number && steps.pr-files.outputs.count == '0' }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh pr close ${{ steps.find-pull-request.outputs.number }} --repo $GITHUB_REPOSITORY
- name: Approve pull request
if: ${{ steps.find-pull-request.outputs.number && steps.pr-files.outputs.count != '0' }}
uses: juliangruber/approve-pull-request-action@c67a4808d52e44ea03656f6646ba24a010304f03
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ steps.find-pull-request.outputs.number }}
- name: Admin merge the pull request
if: ${{ steps.find-pull-request.outputs.number && steps.pr-files.outputs.count != '0' }}
env:
GITHUB_TOKEN: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
PR_NUMBER: ${{ steps.find-pull-request.outputs.number }}
run: |
gh pr merge $PR_NUMBER --admin --merge
- name: Send Slack notification if workflow fails
uses: someimportantcompany/github-actions-slack-message@1d367080235edfa53df415bd8e0bbab480f29bad
if: failure()
with:
channel: ${{ secrets.DOCS_ALERTS_SLACK_CHANNEL_ID }}
bot-token: ${{ secrets.SLACK_DOCS_BOT_TOKEN }}
color: failure
text: The last repo-sync run for ${{github.repository}} failed. See https://github.com/${{github.repository}}/actions?query=workflow%3A%22Repo+Sync%22