Merge pull request #22755 from backstage/rugvip/loc
scripts: add script to print code ownership
This commit is contained in:
Executable
+139
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env node
|
||||
/*
|
||||
* Copyright 2021 The Backstage Authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
const fs = require('fs-extra');
|
||||
const globby = require('globby');
|
||||
const sloc = require('sloc');
|
||||
const codeownersUtils = require('codeowners-utils');
|
||||
const { resolve: resolvePath } = require('path');
|
||||
|
||||
async function loadOwners(rootDir) {
|
||||
const codeowners = await codeownersUtils.loadOwners(rootDir);
|
||||
|
||||
return function getOwners(path) {
|
||||
const { owners } = codeownersUtils.matchFile(path, codeowners);
|
||||
if (
|
||||
owners.includes('@backstage/maintainers') &&
|
||||
owners.includes('@backstage/reviewers')
|
||||
) {
|
||||
return owners.filter(owner => owner !== '@backstage/reviewers');
|
||||
}
|
||||
return owners;
|
||||
};
|
||||
}
|
||||
|
||||
function createLocCounter(rootDir) {
|
||||
return async path => {
|
||||
const content = await fs.readFile(resolvePath(rootDir, path), 'utf-8');
|
||||
const stats = sloc(content, 'ts');
|
||||
return stats.source;
|
||||
};
|
||||
}
|
||||
|
||||
async function printOwnerDirectories(allFiles, getOwners, getLoc, onlyOwner) {
|
||||
const countByPath = new Map();
|
||||
|
||||
let total = 0;
|
||||
let totalShare = 0;
|
||||
for (const file of allFiles) {
|
||||
const owners = getOwners(file);
|
||||
const loc = await getLoc(file);
|
||||
|
||||
if (owners.includes(onlyOwner)) {
|
||||
const share = loc / owners.length;
|
||||
total += loc;
|
||||
totalShare += share;
|
||||
|
||||
const path = file.split('/').slice(0, 2).join('/');
|
||||
if ((await fs.stat(path)).isDirectory()) {
|
||||
countByPath.set(path, (countByPath.get(path) || 0) + share);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const sortedPaths = Array.from(countByPath)
|
||||
.map(([path, loc]) => ({ path, loc: Math.round(loc) }))
|
||||
.sort((a, b) => b.loc - a.loc);
|
||||
|
||||
const maxPathLen = Math.max(...sortedPaths.map(({ path }) => path.length));
|
||||
for (const { path, loc } of sortedPaths) {
|
||||
console.log(`${path.padEnd(maxPathLen)} ${loc}`);
|
||||
}
|
||||
console.log();
|
||||
console.log('Total share:', Math.round(totalShare));
|
||||
console.log('Total lines of code:', total);
|
||||
}
|
||||
|
||||
async function printAllOwners(allFiles, getOwners, getLoc) {
|
||||
const countByOwners = new Map();
|
||||
|
||||
let total = 0;
|
||||
for (const file of allFiles) {
|
||||
const owners = getOwners(file);
|
||||
const loc = await getLoc(file);
|
||||
|
||||
total += loc;
|
||||
const share = loc / owners.length;
|
||||
for (const owner of owners) {
|
||||
countByOwners.set(owner, (countByOwners.get(owner) || 0) + share);
|
||||
}
|
||||
}
|
||||
|
||||
const sortedOwners = Array.from(countByOwners)
|
||||
.map(([owner, loc]) => ({ owner, loc: Math.round(loc) }))
|
||||
.sort((a, b) => b.loc - a.loc);
|
||||
|
||||
const maxOwnerLen = Math.max(
|
||||
...sortedOwners.map(({ owner }) => owner.length),
|
||||
);
|
||||
for (const { owner, loc } of sortedOwners) {
|
||||
console.log(`${owner.padEnd(maxOwnerLen)} ${loc}`);
|
||||
}
|
||||
console.log();
|
||||
console.log('Total lines of code:', total);
|
||||
}
|
||||
|
||||
async function main(onlyOwner) {
|
||||
const rootDir = resolvePath(__dirname, '..');
|
||||
|
||||
const allFiles = await globby(
|
||||
[
|
||||
'**/*.{js,jsx,ts,tsx,mjs,cjs}',
|
||||
'!**/*.{generated,test}.*',
|
||||
'!**/{__fixtures__,fixtures}',
|
||||
],
|
||||
{
|
||||
cwd: rootDir,
|
||||
gitignore: true,
|
||||
followSymbolicLinks: false,
|
||||
},
|
||||
);
|
||||
|
||||
const getOwners = await loadOwners(rootDir);
|
||||
const getLoc = createLocCounter(rootDir);
|
||||
|
||||
if (onlyOwner) {
|
||||
await printOwnerDirectories(allFiles, getOwners, getLoc, onlyOwner);
|
||||
} else {
|
||||
await printAllOwners(allFiles, getOwners, getLoc);
|
||||
}
|
||||
}
|
||||
|
||||
main(...process.argv.slice(2)).catch(err => {
|
||||
console.error(err.stack);
|
||||
process.exit(1);
|
||||
});
|
||||
Reference in New Issue
Block a user