codeowners-utils
Version:
Utilities for working with CODEOWNERS files
153 lines • 4.89 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const find_up_1 = __importDefault(require("find-up"));
const locate_path_1 = __importDefault(require("locate-path"));
const path_1 = __importDefault(require("path"));
const fs_1 = __importDefault(require("fs"));
const util_1 = __importDefault(require("util"));
const ignore_1 = __importDefault(require("ignore"));
const cross_spawn_1 = __importDefault(require("cross-spawn"));
let readFile = util_1.default.promisify(fs_1.default.readFile);
/**
* Parse a CODEOWNERS file into an array of entries (will be in reverse order
* of the file).
*/
function parse(str) {
let entries = [];
let lines = str.split("\n");
for (let line of lines) {
let [content, comment] = line.split("#");
let trimmed = content.trim();
if (trimmed === "")
continue;
let [pattern, ...owners] = trimmed.split(/\s+/);
entries.push({ pattern, owners });
}
return entries.reverse();
}
exports.parse = parse;
/**
* Standard locations to search for the CODEOWNERS file in priority order
* (Note: This comes from GitHub).
*/
exports.CODEOWNERS_PATHS = [
".github/CODEOWNERS",
"docs/CODEOWNERS",
"CODEOWNERS",
];
/**
* Find the path of the CODEOWNERS file from the current working directory.
*/
async function findOwnersPath(cwd) {
let git = await find_up_1.default(".git/", { cwd, type: "directory" });
if (!git)
return null;
let root = path_1.default.dirname(git);
let paths = exports.CODEOWNERS_PATHS.map(part => path_1.default.join(root, part));
let codeowners = await locate_path_1.default(paths, { cwd });
return codeowners || null;
}
exports.findOwnersPath = findOwnersPath;
/**
* Find, load, and parse the CODEOWNERS file (if it exists) from the current
* working directory.
*/
async function loadOwners(cwd) {
let file = await findOwnersPath(cwd);
if (!file)
return null;
let contents = await readFile(file, "utf-8");
let entries = parse(contents);
return entries;
}
exports.loadOwners = loadOwners;
/**
* Match a filename against a glob pattern (while respecting .gitignore rules)
*/
function matchPattern(filename, pattern) {
return ignore_1.default()
.add(pattern)
.ignores(filename);
}
exports.matchPattern = matchPattern;
/**
* Match a filename against CODEOWNERS entries to determine which (if any) it
* matches.
*/
function matchFile(filename, entries) {
for (let entry of entries) {
if (matchPattern(filename, entry.pattern)) {
return entry;
}
}
return null;
}
exports.matchFile = matchFile;
/**
* Given a set of files and CODEOWNERS entries, return the set of files which
* are not matched to any CODEOWNERS entries.
*/
function filterUnmatchedFiles(files, entries) {
return files.filter(file => !matchFile(file, entries));
}
exports.filterUnmatchedFiles = filterUnmatchedFiles;
/**
* Spawn a child process and convert it into a promise.
* @internal
*/
function spawn(cmd, args, opts, onData) {
return new Promise((resolve, reject) => {
let proc = cross_spawn_1.default(cmd, args, opts);
proc.stdout.on("data", onData);
proc.on("error", reject);
proc.on("close", code => {
if (code !== 0) {
reject(new Error(`"${cmd} ${args.join(" ")}" exited with non-zero exit code: ${code}`)); // prettier-ignore
}
else {
resolve();
}
});
});
}
/**
* Use git to list all files in a repository.
* @internal
*/
async function lsFiles(cwd, onFiles) {
await spawn("git", ["ls-files", "--others", "--exclude-standard"], { cwd, stdio: ["ignore", "pipe", "inherit"] }, data => {
let files = data
.toString()
.trim()
.split("\n");
onFiles(files);
});
}
/**
* Find all of the files in a git repository which are not matched by any code
* owners using a set of CODEOWNERS entries.
*/
async function findUnmatchedFilesFromEntries(entries, cwd) {
let unmatched = [];
await lsFiles(cwd, files => {
unmatched = unmatched.concat(filterUnmatchedFiles(files, entries));
});
return unmatched;
}
exports.findUnmatchedFilesFromEntries = findUnmatchedFilesFromEntries;
/**
* Find all of the files in a git repository which are not matched by any code
* owners.
*/
async function findUnmatchedFiles(cwd) {
let entries = await loadOwners(cwd);
if (!entries)
return null;
let unmatched = await findUnmatchedFilesFromEntries(entries, cwd);
return unmatched;
}
exports.findUnmatchedFiles = findUnmatchedFiles;
//# sourceMappingURL=codeowners-utils.js.map