// Tests for the Forgejo release-object backfill. // Pure selector is the unit under test — the API shell (curl via release-plugin.mjs's // forgejoApi) is exercised against the live instance, not here. import { test } from 'node:test'; import assert from 'node:assert/strict'; import { planBackfill, EXCLUDED_TAGS } from './backfill-forgejo-releases.mjs'; const repo = (name, tags, releases = []) => ({ name, tags, releases }); const tag = (name, message = '') => ({ name, message }); test('plans a CREATE for a repo whose newest tag has no release object', () => { const r = planBackfill({ repos: [repo('llm-security', [tag('v8.0.0', 'llm-security v8.0.0'), tag('v7.8.3')], ['v7.8.3'])] }); assert.equal(r.create.length, 1); assert.equal(r.create[0].repo, 'llm-security'); assert.equal(r.create[0].tag, 'v8.0.0'); }); test('the release body is the tag message VERBATIM — the backfill invents no release notes', () => { const msg = '0.10.0 — a bundle carries the images its sources declare\n\nFive readers place them.'; const r = planBackfill({ repos: [repo('llm-ingestion-okf', [tag('v0.10.0', msg)], [])] }); assert.equal(r.create[0].body, msg); }); test('skips a repo whose newest tag already has a release object (idempotent re-run)', () => { const r = planBackfill({ repos: [repo('ai-psychosis', [tag('v1.2.2')], ['v1.2.2'])] }); assert.equal(r.create.length, 0); assert.equal(r.skip.length, 1); assert.match(r.skip[0].reason, /already has a release/); }); test('skips a repo with no tags at all, and NAMES the reason — never a silent drop', () => { const r = planBackfill({ repos: [repo('jobbsok', [])] }); assert.equal(r.create.length, 0); assert.equal(r.skip.length, 1); assert.equal(r.skip[0].repo, 'jobbsok'); assert.match(r.skip[0].reason, /no tags/); }); test('only the NEWEST tag is backfilled — an older tag without a release stays untouched', () => { const r = planBackfill({ repos: [repo('config-audit', [tag('v6.0.0'), tag('v5.9.0'), tag('v5.8.0')], [])] }); assert.deepEqual(r.create.map(c => c.tag), ['v6.0.0']); }); test('an excluded tag is reported as a documented EXCEPTION, not dropped silently', () => { const r = planBackfill({ repos: [repo('ktg-plugin-marketplace', [tag('pre-polyrepo-archive', 'Archive of the monorepo')], [])] }); assert.equal(r.create.length, 0); assert.equal(r.skip.length, 1); assert.equal(r.skip[0].excluded, true); assert.match(r.skip[0].reason, /archive/i); }); test('the exclusion register names the repo AND the tag — it can never blanket-skip a repo', () => { const entry = EXCLUDED_TAGS['ktg-plugin-marketplace']; assert.ok(entry, 'the archive tag exception must be registered'); assert.ok(entry['pre-polyrepo-archive'], 'the exception is keyed by TAG, so a future real release in that repo is still backfilled'); const r = planBackfill({ repos: [repo('ktg-plugin-marketplace', [tag('v9.0.0')], [])] }); assert.equal(r.create.length, 1, 'a normal tag in an excluded repo is still a release'); }); test('the summary reports the DENOMINATOR, so a run that verified nothing cannot read as clean', () => { const r = planBackfill({ repos: [repo('a', [tag('v1')], ['v1']), repo('b', [tag('v2')], []), repo('c', [])] }); assert.equal(r.total, 3); assert.equal(r.tagged, 2); });