rsnext/scripts/create-preview-tarballs.js
2024-07-02 15:18:45 +00:00

182 lines
5.9 KiB
JavaScript

// @ts-check
const execa = require('execa')
const fs = require('node:fs/promises')
const os = require('node:os')
const path = require('node:path')
async function main() {
const [
commitSha,
tarballDirectory = path.join(os.tmpdir(), 'vercel-nextjs-preview-tarballs'),
] = process.argv.slice(2)
const repoRoot = path.resolve(__dirname, '..')
await fs.mkdir(tarballDirectory, { recursive: true })
const [{ stdout: shortSha }, { stdout: dateString }] = await Promise.all([
execa('git', ['rev-parse', '--short', commitSha]),
// Source: https://github.com/facebook/react/blob/767f52237cf7892ad07726f21e3e8bacfc8af839/scripts/release/utils.js#L114
execa(`git`, [
'show',
'-s',
'--no-show-signature',
'--format=%cd',
'--date=format:%Y%m%d',
commitSha,
]),
])
const lernaConfig = JSON.parse(
await fs.readFile(path.join(repoRoot, 'lerna.json'), 'utf8')
)
// 15.0.0-canary.17 -> 15.0.0
// 15.0.0 -> 15.0.0
const [semverStableVersion] = lernaConfig.version.split('-')
const version = `${semverStableVersion}-preview-${shortSha}-${dateString}`
console.info(`Designated version: ${version}`)
const nativePackagesDir = path.join(
repoRoot,
'packages/next-swc/crates/napi/npm'
)
const platforms = (await fs.readdir(nativePackagesDir)).filter(
(name) => !name.startsWith('.')
)
console.info(`Creating tarballs for next-swc packages`)
const nextSwcPackageNames = new Set()
await Promise.all(
platforms.map(async (platform) => {
const binaryName = `next-swc.${platform}.node`
try {
await fs.cp(
path.join(repoRoot, 'packages/next-swc/native', binaryName),
path.join(nativePackagesDir, platform, binaryName)
)
} catch (error) {
if (error.code === 'ENOENT') {
console.warn(
`Skipping next-swc platform '${platform}' tarball creation because ${binaryName} was never built.`
)
return
}
throw error
}
const manifest = JSON.parse(
await fs.readFile(
path.join(nativePackagesDir, platform, 'package.json'),
'utf8'
)
)
manifest.version = version
await fs.writeFile(
path.join(nativePackagesDir, platform, 'package.json'),
JSON.stringify(manifest, null, 2) + '\n'
)
// By encoding the package name in the directory, vercel-packages can later extract the package name of a tarball from its path when `tarballDirectory` is zipped.
const packDestination = path.join(tarballDirectory, manifest.name)
await fs.mkdir(packDestination, { recursive: true })
const { stdout } = await execa(
'npm',
['pack', '--pack-destination', packDestination],
{
cwd: path.join(nativePackagesDir, platform),
}
)
// tarball name is printed as the last line of npm-pack
const tarballName = stdout.trim().split('\n').pop()
console.info(`Created tarball ${path.join(packDestination, tarballName)}`)
nextSwcPackageNames.add(manifest.name)
})
)
const lernaListJson = await execa('pnpm', [
'--silent',
'lerna',
'list',
'--json',
])
const packages = JSON.parse(lernaListJson.stdout)
const packagesByVersion = new Map()
for (const packageInfo of packages) {
packagesByVersion.set(
packageInfo.name,
`https://vercel-packages.vercel.app/next/commits/${commitSha}/${packageInfo.name}`
)
}
for (const nextSwcPackageName of nextSwcPackageNames) {
packagesByVersion.set(
nextSwcPackageName,
`https://vercel-packages.vercel.app/next/commits/${commitSha}/${nextSwcPackageName}`
)
}
console.info(`Creating tarballs for regular packages`)
for (const packageInfo of packages) {
if (packageInfo.private) {
continue
}
const packageJsonPath = path.join(packageInfo.location, 'package.json')
const packageJson = await fs.readFile(packageJsonPath, 'utf8')
const manifest = JSON.parse(packageJson)
manifest.version = version
if (packageInfo.name === 'next') {
manifest.optionalDependencies ??= {}
for (const nextSwcPackageName of nextSwcPackageNames) {
manifest.optionalDependencies[nextSwcPackageName] =
packagesByVersion.get(nextSwcPackageName)
}
}
// ensure it depends on packages from this release.
for (const [dependencyName, version] of packagesByVersion) {
if (manifest.dependencies?.[dependencyName] !== undefined) {
manifest.dependencies[dependencyName] = version
}
if (manifest.devDependencies?.[dependencyName] !== undefined) {
manifest.devDependencies[dependencyName] = version
}
if (manifest.peerDependencies?.[dependencyName] !== undefined) {
manifest.peerDependencies[dependencyName] = version
}
if (manifest.optionalDependencies?.[dependencyName] !== undefined) {
manifest.optionalDependencies[dependencyName] = version
}
}
await fs.writeFile(
packageJsonPath,
JSON.stringify(manifest, null, 2) +
// newline will be added by Prettier
'\n'
)
// By encoding the package name in the directory, vercel-packages can later extract the package name of a tarball from its path when `tarballDirectory` is zipped.
const packDestination = path.join(tarballDirectory, manifest.name)
await fs.mkdir(packDestination, { recursive: true })
const { stdout } = await execa(
'npm',
['pack', '--pack-destination', packDestination],
{
cwd: packageInfo.location,
}
)
// tarball name is printed as the last line of npm-pack
const tarballName = stdout.trim().split('\n').pop()
console.info(`Created tarball ${path.join(packDestination, tarballName)}`)
}
console.info(
`When this job is completed, a Next.js preview build will be available under ${packagesByVersion.get('next')}`
)
}
main().catch((err) => {
console.error(err)
process.exit(1)
})