bananareporter 0.3.3 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -5
- package/dist/commands/run/index.js +7 -0
- package/dist/core/index.d.ts +15 -15
- package/dist/integrations/base.d.ts +1 -1
- package/dist/integrations/base.js +1 -1
- package/dist/integrations/git-cli.d.ts +38 -0
- package/dist/integrations/git-cli.js +97 -0
- package/oclif.manifest.json +3 -3
- package/package.json +3 -1
package/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
<img src="docs/assets/banana-reporter-logo.png" alt="Banana Reporter Logo" height="70px"/>
|
4
4
|
</p>
|
5
5
|
<h1 align="center">Banana Reporter</h1>
|
6
|
-
<p align="center">Create a report in CSV, JSON and JSONL from multiple sources (
|
6
|
+
<p align="center">Create a report in CSV, JSON and JSONL from multiple sources (GitLab, GitHub, Git local repository and todo.txt)</p>
|
7
7
|
|
8
8
|
<p align="center">
|
9
9
|
<a href="https://oclif.io"><img src="https://img.shields.io/badge/cli-oclif-brightgreen.svg" alt="oclif"/></a>
|
@@ -28,6 +28,7 @@
|
|
28
28
|
- **Sources Supported**
|
29
29
|
- [GitLab](./docs/sources/gitlab.md): commits
|
30
30
|
- [GitHub](./docs/sources/github.md): commits
|
31
|
+
- [Git CLI (local repository)](./docs/sources/git-cli.md): commits
|
31
32
|
- todo.txt: tasks
|
32
33
|
- **[Request a new source](https://github.com/nya1/bananareporter/issues/new?assignees=&labels=enhancement&template=new-source-request.md&title=)**
|
33
34
|
|
@@ -102,7 +103,7 @@ $ npm install -g bananareporter
|
|
102
103
|
$ bananareporter COMMAND
|
103
104
|
running command...
|
104
105
|
$ bananareporter (--version)
|
105
|
-
bananareporter/0.
|
106
|
+
bananareporter/0.4.3 linux-x64 node-v18.16.0
|
106
107
|
$ bananareporter --help [COMMAND]
|
107
108
|
USAGE
|
108
109
|
$ bananareporter COMMAND
|
@@ -149,9 +150,9 @@ FLAGS
|
|
149
150
|
--delay=<value> [default: 300] global delay in millisecons between http requests
|
150
151
|
--format=<option> (required) [default: json] output file format
|
151
152
|
<options: json|jsonl|csv>
|
152
|
-
--from=2023-
|
153
|
+
--from=2023-06-01 from date (ISO8601)
|
153
154
|
--include-raw-object include raw object in json/jsonl reporter output
|
154
|
-
--to=2023-
|
155
|
+
--to=2023-06-30 to date (ISO8601)
|
155
156
|
|
156
157
|
DESCRIPTION
|
157
158
|
Run report
|
@@ -161,5 +162,5 @@ EXAMPLES
|
|
161
162
|
report with 138 entries saved to ./bananareporter.json
|
162
163
|
```
|
163
164
|
|
164
|
-
_See code: [dist/commands/run/index.ts](https://github.com/nya1/bananareporter/blob/v0.
|
165
|
+
_See code: [dist/commands/run/index.ts](https://github.com/nya1/bananareporter/blob/v0.4.3/dist/commands/run/index.ts)_
|
165
166
|
<!-- commandsstop -->
|
@@ -15,6 +15,7 @@ const github_1 = require("../../integrations/github");
|
|
15
15
|
const todotxt_1 = require("../../integrations/todotxt");
|
16
16
|
const zod_1 = require("zod");
|
17
17
|
const node_path_1 = require("node:path");
|
18
|
+
const git_cli_1 = require("../../integrations/git-cli");
|
18
19
|
class Run extends core_1.Command {
|
19
20
|
static dateStringValidation(input) {
|
20
21
|
if (!dayjs(input).isValid()) {
|
@@ -56,6 +57,12 @@ class Run extends core_1.Command {
|
|
56
57
|
res = await integrationLoaded.fetchData();
|
57
58
|
break;
|
58
59
|
}
|
60
|
+
case base_1.SourceType.Enum['git-cli']: {
|
61
|
+
const integrationLoaded = new git_cli_1.GitCliIntegration(s, validatedConfig);
|
62
|
+
// eslint-disable-next-line no-await-in-loop
|
63
|
+
res = await integrationLoaded.fetchData();
|
64
|
+
break;
|
65
|
+
}
|
59
66
|
case base_1.SourceType.Enum['todo.txt']: {
|
60
67
|
const integrationLoaded = new todotxt_1.TodoTxtIntegration(s, validatedConfig);
|
61
68
|
// eslint-disable-next-line no-await-in-loop
|
package/dist/core/index.d.ts
CHANGED
@@ -23,11 +23,11 @@ export declare const BananaConfig: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
23
23
|
* where to fetch data
|
24
24
|
*/
|
25
25
|
sources: z.ZodArray<z.ZodObject<{
|
26
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
26
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
27
27
|
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
28
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
28
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
29
29
|
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
30
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
30
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
31
31
|
}, z.ZodTypeAny, "passthrough">>, "atleastone">;
|
32
32
|
}, "strip", z.ZodTypeAny, {
|
33
33
|
format: "json" | "csv" | "jsonl";
|
@@ -38,9 +38,9 @@ export declare const BananaConfig: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
38
38
|
configFileLocation: string;
|
39
39
|
delay: number;
|
40
40
|
sources: [z.objectOutputType<{
|
41
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
41
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
42
42
|
}, z.ZodTypeAny, "passthrough">, ...z.objectOutputType<{
|
43
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
43
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
44
44
|
}, z.ZodTypeAny, "passthrough">[]];
|
45
45
|
}, {
|
46
46
|
format: "json" | "csv" | "jsonl";
|
@@ -49,9 +49,9 @@ export declare const BananaConfig: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
49
49
|
to: string;
|
50
50
|
configFileLocation: string;
|
51
51
|
sources: [z.objectInputType<{
|
52
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
52
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
53
53
|
}, z.ZodTypeAny, "passthrough">, ...z.objectInputType<{
|
54
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
54
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
55
55
|
}, z.ZodTypeAny, "passthrough">[]];
|
56
56
|
includeRawObject?: boolean | undefined;
|
57
57
|
delay?: number | undefined;
|
@@ -64,9 +64,9 @@ export declare const BananaConfig: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
64
64
|
configFileLocation: string;
|
65
65
|
delay: number;
|
66
66
|
sources: [z.objectOutputType<{
|
67
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
67
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
68
68
|
}, z.ZodTypeAny, "passthrough">, ...z.objectOutputType<{
|
69
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
69
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
70
70
|
}, z.ZodTypeAny, "passthrough">[]];
|
71
71
|
}, {
|
72
72
|
format: "json" | "csv" | "jsonl";
|
@@ -75,9 +75,9 @@ export declare const BananaConfig: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
75
75
|
to: string;
|
76
76
|
configFileLocation: string;
|
77
77
|
sources: [z.objectInputType<{
|
78
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
78
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
79
79
|
}, z.ZodTypeAny, "passthrough">, ...z.objectInputType<{
|
80
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
80
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
81
81
|
}, z.ZodTypeAny, "passthrough">[]];
|
82
82
|
includeRawObject?: boolean | undefined;
|
83
83
|
delay?: number | undefined;
|
@@ -90,9 +90,9 @@ export declare const BananaConfig: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
90
90
|
configFileLocation: string;
|
91
91
|
delay: number;
|
92
92
|
sources: [z.objectOutputType<{
|
93
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
93
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
94
94
|
}, z.ZodTypeAny, "passthrough">, ...z.objectOutputType<{
|
95
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
95
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
96
96
|
}, z.ZodTypeAny, "passthrough">[]];
|
97
97
|
}, {
|
98
98
|
format: "json" | "csv" | "jsonl";
|
@@ -101,9 +101,9 @@ export declare const BananaConfig: z.ZodEffects<z.ZodEffects<z.ZodObject<{
|
|
101
101
|
to: string;
|
102
102
|
configFileLocation: string;
|
103
103
|
sources: [z.objectInputType<{
|
104
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
104
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
105
105
|
}, z.ZodTypeAny, "passthrough">, ...z.objectInputType<{
|
106
|
-
type: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
106
|
+
type: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
107
107
|
}, z.ZodTypeAny, "passthrough">[]];
|
108
108
|
includeRawObject?: boolean | undefined;
|
109
109
|
delay?: number | undefined;
|
@@ -1,6 +1,6 @@
|
|
1
1
|
import { z } from 'zod';
|
2
2
|
import { BananaConfig } from '../core';
|
3
|
-
export declare const SourceType: z.ZodEnum<["gitlab", "github", "todo.txt"]>;
|
3
|
+
export declare const SourceType: z.ZodEnum<["gitlab", "github", "todo.txt", "git-cli"]>;
|
4
4
|
export type SourceType = z.infer<typeof SourceType>;
|
5
5
|
export interface CommonBananaReporterObj {
|
6
6
|
id: string;
|
@@ -2,7 +2,7 @@
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
3
3
|
exports.IntegrationBase = exports.SourceType = void 0;
|
4
4
|
const zod_1 = require("zod");
|
5
|
-
exports.SourceType = zod_1.z.enum(['gitlab', 'github', 'todo.txt']);
|
5
|
+
exports.SourceType = zod_1.z.enum(['gitlab', 'github', 'todo.txt', 'git-cli']);
|
6
6
|
// TODO improve base integration
|
7
7
|
class IntegrationBase {
|
8
8
|
// eslint-disable-next-line no-useless-constructor, @typescript-eslint/no-empty-function
|
@@ -0,0 +1,38 @@
|
|
1
|
+
import { CommonBananaReporterObj, IntegrationBase } from './base';
|
2
|
+
import { BananaConfig } from '../core';
|
3
|
+
import { z } from 'zod';
|
4
|
+
export type GitCliConfig = z.infer<typeof GitCliConfig>;
|
5
|
+
export declare const GitCliConfig: z.ZodObject<{
|
6
|
+
path: z.ZodEffects<z.ZodString, string, string>;
|
7
|
+
authorUsername: z.ZodString;
|
8
|
+
from: z.ZodOptional<z.ZodString>;
|
9
|
+
to: z.ZodOptional<z.ZodString>;
|
10
|
+
}, "strip", z.ZodTypeAny, {
|
11
|
+
path: string;
|
12
|
+
authorUsername: string;
|
13
|
+
from?: string | undefined;
|
14
|
+
to?: string | undefined;
|
15
|
+
}, {
|
16
|
+
path: string;
|
17
|
+
authorUsername: string;
|
18
|
+
from?: string | undefined;
|
19
|
+
to?: string | undefined;
|
20
|
+
}>;
|
21
|
+
interface GitCliLog {
|
22
|
+
commit: string;
|
23
|
+
commitMessage: string;
|
24
|
+
author: string;
|
25
|
+
dateUnix: number;
|
26
|
+
projectName?: string;
|
27
|
+
branch: string;
|
28
|
+
}
|
29
|
+
export declare class GitCliIntegration extends IntegrationBase {
|
30
|
+
static type: "git-cli";
|
31
|
+
private config;
|
32
|
+
private dateRange;
|
33
|
+
private bananaReporterConfig;
|
34
|
+
constructor(_rawConfig: unknown, bananaReporterConfig: BananaConfig);
|
35
|
+
fetchData(): Promise<CommonBananaReporterObj[]>;
|
36
|
+
toBananaReporterObj(rawData: GitCliLog, _index?: number): CommonBananaReporterObj;
|
37
|
+
}
|
38
|
+
export {};
|
@@ -0,0 +1,97 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.GitCliIntegration = exports.GitCliConfig = void 0;
|
4
|
+
const base_1 = require("./base");
|
5
|
+
// import {Axios} from 'axios'
|
6
|
+
const common_1 = require("../util/common");
|
7
|
+
const zod_1 = require("zod");
|
8
|
+
const dayjs = require("dayjs");
|
9
|
+
const logger_1 = require("../util/logger");
|
10
|
+
const path = require("path");
|
11
|
+
const node_fs_1 = require("node:fs");
|
12
|
+
const shell = require("shelljs");
|
13
|
+
exports.GitCliConfig = zod_1.z.object({
|
14
|
+
// TODO support wildcard
|
15
|
+
path: zod_1.z
|
16
|
+
.string()
|
17
|
+
.min(1)
|
18
|
+
.refine(s => {
|
19
|
+
return path.resolve(s);
|
20
|
+
}),
|
21
|
+
authorUsername: zod_1.z.string().min(1),
|
22
|
+
from: common_1.zIsoString.optional(),
|
23
|
+
to: common_1.zIsoString.optional(),
|
24
|
+
});
|
25
|
+
class GitCliIntegration extends base_1.IntegrationBase {
|
26
|
+
constructor(_rawConfig, bananaReporterConfig) {
|
27
|
+
var _a, _b, _c;
|
28
|
+
super(_rawConfig, bananaReporterConfig);
|
29
|
+
logger_1.logger.debug('git-cli integration');
|
30
|
+
this.config = exports.GitCliConfig.parse(_rawConfig);
|
31
|
+
logger_1.logger.debug('git-cli integration config', this.config);
|
32
|
+
this.bananaReporterConfig = bananaReporterConfig;
|
33
|
+
this.dateRange = {
|
34
|
+
from: (_a = this.config.from) !== null && _a !== void 0 ? _a : this.bananaReporterConfig.from,
|
35
|
+
to: (_b = this.config.to) !== null && _b !== void 0 ? _b : this.bananaReporterConfig.to,
|
36
|
+
};
|
37
|
+
logger_1.logger.debug('git-cli integration dateRange', this.dateRange);
|
38
|
+
if (!((_c = (0, node_fs_1.lstatSync)(this.config.path)) === null || _c === void 0 ? void 0 : _c.isDirectory())) {
|
39
|
+
const errorMsg = `Unable to find path ${this.config.path} or not a valid directory`;
|
40
|
+
logger_1.logger.error(errorMsg);
|
41
|
+
throw new Error(errorMsg);
|
42
|
+
}
|
43
|
+
logger_1.logger.debug(`git-cli path ${this.config.path} exists`);
|
44
|
+
if (!shell.which('git')) {
|
45
|
+
throw new Error('git CLI required for git-cli source');
|
46
|
+
}
|
47
|
+
}
|
48
|
+
async fetchData() {
|
49
|
+
const fromDate = dayjs(this.dateRange.from).startOf('day');
|
50
|
+
const toDate = dayjs(this.dateRange.to).endOf('day');
|
51
|
+
// extract project name from directory
|
52
|
+
const directory = path.basename(this.config.path);
|
53
|
+
// execute git log
|
54
|
+
const gitLogCommand = shell.exec(`git -C ${this.config.path} --no-pager log --branches="*" --author="${this.config.authorUsername
|
55
|
+
// hash - author - date unix - commit message - branch
|
56
|
+
}" --reverse --no-merges --source --format='%H~~~~~%an~~~~~%at~~~~~%s~~~~~%S>%n%n' --after="${fromDate.toISOString()}" --before="${toDate.toISOString()}"`, {
|
57
|
+
silent: true,
|
58
|
+
});
|
59
|
+
if (gitLogCommand.code !== 0) {
|
60
|
+
throw new Error(`unable to execute git log to ${this.config.path}, output: ${gitLogCommand.stderr}`);
|
61
|
+
}
|
62
|
+
const gitLogJson = [];
|
63
|
+
if (gitLogCommand.stdout) {
|
64
|
+
for (const line of gitLogCommand.stdout.split('>\n\n')) {
|
65
|
+
const splitGit = line.split('~~~~~');
|
66
|
+
logger_1.logger.debug('git log', { splitGit });
|
67
|
+
if (splitGit.length !== 5) {
|
68
|
+
continue;
|
69
|
+
}
|
70
|
+
gitLogJson.push({
|
71
|
+
commit: splitGit[0].replace(/\n/g, ''),
|
72
|
+
author: splitGit[1],
|
73
|
+
dateUnix: Number(splitGit[2]),
|
74
|
+
commitMessage: splitGit[3],
|
75
|
+
branch: splitGit[4],
|
76
|
+
});
|
77
|
+
}
|
78
|
+
}
|
79
|
+
return gitLogJson.map((e, i) => {
|
80
|
+
// add project name
|
81
|
+
e.projectName = directory;
|
82
|
+
return this.toBananaReporterObj(e, i);
|
83
|
+
});
|
84
|
+
}
|
85
|
+
toBananaReporterObj(rawData, _index) {
|
86
|
+
return {
|
87
|
+
id: rawData.commit,
|
88
|
+
date: dayjs.unix(rawData.dateUnix).toISOString(),
|
89
|
+
description: rawData.commitMessage,
|
90
|
+
projectName: rawData.projectName,
|
91
|
+
type: GitCliIntegration.type,
|
92
|
+
__raw: this.bananaReporterConfig.includeRawObject ? rawData : undefined,
|
93
|
+
};
|
94
|
+
}
|
95
|
+
}
|
96
|
+
exports.GitCliIntegration = GitCliIntegration;
|
97
|
+
GitCliIntegration.type = base_1.SourceType.Enum['git-cli'];
|
package/oclif.manifest.json
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
{
|
2
|
-
"version": "0.
|
2
|
+
"version": "0.4.3",
|
3
3
|
"commands": {
|
4
4
|
"run": {
|
5
5
|
"id": "run",
|
@@ -26,7 +26,7 @@
|
|
26
26
|
"type": "option",
|
27
27
|
"description": "from date (ISO8601)",
|
28
28
|
"required": false,
|
29
|
-
"helpValue": "2023-
|
29
|
+
"helpValue": "2023-06-01",
|
30
30
|
"multiple": false
|
31
31
|
},
|
32
32
|
"to": {
|
@@ -34,7 +34,7 @@
|
|
34
34
|
"type": "option",
|
35
35
|
"description": "to date (ISO8601)",
|
36
36
|
"required": false,
|
37
|
-
"helpValue": "2023-
|
37
|
+
"helpValue": "2023-06-30",
|
38
38
|
"multiple": false,
|
39
39
|
"dependsOn": [
|
40
40
|
"from"
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "bananareporter",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.3",
|
4
4
|
"description": "Easily generate a report from multiple sources",
|
5
5
|
"author": "nya1",
|
6
6
|
"bin": {
|
@@ -26,6 +26,7 @@
|
|
26
26
|
"lodash": "^4.17.21",
|
27
27
|
"object-path": "^0.11.8",
|
28
28
|
"papaparse": "^5.4.1",
|
29
|
+
"shelljs": "^0.8.5",
|
29
30
|
"winston": "^3.8.2",
|
30
31
|
"zod": "^3.21.4"
|
31
32
|
},
|
@@ -38,6 +39,7 @@
|
|
38
39
|
"@types/node-fetch": "^2.6.2",
|
39
40
|
"@types/object-path": "^0.11.1",
|
40
41
|
"@types/papaparse": "^5.3.7",
|
42
|
+
"@types/shelljs": "^0.8.12",
|
41
43
|
"chai": "^4",
|
42
44
|
"eslint": "^7.32.0",
|
43
45
|
"eslint-config-oclif": "^4",
|