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 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 (e.g. GitLab, GitHub, todo.txt etc.)</p>
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.3.3 linux-x64 node-v18.15.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-03-01 from date (ISO8601)
153
+ --from=2023-06-01 from date (ISO8601)
153
154
  --include-raw-object include raw object in json/jsonl reporter output
154
- --to=2023-03-31 to date (ISO8601)
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.3.3/dist/commands/run/index.ts)_
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
@@ -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'];
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "0.3.3",
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-03-01",
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-03-31",
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.3",
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",