Files

50 lines
1.8 KiB
TypeScript

import assert from "assert";
import { describe, it } from "mocha";
import * as fs from "fs";
// .gitmodules lives at the repo root, which is the cwd for `npm test`.
const GITMODULES = '.gitmodules';
interface Submodule { name: string, path: string, url: string }
function parseGitmodules(text: string): Submodule[] {
var out: Submodule[] = [];
var cur: any = null;
for (var line of text.split('\n')) {
var m;
if ((m = line.match(/^\s*\[\s*submodule\s+"([^"]+)"\s*\]/))) {
cur = { name: m[1] };
out.push(cur);
} else if (cur && (m = line.match(/^\s*(\w+)\s*=\s*(.*?)\s*$/))) {
cur[m[1]] = m[2];
}
}
return out;
}
// git resolves a relative URL ("./chips") against the superproject's remote,
// so "./chips" in a repo hosted at github.com/org/repo becomes
// github.com/org/repo/chips -- a 404 that breaks every CI clone.
function isRelativeURL(url: string) {
return url.startsWith('./') || url.startsWith('../') || !/^[a-z][a-z0-9+.-]*:\/\/|^[^@\/]+@[^:\/]+:./i.test(url);
}
describe('submodules', () => {
it('.gitmodules exists and lists submodules', function () {
if (!fs.existsSync(GITMODULES)) this.skip();
var subs = parseGitmodules(fs.readFileSync(GITMODULES, 'utf8'));
assert.ok(subs.length > 0, 'no submodules parsed from .gitmodules');
});
it('uses absolute URLs that do not depend on the superproject remote', function () {
if (!fs.existsSync(GITMODULES)) this.skip();
var subs = parseGitmodules(fs.readFileSync(GITMODULES, 'utf8'));
for (var sub of subs) {
assert.ok(sub.path, `${sub.name}: missing path`);
assert.ok(sub.url, `${sub.name}: missing url`);
assert.ok(!isRelativeURL(sub.url),
`${sub.name}: relative url "${sub.url}" resolves against the superproject remote and breaks CI; use e.g. https://github.com/8bitworkshop/${sub.name}`);
}
});
});