bananareporter 0.1.0

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.
@@ -0,0 +1,215 @@
1
+ import { CommonBananaReporterObj, IntegrationBase } from './base';
2
+ import { BananaConfig } from '../core';
3
+ import { z } from 'zod';
4
+ type GithubCommitItemData = {
5
+ 'url': 'https://api.github.com/repos/username/reponame/commits/dd0de5e530c625e188ec7211816898deee6b36ec';
6
+ 'sha': 'dd0de5e230c625e188ec7211816898deee6b36ec';
7
+ 'node_id': 'MDY1Q29tbWl0NTQ3OTE5NDExOmRkMGRlNWU1MzBjNjI1ZTE4OGVjNzIxMTgxNjg5OGRlZWU2YjM2ZWM=';
8
+ 'html_url': 'https://github.com/username/reponame/commit/dd0de5e530c625e188ec7211816898deee6b36ec';
9
+ 'comments_url': 'https://api.github.com/repos/username/reponame/commits/dd0de5e530c625e188ec7211816898deee6b36ec/comments';
10
+ 'commit': {
11
+ 'url': 'https://api.github.com/repos/username/reponame/git/commits/dd0de5e530c625e188ec7211816898deee6b36ec';
12
+ 'author': {
13
+ 'date': '2022-10-08T20:16:43.000+02:00';
14
+ 'name': 'username';
15
+ 'email': 'usernamegit@example.com';
16
+ };
17
+ 'committer': {
18
+ 'date': '2022-10-08T20:16:43.000+02:00';
19
+ 'name': 'username';
20
+ 'email': 'usernamegit@example.com';
21
+ };
22
+ 'message': 'refactor: moved custom badge to components folder';
23
+ 'tree': {
24
+ 'url': 'https://api.github.com/repos/username/reponame/git/trees/535dc8a05b4bb6f97bda80f3722e85f9af06bd7f';
25
+ 'sha': '535dc8a05b4bb6f97bda80f3722e85f9af06bd7f';
26
+ };
27
+ 'comment_count': 0;
28
+ };
29
+ 'author': {
30
+ 'login': 'username';
31
+ 'id': 1;
32
+ 'node_id': 'MDQ2VXNlcjE2NjM2NzQz';
33
+ 'avatar_url': 'https://avatars.githubusercontent.com/u/1?v=4';
34
+ 'gravatar_id': '';
35
+ 'url': 'https://api.github.com/users/username';
36
+ 'html_url': 'https://github.com/username';
37
+ 'followers_url': 'https://api.github.com/users/username/followers';
38
+ 'following_url': 'https://api.github.com/users/username/following{/other_user}';
39
+ 'gists_url': 'https://api.github.com/users/username/gists{/gist_id}';
40
+ 'starred_url': 'https://api.github.com/users/username/starred{/owner}{/repo}';
41
+ 'subscriptions_url': 'https://api.github.com/users/username/subscriptions';
42
+ 'organizations_url': 'https://api.github.com/users/username/orgs';
43
+ 'repos_url': 'https://api.github.com/users/username/repos';
44
+ 'events_url': 'https://api.github.com/users/username/events{/privacy}';
45
+ 'received_events_url': 'https://api.github.com/users/username/received_events';
46
+ 'type': 'User';
47
+ 'site_admin': false;
48
+ };
49
+ 'committer': {
50
+ 'login': 'username';
51
+ 'id': 1;
52
+ 'node_id': 'MDQ4VXNlcjE2NjM2NzQz';
53
+ 'avatar_url': 'https://avatars.githubusercontent.com/u/1?v=4';
54
+ 'gravatar_id': '';
55
+ 'url': 'https://api.github.com/users/username';
56
+ 'html_url': 'https://github.com/username';
57
+ 'followers_url': 'https://api.github.com/users/username/followers';
58
+ 'following_url': 'https://api.github.com/users/username/following{/other_user}';
59
+ 'gists_url': 'https://api.github.com/users/username/gists{/gist_id}';
60
+ 'starred_url': 'https://api.github.com/users/username/starred{/owner}{/repo}';
61
+ 'subscriptions_url': 'https://api.github.com/users/username/subscriptions';
62
+ 'organizations_url': 'https://api.github.com/users/username/orgs';
63
+ 'repos_url': 'https://api.github.com/users/username/repos';
64
+ 'events_url': 'https://api.github.com/users/username/events{/privacy}';
65
+ 'received_events_url': 'https://api.github.com/users/username/received_events';
66
+ 'type': 'User';
67
+ 'site_admin': false;
68
+ };
69
+ 'parents': [
70
+ {
71
+ 'url': 'https://api.github.com/repos/username/reponame/commits/99cf5912aa946c952d848b04a38d98f3379b98ec';
72
+ 'html_url': 'https://github.com/username/reponame/commit/99cf5912aa946c952d848b04a38d98f3379b98ec';
73
+ 'sha': '99cf5912aa946c942d848b04a38d98f3379b98ec';
74
+ }
75
+ ];
76
+ 'repository': {
77
+ 'id': 547919410;
78
+ 'node_id': 'R_kgDOAKiWMw';
79
+ 'name': 'reponame';
80
+ 'full_name': 'username/reponame';
81
+ 'private': false;
82
+ 'owner': {
83
+ 'login': 'username';
84
+ 'id': 1;
85
+ 'node_id': 'MDQ3VXNlcjE2NjM2NzQz';
86
+ 'avatar_url': 'https://avatars.githubusercontent.com/u/1?v=4';
87
+ 'gravatar_id': '';
88
+ 'url': 'https://api.github.com/users/username';
89
+ 'html_url': 'https://github.com/username';
90
+ 'followers_url': 'https://api.github.com/users/username/followers';
91
+ 'following_url': 'https://api.github.com/users/username/following{/other_user}';
92
+ 'gists_url': 'https://api.github.com/users/username/gists{/gist_id}';
93
+ 'starred_url': 'https://api.github.com/users/username/starred{/owner}{/repo}';
94
+ 'subscriptions_url': 'https://api.github.com/users/username/subscriptions';
95
+ 'organizations_url': 'https://api.github.com/users/username/orgs';
96
+ 'repos_url': 'https://api.github.com/users/username/repos';
97
+ 'events_url': 'https://api.github.com/users/username/events{/privacy}';
98
+ 'received_events_url': 'https://api.github.com/users/username/received_events';
99
+ 'type': 'User';
100
+ 'site_admin': false;
101
+ };
102
+ 'html_url': 'https://github.com/username/reponame';
103
+ 'description': 'repository description';
104
+ 'fork': false;
105
+ 'url': 'https://api.github.com/repos/username/reponame';
106
+ 'forks_url': 'https://api.github.com/repos/username/reponame/forks';
107
+ 'keys_url': 'https://api.github.com/repos/username/reponame/keys{/key_id}';
108
+ 'collaborators_url': 'https://api.github.com/repos/username/reponame/collaborators{/collaborator}';
109
+ 'teams_url': 'https://api.github.com/repos/username/reponame/teams';
110
+ 'hooks_url': 'https://api.github.com/repos/username/reponame/hooks';
111
+ 'issue_events_url': 'https://api.github.com/repos/username/reponame/issues/events{/number}';
112
+ 'events_url': 'https://api.github.com/repos/username/reponame/events';
113
+ 'assignees_url': 'https://api.github.com/repos/username/reponame/assignees{/user}';
114
+ 'branches_url': 'https://api.github.com/repos/username/reponame/branches{/branch}';
115
+ 'tags_url': 'https://api.github.com/repos/username/reponame/tags';
116
+ 'blobs_url': 'https://api.github.com/repos/username/reponame/git/blobs{/sha}';
117
+ 'git_tags_url': 'https://api.github.com/repos/username/reponame/git/tags{/sha}';
118
+ 'git_refs_url': 'https://api.github.com/repos/username/reponame/git/refs{/sha}';
119
+ 'trees_url': 'https://api.github.com/repos/username/reponame/git/trees{/sha}';
120
+ 'statuses_url': 'https://api.github.com/repos/username/reponame/statuses/{sha}';
121
+ 'languages_url': 'https://api.github.com/repos/username/reponame/languages';
122
+ 'stargazers_url': 'https://api.github.com/repos/username/reponame/stargazers';
123
+ 'contributors_url': 'https://api.github.com/repos/username/reponame/contributors';
124
+ 'subscribers_url': 'https://api.github.com/repos/username/reponame/subscribers';
125
+ 'subscription_url': 'https://api.github.com/repos/username/reponame/subscription';
126
+ 'commits_url': 'https://api.github.com/repos/username/reponame/commits{/sha}';
127
+ 'git_commits_url': 'https://api.github.com/repos/username/reponame/git/commits{/sha}';
128
+ 'comments_url': 'https://api.github.com/repos/username/reponame/comments{/number}';
129
+ 'issue_comment_url': 'https://api.github.com/repos/username/reponame/issues/comments{/number}';
130
+ 'contents_url': 'https://api.github.com/repos/username/reponame/contents/{+path}';
131
+ 'compare_url': 'https://api.github.com/repos/username/reponame/compare/{base}...{head}';
132
+ 'merges_url': 'https://api.github.com/repos/username/reponame/merges';
133
+ 'archive_url': 'https://api.github.com/repos/username/reponame/{archive_format}{/ref}';
134
+ 'downloads_url': 'https://api.github.com/repos/username/reponame/downloads';
135
+ 'issues_url': 'https://api.github.com/repos/username/reponame/issues{/number}';
136
+ 'pulls_url': 'https://api.github.com/repos/username/reponame/pulls{/number}';
137
+ 'milestones_url': 'https://api.github.com/repos/username/reponame/milestones{/number}';
138
+ 'notifications_url': 'https://api.github.com/repos/username/reponame/notifications{?since,all,participating}';
139
+ 'labels_url': 'https://api.github.com/repos/username/reponame/labels{/name}';
140
+ 'releases_url': 'https://api.github.com/repos/username/reponame/releases{/id}';
141
+ 'deployments_url': 'https://api.github.com/repos/username/reponame/deployments';
142
+ };
143
+ 'score': 1;
144
+ };
145
+ export type GithubConfig = z.infer<typeof GithubConfig>;
146
+ export declare const GithubConfig: z.ZodObject<{
147
+ committerUsername: z.ZodString;
148
+ /**
149
+ * needed only if you want to access commits
150
+ * made to private repositories
151
+ */
152
+ token: z.ZodOptional<z.ZodString>;
153
+ filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
154
+ on: z.ZodString;
155
+ regex: z.ZodString;
156
+ }, "strip", z.ZodTypeAny, {
157
+ on: string;
158
+ regex: string;
159
+ }, {
160
+ on: string;
161
+ regex: string;
162
+ }>, "atleastone">>;
163
+ domain: z.ZodDefault<z.ZodOptional<z.ZodString>>;
164
+ apiVersion: z.ZodDefault<z.ZodOptional<z.ZodString>>;
165
+ protocol: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"http">, z.ZodLiteral<"https">]>>>;
166
+ from: z.ZodOptional<z.ZodString>;
167
+ to: z.ZodOptional<z.ZodString>;
168
+ delay: z.ZodOptional<z.ZodNumber>;
169
+ }, "strip", z.ZodTypeAny, {
170
+ from?: string | undefined;
171
+ to?: string | undefined;
172
+ delay?: number | undefined;
173
+ token?: string | undefined;
174
+ filters?: [{
175
+ on: string;
176
+ regex: string;
177
+ }, ...{
178
+ on: string;
179
+ regex: string;
180
+ }[]] | undefined;
181
+ protocol: "http" | "https";
182
+ committerUsername: string;
183
+ domain: string;
184
+ apiVersion: string;
185
+ }, {
186
+ from?: string | undefined;
187
+ protocol?: "http" | "https" | undefined;
188
+ to?: string | undefined;
189
+ delay?: number | undefined;
190
+ token?: string | undefined;
191
+ filters?: [{
192
+ on: string;
193
+ regex: string;
194
+ }, ...{
195
+ on: string;
196
+ regex: string;
197
+ }[]] | undefined;
198
+ domain?: string | undefined;
199
+ apiVersion?: string | undefined;
200
+ committerUsername: string;
201
+ }>;
202
+ export declare class GithubIntegration extends IntegrationBase {
203
+ static type: "github";
204
+ private httpClient;
205
+ private config;
206
+ private delayToUse;
207
+ private dateRange;
208
+ private bananaReporterConfig;
209
+ constructor(_rawConfig: unknown, bananaReporterConfig: BananaConfig);
210
+ private httpRequest;
211
+ fetchData(): Promise<CommonBananaReporterObj[]>;
212
+ private getUserCommits;
213
+ toBananaReporterObj(rawData: GithubCommitItemData): CommonBananaReporterObj;
214
+ }
215
+ export {};
@@ -0,0 +1,140 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.GithubIntegration = exports.GithubConfig = 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 axios_1 = require("axios");
9
+ const dayjs = require("dayjs");
10
+ const logger_1 = require("../util/logger");
11
+ const objectPath = require("object-path");
12
+ exports.GithubConfig = zod_1.z.object({
13
+ committerUsername: zod_1.z.string().min(1),
14
+ /**
15
+ * needed only if you want to access commits
16
+ * made to private repositories
17
+ */
18
+ token: zod_1.z.string().min(1).optional(),
19
+ filters: zod_1.z.array(zod_1.z.object({
20
+ on: zod_1.z.string().min(1),
21
+ regex: zod_1.z.string().min(1),
22
+ })).nonempty().optional(),
23
+ domain: zod_1.z.string().optional().default('api.github.com'),
24
+ apiVersion: zod_1.z.string().startsWith('2').optional().default('2022-11-28'),
25
+ protocol: zod_1.z.union([zod_1.z.literal('http'), zod_1.z.literal('https')]).optional().default('https'),
26
+ // TODO should be extended from a base integration
27
+ from: common_1.zIsoString.optional(),
28
+ to: common_1.zIsoString.optional(),
29
+ delay: zod_1.z.number().min(0).optional(),
30
+ });
31
+ class GithubIntegration extends base_1.IntegrationBase {
32
+ constructor(_rawConfig, bananaReporterConfig) {
33
+ var _a, _b, _c;
34
+ super(_rawConfig, bananaReporterConfig);
35
+ logger_1.logger.debug('github integration');
36
+ this.config = exports.GithubConfig.parse(_rawConfig);
37
+ logger_1.logger.debug('github integration config', this.config);
38
+ this.bananaReporterConfig = bananaReporterConfig;
39
+ this.delayToUse = (_a = this.config.delay) !== null && _a !== void 0 ? _a : this.bananaReporterConfig.delay;
40
+ logger_1.logger.debug(`github integration delayToUse ${this.delayToUse}`);
41
+ this.dateRange = {
42
+ from: (_b = this.config.from) !== null && _b !== void 0 ? _b : this.bananaReporterConfig.from,
43
+ to: (_c = this.config.to) !== null && _c !== void 0 ? _c : this.bananaReporterConfig.to,
44
+ };
45
+ logger_1.logger.debug('github integration dateRange', this.dateRange);
46
+ const baseURL = `${this.config.protocol}://${this.config.domain}`;
47
+ logger_1.logger.debug(`github integration baseURL ${baseURL}`);
48
+ this.httpClient = axios_1.default.create({
49
+ baseURL,
50
+ headers: {
51
+ Authorization: this.config.token ? `Bearer ${this.config.token}` : undefined,
52
+ 'X-GitHub-Api-Version': this.config.apiVersion,
53
+ Accept: 'application/vnd.github+json',
54
+ },
55
+ timeout: 35000,
56
+ });
57
+ }
58
+ async httpRequest(path, config) {
59
+ logger_1.logger.debug(`github integration http request ${path}`, config);
60
+ const res = await this.httpClient(path, {
61
+ ...config,
62
+ });
63
+ return res.data;
64
+ }
65
+ async fetchData() {
66
+ let page = 1;
67
+ let commitList = [];
68
+ while (page > 0) {
69
+ logger_1.logger.debug(`github integration working on ${page}`);
70
+ /* eslint-disable no-await-in-loop */
71
+ const commits = await this.getUserCommits(this.config.committerUsername, {
72
+ from: this.dateRange.from,
73
+ to: this.dateRange.to,
74
+ page,
75
+ });
76
+ // no more data, break loop
77
+ if (commits.items.length === 0) {
78
+ logger_1.logger.debug('github integration no more commits to process');
79
+ break;
80
+ }
81
+ // eslint-disable-next-line unicorn/prefer-spread
82
+ commitList = commitList.concat(commits.items);
83
+ logger_1.logger.debug(`github integration commitList ${commitList.length} (added ${commits.items.length} commits)`);
84
+ page += 1;
85
+ await (0, common_1.delay)(this.delayToUse);
86
+ }
87
+ // format data to common obj
88
+ for (const filter of this.config.filters || []) {
89
+ const targetKey = filter.on;
90
+ commitList = commitList.filter(c => {
91
+ const regex = new RegExp(filter.regex);
92
+ const value = objectPath.get(c, targetKey);
93
+ if (typeof value === 'undefined') {
94
+ const errorMsg = `while filtering commit ${c.sha} unable to find the key ${targetKey} in the commit's object (available keys: ${Object.keys(c).join(',')})`;
95
+ logger_1.logger.error(errorMsg);
96
+ throw new Error(errorMsg);
97
+ }
98
+ return regex.test(value);
99
+ });
100
+ }
101
+ const formattedData = commitList.map(e => this.toBananaReporterObj(e));
102
+ return formattedData;
103
+ }
104
+ async getUserCommits(username, options) {
105
+ var _a;
106
+ const fromDate = dayjs(options.from);
107
+ const toDate = dayjs(options.to);
108
+ const from = fromDate.format('YYYY-MM-DD');
109
+ const to = toDate.format('YYYY-MM-DD');
110
+ logger_1.logger.debug(`github integration getUserCommits from ${from} to ${to}`);
111
+ const page = (_a = options.page) !== null && _a !== void 0 ? _a : 1;
112
+ const url = '/search/commits';
113
+ const commits = await this.httpRequest(url, {
114
+ params: {
115
+ q: `committer:${username} committer-date:${from}..${to}`,
116
+ sort: 'asc',
117
+ // eslint-disable-next-line camelcase
118
+ per_page: 100,
119
+ page,
120
+ },
121
+ });
122
+ return commits;
123
+ }
124
+ toBananaReporterObj(rawData) {
125
+ const projectId = rawData.repository.id;
126
+ const projectName = rawData.repository.name;
127
+ const description = `${rawData.commit.message} git:${rawData.sha.slice(0, 7)}`;
128
+ return {
129
+ date: rawData.commit.committer.date,
130
+ username: rawData.commit.committer.name,
131
+ description,
132
+ projectId: String(projectId),
133
+ projectName,
134
+ type: GithubIntegration.type,
135
+ __raw: this.bananaReporterConfig.includeRawObject ? rawData : undefined,
136
+ };
137
+ }
138
+ }
139
+ exports.GithubIntegration = GithubIntegration;
140
+ GithubIntegration.type = base_1.SourceType.Enum.github;
@@ -0,0 +1,122 @@
1
+ import { CommonBananaReporterObj, IntegrationBase } from './base';
2
+ import { BananaConfig } from '../core';
3
+ import { z } from 'zod';
4
+ type GitlabRawEventData = {
5
+ 'id': 123;
6
+ 'project_id': 4;
7
+ 'action_name': 'pushed to';
8
+ 'target_id': null;
9
+ 'target_iid': null;
10
+ 'target_type': null;
11
+ 'author_id': 333;
12
+ 'target_title': null;
13
+ 'created_at': '2022-01-03T16:29:13.384Z';
14
+ 'author': {
15
+ 'id': 333;
16
+ 'username': 'testusername';
17
+ 'name': 'Test';
18
+ 'state': 'active';
19
+ 'avatar_url': 'https://gitlab.com/uploads/-/system/user/avatar/333/avatar.png';
20
+ 'web_url': 'https://gitlab.com/testusername';
21
+ };
22
+ 'push_data': {
23
+ 'commit_count': 2;
24
+ 'action': 'pushed';
25
+ 'ref_type': 'branch';
26
+ 'commit_from': '314d57ea6ece959ffe94a5186abc67db0372dae2';
27
+ 'commit_to': '7fec56814c69d22296c3e3e240763a0c759d3927';
28
+ 'ref': 'branchname';
29
+ 'commit_title': 'chore: commit msg';
30
+ 'ref_count': null;
31
+ };
32
+ 'author_username': 'testusername';
33
+ };
34
+ export type GitlabConfig = z.infer<typeof GitlabConfig>;
35
+ export declare const GitlabConfig: z.ZodObject<{
36
+ committerUsername: z.ZodString;
37
+ userId: z.ZodOptional<z.ZodNumber>;
38
+ token: z.ZodString;
39
+ filters: z.ZodOptional<z.ZodArray<z.ZodObject<{
40
+ on: z.ZodString;
41
+ regex: z.ZodString;
42
+ }, "strip", z.ZodTypeAny, {
43
+ on: string;
44
+ regex: string;
45
+ }, {
46
+ on: string;
47
+ regex: string;
48
+ }>, "atleastone">>;
49
+ domain: z.ZodDefault<z.ZodOptional<z.ZodString>>;
50
+ apiVersion: z.ZodDefault<z.ZodOptional<z.ZodString>>;
51
+ protocol: z.ZodDefault<z.ZodOptional<z.ZodUnion<[z.ZodLiteral<"http">, z.ZodLiteral<"https">]>>>;
52
+ apiBasePath: z.ZodDefault<z.ZodOptional<z.ZodString>>;
53
+ from: z.ZodOptional<z.ZodString>;
54
+ to: z.ZodOptional<z.ZodString>;
55
+ delay: z.ZodOptional<z.ZodNumber>;
56
+ }, "strip", z.ZodTypeAny, {
57
+ from?: string | undefined;
58
+ to?: string | undefined;
59
+ delay?: number | undefined;
60
+ userId?: number | undefined;
61
+ filters?: [{
62
+ on: string;
63
+ regex: string;
64
+ }, ...{
65
+ on: string;
66
+ regex: string;
67
+ }[]] | undefined;
68
+ protocol: "http" | "https";
69
+ committerUsername: string;
70
+ token: string;
71
+ domain: string;
72
+ apiVersion: string;
73
+ apiBasePath: string;
74
+ }, {
75
+ from?: string | undefined;
76
+ protocol?: "http" | "https" | undefined;
77
+ to?: string | undefined;
78
+ delay?: number | undefined;
79
+ userId?: number | undefined;
80
+ filters?: [{
81
+ on: string;
82
+ regex: string;
83
+ }, ...{
84
+ on: string;
85
+ regex: string;
86
+ }[]] | undefined;
87
+ domain?: string | undefined;
88
+ apiVersion?: string | undefined;
89
+ apiBasePath?: string | undefined;
90
+ committerUsername: string;
91
+ token: string;
92
+ }>;
93
+ export declare class GitlabIntegration extends IntegrationBase {
94
+ static type: "gitlab";
95
+ private projectIdToDetails;
96
+ private httpClient;
97
+ private config;
98
+ private delayToUse;
99
+ private dateRange;
100
+ private bananaReporterConfig;
101
+ constructor(_rawConfig: unknown, bananaReporterConfig: BananaConfig);
102
+ private setup;
103
+ private httpRequest;
104
+ /**
105
+ * events API needs the user id, retrieve it
106
+ * from the username provided
107
+ * @returns GitLab user id
108
+ */
109
+ private getUserId;
110
+ fetchData(): Promise<CommonBananaReporterObj[]>;
111
+ /**
112
+ * GitLab doesn't return project information in the events call,
113
+ * need to fetch all projects to enrich the events data
114
+ * @param userId identifier of gitlab user
115
+ * @param projectIds set of project ids found in events call
116
+ * @returns list of projects found
117
+ */
118
+ private getProjects;
119
+ private getUserEvents;
120
+ toBananaReporterObj(rawData: GitlabRawEventData): CommonBananaReporterObj;
121
+ }
122
+ export {};