Skip to content

Commit

Permalink
run knowledge gap analysis applying the filtering for ignored files
Browse files Browse the repository at this point in the history
  • Loading branch information
anton-107 committed Jan 8, 2025
1 parent 6e261a7 commit fc755c4
Show file tree
Hide file tree
Showing 8 changed files with 111 additions and 59 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
.env
node_modules
.idea
.idea
.cache
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ CLI wrapper around https://github.com/anton-107/codebase-stats-collector
## Usage

```
npm run cli -- knowledge-gaps <PATH TO GIT REPO> --ignoreFiles /path/to/ignored/folder
npm run cli -- knowledge-gaps <PATH TO LOCAL GIT REPO> --ignoreFiles /path/to/ignored/folder
```
17 changes: 8 additions & 9 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,18 @@ import simpleImportSort from "eslint-plugin-simple-import-sort";
import globals from "globals";
import tseslint from "typescript-eslint";


/** @type {import('eslint').Linter.Config[]} */
export default [
{files: ["**/*.{ts,tsx}"]},
{files: ["**/*.ts"], languageOptions: {sourceType: "script"}},
{languageOptions: { globals: globals.node }},
{ files: ["**/*.{ts,tsx}"] },
{ files: ["**/*.ts"], languageOptions: { sourceType: "script" } },
{ languageOptions: { globals: globals.node } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
comments.recommended,
{
rules: {
"@eslint-community/eslint-comments/no-unused-disable": "error"
}
"@eslint-community/eslint-comments/no-unused-disable": "error",
},
},
{
plugins: {
Expand All @@ -36,6 +35,6 @@ export default [
"max-lines-per-function": ["error", 56],
"max-statements": ["error", 22],
"max-params": ["error", 3],
}
}
];
},
},
];
52 changes: 7 additions & 45 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,9 @@
import { cli, command } from "cleye";
import {GitRepository} from "codebase-stats-collector/dist/git-reader/git-repository.js";
import {getNumberOfContributorsPerFile} from "codebase-stats-collector/dist/stats/number-of-contributors-per-file.js";
import { Readable } from "stream";

export function log(arg1: string, arg2: object | string | null) {
if (arg2 === null) {
// eslint-disable-next-line no-console
console.log(arg1);
return;
}
// eslint-disable-next-line no-console
console.log(arg1, arg2);
}
import { collectKnowledgeGaps } from "./commands/knowledge-gaps.js";
import { log } from "./console.js";

export class CommandLineInterface {
export class CommandLineInterface {
constructor() {}
public run() {
cli({
Expand All @@ -31,45 +21,17 @@ export class CommandLineInterface {
},
async (argv) => {
const dir = argv._.pathToRepository;
log(
"Calculating files with least number of contributors",
dir,
);
log("Calculating files with least number of contributors", dir);
let ignoreFilesPattern: string | null = null;
if (argv.flags.ignoreFiles) {
// eslint-disable-next-line no-console
console.log(
"will ignore the following files in the output: ",
argv.flags.ignoreFiles,
);
ignoreFilesPattern = argv.flags.ignoreFiles;
}

// initialize repo
const repo = new GitRepository(dir);
const commitsStream = new Readable({
objectMode: true,
read() {
// do nothing.
},
});
const commitsWithChangedFiles = await repo.getListOfCommitsWithChangedFiles({
stream: commitsStream,
});
const contributorsPerFile = getNumberOfContributorsPerFile(
commitsWithChangedFiles
).filter((x) => x.isExistingFile);
const topKnowledgeGaps = contributorsPerFile
.sort((a, b) => {
if (a.contributorsNames.length === b.contributorsNames.length) {
return a.lastChange.getTime() - b.lastChange.getTime();
}
return a.contributorsNames.length - b.contributorsNames.length;
})
.slice(0, 50);

log(
"knowledge gaps (files with least number of contributors)",
topKnowledgeGaps
);
await collectKnowledgeGaps(dir, ignoreFilesPattern);
},
),
],
Expand Down
77 changes: 77 additions & 0 deletions src/commands/knowledge-gaps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { debug } from "codebase-stats-collector/dist/console/console.js";
import { SummaryDashboard } from "codebase-stats-collector/dist/dashboard/summary-dashboard.js";
import { GitRepository } from "codebase-stats-collector/dist/git-reader/git-repository.js";
import { ExpandedCommit } from "codebase-stats-collector/dist/interfaces.js";
import { getNumberOfContributorsPerFile } from "codebase-stats-collector/dist/stats/number-of-contributors-per-file.js";
import { Readable } from "stream";

import { log } from "../console.js";

function setupProgressStream(summaryDashboard: SummaryDashboard): Readable {
let commitsCounter = 0;

const commitsStream = new Readable({
objectMode: true,
read() {
// do nothing.
},
});
commitsStream.on("data", (commit: ExpandedCommit) => {
debug("Commit", commit);

commitsCounter += 1;
summaryDashboard.setCurrentProgress(commitsCounter, commit);
});
commitsStream.on("error", (err) => {
debug("error reading commits", { err });
});
commitsStream.on("end", () => {
debug("done reading commits", {});
});
commitsStream.on("close", () => {
debug("stream closed", {});
});
return commitsStream;
}

export async function collectKnowledgeGaps(
dir: string,
ignoreFiles: string | null,
): Promise<void> {
// initialize repo
const repo = new GitRepository(dir);

// initialize summary dashboard:
const summaryDashboard = new SummaryDashboard([]);
summaryDashboard.startProgress();

const commitsStream = setupProgressStream(summaryDashboard);

// number of total commits:
const commits = await repo.getListOfCommits();
summaryDashboard.setCommits(commits);

const commitsWithChangedFiles = await repo.getListOfCommitsWithChangedFiles({
stream: commitsStream,
});
const contributorsPerFile = getNumberOfContributorsPerFile(
commitsWithChangedFiles,
).filter((x) => x.isExistingFile);
let knowledgeGaps = contributorsPerFile.sort((a, b) => {
if (a.contributorsNames.length === b.contributorsNames.length) {
return a.lastChange.getTime() - b.lastChange.getTime();
}
return a.contributorsNames.length - b.contributorsNames.length;
});

if (ignoreFiles) {
knowledgeGaps = knowledgeGaps.filter((x) => !x.filePath.match(ignoreFiles));
}

const topKnowledgeGaps = knowledgeGaps.slice(0, 50);

log(
"knowledge gaps (files with least number of contributors)",
topKnowledgeGaps,
);
}
9 changes: 9 additions & 0 deletions src/console.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export function log(arg1: string, arg2: object | string | null) {
if (arg2 === null) {
// eslint-disable-next-line no-console
console.log(arg1);
return;
}
// eslint-disable-next-line no-console
console.log(arg1, arg2);
}
5 changes: 2 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { CommandLineInterface } from "./cli.js";


export function main() {
new CommandLineInterface().run();
new CommandLineInterface().run();
}
main();
main();
5 changes: 5 additions & 0 deletions tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -107,5 +107,10 @@
/* Completeness */
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
"skipLibCheck": true /* Skip type checking all .d.ts files. */
},
"ts-node": {
"experimentalSpecifierResolution": "node",
"transpileOnly": true,
"esm": true
}
}

0 comments on commit fc755c4

Please sign in to comment.