Skip to content

Commit 103e919

Browse files
committed
Add first draft of group and subgroup querying
1 parent 52c4ca6 commit 103e919

File tree

13 files changed

+316
-39
lines changed

13 files changed

+316
-39
lines changed

gtt-report.js

Lines changed: 96 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ const moment = require('moment');
66
const Cli = require('./include/cli');
77
const Config = require('./include/file-config');
88
const Report = require('./models/report');
9+
const Owner = require('./models/owner');
10+
const ReportCollection = require('./models/reportCollection');
911

1012
const Output = {
1113
table: require('./output/table'),
@@ -31,9 +33,11 @@ program
3133
.option('-u --user <user>', 'only query times from the given user')
3234
.option('-m --milestone <milestone>', 'include issues from the given milestone')
3335
.option('-q --query <query>', 'query the given data types: issues, merge_requests', collect, null)
36+
.option('-e --type <type>', 'specify the query type: project, user, group')
3437
.option('-r --report <report>', 'include in the report: stats, issues, merge_requests, records', collect, null)
3538
.option('-o --output <output>', 'use the given output', collect, null)
3639
.option('-l --file <file>', 'save report to the given file')
40+
.option('--subgroups', 'include sub groups')
3741
.option('--include_by_labels <labels>', 'only include issues that have the given labels', collect, null)
3842
.option('--exclude_by_labels <labels>', 'exclude issues that have the given labels', collect, null)
3943
.option('--include_labels <labels>', 'only include the given labels in the report', collect, null)
@@ -82,7 +86,9 @@ config
8286
.set('quiet', program.quiet)
8387
.set('showWithoutTimes', program.show_without_times)
8488
.set('userColumns', program.user_columns)
85-
.set('proxy', program.proxy);
89+
.set('proxy', program.proxy)
90+
.set('type', program.type)
91+
.set('subgroups', program.subgroups);
8692

8793
Cli.quiet = config.get('quiet');
8894

@@ -109,8 +115,10 @@ if (!config.get('to').isValid()) {
109115
Cli.error(`TO is not a in valid ISO date format.`);
110116
}
111117

112-
// create report
113-
let report = new Report(config), output;
118+
// create stuff
119+
let reports = new ReportCollection(config),
120+
master = new Report(config),
121+
output;
114122

115123
// file prompt
116124
new Promise(resolve => {
@@ -123,37 +131,75 @@ new Promise(resolve => {
123131
}
124132
})
125133

126-
// get project
127-
.then(() => {
128-
Cli.list(`${Cli.look} Resolving project "${config.get('project')}"`);
129-
return report.getProject();
130-
})
131-
132-
// get members
134+
// get project(s)
133135
.then(() => new Promise((resolve, reject) => {
136+
Cli.list(`${Cli.look} Resolving "${config.get('project')}"`);
137+
let owner = new Owner(config);
138+
139+
switch (config.get('type')) {
140+
case 'project':
141+
let report = new Report(config);
142+
reports.push(report);
143+
report.getProject()
144+
.then(() => resolve())
145+
.catch(e => reject(e));
146+
break;
147+
148+
case 'group':
149+
owner.getGroup()
150+
.then(() => {
151+
if (!config.get('subgroups')) return new Promise(r => r());
152+
return owner.getSubGroups();
153+
})
154+
.then(() => owner.getProjectsByGroup()
155+
.then(() => {
156+
owner.projects.forEach(project => {
157+
reports.push(new Report(config, project));
158+
});
159+
Cli.out(`\r${Cli.look} Selected projects: ${owner.listProjects()}\n`);
160+
resolve();
161+
}))
162+
.catch(e => reject(e));
163+
break;
164+
}
165+
}))
166+
167+
// get members and user columns
168+
.then(() => new Promise(resolve => {
134169
if (!config.get('userColumns')) return resolve();
135170

136-
report.project.members()
137-
.then(() => {
138-
let columns = report.project.users.map(user => `time_${user}`);
171+
reports
172+
.forEach((report, done) => {
173+
report.project.members()
174+
.then(() => {
175+
let columns = report.project.users.map(user => `time_${user}`);
176+
177+
config.set('issueColumns', _.uniq(config.get('issueColumns').concat(columns)));
178+
config.set('mergeRequestColumns', _.uniq(config.get('mergeRequestColumns').concat(columns)));
139179

140-
config.set('issueColumns', _.uniq(config.get('issueColumns').concat(columns)));
141-
config.set('mergeRequestColumns', _.uniq(config.get('mergeRequestColumns').concat(columns)));
142-
resolve();
180+
done();
181+
})
182+
.catch(error => done(error));
143183
})
144-
.catch(error => reject(error));
184+
.catch(error => Cli.x(`could not fetch project.`, error))
185+
.then(() => resolve());
145186
}))
146187
.then(() => Cli.mark())
147-
.catch(error => Cli.x(`could not fetch project.`, error))
188+
.catch(error => Cli.x(`Could not resolve "${config.get('project')}"`, error))
148189

149190
// get issues
150191
.then(() => new Promise(resolve => {
151192
if (!config.get('query').includes('issues')) return resolve();
152193

153194
Cli.list(`${Cli.fetch} Fetching issues`);
154-
report.getIssues()
155-
.then(() => Cli.mark())
195+
196+
reports
197+
.forEach((report, done) => {
198+
report.getIssues()
199+
.then(() => done());
200+
})
156201
.catch(error => Cli.x(`could not fetch issues.`, error))
202+
.then(() => Cli.mark())
157203
.then(() => resolve());
158204
}))
159205

@@ -162,41 +208,61 @@ new Promise(resolve => {
162208
if (!config.get('query').includes('merge_requests')) return resolve();
163209

164210
Cli.list(`${Cli.fetch} Fetching merge requests`);
165-
report.getMergeRequests()
166-
.then(() => Cli.mark())
211+
212+
reports
213+
.forEach((report, done) => {
214+
report.getMergeRequests()
215+
.catch(error => done(error))
216+
.then(() => done());
217+
})
167218
.catch(error => Cli.x(`could not fetch merge requests.`, error))
219+
.then(() => Cli.mark())
220+
.then(() => resolve());
221+
}))
222+
223+
// merge reports
224+
.then(() => new Promise(resolve => {
225+
Cli.list(`${Cli.merge} Merging reports`);
226+
227+
reports
228+
.forEach((report, done) => {
229+
master.merge(report);
230+
done();
231+
})
232+
.catch(error => Cli.x(`could not merge reports.`, error))
233+
.then(() => Cli.mark())
168234
.then(() => resolve());
169235
}))
170236

171237
// process issues
172238
.then(() => new Promise(resolve => {
173-
if (!config.get('query').includes('issues') || report.issues.length === 0) return resolve();
239+
if (!config.get('query').includes('issues') || master.issues.length === 0) return resolve();
174240

175-
Cli.bar(`${Cli.process}️ Processing issues`, report.issues.length);
176-
report.processIssues(() => Cli.advance())
241+
Cli.bar(`${Cli.process}️ Processing issues`, master.issues.length);
242+
master.processIssues(() => Cli.advance())
177243
.then(() => Cli.mark())
178244
.catch(error => Cli.x(`could not process issues.`, error))
179245
.then(() => resolve());
180246
}))
181247

182248
// process merge requests
183249
.then(() => new Promise(resolve => {
184-
if (!config.get('query').includes('merge_requests') || report.mergeRequests.length === 0) return resolve();
250+
if (!config.get('query').includes('merge_requests') || master.mergeRequests.length === 0) return resolve();
185251

186-
Cli.bar(`${Cli.process}️️ Processing merge requests`, report.mergeRequests.length);
187-
report.processMergeRequests(() => Cli.advance())
252+
Cli.bar(`${Cli.process}️️ Processing merge requests`, master.mergeRequests.length);
253+
master.processMergeRequests(() => Cli.advance())
188254
.then(() => Cli.mark())
189255
.catch(error => Cli.x(`could not process merge requests.`, error))
190256
.then(() => resolve());
191257
}))
192258

193259
// make report
194260
.then(() => new Promise(resolve => {
195-
if (report.issues.length === 0 && report.mergeRequests.length === 0)
261+
if (master.issues.length === 0 && master.mergeRequests.length === 0)
196262
Cli.error('No issues or merge requests matched your criteria.');
197263

198264
Cli.list(`${Cli.output} Making report`);
199-
output = new Output[config.get('output')](config, report);
265+
output = new Output[config.get('output')](config, master);
200266
output.make();
201267
Cli.mark();
202268
resolve();

include/cli.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ class cli {
3838
return '📃';
3939
}
4040

41+
static get merge() {
42+
return '📎';
43+
}
44+
4145
static get party() {
4246
return '🥑';
4347
// return '🍺';

include/config.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ const Time = require('./../models/time');
44

55
const dates = ['from', 'to'];
66
const defaults = {
7+
type: 'project',
8+
subgroups: false,
79
url: 'https://gitlab.com/api/v4',
810
token: false,
911
proxy: false,

models/hasTimes.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ class hasTimes extends Base {
6969
let created = moment(note.created_at), match, subMatch, removeMatch;
7070

7171
if (
72-
// filter out user notes
72+
// filter out user notes
7373
!note.system ||
7474
// only include times by the configured user
7575
(this.config.get('user') && this.config.get('user') !== note.author.username) ||
@@ -87,6 +87,7 @@ class hasTimes extends Base {
8787
timeSpent += time.seconds;
8888
timeUsers[note.author.username] += time.seconds;
8989

90+
time.project_namespace = this.project_namespace;
9091
times.push(time);
9192

9293
done();

models/owner.js

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
const _ = require('underscore');
2+
3+
const Base = require('./base');
4+
const Color = require('colors');
5+
6+
/**
7+
* owner model
8+
*/
9+
class owner extends Base {
10+
constructor(config) {
11+
super(config);
12+
this.projects = [];
13+
this.groups = [];
14+
this.users = [];
15+
}
16+
17+
/**
18+
* list projects
19+
* @returns {string|*}
20+
*/
21+
listProjects() {
22+
return this.projects.map(p => p.path_with_namespace.bold.blue).join(',');
23+
}
24+
25+
/**
26+
* query and set the group
27+
* @returns {Promise}
28+
*/
29+
getGroup() {
30+
return new Promise((resolve, reject) => {
31+
this.get(`groups/?search=${encodeURIComponent(this.config.get('project'))}`)
32+
.then(group => {
33+
if (group.body.length === 0) return reject();
34+
let filtered = group.body.filter(u => u.path === this.config.get('project'));
35+
if (filtered.length === 0) return reject();
36+
this.groups = this.groups.concat(filtered);
37+
resolve();
38+
})
39+
.catch(e => reject(e));
40+
});
41+
}
42+
43+
/**
44+
* get sub groups
45+
* @returns {Promise}
46+
*/
47+
getSubGroups() {
48+
return new Promise((resolve, reject) => {
49+
this.get(`groups`)
50+
.then(groups => {
51+
if (groups.body.length === 0) return reject();
52+
let filtered = groups.body.filter(u => this.groups.map(g => g.id).indexOf(u.parent_id) !== -1);
53+
if (filtered.length === 0) return reject();
54+
this.groups = this.groups.concat(filtered);
55+
resolve();
56+
})
57+
.catch(e => reject(e));
58+
});
59+
}
60+
61+
// /**
62+
// * query and set the user
63+
// * @returns {Promise}
64+
// */
65+
// getUser() {
66+
// return new Promise((resolve, reject) => {
67+
// this.get(`users/?username=${encodeURIComponent(this.config.get('project'))}`)
68+
// .then(user => {
69+
// if (user.body.length === 0) return reject();
70+
// let filtered = user.body.filter(u => u.username === this.config.get('project'));
71+
// if (filtered.length === 0) return reject();
72+
// this.user = filtered[0];
73+
// resolve();
74+
// })
75+
// .catch(e => reject(e));
76+
// });
77+
// }
78+
//
79+
// /**
80+
// * query and set the projects by a user
81+
// * @returns {Promise}
82+
// */
83+
// getProjectsByUser() {
84+
// return new Promise((resolve, reject) => {
85+
// this.get(`users/${this.user.id}/projects`)
86+
// .then(projects => {
87+
// this.projects = this.projects.concat(projects.body);
88+
// resolve();
89+
// })
90+
// .catch(e => reject(e));
91+
// });
92+
// }
93+
94+
/**
95+
* query and set the projects by a user
96+
* @returns {Promise}
97+
*/
98+
getProjectsByGroup() {
99+
return this.parallel(this.groups, (group, done) => {
100+
this.get(`groups/${group.id}/projects`)
101+
.then(projects => {
102+
this.projects = this.projects.concat(projects.body);
103+
done();
104+
})
105+
.catch(e => done(e));
106+
});
107+
}
108+
}
109+
110+
module.exports = owner;

0 commit comments

Comments
 (0)