158 lines
5.2 KiB
JavaScript
158 lines
5.2 KiB
JavaScript
const {Buffer} = require('buffer');
|
|
const {exec} = require('child_process');
|
|
const {createHash} = require('crypto');
|
|
const {createReadStream} = require('fs');
|
|
const {cp, mkdir} = require('fs/promises');
|
|
const {join} = require('path');
|
|
|
|
const {
|
|
processCode,
|
|
run,
|
|
spawnWith,
|
|
writeFile,
|
|
} = require('@flecks/core/src/server');
|
|
const Arborist = require('@npmcli/arborist');
|
|
const {glob} = require('glob');
|
|
|
|
const concurrent = require('./concurrent');
|
|
|
|
const {
|
|
FLECKS_CORE_ROOT = process.cwd(),
|
|
} = process.env;
|
|
|
|
const args = ['npm', 'publish', ...process.argv.slice(2)];
|
|
const bumpedVersions = {};
|
|
const creators = ['create-app', 'create-fleck'];
|
|
const localVersions = {};
|
|
const packCache = join(FLECKS_CORE_ROOT, 'node_modules', '.cache', '@flecks', 'publish');
|
|
const {workspaces} = require(join(FLECKS_CORE_ROOT, 'package.json'));
|
|
|
|
// Get integrity sums for creator dependencies.
|
|
const packPkg = async (pkg) => {
|
|
await processCode(spawnWith(
|
|
['npm', 'pack', '--pack-destination', packCache],
|
|
{cwd: join(FLECKS_CORE_ROOT, 'packages', pkg, 'dist', 'fleck'), stdio: 'ignore'},
|
|
));
|
|
};
|
|
|
|
const bumpDependencies = (dependencies) => (
|
|
Object.fromEntries(
|
|
Object.entries(dependencies)
|
|
.map(([pkg, version]) => ([pkg, localVersions[pkg] || version])),
|
|
)
|
|
);
|
|
|
|
const integrityForPkg = async (pkg) => {
|
|
const pack = join(packCache, `flecks-${pkg.split('/')[1]}-${localVersions[pkg]}.tgz`);
|
|
const buffers = [];
|
|
// eslint-disable-next-line no-restricted-syntax
|
|
for await (const data of createReadStream(pack).pipe(createHash('sha512'))) {
|
|
buffers.push(data);
|
|
}
|
|
return `sha512-${Buffer.concat(buffers).toString('base64')}`;
|
|
};
|
|
|
|
const shrinkwrap = async (path) => {
|
|
const arb = new Arborist({
|
|
path,
|
|
registry: await run('npm config get registry'),
|
|
});
|
|
const {meta} = await arb.buildIdealTree({saveType: 'prod'});
|
|
const shrinkwrap = await meta.commit();
|
|
shrinkwrap.packages = Object.fromEntries(
|
|
await Promise.all(
|
|
Object.entries(shrinkwrap.packages)
|
|
.map(async ([pkg, config]) => {
|
|
if (pkg.match(/node_modules\/@flecks\/[^/]+$/)) {
|
|
if (config.dependencies) {
|
|
config.dependencies = bumpDependencies(config.dependencies);
|
|
}
|
|
if (config.devDependencies) {
|
|
config.devDependencies = bumpDependencies(config.devDependencies);
|
|
}
|
|
const subpkg = pkg.split('/').slice(1).join('/');
|
|
config.version = localVersions[subpkg];
|
|
config.integrity = await integrityForPkg(subpkg);
|
|
}
|
|
return [pkg, config];
|
|
}),
|
|
),
|
|
);
|
|
return shrinkwrap;
|
|
};
|
|
|
|
const shrinkwrapsAndPublish = async (creator) => {
|
|
const dist = join(FLECKS_CORE_ROOT, 'packages', creator, 'dist', 'fleck');
|
|
const fakePackage = join(packCache, creator);
|
|
await mkdir(fakePackage, {recursive: true});
|
|
// Get a shrinkwrap from template package.json and insert it as a package-lock.json.
|
|
await cp(join(dist, 'template', 'package.json.noconflict'), join(fakePackage, 'package.json'));
|
|
await writeFile(
|
|
join(dist, 'template', 'package-lock.json.noconflict'),
|
|
JSON.stringify(await shrinkwrap(fakePackage), null, 2),
|
|
);
|
|
// Get a shrinkwrap from the built creator and insert it as shrinkwrap.
|
|
await writeFile(
|
|
join(dist, 'npm-shrinkwrap.json'),
|
|
JSON.stringify(await shrinkwrap(dist), null, 2),
|
|
);
|
|
// Publish.
|
|
await processCode(spawnWith(args, {cwd: dist}));
|
|
};
|
|
|
|
// npm can be slow...
|
|
const waitForPkgToPublish = (pkg) => (
|
|
new Promise(async (resolve) => {
|
|
if (await run(`npm view ${pkg}@${localVersions[pkg]}`)) {
|
|
resolve();
|
|
}
|
|
const handle = setInterval(async () => {
|
|
if (await run(`npm view ${pkg}@${localVersions[pkg]}`)) {
|
|
clearInterval(handle);
|
|
resolve();
|
|
}
|
|
}, 5000);
|
|
})
|
|
);
|
|
|
|
(async () => {
|
|
await concurrent(
|
|
(await Promise.all(workspaces.map((path) => glob(join(FLECKS_CORE_ROOT, path))))).flat(),
|
|
async (cwd) => {
|
|
const {name, version} = require(join(cwd, 'package.json'));
|
|
const [localVersion, remoteVersion] = await Promise.all([
|
|
version,
|
|
run(`npm view ${name} version`),
|
|
]);
|
|
localVersions[name] = version;
|
|
if (localVersion === remoteVersion) {
|
|
return undefined;
|
|
}
|
|
bumpedVersions[name] = version;
|
|
// Skip creators for now.
|
|
if (creators.some((creator) => name.endsWith(creator))) {
|
|
return undefined;
|
|
}
|
|
return processCode(spawnWith(args, {cwd: join(cwd, 'dist', 'fleck')}));
|
|
},
|
|
);
|
|
// No creators? Bail.
|
|
if (!bumpedVersions['@flecks/create-app'] && !bumpedVersions['@flecks/create-fleck']) {
|
|
return;
|
|
}
|
|
// Pack dependencies.
|
|
await mkdir(packCache, {recursive: true});
|
|
const dependencies = ['build', 'core', 'fleck', 'server'];
|
|
await Promise.all(dependencies.map((pkg) => waitForPkgToPublish(`@flecks/${pkg}`)));
|
|
await Promise.all(dependencies.map(packPkg));
|
|
if (bumpedVersions['@flecks/create-fleck']) {
|
|
await shrinkwrapsAndPublish('create-fleck');
|
|
}
|
|
if (bumpedVersions['@flecks/create-app']) {
|
|
// Needs packed create-fleck for package lock.
|
|
await packPkg('create-fleck');
|
|
await waitForPkgToPublish('@flecks/create-fleck');
|
|
await shrinkwrapsAndPublish('create-app');
|
|
}
|
|
})();
|