Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions scripts/release-setup.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,19 @@ for (const name of siblings) {
// Installed, and from the lockfile now checked out: npm records what it
// installed in node_modules/.package-lock.json, and a pull that changes the
// lockfile leaves that record older than it.
// `npm ci` empties node_modules before it installs, and follows a symbolic
// link there: a worktree that links to another checkout's install would have
// that checkout's packages removed. Such a checkout is prepared by hand.
const refuseLinkedModules = (directory) => {
const modules = join(directory, 'node_modules')
let link
try {
link = lstatSync(modules).isSymbolicLink() ? readlinkSync(modules) : undefined
} catch {
return
}
if (link) throw new Error(`release setup: ${modules} is a link to ${link}; npm would install into that checkout`)
}
const installed = (directory) => {
const record = join(directory, 'node_modules', '.package-lock.json')
const lock = join(directory, 'package-lock.json')
Expand All @@ -84,11 +97,16 @@ for (const repository of [compiler, ...siblings.map((name) => join(workspace, na
.filter((file) => /(^|\/)package-lock\.json$/.test(file))
for (const lock of locks) {
const directory = join(repository, dirname(lock))
if (reinstall || !installed(directory)) step(directory, ['npm', 'ci', '--no-audit', '--no-fund'])
if (reinstall || !installed(directory)) {
refuseLinkedModules(directory)
step(directory, ['npm', 'ci', '--no-audit', '--no-fund'])
}
}
// A package that locks nothing (parallel) installs its declared ranges.
if (!locks.length && existsSync(join(repository, 'package.json')) && (reinstall || !installed(repository)))
if (!locks.length && existsSync(join(repository, 'package.json')) && (reinstall || !installed(repository))) {
refuseLinkedModules(repository)
step(repository, ['npm', 'install', '--no-package-lock', '--no-audit', '--no-fund'])
}
}

const windowsPackage = join(workspace, 'windows/packages/geastack-windows')
Expand Down
40 changes: 32 additions & 8 deletions scripts/release-suite.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,17 @@ const onlyAt = process.argv.findIndex((argument) => argument === '--only' || arg
const only = onlyAt < 0 ? undefined : (process.argv[onlyAt].slice(7) || process.argv[onlyAt + 1] || '').split(',')
const wanted = (lane) => !only || only.includes(lane)

const buildHostReachable = (host) => {
if (process.env.GEA_PARALLEL_HOST) return true
try {
execFileSync('ssh', ['-o', 'BatchMode=yes', '-o', 'ConnectTimeout=5', host, 'true'], { stdio: 'ignore' })
return true
} catch {
console.log(`parallel: ${host} is unreachable, the native fixtures build on this host`)
return false
}
}

const checkout = (name, marker) => {
const directory = join(workspace, name)
if (!workspace || !existsSync(join(directory, marker)))
Expand Down Expand Up @@ -185,6 +196,11 @@ if (wanted('core')) {
// not skipped quietly: the summary names every one this host left unrun.
if (process.platform !== 'darwin' && readFileSync(join(tests, file), 'utf8').includes('-framework'))
hostOnly.push(`core: ${file} (links a macOS framework)`)
// The companion tests compile the generated C++ of a gea-companion macOS
// build, which they expect under apple's targets/macos/generated and no
// lane produces; the summary names them until one does.
else if (file.startsWith('run-gea-companion-'))
hostOnly.push(`core: ${file} (needs a gea-companion macOS build's generated C++, which no lane produces)`)
else add('core', file, examples, ['bash', join(tests, file)], env)
}
}
Expand All @@ -211,8 +227,11 @@ if (wanted('parallel')) {
add('parallel', 'test', parallel, ['npm', 'test'])
add('parallel', 'refusals', parallel, ['npm', 'run', 'test:refusals'])
// Linux and Windows build and run the fixtures on this host; elsewhere the
// runner ships them to its Linux build machine.
add('parallel', 'native', parallel, ['node', 'test/run-native.mjs', ...(process.platform !== 'darwin' ? ['--host=local'] : [])])
// runner ships them to its Linux build machine, GEA_PARALLEL_HOST or its
// default -- unless that machine cannot be reached, when this host, which
// has the sanitizers the fixtures build with, builds and runs them itself.
const local = process.platform !== 'darwin' || !buildHostReachable(process.env.GEA_PARALLEL_HOST ?? 'dashwin-geastack')
add('parallel', 'native', parallel, ['node', 'test/run-native.mjs', ...(local ? ['--host=local'] : [])])
if (process.platform === 'win32')
hostOnly.push('parallel: the ThreadSanitizer builds of test/run-native.mjs (clang has no ThreadSanitizer on Windows)')
}
Expand Down Expand Up @@ -354,13 +373,18 @@ if (wanted('perf')) {
// @geastack/parallel workloads (against Rayon and a C++ pool), compared with
// the baseline benchmarks/ records for this machine. A machine without one
// fails: an unmeasured release has not passed this lane.
const benchmarks = checkout('benchmarks', 'node/release-gate/perf-gate.mjs')
if (process.platform === 'linux' && process.arch === 'x64')
last('perf', 'HTTP and parallel performance gate', benchmarks, ['node', 'node/release-gate/perf-gate.mjs', '--fix-loopback'], {
GEA_COMPILER_DIR: compiler,
GEA_NODE_COMPAT_DIR: join(workspace, 'node-compat'),
PARALLEL_ROOT: join(workspace, 'parallel')
})
last(
'perf',
'HTTP and parallel performance gate',
checkout('benchmarks', 'node/release-gate/perf-gate.mjs'),
['node', 'node/release-gate/perf-gate.mjs', '--fix-loopback'],
{
GEA_COMPILER_DIR: compiler,
GEA_NODE_COMPAT_DIR: join(workspace, 'node-compat'),
PARALLEL_ROOT: join(workspace, 'parallel')
}
)
else hostOnly.push('perf: the HTTP and parallel performance gate (needs Linux on x86-64)')
}

Expand Down
2 changes: 1 addition & 1 deletion test/gea-commonjs.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { compile } from '../dist/compiler.js'
import { adoptGeaPackage, geaCommonJsGlobals } from '../dist/plugins/gea/host.js'

const root = resolve(import.meta.dirname, '..')
const plugin = resolve(root, '../core/packages/geatsc-plugin-gea')
const plugin = resolve(process.env.GEA_CORE_ROOT ?? resolve(root, '../core'), 'packages/geatsc-plugin-gea')
adoptGeaPackage(resolve(plugin, 'dist/index.js'))
assert.equal(geaCommonJsGlobals().size, 3)
const result = compile({
Expand Down
2 changes: 1 addition & 1 deletion test/gea-host-namespace-members.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { adoptGeaPackage } from '../dist/plugins/gea/host.js'

const root = resolve(import.meta.dirname, '..')
const fixture = resolve(root, 'test/fixtures/gea-host-namespace-members')
adoptGeaPackage(resolve(root, '../core/packages/geatsc-plugin-gea/dist/index.js'))
adoptGeaPackage(resolve(process.env.GEA_CORE_ROOT ?? resolve(root, '../core'), 'packages/geatsc-plugin-gea/dist/index.js'))

// A namespace path's member call renders the host's free function; the path
// itself is never a value, and no logical receiver crosses the call.
Expand Down
2 changes: 1 addition & 1 deletion test/native-rtc.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const root = resolve(import.meta.dirname, '..')
const output = resolve(root, 'measurements/cxx-native-rtc')
mkdirSync(output, { recursive: true })
process.env.TMPDIR = output
const core = resolve(root, '../core')
const core = process.env.GEA_CORE_ROOT ?? resolve(root, '../core')
adoptGeaPackage(resolve(core, 'packages/geatsc-plugin-gea/dist/index.js'))
const flags = [
'-std=c++20',
Expand Down
Loading