[fix] default parameter run records parameters in session for replay[fix] remove default parameters for several cubes
This commit is contained in:
@@ -0,0 +1,51 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Prints the workspace packages a package links to, as `<name> <version>` lines.
|
||||
*
|
||||
* The version is the one the linked package declares *right now*, which is
|
||||
* exactly what `pnpm publish` will substitute for `workspace:*` when it packs.
|
||||
* A release can therefore check that each of them is already on the registry
|
||||
* before shipping a manifest that points at a version nobody can install.
|
||||
*
|
||||
* node scripts/linked-deps.mjs packages/nopy
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const PACKAGES_DIR = 'packages';
|
||||
const RANGE_FIELDS = ['dependencies', 'peerDependencies', 'optionalDependencies'];
|
||||
|
||||
const target = process.argv[2];
|
||||
if (!target) {
|
||||
console.error('Usage: node scripts/linked-deps.mjs <package-dir>');
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
const read = (dir) => JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8'));
|
||||
|
||||
// Resolved by name rather than by directory: nothing guarantees that
|
||||
// `@bitsquare/nopy-cube` lives in `packages/nopy-cube`.
|
||||
const versionByName = new Map(
|
||||
fs
|
||||
.readdirSync(PACKAGES_DIR)
|
||||
.map((name) => path.join(PACKAGES_DIR, name))
|
||||
.filter((dir) => fs.existsSync(path.join(dir, 'package.json')))
|
||||
.map((dir) => read(dir))
|
||||
.map((manifest) => [manifest.name, manifest.version])
|
||||
);
|
||||
|
||||
const manifest = read(target);
|
||||
const linked = RANGE_FIELDS.flatMap((field) => Object.entries(manifest[field] ?? {}))
|
||||
.filter(([, range]) => range.startsWith('workspace:'))
|
||||
.map(([name]) => name);
|
||||
|
||||
for (const name of linked) {
|
||||
const version = versionByName.get(name);
|
||||
if (version === undefined) {
|
||||
console.error(`${manifest.name} links to ${name}, which is not in ${PACKAGES_DIR}/.`);
|
||||
process.exit(1);
|
||||
}
|
||||
console.log(`${name} ${version}`);
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Prints the publishable workspace package directories, dependencies first.
|
||||
*
|
||||
* `packages/*` in alphabetical order puts `nopy` ahead of the `nopy-cube` it
|
||||
* depends on, which leaves a window where the registry holds a package whose
|
||||
* dependency does not exist yet. Ordering the publish by the workspace graph
|
||||
* closes it. One directory per line, so the caller can `for dir in $(…)`.
|
||||
*/
|
||||
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
|
||||
const PACKAGES_DIR = 'packages';
|
||||
const RANGE_FIELDS = ['dependencies', 'peerDependencies', 'optionalDependencies'];
|
||||
|
||||
const packages = fs
|
||||
.readdirSync(PACKAGES_DIR)
|
||||
.map((name) => path.join(PACKAGES_DIR, name))
|
||||
.filter((dir) => fs.existsSync(path.join(dir, 'package.json')))
|
||||
.map((dir) => ({ dir, manifest: JSON.parse(fs.readFileSync(path.join(dir, 'package.json'))) }))
|
||||
.filter(({ manifest }) => !manifest.private);
|
||||
|
||||
const dirByName = new Map(packages.map(({ dir, manifest }) => [manifest.name, dir]));
|
||||
|
||||
/** The other workspace packages this one links to, by directory. */
|
||||
const dependenciesOf = ({ manifest }) =>
|
||||
RANGE_FIELDS.flatMap((field) => Object.entries(manifest[field] ?? {}))
|
||||
.filter(([, range]) => range.startsWith('workspace:'))
|
||||
.map(([name]) => dirByName.get(name))
|
||||
.filter((dir) => dir !== undefined);
|
||||
|
||||
const ordered = [];
|
||||
const emitted = new Set();
|
||||
const visiting = new Set();
|
||||
|
||||
const visit = (pkg) => {
|
||||
if (emitted.has(pkg.dir)) return;
|
||||
if (visiting.has(pkg.dir)) {
|
||||
// pnpm rejects a workspace cycle at install time, so reaching this means
|
||||
// something stranger than a bad dependency edge.
|
||||
throw new Error(`Dependency cycle in the workspace, at ${pkg.dir}`);
|
||||
}
|
||||
visiting.add(pkg.dir);
|
||||
for (const dir of dependenciesOf(pkg)) {
|
||||
visit(packages.find((candidate) => candidate.dir === dir));
|
||||
}
|
||||
visiting.delete(pkg.dir);
|
||||
emitted.add(pkg.dir);
|
||||
ordered.push(pkg.dir);
|
||||
};
|
||||
|
||||
// Alphabetical among packages the graph does not separate, so the output is
|
||||
// stable across runs and platforms.
|
||||
for (const pkg of [...packages].sort((a, b) => a.dir.localeCompare(b.dir))) visit(pkg);
|
||||
|
||||
console.log(ordered.join('\n'));
|
||||
@@ -0,0 +1,72 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* Asserts that every publishable package is installable once packed.
|
||||
*
|
||||
* `@bitsquare/nopy` depends on `@bitsquare/nopy-cube` through `workspace:*`, and
|
||||
* `link-workspace-packages` is off, so a plain semver range would resolve from
|
||||
* the registry instead of linking the workspace copy — the protocol is not
|
||||
* optional. But npm has no idea what `workspace:` means: a tarball that still
|
||||
* carries one fails at install time with EUNSUPPORTEDPROTOCOL, long after the
|
||||
* publish went green. `pnpm publish` rewrites the range at pack time; this
|
||||
* checks that it actually did, on the artefact rather than on the promise.
|
||||
*
|
||||
* Run it in CI between the build and the publish. Failing here costs a red run;
|
||||
* failing in the registry costs a version number.
|
||||
*/
|
||||
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import fs from 'node:fs';
|
||||
import os from 'node:os';
|
||||
import path from 'node:path';
|
||||
|
||||
const PACKAGES_DIR = 'packages';
|
||||
const RANGE_FIELDS = ['dependencies', 'peerDependencies', 'optionalDependencies'];
|
||||
|
||||
const packages = fs
|
||||
.readdirSync(PACKAGES_DIR)
|
||||
.map((name) => path.join(PACKAGES_DIR, name))
|
||||
.filter((dir) => fs.existsSync(path.join(dir, 'package.json')))
|
||||
.filter((dir) => !JSON.parse(fs.readFileSync(path.join(dir, 'package.json'), 'utf-8')).private);
|
||||
|
||||
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'verify-pack-'));
|
||||
const failures = [];
|
||||
|
||||
try {
|
||||
for (const dir of packages) {
|
||||
// `pnpm pack` has no --ignore-scripts, so prepack runs and rebuilds. That is
|
||||
// incremental, and it means the tarball under test is the one publish ships.
|
||||
const output = execFileSync('pnpm', ['pack', '--pack-destination', tmpDir], {
|
||||
cwd: dir,
|
||||
encoding: 'utf-8',
|
||||
});
|
||||
// pnpm prints the tarball path last; anything before it is progress noise.
|
||||
const tarball = output.trim().split('\n').at(-1).trim();
|
||||
|
||||
const manifest = JSON.parse(
|
||||
execFileSync('tar', ['-xzOf', tarball, 'package/package.json'], { encoding: 'utf-8' })
|
||||
);
|
||||
|
||||
const ranges = RANGE_FIELDS.flatMap((field) =>
|
||||
Object.entries(manifest[field] ?? {}).map(([name, range]) => ({ field, name, range }))
|
||||
);
|
||||
const unresolved = ranges.filter(({ range }) => range.startsWith('workspace:'));
|
||||
|
||||
for (const { field, name, range } of unresolved) {
|
||||
failures.push(`${manifest.name}: ${field}.${name} is still '${range}'`);
|
||||
}
|
||||
|
||||
const linked = ranges.filter(({ name }) => name.startsWith('@bitsquare/'));
|
||||
const summary = linked.map(({ name, range }) => `${name}@${range}`).join(', ');
|
||||
console.log(`${manifest.name}@${manifest.version} — ${summary || 'no workspace dependencies'}`);
|
||||
}
|
||||
} finally {
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
if (failures.length > 0) {
|
||||
console.error('\nUnresolved workspace ranges in packed manifests:');
|
||||
for (const failure of failures) console.error(` ${failure}`);
|
||||
console.error('\nPublish with `pnpm publish`, not `npm publish`.');
|
||||
process.exit(1);
|
||||
}
|
||||
Reference in New Issue
Block a user