Skip to content

Commit a970f28

Browse files
ijjkstyfleztanner
authored
Add code freeze GitHub actions for releasing (#56325)
Co-authored-by: Steven <[email protected]> Co-authored-by: Zack Tanner <[email protected]>
1 parent 5fbc23e commit a970f28

File tree

2 files changed

+161
-0
lines changed

2 files changed

+161
-0
lines changed

.github/workflows/code_freeze.yml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
on:
2+
workflow_dispatch:
3+
inputs:
4+
type:
5+
description: Enable/disable code freeze
6+
required: true
7+
type: choice
8+
options:
9+
- enable
10+
- disable
11+
12+
secrets:
13+
CODE_FREEZE_TOKEN:
14+
required: true
15+
16+
name: Code Freeze
17+
18+
env:
19+
NAPI_CLI_VERSION: 2.14.7
20+
TURBO_VERSION: 1.10.9
21+
NODE_MAINTENANCE_VERSION: 16
22+
NODE_LTS_VERSION: 18
23+
24+
jobs:
25+
start:
26+
runs-on: ubuntu-latest
27+
28+
environment: release-${{ github.event.inputs.releaseType }}
29+
steps:
30+
- name: Setup node
31+
uses: actions/setup-node@v3
32+
with:
33+
node-version: 18
34+
check-latest: true
35+
36+
- run: git clone https://github.com/vercel/next.js.git --depth=1 .
37+
38+
# https://github.com/actions/virtual-environments/issues/1187
39+
- name: tune linux network
40+
run: sudo ethtool -K eth0 tx off rx off
41+
42+
- run: node ./scripts/code-freeze.js --type ${{ github.event.inputs.type }}
43+
env:
44+
CODE_FREEZE_TOKEN: ${{ secrets.CODE_FREEZE_TOKEN }}

scripts/code-freeze.js

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
const authToken = process.env.CODE_FREEZE_TOKEN
2+
3+
if (!authToken) {
4+
throw new Error(`missing CODE_FREEZE_TOKEN env`)
5+
}
6+
7+
const codeFreezeRule = {
8+
context: 'Potentially publish release',
9+
app_id: 15368,
10+
}
11+
12+
async function updateRules(newRules) {
13+
const res = await fetch(
14+
`https://api.github.com/repos/vercel/next.js/branches/canary/protection`,
15+
{
16+
method: 'PUT',
17+
headers: {
18+
Accept: 'application/vnd.github+json',
19+
Authorization: `Bearer ${authToken}`,
20+
'X-GitHub-Api-Version': '2022-11-28',
21+
},
22+
body: JSON.stringify(newRules),
23+
}
24+
)
25+
26+
if (!res.ok) {
27+
throw new Error(
28+
`Failed to check for rule ${res.status} ${await res.text()}`
29+
)
30+
}
31+
}
32+
33+
async function getCurrentRules() {
34+
const res = await fetch(
35+
`https://api.github.com/repos/vercel/next.js/branches/canary/protection`,
36+
{
37+
headers: {
38+
Accept: 'application/vnd.github+json',
39+
Authorization: `Bearer ${authToken}`,
40+
'X-GitHub-Api-Version': '2022-11-28',
41+
},
42+
}
43+
)
44+
45+
if (!res.ok) {
46+
throw new Error(
47+
`Failed to check for rule ${res.status} ${await res.text()}`
48+
)
49+
}
50+
const data = await res.json()
51+
52+
return {
53+
required_status_checks: {
54+
strict: data.required_status_checks.strict,
55+
// checks: data.required_status_checks.checks,
56+
contexts: data.required_status_checks.contexts,
57+
},
58+
enforce_admins: data.enforce_admins.enabled,
59+
required_pull_request_reviews: {
60+
dismiss_stale_reviews:
61+
data.required_pull_request_reviews.dismiss_stale_reviews,
62+
require_code_owner_reviews:
63+
data.required_pull_request_reviews.require_code_owner_reviews,
64+
require_last_push_approval:
65+
data.required_pull_request_reviews.require_last_push_approval,
66+
required_approving_review_count:
67+
data.required_pull_request_reviews.required_approving_review_count,
68+
},
69+
restrictions: data.restrictions || {
70+
users: [],
71+
teams: [],
72+
apps: [],
73+
},
74+
}
75+
}
76+
77+
async function main() {
78+
const typeIdx = process.argv.indexOf('--type')
79+
const type = process.argv[typeIdx + 1]
80+
81+
if (type !== 'enable' && type !== 'disable') {
82+
throw new Error(`--type should be enable or disable`)
83+
}
84+
const isEnable = type === 'enable'
85+
const currentRules = await getCurrentRules()
86+
const hasRule = currentRules.required_status_checks.contexts?.some((ctx) => {
87+
return ctx === codeFreezeRule.context
88+
})
89+
90+
console.log(currentRules)
91+
92+
if (isEnable) {
93+
if (hasRule) {
94+
console.log(`Already enabled`)
95+
return
96+
}
97+
currentRules.required_status_checks.contexts.push(codeFreezeRule.context)
98+
await updateRules(currentRules)
99+
console.log('Enabled code freeze')
100+
} else {
101+
if (!hasRule) {
102+
console.log(`Already disabled`)
103+
return
104+
}
105+
currentRules.required_status_checks.contexts =
106+
currentRules.required_status_checks.contexts.filter(
107+
(ctx) => ctx !== codeFreezeRule.context
108+
)
109+
await updateRules(currentRules)
110+
console.log('Disabled code freeze')
111+
}
112+
}
113+
114+
main().catch((err) => {
115+
console.error(err)
116+
process.exit(1)
117+
})

0 commit comments

Comments
 (0)