92 lines
4.8 KiB
JavaScript
92 lines
4.8 KiB
JavaScript
'use strict';
|
|
|
|
const { test } = require('node:test');
|
|
const assert = require('node:assert/strict');
|
|
const fs = require('node:fs');
|
|
const os = require('node:os');
|
|
const path = require('node:path');
|
|
const { execFileSync } = require('node:child_process');
|
|
const { getBuildId, isGitRevision } = require('../src/utils/buildId');
|
|
|
|
test('build ID resolves real Git checkouts, packed refs, worktrees, baked images and unknown sources', t => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ped-build-id-'));
|
|
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
const repo = path.join(root, 'repo');
|
|
fs.mkdirSync(repo);
|
|
const git = (...args) => execFileSync('git', ['-C', repo, ...args], {
|
|
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
|
|
}).trim();
|
|
git('init');
|
|
git('-c', 'user.name=Build Test', '-c', 'user.email=build@example.invalid',
|
|
'-c', 'commit.gpgsign=false', 'commit', '--allow-empty', '-m', 'test');
|
|
const sha = git('rev-parse', 'HEAD');
|
|
assert.equal(sha.length, 40);
|
|
assert.equal(getBuildId(repo), sha);
|
|
|
|
git('pack-refs', '--all', '--prune');
|
|
assert.equal(fs.existsSync(path.join(repo, '.git', git('symbolic-ref', 'HEAD'))), false);
|
|
assert.equal(getBuildId(repo), sha);
|
|
|
|
const worktree = path.join(root, 'worktree');
|
|
git('worktree', 'add', '--detach', worktree, 'HEAD');
|
|
assert.equal(fs.statSync(path.join(worktree, '.git')).isFile(), true);
|
|
assert.equal(getBuildId(worktree), sha);
|
|
git('checkout', '--detach', 'HEAD');
|
|
assert.equal(getBuildId(repo), sha);
|
|
|
|
// No accidental ancestor Git discovery for an unversioned source directory.
|
|
const plain = path.join(repo, 'plain');
|
|
fs.mkdirSync(plain);
|
|
assert.equal(getBuildId(plain), 'unknown');
|
|
const baked = 'b'.repeat(40);
|
|
fs.writeFileSync(path.join(plain, 'BUILD_ID'), baked + '\n');
|
|
assert.equal(getBuildId(plain), baked);
|
|
fs.writeFileSync(path.join(worktree, 'BUILD_ID'), baked);
|
|
assert.equal(getBuildId(worktree), baked, 'baked metadata takes precedence');
|
|
for (const invalid of ['unknown', '', 'abc1234', 'z'.repeat(40), '<script>', sha + '\r\nInjected: yes']) {
|
|
fs.writeFileSync(path.join(worktree, 'BUILD_ID'), invalid);
|
|
assert.equal(getBuildId(worktree), 'unknown');
|
|
assert.equal(isGitRevision(invalid), false);
|
|
}
|
|
assert.equal(isGitRevision(sha + '\n'), false);
|
|
assert.equal(isGitRevision(sha.toUpperCase()), false);
|
|
fs.writeFileSync(path.join(plain, '.git'), 'gitdir: /nonexistent/ped-build-test\n');
|
|
fs.unlinkSync(path.join(plain, 'BUILD_ID'));
|
|
assert.equal(getBuildId(plain), 'unknown');
|
|
});
|
|
|
|
test('manual build script passes the full revision to Compose without starting services', t => {
|
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'ped-build-script-'));
|
|
t.after(() => fs.rmSync(root, { recursive: true, force: true }));
|
|
fs.mkdirSync(path.join(root, 'scripts'));
|
|
fs.copyFileSync(path.join(__dirname, '../scripts/build-image.sh'), path.join(root, 'scripts/build-image.sh'));
|
|
const bin = path.join(root, 'bin');
|
|
fs.mkdirSync(bin);
|
|
fs.writeFileSync(path.join(bin, 'docker'), '#!/bin/sh\nprintf "%s\\n" "$GIT_REVISION" "$@"\n', { mode: 0o755 });
|
|
const build = (env = {}) => execFileSync('/bin/sh', [path.join(root, 'scripts/build-image.sh'), '--no-cache'], {
|
|
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
|
|
env: { ...process.env, PATH: bin + path.delimiter + process.env.PATH, GIT_REVISION: 'bad-override', ...env },
|
|
}).trim().split('\n');
|
|
assert.deepEqual(build(), ['unknown', 'compose', 'build', '--no-cache', 'pediatric-scribe']);
|
|
const git = (...args) => execFileSync('git', ['-C', root, ...args], {
|
|
encoding: 'utf8', stdio: ['ignore', 'pipe', 'pipe'],
|
|
}).trim();
|
|
git('init');
|
|
git('-c', 'user.name=Build Test', '-c', 'user.email=build@example.invalid',
|
|
'-c', 'commit.gpgsign=false', 'commit', '--allow-empty', '-m', 'test');
|
|
const sha = git('rev-parse', 'HEAD');
|
|
assert.deepEqual(build(), [sha, 'compose', 'build', '--no-cache', 'pediatric-scribe']);
|
|
|
|
const foreign = path.join(root, 'foreign');
|
|
git('init', foreign);
|
|
git('-C', foreign, '-c', 'user.name=Build Test', '-c', 'user.email=build@example.invalid',
|
|
'-c', 'commit.gpgsign=false', 'commit', '--allow-empty', '-m', 'foreign');
|
|
assert.notEqual(git('-C', foreign, 'rev-parse', 'HEAD'), sha);
|
|
const controls = { GIT_DIR: path.join(foreign, '.git'), GIT_WORK_TREE: foreign,
|
|
GIT_CONFIG_COUNT: '1', GIT_CONFIG_KEY_0: 'core.bare', GIT_CONFIG_VALUE_0: 'true' };
|
|
assert.deepEqual(build(controls), [sha, 'compose', 'build', '--no-cache', 'pediatric-scribe']);
|
|
// A Docker-only source archive still works without Git installed.
|
|
fs.rmSync(path.join(root, '.git'), { recursive: true });
|
|
fs.symlinkSync('/usr/bin/dirname', path.join(bin, 'dirname'));
|
|
assert.deepEqual(build({ ...controls, PATH: bin }), ['unknown', 'compose', 'build', '--no-cache', 'pediatric-scribe']);
|
|
});
|