forked from github/docs
-
Notifications
You must be signed in to change notification settings - Fork 0
261 lines (234 loc) · 10.9 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
# 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: '10,40 * * * *' # every 30 minutes
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@db875662766249c049b2dcd85293892d61cb0b51
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@2b34a689ec86a68d8ab9478298f91d5401337b7d
with:
github-token: ${{ secrets.DOCS_BOT_SPAM_VISION }}
script: |
const { owner, repo } = context.repo
const { data: pr } = await github.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.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.issues.update({
owner,
repo,
issue_number: pr.number,
labels: ['invalid'],
state: 'closed'
})
// Comment on the PR
await github.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@ec3a7ce113134d7a93b817d10a8272cb61118579
# Set up npm and run npm ci to run husky to get githooks for LFS
- name: Setup node
uses: actions/setup-node@1f8c6b94b26d0feae1e387ca63ccbdc44d27b561
with:
node-version: 16.13.x
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@65194d8015be7624d231796ddee1cd52a5023cb3
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@db875662766249c049b2dcd85293892d61cb0b51
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@2b34a689ec86a68d8ab9478298f91d5401337b7d
with:
script: |
try {
await github.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@2b34a689ec86a68d8ab9478298f91d5401337b7d
with:
github-token: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
script: |
const mainHeadSha = await github.git.getRef({
...context.repo,
ref: 'heads/main'
})
console.log(`heads/main sha: ${mainHeadSha.data.object.sha}`)
const pull = await github.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.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.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@2b34a689ec86a68d8ab9478298f91d5401337b7d
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.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@c530832d4d346c597332e20e03605aa94fa150a8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
number: ${{ steps.find-pull-request.outputs.number }}
- name: Enable GitHub auto-merge
if: ${{ steps.find-pull-request.outputs.number && steps.pr-files.outputs.count != '0' }}
env:
GITHUB_TOKEN: ${{ secrets.OCTOMERGER_PAT_WITH_REPO_AND_WORKFLOW_SCOPE }}
AUTOMERGE_PR_NUMBER: ${{ steps.find-pull-request.outputs.number }}
run: node .github/actions-scripts/enable-automerge.js
- name: Send Slack notification if workflow fails
uses: someimportantcompany/github-actions-slack-message@f8d28715e7b8a4717047d23f48c39827cacad340
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