Skip to content

Commit da29109

Browse files
authored
Apply publish step optimizations (#43620)
Follow-up to #32337 this removes the un-necessary step where we fetch all of the tags which requires pulling a lot of un-necessary git history inflating cache size and publish times. The only reason these tags were needing to be fetched is due to an issue in how the `actions/checkout` step works (actions/checkout#882). This reduces the publish times by at least 4 minutes by removing the tags fetching step https://github.com/vercel/next.js/actions/runs/3598569786/jobs/6061449995#step:16:14 As a further optimization this adds concurrency to the `npm publish` calls themselves to hopefully reduce time spent there as well.
1 parent 2063ff3 commit da29109

File tree

5 files changed

+150
-127
lines changed

5 files changed

+150
-127
lines changed

.github/workflows/build_test_deploy.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,11 +84,10 @@ jobs:
8484
- run: pnpm install
8585
- run: pnpm run build
8686
- run: node run-tests.js --timings --write-timings -g 1/1
87-
- run: node ./scripts/fetch-tags.mjs ${{ github.sha }}
8887

8988
- id: check-release
9089
run: |
91-
if [[ $(git describe --exact-match 2> /dev/null || :) = v* ]];
90+
if [[ $(node ./scripts/check-is-release.js 2> /dev/null || :) = v* ]];
9291
then
9392
echo "::set-output name=IS_RELEASE::true"
9493
else
@@ -893,7 +892,7 @@ jobs:
893892

894893
- run: npm i -g pnpm@${PNPM_VERSION}
895894
- run: echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
896-
- run: ./scripts/publish-native.js $GITHUB_REF
895+
- run: ./scripts/publish-native.js
897896
- run: ./scripts/publish-release.js
898897

899898
testDeployE2E:
Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { execSync } from 'child_process'
2-
import execa from 'execa'
3-
;(async () => {
1+
const { execSync } = require('child_process')
2+
3+
const checkIsRelease = async () => {
44
let commitId = process.argv[2] || ''
55

66
// parse only the last string which should be version if
@@ -14,21 +14,13 @@ import execa from 'execa'
1414
const versionString = commitMsg.split(' ').pop().trim()
1515
const publishMsgRegex = /^v\d{1,}\.\d{1,}\.\d{1,}(-\w{1,}\.\d{1,})?$/
1616

17-
console.log({ commitId, commitMsg, versionString })
18-
1917
if (publishMsgRegex.test(versionString)) {
20-
console.log('publish commit, fetching tags')
21-
22-
const result = await execa(
23-
'git',
24-
['fetch', '--depth=1', 'origin', '+refs/tags/*:refs/tags/*'],
25-
{
26-
stdio: ['ignore', 'inherit', 'inherit'],
27-
}
28-
)
29-
30-
process.exit(result.exitCode)
18+
console.log(versionString)
19+
process.exit(0)
3120
} else {
32-
console.log('not publish commit')
21+
console.log('not publish commit', { commitId, commitMsg, versionString })
22+
process.exit(1)
3323
}
34-
})()
24+
}
25+
26+
checkIsRelease()

scripts/publish-native.js

Lines changed: 101 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -1,112 +1,132 @@
11
#!/usr/bin/env node
22

33
const path = require('path')
4-
const { readFile, readdir, writeFile } = require('fs/promises')
4+
const execa = require('execa')
55
const { copy } = require('fs-extra')
6-
const { execSync } = require('child_process')
6+
const { Sema } = require('async-sema')
7+
const { readFile, readdir, writeFile } = require('fs/promises')
78

89
const cwd = process.cwd()
910

1011
;(async function () {
1112
try {
13+
const publishSema = new Sema(2)
14+
1215
let version = JSON.parse(
1316
await readFile(path.join(cwd, 'lerna.json'))
1417
).version
15-
let gitref = process.argv.slice(2)[0]
1618

1719
// Copy binaries to package folders, update version, and publish
1820
let nativePackagesDir = path.join(cwd, 'packages/next-swc/crates/napi/npm')
1921
let platforms = (await readdir(nativePackagesDir)).filter(
2022
(name) => !name.startsWith('.')
2123
)
2224

23-
for (let platform of platforms) {
24-
try {
25-
let binaryName = `next-swc.${platform}.node`
26-
await copy(
27-
path.join(cwd, 'packages/next-swc/native', binaryName),
28-
path.join(nativePackagesDir, platform, binaryName)
29-
)
30-
let pkg = JSON.parse(
31-
await readFile(path.join(nativePackagesDir, platform, 'package.json'))
32-
)
33-
pkg.version = version
34-
await writeFile(
35-
path.join(nativePackagesDir, platform, 'package.json'),
36-
JSON.stringify(pkg, null, 2)
37-
)
38-
execSync(
39-
`npm publish ${path.join(
40-
nativePackagesDir,
41-
platform
42-
)} --access public ${
43-
gitref.includes('canary') ? ' --tag canary' : ''
44-
}`
45-
)
46-
} catch (err) {
47-
// don't block publishing other versions on single platform error
48-
console.error(`Failed to publish`, platform)
25+
await Promise.all(
26+
platforms.map(async (platform) => {
27+
await publishSema.acquire()
4928

50-
if (
51-
err.message &&
52-
err.message.includes(
53-
'You cannot publish over the previously published versions'
29+
try {
30+
let binaryName = `next-swc.${platform}.node`
31+
await copy(
32+
path.join(cwd, 'packages/next-swc/native', binaryName),
33+
path.join(nativePackagesDir, platform, binaryName)
34+
)
35+
let pkg = JSON.parse(
36+
await readFile(
37+
path.join(nativePackagesDir, platform, 'package.json')
38+
)
39+
)
40+
pkg.version = version
41+
await writeFile(
42+
path.join(nativePackagesDir, platform, 'package.json'),
43+
JSON.stringify(pkg, null, 2)
5444
)
55-
) {
56-
console.error('Ignoring already published error', platform)
57-
} else {
58-
// throw err
45+
await execa(
46+
`npm publish ${path.join(
47+
nativePackagesDir,
48+
platform
49+
)} --access public ${
50+
version.includes('canary') ? ' --tag canary' : ''
51+
}`,
52+
{ stdio: 'inherit' }
53+
)
54+
} catch (err) {
55+
// don't block publishing other versions on single platform error
56+
console.error(`Failed to publish`, platform)
57+
58+
if (
59+
err.message &&
60+
err.message.includes(
61+
'You cannot publish over the previously published versions'
62+
)
63+
) {
64+
console.error('Ignoring already published error', platform)
65+
} else {
66+
// throw err
67+
}
68+
} finally {
69+
publishSema.release()
5970
}
60-
}
61-
// lerna publish in next step sill fail if git status is not clean
62-
execSync(
63-
`git update-index --skip-worktree ${path.join(
64-
nativePackagesDir,
65-
platform,
66-
'package.json'
67-
)}`
68-
)
69-
}
71+
// lerna publish in next step sill fail if git status is not clean
72+
await execa(
73+
`git update-index --skip-worktree ${path.join(
74+
nativePackagesDir,
75+
platform,
76+
'package.json'
77+
)}`,
78+
{ stdio: 'inherit' }
79+
)
80+
})
81+
)
7082

7183
// Update name/version of wasm packages and publish
7284
let wasmDir = path.join(cwd, 'packages/next-swc/crates/wasm')
73-
for (let wasmTarget of ['web', 'nodejs']) {
74-
let wasmPkg = JSON.parse(
75-
await readFile(path.join(wasmDir, `pkg-${wasmTarget}/package.json`))
76-
)
77-
wasmPkg.name = `@next/swc-wasm-${wasmTarget}`
78-
wasmPkg.version = version
7985

80-
await writeFile(
81-
path.join(wasmDir, `pkg-${wasmTarget}/package.json`),
82-
JSON.stringify(wasmPkg, null, 2)
83-
)
86+
await Promise.all(
87+
['web', 'nodejs'].map(async (wasmTarget) => {
88+
await publishSema.acquire()
8489

85-
try {
86-
execSync(
87-
`npm publish ${path.join(
88-
wasmDir,
89-
`pkg-${wasmTarget}`
90-
)} --access public ${
91-
gitref.includes('canary') ? ' --tag canary' : ''
92-
}`
90+
let wasmPkg = JSON.parse(
91+
await readFile(path.join(wasmDir, `pkg-${wasmTarget}/package.json`))
9392
)
94-
} catch (err) {
95-
// don't block publishing other versions on single platform error
96-
console.error(`Failed to publish`, wasmTarget)
93+
wasmPkg.name = `@next/swc-wasm-${wasmTarget}`
94+
wasmPkg.version = version
9795

98-
if (
99-
err.message &&
100-
err.message.includes(
101-
'You cannot publish over the previously published versions'
96+
await writeFile(
97+
path.join(wasmDir, `pkg-${wasmTarget}/package.json`),
98+
JSON.stringify(wasmPkg, null, 2)
99+
)
100+
101+
try {
102+
await execa(
103+
`npm publish ${path.join(
104+
wasmDir,
105+
`pkg-${wasmTarget}`
106+
)} --access public ${
107+
version.includes('canary') ? ' --tag canary' : ''
108+
}`,
109+
{ stdio: 'inherit' }
102110
)
103-
) {
104-
console.error('Ignoring already published error', wasmTarget)
105-
} else {
106-
// throw err
111+
} catch (err) {
112+
// don't block publishing other versions on single platform error
113+
console.error(`Failed to publish`, wasmTarget)
114+
115+
if (
116+
err.message &&
117+
err.message.includes(
118+
'You cannot publish over the previously published versions'
119+
)
120+
) {
121+
console.error('Ignoring already published error', wasmTarget)
122+
} else {
123+
// throw err
124+
}
125+
} finally {
126+
publishSema.release()
107127
}
108-
}
109-
}
128+
})
129+
)
110130

111131
// Update optional dependencies versions
112132
let nextPkg = JSON.parse(
@@ -122,7 +142,9 @@ const cwd = process.cwd()
122142
JSON.stringify(nextPkg, null, 2)
123143
)
124144
// lerna publish in next step will fail if git status is not clean
125-
execSync('git update-index --skip-worktree packages/next/package.json')
145+
await execa('git update-index --skip-worktree packages/next/package.json', {
146+
stdio: 'inherit',
147+
})
126148
} catch (err) {
127149
console.error(err)
128150
process.exit(1)

scripts/publish-release.js

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,20 @@
22
// @ts-check
33

44
const path = require('path')
5-
const { readdir } = require('fs/promises')
5+
const execa = require('execa')
6+
const { Sema } = require('async-sema')
67
const { execSync } = require('child_process')
7-
const { readJson } = require('fs-extra')
8+
const { readJson, readdir } = require('fs-extra')
89

910
const cwd = process.cwd()
1011

1112
;(async function () {
1213
let isCanary = true
1314

14-
if (!process.env.NPM_TOKEN) {
15-
console.log('No NPM_TOKEN, exiting...')
16-
return
17-
}
18-
1915
try {
20-
const tagOutput = execSync('git describe --exact-match').toString()
16+
const tagOutput = execSync(
17+
`node ${path.join(__dirname, 'check-is-release.js')}`
18+
).toString()
2119
console.log(tagOutput)
2220

2321
if (tagOutput.trim().startsWith('v')) {
@@ -34,15 +32,23 @@ const cwd = process.cwd()
3432
}
3533
console.log(`Publishing ${isCanary ? 'canary' : 'stable'}`)
3634

35+
if (!process.env.NPM_TOKEN) {
36+
console.log('No NPM_TOKEN, exiting...')
37+
return
38+
}
39+
3740
const packagesDir = path.join(cwd, 'packages')
3841
const packageDirs = await readdir(packagesDir)
42+
const publishSema = new Sema(2)
3943

4044
const publish = async (pkg, retry = 0) => {
4145
try {
42-
execSync(
46+
await publishSema.acquire()
47+
await execa(
4348
`npm publish ${path.join(packagesDir, pkg)} --access public${
4449
isCanary ? ' --tag canary' : ''
45-
}`
50+
}`,
51+
{ stdio: 'inherit' }
4652
)
4753
} catch (err) {
4854
console.error(`Failed to publish ${pkg}`, err)
@@ -66,18 +72,22 @@ const cwd = process.cwd()
6672
await publish(pkg, retry + 1)
6773
}
6874
throw err
75+
} finally {
76+
publishSema.release()
6977
}
7078
}
7179

72-
for (const packageDir of packageDirs) {
73-
const pkgJson = await readJson(
74-
path.join(packagesDir, packageDir, 'package.json')
75-
)
80+
await Promise.all(
81+
packageDirs.map(async (packageDir) => {
82+
const pkgJson = await readJson(
83+
path.join(packagesDir, packageDir, 'package.json')
84+
)
7685

77-
if (pkgJson.private) {
78-
console.log(`Skipping private package ${packageDir}`)
79-
continue
80-
}
81-
await publish(packageDir)
82-
}
86+
if (pkgJson.private) {
87+
console.log(`Skipping private package ${packageDir}`)
88+
return
89+
}
90+
await publish(packageDir)
91+
})
92+
)
8393
})()

scripts/release-stats.sh

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
11
#!/bin/bash
22

3-
git describe --exact-match
4-
5-
if [[ ! $? -eq 0 ]];then
6-
echo "Nothing to publish, exiting.."
7-
touch .github/actions/next-stats-action/SKIP_NEXT_STATS.txt
8-
exit 0;
3+
if [[ $(node ./scripts/check-is-release.js 2> /dev/null || :) = v* ]];
4+
then
5+
echo "Publish occurred, running release stats..."
6+
else
7+
echo "Not publish commit, exiting..."
8+
touch .github/actions/next-stats-action/SKIP_NEXT_STATS.txt
9+
exit 0;
910
fi
1011

1112
if [[ -z "$NPM_TOKEN" ]];then
1213
echo "No NPM_TOKEN, exiting.."
1314
exit 0;
1415
fi
1516

16-
echo "Publish occurred, running release stats..."
1717
echo "Waiting 30 seconds to allow publish to finalize"
1818
sleep 30

0 commit comments

Comments
 (0)