-
Notifications
You must be signed in to change notification settings - Fork 86
/
Copy pathprepare.mjs
144 lines (133 loc) · 4.96 KB
/
prepare.mjs
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
// @ts-check
// this installs and builds all the fixtures
// Needed to run before executing the integration tests
import { readdirSync } from 'node:fs'
import { rm, readFile } from 'node:fs/promises'
import { join } from 'node:path'
import { argv } from 'node:process'
import { Transform } from 'node:stream'
import { fileURLToPath } from 'node:url'
import { cpus } from 'node:os'
import { execaCommand } from 'execa'
import glob from 'fast-glob'
import pLimit from 'p-limit'
import { setNextVersionInFixture } from './utils/next-version-helpers.mjs'
const NEXT_VERSION = process.env.NEXT_VERSION ?? 'latest'
const fixturesDir = fileURLToPath(new URL(`./fixtures`, import.meta.url))
const fixtureFilter = argv[2] ?? ''
// E2E tests run next builds, so we don't need to prepare those ahead of time for integration tests
const e2eOnlyFixtures = new Set([
'after',
'cli-before-regional-blobs-support',
'dist-dir',
'middleware-i18n-excluded-paths',
// There is also a bug on Windows on Node.js 18.20.6, that cause build failures on this fixture
// see https://github.com/opennextjs/opennextjs-netlify/actions/runs/13268839161/job/37043172448?pr=2749#step:12:78
'middleware-og',
'middleware-single-matcher',
'nx-integrated',
'turborepo',
'turborepo-npm',
'unstable-cache',
])
const limit = pLimit(Math.max(2, cpus().length / 2))
const fixtures = readdirSync(fixturesDir)
// Ignoring things like `.DS_Store`.
.filter((fixture) => !fixture.startsWith('.'))
// Applying the filter, if one is set.
.filter((fixture) => !fixtureFilter || fixture.startsWith(fixtureFilter))
// Filter out fixtures that are only needed for E2E tests
.filter((fixture) => !e2eOnlyFixtures.has(fixture))
console.log(`🧪 Preparing fixtures: ${fixtures.join(', ')}`)
const fixtureList = new Set(fixtures)
const fixtureCount = fixtures.length
const promises = fixtures.map((fixture) =>
limit(async () => {
console.log(`[${fixture}] Preparing fixture`)
const cwd = join(fixturesDir, fixture)
const publishDirectories = await glob(['**/.next', '**/.turbo'], {
onlyDirectories: true,
cwd,
absolute: true,
})
await Promise.all(publishDirectories.map((dir) => rm(dir, { recursive: true, force: true })))
if (NEXT_VERSION !== 'latest') {
await setNextVersionInFixture(cwd, NEXT_VERSION, {
logPrefix: `[${fixture}] `,
})
}
let cmd = ``
const { packageManager } = JSON.parse(await readFile(join(cwd, 'package.json'), 'utf8'))
if (packageManager?.startsWith('pnpm')) {
// We disable frozen-lockfile because we may have changed the version of Next.js
cmd = `pnpm install --frozen-lockfile=false ${
process.env.DEBUG || NEXT_VERSION !== 'latest' ? '' : '--reporter silent'
}`
} else {
// npm is the default
cmd = `npm install --no-audit --progress=false --prefer-offline --legacy-peer-deps`
await rm(join(cwd, 'package-lock.json'), { force: true })
}
const addPrefix = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().replace(/\n/gm, `\n[${fixture}] `))
callback()
},
flush(callback) {
// final transform might create non-terminated line with a prefix
// so this is just to make sure we end with a newline so further writes
// to same destination stream start on a new line for better readability
this.push('\n')
callback()
},
})
console.log(`[${fixture}] Running \`${cmd}\`...`)
const output = execaCommand(cmd, {
cwd,
stdio: 'pipe',
env: { ...process.env, FORCE_COLOR: '1' },
})
if (process.env.DEBUG) {
output.stdout?.pipe(addPrefix).pipe(process.stdout)
}
output.stderr?.pipe(addPrefix).pipe(process.stderr)
return output.finally(async () => {
if (NEXT_VERSION !== 'latest') {
await setNextVersionInFixture(cwd, 'latest', {
logPrefix: `[${fixture}] `,
operation: 'revert',
})
}
if (output.exitCode !== 0) {
const errorMessage = `[${fixture}] 🚨 Failed to install dependencies or build a fixture`
console.error(errorMessage)
throw new Error(errorMessage)
}
fixtureList.delete(fixture)
})
}).finally(() => {
console.log(
`[${fixture}] Done. ${limit.pendingCount + limit.activeCount}/${fixtureCount} remaining.`,
)
if (limit.activeCount < 5 && limit.activeCount > 0) {
console.log(`[${fixture}] Waiting for ${Array.from(fixtureList).join(', ')}`)
}
}),
)
const prepareFixturesResults = await Promise.allSettled(promises)
const failedFixturesErrors = prepareFixturesResults
.map((promise) => {
if (promise.status === 'rejected') {
return promise.reason
}
return null
})
.filter(Boolean)
if (failedFixturesErrors.length > 0) {
console.error('Some fixtures failed to prepare:')
for (const error of failedFixturesErrors) {
console.error(error.message)
}
process.exit(1)
}
console.log('🎉 All fixtures prepared')