paperclip/.github/scripts/tests/check-pr-release-bootstrap....

266 lines
8.0 KiB
JavaScript

import { test } from 'node:test';
import assert from 'node:assert/strict';
import {
addedWorkspaceDependencyNames,
checkReleaseBootstrap,
} from '../check-pr-release-bootstrap.mjs';
const MANIFEST_PATH = 'scripts/release-package-manifest.json';
function encodeManifest(entries) {
return { content: Buffer.from(JSON.stringify(entries)).toString('base64') };
}
function stubGitHub({ base = [], head = [] }) {
return async (path) => {
if (path.includes('ref=refs%2Fpull%2F')) return encodeManifest(head);
if (path.includes(`/contents/`)) return encodeManifest(base);
throw new Error(`unexpected fetch: ${path}`);
};
}
const manifestChangedFile = { filename: MANIFEST_PATH, status: 'modified' };
test('does nothing (and fetches nothing) when the manifest is untouched', async () => {
const result = await checkReleaseBootstrap(
[{ filename: 'server/src/index.ts', status: 'modified' }],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: async () => { throw new Error('should not fetch'); },
registryPackageExists: async () => { throw new Error('should not look up'); },
}
);
assert.deepEqual(result, { passed: true, informational: [] });
});
test('notices a new publishFromCi:true package that is missing from npm', async () => {
const result = await checkReleaseBootstrap(
[manifestChangedFile],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({
base: [{ dir: 'a', name: '@paperclipai/existing', publishFromCi: true }],
head: [
{ dir: 'a', name: '@paperclipai/existing', publishFromCi: true },
{ dir: 'b', name: '@paperclipai/brand-new', publishFromCi: true },
],
}),
registryPackageExists: async (name) => name !== '@paperclipai/brand-new',
}
);
assert.equal(result.informational.length, 1);
assert.match(result.informational[0], /@paperclipai\/brand-new/);
assert.match(result.informational[0], /release:bootstrap-package -- @paperclipai\/brand-new --publish/);
assert.match(result.informational[0], /No contributor action/);
});
test('stays quiet when the new package already exists on npm', async () => {
const result = await checkReleaseBootstrap(
[manifestChangedFile],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({
base: [],
head: [{ dir: 'b', name: '@paperclipai/already-bootstrapped', publishFromCi: true }],
}),
registryPackageExists: async () => true,
}
);
assert.deepEqual(result.informational, []);
});
test('notices a publishFromCi flip from false to true on a missing package', async () => {
const result = await checkReleaseBootstrap(
[manifestChangedFile],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({
base: [{ dir: 'b', name: '@paperclipai/flipped', publishFromCi: false }],
head: [{ dir: 'b', name: '@paperclipai/flipped', publishFromCi: true }],
}),
registryPackageExists: async () => false,
}
);
assert.equal(result.informational.length, 1);
assert.match(result.informational[0], /@paperclipai\/flipped/);
});
test('notices a publishFromCi:false package that published packages newly depend on', async () => {
const files = [
manifestChangedFile,
{
filename: 'server/package.json',
status: 'modified',
patch: '@@ -1 +1 @@\n+ "@paperclipai/adapter-kimi-local": "workspace:*",',
},
];
const result = await checkReleaseBootstrap(
files,
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({
base: [],
head: [{ dir: 'b', name: '@paperclipai/adapter-kimi-local', publishFromCi: false }],
}),
registryPackageExists: async () => false,
}
);
assert.equal(result.informational.length, 1);
assert.match(result.informational[0], /depend on it/);
assert.match(result.informational[0], /"publishFromCi": true/);
assert.match(result.informational[0], /drop the workspace dependency/);
});
test('notices a newly added dependency on an existing unpublished package even when the manifest is untouched', async () => {
const files = [
{
filename: 'server/package.json',
status: 'modified',
patch: '@@ -1 +1 @@\n+ "@paperclipai/adapter-hermes-gateway": "workspace:*",',
},
];
const manifest = [{ dir: 'g', name: '@paperclipai/adapter-hermes-gateway', publishFromCi: false }];
const result = await checkReleaseBootstrap(
files,
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({ base: manifest, head: manifest }),
registryPackageExists: async () => false,
}
);
assert.equal(result.informational.length, 1);
assert.match(result.informational[0], /@paperclipai\/adapter-hermes-gateway/);
assert.match(result.informational[0], /depend on it/);
});
test('stays quiet for a publishFromCi:false package nothing depends on', async () => {
const result = await checkReleaseBootstrap(
[manifestChangedFile],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({
base: [],
head: [{ dir: 'b', name: '@paperclipai/deliberately-private', publishFromCi: false }],
}),
registryPackageExists: async () => { throw new Error('should not look up'); },
}
);
assert.deepEqual(result.informational, []);
});
test('never looks up names outside the @paperclipai scope', async () => {
const lookedUp = [];
const result = await checkReleaseBootstrap(
[manifestChangedFile],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({
base: [],
head: [
{ dir: 'x', name: '@evil/probe', publishFromCi: true },
{ dir: 'y', name: 'unscoped-name', publishFromCi: true },
{ dir: 'z', name: '@paperclipai/UPPER', publishFromCi: true },
],
}),
registryPackageExists: async (name) => {
lookedUp.push(name);
return false;
},
}
);
assert.deepEqual(lookedUp, []);
assert.deepEqual(result.informational, []);
});
test('stays quiet when the registry lookup fails', async () => {
const result = await checkReleaseBootstrap(
[manifestChangedFile],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: stubGitHub({
base: [],
head: [{ dir: 'b', name: '@paperclipai/brand-new', publishFromCi: true }],
}),
registryPackageExists: async () => { throw new Error('registry down'); },
}
);
assert.deepEqual(result, { passed: true, informational: [] });
});
test('treats a missing base manifest as empty (every head entry is new)', async () => {
const result = await checkReleaseBootstrap(
[manifestChangedFile],
'token',
'paperclipai/paperclip',
9967,
'master',
{
fetchFromGitHub: async (path) => {
if (path.includes('ref=refs%2Fpull%2F')) {
return encodeManifest([{ dir: 'b', name: '@paperclipai/brand-new', publishFromCi: true }]);
}
throw new Error('404 base manifest');
},
registryPackageExists: async () => false,
}
);
assert.equal(result.informational.length, 1);
});
test('addedWorkspaceDependencyNames reads only added lines of package.json patches', () => {
const names = addedWorkspaceDependencyNames([
{
filename: 'server/package.json',
patch: [
'@@ -1,3 +1,4 @@',
' "@paperclipai/context-line": "workspace:*",',
'- "@paperclipai/removed-dep": "workspace:*",',
'+ "@paperclipai/added-dep": "workspace:*",',
].join('\n'),
},
{ filename: 'ui/src/index.ts', patch: '+ "@paperclipai/not-a-pkg-json": "workspace:*",' },
{ filename: 'node_modules/x/package.json', patch: '+ "@paperclipai/vendored": "workspace:*",' },
]);
assert.deepEqual([...names], ['@paperclipai/added-dep']);
});