From 15a3d25cc571e3b4822e8d17ec5812ba310152cd Mon Sep 17 00:00:00 2001 From: kriskbx Date: Thu, 12 Oct 2017 16:29:32 +0200 Subject: [PATCH 1/8] Add time format ceiling --- readme.md | 17 +++++++++++++++++ src/gtt-log.js | 4 +--- src/models/time.js | 8 ++++++++ 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/readme.md b/readme.md index 6c41e93..3253ffd 100755 --- a/readme.md +++ b/readme.md @@ -717,6 +717,23 @@ timeFormat: "[%sign][%minutes_overall]" 1095 ``` +##### `[%hours_overall:2]`, `[%days_overall:3]` + +You can ceil any float value by adding the number of decimals to keep separated with a `:`. + +**Example config:** + +```yaml +timeFormat: "[%sign][%hours_overall:2]" +``` + +**Example outputs:** + +```shell +0,51 +18,25 +``` + ## how to use gtt as a library Add as a dependency using yarn: diff --git a/src/gtt-log.js b/src/gtt-log.js index cc7547c..16c6b41 100755 --- a/src/gtt-log.js +++ b/src/gtt-log.js @@ -18,9 +18,7 @@ Cli.verbose = program.verbose; let config = new Config(__dirname).set('hoursPerDay', program.hours_per_day), tasks = new Tasks(config), - timeFormat = config.set('timeFormat', program.time_format).get('timeFormat'); - -timeFormat = _.isObject(timeFormat) && timeFormat['log'] ? timeFormat['log'] : timeFormat; + timeFormat = config.set('timeFormat', program.time_format).get('timeFormat', 'log'); function toHumanReadable(input) { return Time.toHumanReadable(Math.ceil(input), config.get('hoursPerDay'), timeFormat); diff --git a/src/models/time.js b/src/models/time.js index 7ecb7b2..2c37046 100755 --- a/src/models/time.js +++ b/src/models/time.js @@ -5,6 +5,7 @@ const defaultTimeFormat = '[%sign][%days>d ][%hours>h ][%minutes>m ][%seconds>s] const mappings = ['complete', 'sign', 'weeks', 'days', 'hours', 'minutes', 'seconds']; const regex = /^(?:([-])\s*)?(?:(\d+)w\s*)?(?:(\d+)d\s*)?(?:(\d+)h\s*)?(?:(\d+)m\s*)?(?:(\d+)s\s*)?$/; const conditionalRegex = /(\[\%([^\>\]]*)\>([^\]]*)\])/ig; +const roundedRegex = /(\[\%([^\>\]]*)\:([^\]]*)\])/ig; const defaultRegex = /(\[\%([^\]]*)\])/ig; Number.prototype.padLeft = function (n, str) { @@ -127,6 +128,13 @@ class time { output = output.replace(match[0], inserts[match[2]] > 0 ? inserts[match[2]] + match[3] : ''); } + // rounded + while ((match = roundedRegex.exec(format)) !== null) { + if (match.index === roundedRegex.lastIndex) roundedRegex.lastIndex++; + // console.log(match); process.exit(); + output = output.replace(match[0], Math.ceil(inserts[match[2]] * Math.pow(10, match[3])) / Math.pow(10, match[3])); + } + // default format = output; while ((match = defaultRegex.exec(format)) !== null) { From 17bec44e5254255f2cf29fb674afb9f1b17369c0 Mon Sep 17 00:00:00 2001 From: kriskbx Date: Sat, 14 Oct 2017 12:51:13 +0200 Subject: [PATCH 2/8] Add rounded conditionals to time format --- src/models/time.js | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/src/models/time.js b/src/models/time.js index 2c37046..d30ed61 100755 --- a/src/models/time.js +++ b/src/models/time.js @@ -6,6 +6,7 @@ const mappings = ['complete', 'sign', 'weeks', 'days', 'hours', 'minutes', 'seco const regex = /^(?:([-])\s*)?(?:(\d+)w\s*)?(?:(\d+)d\s*)?(?:(\d+)h\s*)?(?:(\d+)m\s*)?(?:(\d+)s\s*)?$/; const conditionalRegex = /(\[\%([^\>\]]*)\>([^\]]*)\])/ig; const roundedRegex = /(\[\%([^\>\]]*)\:([^\]]*)\])/ig; +const conditionalSimpleRegex = /(.*)\>(.*)/ig; const defaultRegex = /(\[\%([^\]]*)\])/ig; Number.prototype.padLeft = function (n, str) { @@ -96,7 +97,7 @@ class time { * @returns {string} */ static toHumanReadable(input, hoursPerDay = 8, format = time.defaultTimeFormat) { - let sign = parseInt(input) < 0 ? '-' : '', output = format, match; + let sign = parseInt(input) < 0 ? '-' : '', output = format, match, conditionalMatch; input = Math.abs(input); let secondsInADay = 60 * 60 * hoursPerDay; @@ -122,19 +123,25 @@ class time { inserts.seconds = ((input % secondsInADay) % secondsInAnHour) % secondsInAMinute; inserts.Seconds = inserts.seconds.padLeft(2, 0); + // rounded + while ((match = roundedRegex.exec(format)) !== null) { + if (match.index === roundedRegex.lastIndex) roundedRegex.lastIndex++; + let time; + + if ((conditionalMatch = conditionalSimpleRegex.exec(match[3])) !== null) { + match[3] = conditionalMatch[1] + } + + time = Math.ceil(inserts[match[2]] * Math.pow(10, match[3])) / Math.pow(10, match[3]); + output = output.replace(match[0], time !== 0 && conditionalMatch ? time + conditionalMatch[2] : ''); + } + // conditionals while ((match = conditionalRegex.exec(format)) !== null) { if (match.index === conditionalRegex.lastIndex) conditionalRegex.lastIndex++; output = output.replace(match[0], inserts[match[2]] > 0 ? inserts[match[2]] + match[3] : ''); } - // rounded - while ((match = roundedRegex.exec(format)) !== null) { - if (match.index === roundedRegex.lastIndex) roundedRegex.lastIndex++; - // console.log(match); process.exit(); - output = output.replace(match[0], Math.ceil(inserts[match[2]] * Math.pow(10, match[3])) / Math.pow(10, match[3])); - } - // default format = output; while ((match = defaultRegex.exec(format)) !== null) { From 3617da5e3b1215c14e84651af304d5134cd94c8b Mon Sep 17 00:00:00 2001 From: kriskbx Date: Thu, 19 Oct 2017 11:07:36 +0200 Subject: [PATCH 3/8] Fix missing time when there's no conditional in the ceiling function --- src/models/time.js | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/models/time.js b/src/models/time.js index d30ed61..7bd267e 100755 --- a/src/models/time.js +++ b/src/models/time.js @@ -6,7 +6,7 @@ const mappings = ['complete', 'sign', 'weeks', 'days', 'hours', 'minutes', 'seco const regex = /^(?:([-])\s*)?(?:(\d+)w\s*)?(?:(\d+)d\s*)?(?:(\d+)h\s*)?(?:(\d+)m\s*)?(?:(\d+)s\s*)?$/; const conditionalRegex = /(\[\%([^\>\]]*)\>([^\]]*)\])/ig; const roundedRegex = /(\[\%([^\>\]]*)\:([^\]]*)\])/ig; -const conditionalSimpleRegex = /(.*)\>(.*)/ig; +const conditionalSimpleRegex = /([0-9]*)\>(.*)/ig; const defaultRegex = /(\[\%([^\]]*)\])/ig; Number.prototype.padLeft = function (n, str) { @@ -97,7 +97,7 @@ class time { * @returns {string} */ static toHumanReadable(input, hoursPerDay = 8, format = time.defaultTimeFormat) { - let sign = parseInt(input) < 0 ? '-' : '', output = format, match, conditionalMatch; + let sign = parseInt(input) < 0 ? '-' : '', output = format, match; input = Math.abs(input); let secondsInADay = 60 * 60 * hoursPerDay; @@ -126,14 +126,15 @@ class time { // rounded while ((match = roundedRegex.exec(format)) !== null) { if (match.index === roundedRegex.lastIndex) roundedRegex.lastIndex++; - let time; + let time, conditionalMatch, decimals = match[3]; - if ((conditionalMatch = conditionalSimpleRegex.exec(match[3])) !== null) { - match[3] = conditionalMatch[1] + if ((conditionalMatch = conditionalSimpleRegex.exec(decimals)) !== null) { + decimals = conditionalMatch[1] } - time = Math.ceil(inserts[match[2]] * Math.pow(10, match[3])) / Math.pow(10, match[3]); - output = output.replace(match[0], time !== 0 && conditionalMatch ? time + conditionalMatch[2] : ''); + decimals = parseInt(decimals); + time = Math.ceil(inserts[match[2]] * Math.pow(10, decimals)) / Math.pow(10, decimals); + output = output.replace(match[0], time !== 0 && conditionalMatch ? time + conditionalMatch[2] : time); } // conditionals From 6cf60b871eb26ca0f9597480ebb11adffac43ec3 Mon Sep 17 00:00:00 2001 From: kriskbx Date: Thu, 19 Oct 2017 11:10:51 +0200 Subject: [PATCH 4/8] Release 1.7.0 --- Dockerfile | 2 +- package.json | 2 +- src/gtt.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Dockerfile b/Dockerfile index 605215f..17f1e79 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ FROM node:8.2.1-alpine -ENV GTT_VERSION 1.6.11 +ENV GTT_VERSION 1.7.0 RUN yarn global add --prefix /usr/local "gitlab-time-tracker@$GTT_VERSION" diff --git a/package.json b/package.json index d423b78..ddf9b53 100755 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "gitlab-time-tracker", - "version": "1.6.11", + "version": "1.7.0", "description": "A command line interface for GitLabs time tracking feature.", "bugs": { "url": "https://github.com/kriskbx/gitlab-time-tracker/issues" diff --git a/src/gtt.js b/src/gtt.js index 0dedde0..8e51db5 100755 --- a/src/gtt.js +++ b/src/gtt.js @@ -1,6 +1,6 @@ #!/usr/bin/env node -const version = '1.6.11'; +const version = '1.7.0'; const program = require('commander'); program From 4a04ae9a287d0fd897118b70dfe59752d9ba22ba Mon Sep 17 00:00:00 2001 From: Wolfgang Wohanka Date: Mon, 23 Oct 2017 22:15:07 +0200 Subject: [PATCH 5/8] gtt List von Stefan @zealot128 --- package-lock.json | 2 +- src/gtt-list.js | 38 ++++++++++++++++++++++++++++++++++++++ src/gtt.js | 1 + src/include/tasks.js | 5 +++++ src/models/branch.js | 25 +++++++++++++++++++++++++ src/models/issue.js | 18 ++++++++++++++++++ 6 files changed, 88 insertions(+), 1 deletion(-) create mode 100644 src/gtt-list.js create mode 100644 src/models/branch.js diff --git a/package-lock.json b/package-lock.json index 9076704..3cdc760 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "gitlab-time-tracker", - "version": "1.6.5", + "version": "1.7.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/src/gtt-list.js b/src/gtt-list.js new file mode 100644 index 0000000..0a55199 --- /dev/null +++ b/src/gtt-list.js @@ -0,0 +1,38 @@ +const program = require('commander'); +const colors = require('colors'); +const moment = require('moment'); +const Table = require('cli-table'); + + +const Config = require('./include/file-config'); +const Cli = require('./include/cli'); +const Tasks = require('./include/tasks'); + +program + .arguments('[project]') + .option('--verbose', 'show verbose output') + .option('-c, --closed', 'show closed issues (instead of opened only)') + .option('--my', 'show only issues assigned to me') + .parse(process.argv); + +Cli.verbose = program.verbose; + +let config = new Config(process.cwd()), + tasks = new Tasks(config), + type = program.type ? program.type : 'issue', + project = program.args[0]; + +tasks.list(project, program.closed ? 'closed' : 'opened', program.my) + .then(issues => { + let table = new Table({ + style : {compact : true, 'padding-left' : 1} + }); + if (issues.length == 0) { + console.log("No issues found."); + } + issues.forEach(issue => { + table.push([issue.iid.toString().magenta, issue.title.green + "\n" + issue.data.web_url.gray, issue.state]) + }) + console.log(table.toString()); + }) + .catch(error => Cli.error(error)); \ No newline at end of file diff --git a/src/gtt.js b/src/gtt.js index 8e51db5..af3a444 100755 --- a/src/gtt.js +++ b/src/gtt.js @@ -11,6 +11,7 @@ program .command('stop', 'stop monitoring time') .command('resume [project]', 'resume monitoring time for last stopped record') .command('cancel', 'cancel and discard active monitoring time') + .command('list [project]', 'list all open issues') .command('log', 'log recorded time records') .command('sync', 'sync local time records to GitLab') .command('edit [id]', 'edit time record by the given id') diff --git a/src/include/tasks.js b/src/include/tasks.js index 79a3b16..586e433 100755 --- a/src/include/tasks.js +++ b/src/include/tasks.js @@ -196,6 +196,11 @@ class tasks { }); } + list(project, state, my) { + this.config.set('project', project); + return (new classes['issue'](this.config, {})).list(this.config.get('project'), state, my); + } + /** * * @param project diff --git a/src/models/branch.js b/src/models/branch.js new file mode 100644 index 0000000..88dfeee --- /dev/null +++ b/src/models/branch.js @@ -0,0 +1,25 @@ +const _ = require('underscore'); +const Base = require('./base'); + +/** + * branch model + */ +class branch extends Base { + constructor(config) { + super(config); + } + + make(project, id) { + let promise; + console.log(project); + + promise = this.post(`projects/${encodeURIComponent(project)}/repository/branches`, {branch: id, ref: 'master'}); + + return promise; + } + + + +} + +module.exports = branch; \ No newline at end of file diff --git a/src/models/issue.js b/src/models/issue.js index ddf7c5c..a96ed30 100755 --- a/src/models/issue.js +++ b/src/models/issue.js @@ -28,6 +28,24 @@ class issue extends hasTimes { return promise; } + + list(project, state, my) { + return new Promise((resolve, reject) => { + let promise; + const query = `scope=${my ? "assigned-to-me" : "all"}&state=${state}`; + if (project) { + promise = this.get(`projects/${encodeURIComponent(project)}/issues?${query}`); + } else { + promise = this.get(`issues/?${query}`); + } + promise.then(response => { + const issues = response.body.map(issue => new this.constructor(this.config, issue)) + resolve(issues) + }); + promise.catch(error => reject(error)) + }) + } + /* * properties From bb01e4799f8d660d1b515cab29b0546f5b802164 Mon Sep 17 00:00:00 2001 From: Wolfgang Wohanka Date: Mon, 23 Oct 2017 22:24:27 +0200 Subject: [PATCH 6/8] Added Merge_request List in Model --- src/models/issue.js | 6 +++--- src/models/mergeRequest.js | 17 +++++++++++++++++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/models/issue.js b/src/models/issue.js index a96ed30..994cab0 100755 --- a/src/models/issue.js +++ b/src/models/issue.js @@ -28,9 +28,9 @@ class issue extends hasTimes { return promise; } - - list(project, state, my) { - return new Promise((resolve, reject) => { + + list(project, state, my) { + return new Promise((resolve, reject) => { let promise; const query = `scope=${my ? "assigned-to-me" : "all"}&state=${state}`; if (project) { diff --git a/src/models/mergeRequest.js b/src/models/mergeRequest.js index 5ea2f95..a67eb8d 100755 --- a/src/models/mergeRequest.js +++ b/src/models/mergeRequest.js @@ -25,6 +25,23 @@ class mergeRequest extends hasTimes { return promise; } + + list(project, state, my) { + return new Promise((resolve, reject) => { + let promise; + const query = `scope=${my ? "assigned-to-me" : "all"}&state=${state}`; + if (project) { + promise = this.get(`projects/${encodeURIComponent(project)}/merge_requests?${query}`); + } else { + promise = this.get(`merge_requests/?${query}`); + } + promise.then(response => { + const issues = response.body.map(issue => new this.constructor(this.config, issue)) + resolve(issues) + }); + promise.catch(error => reject(error)) + }) + } /* * properties From 7715f4e98dc4500d8fae143ac50bc75a718997ea Mon Sep 17 00:00:00 2001 From: Wolfgang Wohanka Date: Mon, 23 Oct 2017 22:37:51 +0200 Subject: [PATCH 7/8] gtt-list: Added Type merge_request --- src/gtt-list.js | 5 +++-- src/include/tasks.js | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/gtt-list.js b/src/gtt-list.js index 0a55199..82c8575 100644 --- a/src/gtt-list.js +++ b/src/gtt-list.js @@ -11,6 +11,7 @@ const Tasks = require('./include/tasks'); program .arguments('[project]') .option('--verbose', 'show verbose output') + .option('-t, --type ', 'specify resource type: issue, merge_request') .option('-c, --closed', 'show closed issues (instead of opened only)') .option('--my', 'show only issues assigned to me') .parse(process.argv); @@ -22,13 +23,13 @@ let config = new Config(process.cwd()), type = program.type ? program.type : 'issue', project = program.args[0]; -tasks.list(project, program.closed ? 'closed' : 'opened', program.my) +tasks.list(project, program.closed ? 'closed' : 'opened', program.my, program.type) .then(issues => { let table = new Table({ style : {compact : true, 'padding-left' : 1} }); if (issues.length == 0) { - console.log("No issues found."); + console.log("No ${programm.type}s found."); } issues.forEach(issue => { table.push([issue.iid.toString().magenta, issue.title.green + "\n" + issue.data.web_url.gray, issue.state]) diff --git a/src/include/tasks.js b/src/include/tasks.js index 586e433..2bc2fe9 100755 --- a/src/include/tasks.js +++ b/src/include/tasks.js @@ -196,9 +196,9 @@ class tasks { }); } - list(project, state, my) { + list(project, state, my, type) { this.config.set('project', project); - return (new classes['issue'](this.config, {})).list(this.config.get('project'), state, my); + return (new classes[type](this.config, {})).list(this.config.get('project'), state, my); } /** From 699281c6ad67bfd34739e5549c1a0f4ebb852483 Mon Sep 17 00:00:00 2001 From: hendrixfan Date: Mon, 23 Oct 2017 22:46:53 +0200 Subject: [PATCH 8/8] Branch Model was added by mistake --- src/models/branch.js | 25 ------------------------- 1 file changed, 25 deletions(-) delete mode 100644 src/models/branch.js diff --git a/src/models/branch.js b/src/models/branch.js deleted file mode 100644 index 88dfeee..0000000 --- a/src/models/branch.js +++ /dev/null @@ -1,25 +0,0 @@ -const _ = require('underscore'); -const Base = require('./base'); - -/** - * branch model - */ -class branch extends Base { - constructor(config) { - super(config); - } - - make(project, id) { - let promise; - console.log(project); - - promise = this.post(`projects/${encodeURIComponent(project)}/repository/branches`, {branch: id, ref: 'master'}); - - return promise; - } - - - -} - -module.exports = branch; \ No newline at end of file