/** * Which refs moved between two versions of a repository record. * * The record carries every ref with its object id, so a push is detectable * from the record alone. No git connection is needed to decide whether to run. */ /** * @typedef {Object} RefChange * @property {string} name - full ref name * @property {string} sha - object id it points at now * @property {string|null} previousSha - null when the ref is new */ /** * Refs that are new or point somewhere else than the last run saw. A ref that * disappeared is not a change: deleting a branch starts no run. * @param {Record} previous - ref name to object id * @param {Array<{name: string, sha: string}>} current * @returns {RefChange[]} */ export function diffRefs(previous, current) { /** @type {RefChange[]} */ const changes = []; for (const ref of current) { const previousSha = previous[ref.name] ?? null; if (previousSha === ref.sha) continue; changes.push({ name: ref.name, sha: ref.sha, previousSha }); } return changes; } /** * Refs the last run saw that are not there now. * * Deleting a branch starts no run, so `diffRefs` passes over these. What they * do end is the branch's history: a rebase and a name reused for other work * both give a tip the last one cannot reach, and nothing in the graph tells * the two apart. The deletion does. * @param {Record} previous - ref name to object id * @param {Array<{name: string, sha: string}>} current * @returns {string[]} full ref names */ export function removedRefs(previous, current) { const held = new Set(current.map((ref) => ref.name)); return Object.keys(previous).filter((name) => !held.has(name)); } /** * @param {Array<{name: string, sha: string}>} refs * @returns {Record} */ export function refsToState(refs) { /** @type {Record} */ const state = {}; for (const ref of refs) state[ref.name] = ref.sha; return state; }