Merge pull request #22755 from backstage/rugvip/loc

scripts: add script to print code ownership
This commit is contained in:
Patrik Oldsberg
2024-02-06 13:07:41 +01:00
committed by GitHub
3 changed files with 160 additions and 5 deletions
+139
View File
@@ -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);
});