chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
// The commit that merges a pull request, and what it is allowed to merge.
import { describe, expect, it } from 'vitest';
import {
buildMergeCommit,
mergeable,
mergeTrailers,
} from '../src/merge-commit.js';
import { indexPacks, parseCommit } from '../src/objects.js';
import { writePack } from '../src/pack-write.js';
/** @param {string} name */
const sha = (name) => name.repeat(40).slice(0, 40);
const MAIN = sha('m');
const TIP = sha('t');
const TREE = sha('r');
const by = { name: 'Alice', email: 'alice@example.com' };
// A fixed instant, so the commit id a test asserts on does not move.
const AT = Date.UTC(2026, 7, 24, 12, 0, 0);
describe('mergeable', () => {
it('accepts a branch whose merge base is main itself', () => {
expect(mergeable({ base: MAIN, sha: TIP }, MAIN).can).toBe(true);
});
it('accepts a branch main has moved under; the merge itself decides', () => {
expect(mergeable({ base: sha('o'), sha: TIP }, MAIN).can).toBe(true);
});
it('refuses a branch main already reaches', () => {
const answer = mergeable({ base: TIP, sha: TIP }, MAIN);
expect(answer.can).toBe(false);
expect(answer.why).toMatch(/already reaches/);
});
it('refuses a branch sharing no history with main', () => {
expect(mergeable({ base: null, sha: TIP }, MAIN).can).toBe(false);
});
it('refuses main itself', () => {
expect(mergeable({ base: MAIN, sha: MAIN }, MAIN).can).toBe(false);
});
});
describe('mergeTrailers', () => {
it('names the copy and the ref the work came from', () => {
expect(
mergeTrailers({
did: 'did:plc:bob',
repo: 'project',
ref: 'refs/heads/fix',
}),
).toEqual([
'Merged-from: at://did:plc:bob/dev.pdsjs.git.repo/project',
'Merged-ref: refs/heads/fix',
]);
});
});
describe('buildMergeCommit', () => {
/**
* @param {'merge'|'squash'} mode
* @param {{body?: string, trailers?: string[]}} [extra]
*/
const build = (mode, extra = {}) =>
buildMergeCommit({
mode,
tree: TREE,
mainTip: MAIN,
branchTip: TIP,
by,
at: AT,
subject: 'add farewell()',
...extra,
});
it('gives a merge two parents, main first', async () => {
const commit = build('merge');
const objects = await indexPacks([writePack([commit])]);
const parsed = parseCommit(
/** @type {{data: Uint8Array}} */ (objects.get(commit.sha)).data,
);
expect(parsed.parents).toEqual([MAIN, TIP]);
expect(parsed.tree).toBe(TREE);
});
it('gives a squash main alone, so the graph says nothing', async () => {
const commit = build('squash');
const objects = await indexPacks([writePack([commit])]);
const parsed = parseCommit(
/** @type {{data: Uint8Array}} */ (objects.get(commit.sha)).data,
);
expect(parsed.parents).toEqual([MAIN]);
});
it('carries the trailers in their own block', () => {
const commit = build('squash', {
body: 'Two greetings, one register.',
trailers: mergeTrailers({
did: 'did:plc:bob',
repo: 'project',
ref: 'refs/heads/fix',
}),
});
const message = new TextDecoder().decode(commit.data);
expect(message).toContain(
'\nadd farewell()\n\nTwo greetings, one register.\n\nMerged-from: at://did:plc:bob/dev.pdsjs.git.repo/project\nMerged-ref: refs/heads/fix\n',
);
});
it('leaves no blank lines behind a subject with nothing after it', () => {
const message = new TextDecoder().decode(build('merge').data);
expect(message.endsWith('\nadd farewell()\n')).toBe(true);
});
it('is the same commit for the same inputs', () => {
expect(build('merge').sha).toBe(build('merge').sha);
expect(build('merge').sha).not.toBe(build('squash').sha);
});
});