Skip to content
This repository was archived by the owner on May 22, 2025. It is now read-only.

Commit 518e7e9

Browse files
authored
Merge pull request #49 from kriskbx/master
update dev
2 parents 631f578 + 088acaa commit 518e7e9

File tree

9 files changed

+134
-25
lines changed

9 files changed

+134
-25
lines changed

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
FROM node:8.2.1-alpine
22

3-
ENV GTT_VERSION 1.7.2
3+
ENV GTT_VERSION 1.7.4
44

55
RUN yarn global add --prefix /usr/local "gitlab-time-tracker@$GTT_VERSION"
66

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gitlab-time-tracker",
3-
"version": "1.7.2",
3+
"version": "1.7.4",
44
"description": "A command line interface for GitLabs time tracking feature.",
55
"bugs": {
66
"url": "https://github.com/kriskbx/gitlab-time-tracker/issues"

preview/icon.png

3.92 KB
Loading

readme.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# gtt
1+
# ![gtt](https://raw.githubusercontent.com/kriskbx/gitlab-time-tracker/master/preview/icon.png) gtt
22

33
[![npm](https://img.shields.io/npm/dt/gitlab-time-tracker.svg?style=flat-square)](https://www.npmjs.com/package/gitlab-time-tracker)
44
[![npm](https://img.shields.io/npm/v/gitlab-time-tracker.svg?style=flat-square)](https://www.npmjs.com/package/gitlab-time-tracker)
@@ -30,6 +30,7 @@ stored on GitLab.
3030
* [config file](#config-file)
3131
* [time format](#time-format)
3232
* [how to use gtt as a library](#how-to-use-gtt-as-a-library)
33+
* [dumps](#dumps)
3334
* [faqs](#faqs)
3435
* [contributing](#contributing)
3536
* [buy me a beer 🍺](#buy-me-a-beer)
@@ -72,7 +73,7 @@ token: 01234567891011
7273
7374
## updating
7475
75-
**Updating from version <= 1.5? Please [click here](https://github.com/kriskbx/gitlab-time-tracker/blob/master/upgrade.md)!**
76+
**Updating from version <= 1.5? Please [click here](https://github.com/kriskbx/gitlab-time-tracker/blob/master/UPGRADE.md)!**
7677
7778
Update gtt via yarn:
7879
@@ -796,6 +797,10 @@ report.mergeRequests.forEach(mergeRequest => {
796797
});
797798
```
798799

800+
## dumps
801+
802+
Starting with 1.7.4 gtt can dump the results of all API requests within a report and use it on another machine without access to the GitLab instance itself. This is very useful for debugging purposes. If you stumble upon a bug which could be unique to your set of data, please rerun the report with these options to save a dump to the given file: `--output=dump --file=/path/dump.json` Check your dump for sensitive information and provide it when asked.
803+
799804
## faqs
800805

801806
#### What is the difference between 'total spent' and 'spent'?

src/gtt-report.js

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@ const Output = {
1313
table: require('./output/table'),
1414
csv: require('./output/csv'),
1515
pdf: require('./output/pdf'),
16-
markdown: require('./output/markdown')
16+
markdown: require('./output/markdown'),
17+
dump: require('./output/dump')
1718
};
1819

1920
// this collects options
@@ -56,12 +57,24 @@ program
5657
.option('--check_token', 'check the access token')
5758
.option('--show_without_times', 'show issues/merge requests without time records')
5859
.option('-p --proxy <proxy>', 'use a proxy server with the given url')
60+
.option('--from_dump <file>', 'instead of querying gitlab, use data from the given dump file')
5961
.parse(process.argv);
6062

6163
// init helpers
6264
let config = new Config(process.cwd());
6365
let cli = new Cli(program.args);
6466

67+
// if using a dump, set the config accordingly
68+
if (program.from_dump && fs.existsSync(program.from_dump)) {
69+
let data = JSON.parse(fs.readFileSync(program.from_dump));
70+
71+
if (data.data) _.each(data.data, (v, i) => {
72+
config.set(i, v);
73+
});
74+
75+
if (data._dump) config.dump = data._dump;
76+
}
77+
6578
// overwrite config with args and opts
6679
config
6780
.set('project', cli.project())
@@ -94,12 +107,12 @@ config
94107
.set('type', program.type)
95108
.set('subgroups', program.subgroups)
96109
.set('_verbose', program.verbose)
97-
.set('_checkToken', program.check_token);
110+
.set('_checkToken', program.check_token)
111+
.set('_createDump', program.output === 'dump');
98112

99113
Cli.quiet = config.get('quiet');
100114
Cli.verbose = config.get('_verbose');
101115

102-
103116
// create stuff
104117
let reports = new ReportCollection(config),
105118
master = new Report(config),

src/gtt.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env node
22

3-
const version = '1.7.2';
3+
const version = '1.7.4';
44
const program = require('commander');
55

66
program

src/models/base.js

Lines changed: 65 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
const request = require('request-promise-native');
22
const url = require('url');
33
const async = require('async');
4+
const crypto = require('crypto');
45

56
/**
67
* base model
@@ -29,17 +30,25 @@ class base {
2930
* @returns {*}
3031
*/
3132
post(path, data) {
33+
let key = base.createDumpKey(path, data);
34+
if (this.config.dump) return this.getDump(key);
35+
3236
data.private_token = this.token;
3337

34-
return request.post(`${this.url}${path}`, {
35-
json: true,
36-
body: data,
37-
insecure: this._insecure,
38-
proxy: this._proxy,
39-
resolveWithFullResponse: true,
40-
headers: {
41-
'PRIVATE-TOKEN': this.token
42-
}
38+
return new Promise((resolve, reject) => {
39+
request.post(`${this.url}${path}`, {
40+
json: true,
41+
body: data,
42+
insecure: this._insecure,
43+
proxy: this._proxy,
44+
resolveWithFullResponse: true,
45+
headers: {
46+
'PRIVATE-TOKEN': this.token
47+
}
48+
}).then(response => {
49+
if (this.config.get('_createDump')) this.setDump(response, key);
50+
resolve(response);
51+
}).catch(e => reject(e));
4352
});
4453
}
4554

@@ -51,17 +60,25 @@ class base {
5160
* @returns {Promise}
5261
*/
5362
get(path, page = 1, perPage = this._perPage) {
63+
let key = base.createDumpKey(path, page, perPage);
64+
if (this.config.dump) return this.getDump(key);
65+
5466
path += (path.includes('?') ? '&' : '?') + `private_token=${this.token}`;
5567
path += `&page=${page}&per_page=${perPage}`;
5668

57-
return request(`${this.url}${path}`, {
58-
json: true,
59-
insecure: this._insecure,
60-
proxy: this._proxy,
61-
resolveWithFullResponse: true,
62-
headers: {
63-
'PRIVATE-TOKEN': this.token
64-
}
69+
return new Promise((resolve, reject) => {
70+
request(`${this.url}${path}`, {
71+
json: true,
72+
insecure: this._insecure,
73+
proxy: this._proxy,
74+
resolveWithFullResponse: true,
75+
headers: {
76+
'PRIVATE-TOKEN': this.token
77+
}
78+
}).then(response => {
79+
if (this.config.get('_createDump')) this.setDump(response, key);
80+
resolve(response);
81+
}).catch(e => reject(e));
6582
});
6683
}
6784

@@ -124,6 +141,29 @@ class base {
124141
}, runners);
125142
}
126143

144+
/**
145+
* save the given response to dump
146+
* @param response
147+
* @param key
148+
*/
149+
setDump(response, key) {
150+
if (!this.config._dump) this.config._dump = {};
151+
152+
this.config._dump[key] = {
153+
headers: response.headers,
154+
body: response.body
155+
};
156+
}
157+
158+
/**
159+
* get from dump
160+
* @param key
161+
* @returns {Promise}
162+
*/
163+
getDump(key) {
164+
return new Promise(r => r(this.config.dump[key]));
165+
}
166+
127167
/**
128168
* create a task list to get all pages from
129169
* the given path
@@ -142,6 +182,14 @@ class base {
142182

143183
return tasks;
144184
}
185+
186+
/**
187+
* create a key representing a request
188+
* @param args
189+
*/
190+
static createDumpKey(...args) {
191+
return crypto.createHash('md5').update(JSON.stringify(args)).digest("hex");
192+
}
145193
}
146194

147195
module.exports = base;

src/output/base.js

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,9 +120,22 @@ class base {
120120
totalEstimate += parseInt(issue.stats.time_estimate);
121121
totalSpent += parseInt(issue.stats.total_time_spent);
122122
});
123+
124+
this.report[type].sort((a, b) => {
125+
if (a.iid === b.iid) return 0;
126+
127+
return (a.iid - b.iid) < 0 ? 1 : -1;
128+
});
123129
});
124130

131+
125132
this.times = times;
133+
this.times.sort((a, b) => {
134+
if (a.date.isSame(b.date)) return 0;
135+
136+
return a.date.isBefore(b.date) ? 1 : -1;
137+
});
138+
126139
this.users = _.mapObject(users, user => this.config.toHumanReadable(user, 'stats'));
127140
this.projects = _.mapObject(projects, project => this.config.toHumanReadable(project, 'stats'));
128141
this.stats = {

src/output/dump.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const Base = require('./base');
2+
const Report = require('../models/report');
3+
4+
class dump extends Base {
5+
constructor(config, report) {
6+
super(config, report);
7+
8+
config.set('url', null, true);
9+
config.set('token', null, true);
10+
config.set('_createDump', false);
11+
config.workDir = null;
12+
config.cache = null;
13+
14+
this.write(JSON.stringify(config));
15+
}
16+
17+
makeStats() {
18+
}
19+
20+
makeIssues() {
21+
}
22+
23+
makeMergeRequests() {
24+
}
25+
26+
makeRecords() {
27+
}
28+
}
29+
30+
module.exports = dump;

0 commit comments

Comments
 (0)