-
-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Expand file tree
/
Copy pathregistrySetup.ts
More file actions
142 lines (122 loc) · 4.22 KB
/
registrySetup.ts
File metadata and controls
142 lines (122 loc) · 4.22 KB
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
/* eslint-disable no-console */
import { spawn, spawnSync, type ChildProcess } from 'child_process';
import * as fs from 'fs';
import * as http from 'http';
import * as path from 'path';
import { publishPackages } from './lib/publishPackages';
const VERDACCIO_PORT = 4873;
let verdaccioChild: ChildProcess | undefined;
export interface RegistrySetupOptions {
/**
* When true, Verdaccio is spawned detached with stdio disconnected from the parent.
* Use for `prepare.ts` so `yarn test:prepare` can exit while the registry keeps running.
* (Inherited stdio otherwise keeps the parent process tied to the child on many systems.)
*/
daemonize?: boolean;
}
/** Stops any Verdaccio runner from a previous prepare/run so port 4873 is free. */
function killStrayVerdaccioRunner(): void {
spawnSync('pkill', ['-f', 'verdaccio-runner.mjs'], { stdio: 'ignore' });
}
async function groupCIOutput(groupTitle: string, fn: () => void | Promise<void>): Promise<void> {
if (process.env.CI) {
console.log(`::group::${groupTitle}`);
try {
await Promise.resolve(fn());
} finally {
console.log('::endgroup::');
}
} else {
await Promise.resolve(fn());
}
}
function waitUntilVerdaccioResponds(maxRetries: number = 60): Promise<void> {
const pingUrl = `http://127.0.0.1:${VERDACCIO_PORT}/-/ping`;
function tryOnce(): Promise<boolean> {
return new Promise(resolve => {
const req = http.get(pingUrl, res => {
res.resume();
resolve((res.statusCode ?? 0) > 0 && (res.statusCode ?? 500) < 500);
});
req.on('error', () => resolve(false));
req.setTimeout(2000, () => {
req.destroy();
resolve(false);
});
});
}
return (async () => {
for (let i = 0; i < maxRetries; i++) {
if (await tryOnce()) {
return;
}
await new Promise(r => setTimeout(r, 1000));
}
throw new Error('Verdaccio did not start in time.');
})();
}
function startVerdaccioChild(configPath: string, port: number, daemonize: boolean): ChildProcess {
const runnerPath = path.join(__dirname, 'verdaccio-runner.mjs');
const verbose = process.env.E2E_VERDACCIO_VERBOSE === '1';
return spawn(process.execPath, [runnerPath, configPath, String(port)], {
detached: daemonize,
stdio: daemonize && !verbose ? 'ignore' : 'inherit',
});
}
async function stopVerdaccioChild(): Promise<void> {
const child = verdaccioChild;
verdaccioChild = undefined;
if (!child || child.killed) {
return;
}
child.kill('SIGTERM');
await new Promise<void>(resolve => {
child.once('exit', () => resolve());
setTimeout(resolve, 5000);
});
}
export async function registrySetup(options: RegistrySetupOptions = {}): Promise<void> {
const { daemonize = false } = options;
await groupCIOutput('Test Registry Setup', async () => {
killStrayVerdaccioRunner();
const configPath = path.join(__dirname, 'verdaccio-config', 'config.yaml');
const storagePath = path.join(__dirname, 'verdaccio-config', 'storage');
// Clear previous registry storage to ensure a fresh state
fs.rmSync(storagePath, { recursive: true, force: true });
// Verdaccio runs in a child process so tarball uploads are not starved by the
// same Node event loop as ts-node (in-process runServer + npm publish could hang).
console.log('Starting Verdaccio...');
verdaccioChild = startVerdaccioChild(configPath, VERDACCIO_PORT, daemonize);
try {
await waitUntilVerdaccioResponds(60);
console.log('Verdaccio is ready');
await publishPackages();
} catch (error) {
await stopVerdaccioChild();
throw error;
}
});
console.log('');
console.log('');
}
/**
* Detach the Verdaccio child so `ts-node` can exit while the registry keeps running
* (e.g. CI: `yarn test:prepare` then `pnpm test:build` in later steps).
*/
export function registryRelease(): void {
const child = verdaccioChild;
verdaccioChild = undefined;
if (child && !child.killed) {
child.unref();
}
}
export async function registryCleanup(): Promise<void> {
await stopVerdaccioChild();
killStrayVerdaccioRunner();
const pidFile = path.join(__dirname, 'verdaccio-config', '.verdaccio.pid');
try {
fs.unlinkSync(pidFile);
} catch {
// File may not exist
}
}