import { resolveCommit, GitSource, UNKNOWN_COMMIT } from '../../src/buildInfo'; // A source with nothing in it, so each test states only the files it cares // about. Every field is deliberately explicit — a missing `.git` is a normal // case here, not an edge one, and it has to be as easy to write as the others. function source(overrides: Partial = {}): GitSource { return { head: null, readRef: () => null, packedRefs: null, ...overrides }; } const SHA = '846646f7ec8ec0087ec1d89bcee8ab1865b57a7a'; describe('resolveCommit', () => { // What a fresh clone at a specific commit looks like — Portainer checks out // a ref, and a detached HEAD holds the SHA with no indirection at all. it('reads a detached HEAD directly', () => { expect(resolveCommit(source({ head: `${SHA}\n` }))).toBe('846646f'); }); // What a working checkout looks like, including this repository. it('follows a symbolic HEAD to its ref file', () => { expect( resolveCommit( source({ head: 'ref: refs/heads/main\n', readRef: (ref) => (ref === 'refs/heads/main' ? `${SHA}\n` : null) }) ) ).toBe('846646f'); }); // A ref that has been packed has no loose file. Without this the common case // of a freshly cloned repository resolves to unknown. it('falls back to packed-refs when the ref file is absent', () => { expect( resolveCommit( source({ head: 'ref: refs/heads/main\n', packedRefs: `# pack-refs with: peeled fully-peeled sorted\n${SHA} refs/heads/main\n` }) ) ).toBe('846646f'); }); it('picks the right entry out of a packed-refs with many', () => { const other = 'ffffffffffffffffffffffffffffffffffffffff'; expect( resolveCommit( source({ head: 'ref: refs/heads/main\n', packedRefs: `# pack-refs with: peeled fully-peeled sorted\n` + `${other} refs/heads/other\n` + `${SHA} refs/heads/main\n` + `${other} refs/tags/v1\n` }) ) ).toBe('846646f'); }); // Annotated tags write a second `^` line for the object the tag points // at. It is not a ref line and must not be mistaken for one. it('ignores peeled tag lines in packed-refs', () => { expect( resolveCommit( source({ head: 'ref: refs/tags/v1\n', packedRefs: `${SHA} refs/tags/v1\n` + `^ffffffffffffffffffffffffffffffffffffffff\n` }) ) ).toBe('846646f'); }); // Every failure below returns UNKNOWN rather than throwing. This runs during // a Docker build; a version stamp must never be the thing that stops a deploy. it('is unknown when there is no .git at all', () => { expect(resolveCommit(source())).toBe(UNKNOWN_COMMIT); }); it('is unknown when the ref resolves to nothing', () => { expect(resolveCommit(source({ head: 'ref: refs/heads/main\n' }))).toBe(UNKNOWN_COMMIT); }); it('is unknown when packed-refs does not mention the ref', () => { expect( resolveCommit( source({ head: 'ref: refs/heads/gone\n', packedRefs: `${SHA} refs/heads/main\n` }) ) ).toBe(UNKNOWN_COMMIT); }); // A HEAD that is neither a ref line nor a SHA. Returning it verbatim would // put arbitrary file contents on the admin screen. it('is unknown when HEAD is not something it recognises', () => { expect(resolveCommit(source({ head: 'not a sha and not a ref\n' }))).toBe(UNKNOWN_COMMIT); }); it('is unknown when HEAD is empty', () => { expect(resolveCommit(source({ head: ' \n' }))).toBe(UNKNOWN_COMMIT); }); });