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

Commit b61771a

Browse files
committed
refactored everything.
1 parent 3d14463 commit b61771a

25 files changed

+2114
-511
lines changed

Dockerfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,5 @@
11
FROM php:7.1
2+
3+
MAINTAINER Kris Siepert <[email protected]>
4+
5+
# WIP

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
{
22
"name": "kriskbx/gitlab-time-tracker",
3+
"description": "A command line interface that makes working with GitLabs time tracking feature more enjoyable.",
34
"license": "GPL v2",
45
"authors": [
56
{
@@ -12,7 +13,8 @@
1213
"m4tthumphrey/php-gitlab-api": "^7.15",
1314
"illuminate/support": "^5.4",
1415
"nesbot/carbon": "^1.22",
15-
"symfony/yaml": "^3.2"
16+
"symfony/yaml": "^3.2",
17+
"symfony/process": "^3.2"
1618
},
1719
"autoload": {
1820
"psr-4": {

composer.lock

Lines changed: 51 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

readme.md

Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
# gitlab-time-tracker
2+
3+
> A command line interface that makes working with GitLabs time tracking feature more enjoyable.
4+
5+
### requirements
6+
7+
* **php >= 7.0** (5.6 won't work)
8+
9+
### installation
10+
11+
#### using composer
12+
13+
Make sure composer is [installed globally](https://getcomposer.org/doc/00-intro.md#globally) and `~/.composer/vendor/bin` is in your [PATH](http://subinsb.com/install-run-composer-binaries-globally). Then simply run:
14+
15+
```
16+
composer global require kriskbx/gitlab-time-tracker
17+
```
18+
19+
#### using docker
20+
21+
> coming soon
22+
23+
### commands
24+
25+
#### login
26+
27+
Login to gitlab.com or your own GitLab instance using a private token.
28+
29+
```
30+
gtt login
31+
```
32+
33+
#### edit configuration
34+
35+
Edit the global configuration file. [Available options](#options)
36+
37+
```
38+
gtt edit
39+
```
40+
41+
#### reports
42+
43+
Get a report for your project or issue.
44+
45+
```
46+
# available report commands
47+
gtt report ["namespace/project"] [issue_id]
48+
gtt report:month ["2017-03"] ["namespace/project"]
49+
gtt report:day ["2017-03-01"] ["namespace/project"]
50+
51+
# include closed issues
52+
gtt report --closed=true
53+
54+
# limit to a user
55+
gtt report --user=username
56+
57+
# limit to a milestone
58+
gtt report --milestone=milestone_name
59+
60+
# overwrite the default date format or the date format stored in your config
61+
gtt report --date_format="d.m.Y H:i:s"
62+
63+
# overwrite the default columns or the columns stored in your config
64+
gtt report --columns=iid --columns=title --columns=estimation
65+
66+
# only include the given labels in the results, overwrites the includeLabels stored in your config file
67+
gtt report --include_labels=pending --include_labels=approved
68+
69+
# exclude the given labels from the results, overwrites the excludeLabels stored in your config file
70+
gtt report --exclude_labels=bug --exclude_labels=feature
71+
72+
# choose a different output than a stdout table (csv & json coming soon)
73+
gtt report --output=markdown --file=filename.md
74+
```
75+
76+
#### time tracking
77+
78+
> coming soon
79+
80+
### configuration options
81+
82+
Here's a sample configuration file including all available options:
83+
84+
```
85+
# url to the gitlab api. make sure there's a trailing slash
86+
url: http://gitlab.com/api/v4/
87+
88+
# your api token
89+
token: abcdefghijklmnopqrst
90+
91+
# default project
92+
project: namespace/projectname
93+
94+
# include closed by default
95+
closed: true
96+
97+
# default milestone
98+
milestone: milestone_name
99+
100+
# hours per day
101+
hoursPerDay: 8
102+
103+
# columns
104+
columns:
105+
- iid
106+
- title
107+
- estimation
108+
109+
# date format
110+
dateFormat: Y-m-d H:i:s
111+
112+
# default output
113+
output: markdown
114+
115+
# exclude the following labels in the results
116+
excludeLabels:
117+
- bug
118+
- feature
119+
120+
# only include the following labels in the result
121+
includeLabels:
122+
- pending
123+
- approved
124+
```
125+
126+
### faqs
127+
128+
#### It takes a long time to get Issues and process them
129+
130+
There's no API for querying time results, so I have to fetch all the comments and parse them for time spent. That process takes quite a while (2 additional requests for each Issue). I'm sorry, blame GitLab for implementing it that way.
131+
132+
#### GitLab will probably ship some of these features sooner or later
133+
134+
Yeah, I'm aware of that. For now (March 2017) GitLabs time tracking is a mess and this tool makes it way better.
135+
136+
#### why php? why not ruby/node/go/python/erlang?
137+
138+
Because I'm a PHP dev. And I like PHP. Actually PHP is not that bad. Shut up and get a life.
139+
140+
### license
141+
142+
GPL v2

src/Api/Issues.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
4+
namespace kriskbx\gtt\Api;
5+
6+
7+
class Issues extends \Gitlab\Api\Issues
8+
{
9+
/**
10+
* @param int $project_id
11+
* @param int $issue_id
12+
* @param int $page
13+
* @param int $per_page
14+
*
15+
* @return mixed
16+
*/
17+
public function showComments($project_id, $issue_id, $page = 1, $per_page = self::PER_PAGE)
18+
{
19+
$params = array_merge(array(
20+
'page' => $page,
21+
'per_page' => $per_page
22+
));
23+
24+
return $this->get($this->getProjectPath($project_id, 'issues/'.$this->encodePath($issue_id)).'/notes', $params);
25+
}
26+
}

src/Api/TimeStats.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<?php
2+
3+
4+
namespace kriskbx\gtt\Api;
5+
6+
7+
use Gitlab\Api\AbstractApi;
8+
9+
class TimeStats extends AbstractApi
10+
{
11+
/**
12+
* @param int $project_id
13+
* @param int $issue_id
14+
*
15+
* @return mixed
16+
*/
17+
public function getTimeStats($project_id, $issue_id)
18+
{
19+
return $this->get($this->getProjectPath($project_id, 'issues/' . $this->encodePath($issue_id)) . '/time_stats');
20+
}
21+
}

src/Collection/TimesCollection.php

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<?php
2+
3+
4+
namespace kriskbx\gtt\Collection;
5+
6+
7+
use Illuminate\Support\Collection;
8+
use kriskbx\gtt\Time;
9+
10+
class TimesCollection extends Collection
11+
{
12+
/**
13+
* Convert the times collection to a string.
14+
*
15+
* @param array $params
16+
*
17+
* @return string
18+
*/
19+
public function toString($params = [])
20+
{
21+
// Make sure things are set
22+
$params['displayUserFunction'] = @$params['displayUserFunction'] ?: false;
23+
$params['beforeHeadline'] = @$params['beforeHeadline'] ?: '';
24+
$params['afterHeadline'] = @$params['afterHeadline'] ?: '';
25+
$params['timesDelimiter'] = @$params['timesDelimiter'] ?: '';
26+
$params['break'] = @$params['break'] ?: '';
27+
$params['delimiter'] = $params['break'];
28+
29+
return $this->map(function (Collection $times, $user) use ($params) {
30+
if ($params['displayUserFunction']) {
31+
$string = call_user_func_array($params['displayUserFunction'], [$times, $user, $params]);
32+
} else {
33+
$string = $this->displayUser($times, $user, $params);
34+
}
35+
36+
$string .= $times->toString($params);
37+
38+
return $string;
39+
})->implode($params['timesDelimiter']);
40+
}
41+
42+
/**
43+
* Default function that "displays" a user.
44+
*
45+
* @param Collection $times
46+
* @param string $user
47+
* @param array $params
48+
*
49+
* @return string
50+
*/
51+
protected function displayUser(Collection $times, $user, array $params)
52+
{
53+
$totalTime = Time::humanReadable($times->reduce(function ($carry, Time $item) {
54+
return $carry + (int)$item->getSeconds();
55+
}));
56+
57+
return "{$params['beforeHeadline']}$user: {$totalTime}{$params['afterHeadline']}{$params['break']}";
58+
}
59+
}

src/Collection/macros.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
\Illuminate\Support\Collection::macro('toString', function ($params = []) {
4+
return collect($this->items)
5+
->map(function ($value) use ($params) {
6+
if ( ! is_object($value) && ! is_array($value)) {
7+
return $value;
8+
}
9+
10+
if (is_array($value)) {
11+
return json_encode($value);
12+
}
13+
14+
try {
15+
return call_user_func_array([$value, 'toString'], [$params]);
16+
} catch (Exception $e) {
17+
try {
18+
return call_user_func([$value, 'toJson']);
19+
} catch (Exception $e) {
20+
return json_encode($value);
21+
}
22+
}
23+
})
24+
->implode(@$params['delimiter'] ?: '');
25+
});
26+
27+
\Illuminate\Support\Collection::macro('firstLevelToArray', function () {
28+
return $this->items;
29+
});

0 commit comments

Comments
 (0)