pltt 0.1.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.agignore +1 -0
- data/.gitignore +8 -0
- data/.rubocop.yml +106 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +66 -0
- data/LICENSE.txt +21 -0
- data/README.md +91 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/exe/pltt +15 -0
- data/lib/pltt.rb +6 -0
- data/lib/pltt/actions/base.rb +105 -0
- data/lib/pltt/actions/create.rb +27 -0
- data/lib/pltt/actions/edit.rb +14 -0
- data/lib/pltt/actions/list.rb +20 -0
- data/lib/pltt/actions/resume.rb +20 -0
- data/lib/pltt/actions/start.rb +34 -0
- data/lib/pltt/actions/status.rb +19 -0
- data/lib/pltt/actions/stop.rb +44 -0
- data/lib/pltt/colorize.rb +93 -0
- data/lib/pltt/entry.rb +99 -0
- data/lib/pltt/gitlab_wrapper.rb +40 -0
- data/lib/pltt/runner.rb +66 -0
- data/lib/pltt/version.rb +3 -0
- data/pltt.gemspec +32 -0
- metadata +197 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: e8327a3f012b1d7e9e6587751232ba29b60bc1a7c9ec2b368c0b8ef162c129f6
|
4
|
+
data.tar.gz: fc6b8868a2c388151f4fbfc77bf0b6b7d034faefeab45bf950b41d0cf16a5c3f
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c6e09108e751a25fb217d43c5a40c704a6409f0239e75c1735f02d489ca2846eb2c758cb3df8d95dbcb6007e83aec2a579b05b0007ee421a4c0588c96039f233
|
7
|
+
data.tar.gz: 5fe58994e0787ca17f4c3162436b22634cb9a3094c379d362ee100ae1d0ab51007948470ec4a765189b82798f232f09839656483004b8c3b2cdb0d7f533d47c8
|
data/.agignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
vendor
|
data/.gitignore
ADDED
data/.rubocop.yml
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.5
|
3
|
+
Style/GuardClause:
|
4
|
+
MinBodyLength: 1
|
5
|
+
Enabled: false
|
6
|
+
Style/AndOr:
|
7
|
+
EnforcedStyle: conditionals
|
8
|
+
Style/PercentLiteralDelimiters:
|
9
|
+
PreferredDelimiters: {}
|
10
|
+
Style/Alias:
|
11
|
+
Enabled: false
|
12
|
+
Style/Documentation:
|
13
|
+
Enabled: false
|
14
|
+
Style/PercentLiteralDelimiters:
|
15
|
+
Enabled: false
|
16
|
+
Lint/UnusedMethodArgument:
|
17
|
+
Enabled: false
|
18
|
+
Metrics/ModuleLength:
|
19
|
+
Enabled: false
|
20
|
+
Style/StringLiterals:
|
21
|
+
Enabled: false
|
22
|
+
Style/IfUnlessModifier:
|
23
|
+
Enabled: false
|
24
|
+
Metrics/MethodLength:
|
25
|
+
Enabled: false
|
26
|
+
Metrics/LineLength:
|
27
|
+
Max: 150
|
28
|
+
Metrics/AbcSize:
|
29
|
+
Enabled: false
|
30
|
+
Metrics/ClassLength:
|
31
|
+
Enabled: false
|
32
|
+
Layout/DotPosition:
|
33
|
+
Enabled: false
|
34
|
+
Style/BlockDelimiters:
|
35
|
+
Enabled: false
|
36
|
+
Style/AndOr:
|
37
|
+
Enabled: false
|
38
|
+
Layout/AlignParameters:
|
39
|
+
EnforcedStyle: with_fixed_indentation
|
40
|
+
Rails/ActionFilter:
|
41
|
+
Enabled: false
|
42
|
+
Layout/MultilineMethodCallIndentation:
|
43
|
+
EnforcedStyle: indented
|
44
|
+
Style/FrozenStringLiteralComment:
|
45
|
+
Enabled: false
|
46
|
+
# class Admin::PageController
|
47
|
+
Style/ClassAndModuleChildren:
|
48
|
+
Enabled: false
|
49
|
+
|
50
|
+
# asddsa == 0 -> asddsa.zero?
|
51
|
+
Style/NumericPredicate:
|
52
|
+
Enabled: false
|
53
|
+
Performance/StringReplacement:
|
54
|
+
Enabled: false
|
55
|
+
# ->() {} -- lambda {|a| }
|
56
|
+
Style/Lambda:
|
57
|
+
EnforcedStyle: 'literal'
|
58
|
+
# if bla.nil? -- if bla == nil
|
59
|
+
Style/NilComparison:
|
60
|
+
Enabled: false
|
61
|
+
# Ruby 3
|
62
|
+
Style/FrozenStringLiteralComment:
|
63
|
+
Enabled: false
|
64
|
+
# Rails 5 -> im Controller/Request Test get :foo, params: {}
|
65
|
+
Rails/HttpPositionalArguments:
|
66
|
+
Enabled: false
|
67
|
+
# def bla; end
|
68
|
+
Style/EmptyMethod:
|
69
|
+
Enabled: false
|
70
|
+
# [ "700", "200" ] -> %w[w w]
|
71
|
+
Style/WordArray:
|
72
|
+
Enabled: false
|
73
|
+
# RSpec nervt
|
74
|
+
Metrics/BlockLength:
|
75
|
+
ExcludedMethods: ['task', 'namespace', 'get', 'post', 'describe', 'context', 'specify', 'it', 'route_param', 'draw', 'register', 'register_page', 'controller', 'included', 'params', 'resource', 'with_options', 'use_cassette', 'configure']
|
76
|
+
|
77
|
+
Bundler/OrderedGems:
|
78
|
+
Enabled: false
|
79
|
+
# update_all, update_column
|
80
|
+
# set_ und get_ verbote
|
81
|
+
Naming/AccessorMethodName:
|
82
|
+
Enabled: false
|
83
|
+
Style/TrailingCommaInArrayLiteral:
|
84
|
+
Enabled: false
|
85
|
+
Style/TrailingCommaInHashLiteral:
|
86
|
+
Enabled: false
|
87
|
+
|
88
|
+
Style/SymbolArray:
|
89
|
+
Enabled: false
|
90
|
+
|
91
|
+
Style/AsciiComments:
|
92
|
+
Enabled: false
|
93
|
+
Style/FormatString:
|
94
|
+
Enabled: false
|
95
|
+
Style/FormatStringToken:
|
96
|
+
Enabled: false
|
97
|
+
Metrics/PerceivedComplexity:
|
98
|
+
Enabled: false
|
99
|
+
Style/DoubleNegation:
|
100
|
+
Enabled: false
|
101
|
+
Style/ZeroLengthPredicate:
|
102
|
+
Enabled: false
|
103
|
+
Style/SafeNavigation:
|
104
|
+
Enabled: false
|
105
|
+
Lint/MissingCopEnableDirective:
|
106
|
+
Enabled: false
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
pltt (0.1.0.beta)
|
5
|
+
gitlab (~> 4.4.0)
|
6
|
+
hashids
|
7
|
+
oj
|
8
|
+
terminal-table (>= 1.8.0)
|
9
|
+
thor
|
10
|
+
tty-prompt
|
11
|
+
|
12
|
+
GEM
|
13
|
+
remote: https://rubygems.org/
|
14
|
+
specs:
|
15
|
+
coderay (1.1.2)
|
16
|
+
equatable (0.5.0)
|
17
|
+
gitlab (4.4.0)
|
18
|
+
httparty (>= 0.14.0)
|
19
|
+
terminal-table (>= 1.5.1)
|
20
|
+
hashids (1.0.4)
|
21
|
+
hitimes (1.2.6)
|
22
|
+
httparty (0.16.2)
|
23
|
+
multi_xml (>= 0.5.2)
|
24
|
+
method_source (0.9.0)
|
25
|
+
multi_xml (0.6.0)
|
26
|
+
necromancer (0.4.0)
|
27
|
+
oj (3.6.2)
|
28
|
+
pastel (0.7.2)
|
29
|
+
equatable (~> 0.5.0)
|
30
|
+
tty-color (~> 0.4.0)
|
31
|
+
pry (0.11.3)
|
32
|
+
coderay (~> 1.1.0)
|
33
|
+
method_source (~> 0.9.0)
|
34
|
+
rake (10.5.0)
|
35
|
+
terminal-table (1.8.0)
|
36
|
+
unicode-display_width (~> 1.1, >= 1.1.1)
|
37
|
+
thor (0.20.0)
|
38
|
+
timers (4.1.2)
|
39
|
+
hitimes
|
40
|
+
tty-color (0.4.2)
|
41
|
+
tty-cursor (0.5.0)
|
42
|
+
tty-prompt (0.16.1)
|
43
|
+
necromancer (~> 0.4.0)
|
44
|
+
pastel (~> 0.7.0)
|
45
|
+
timers (~> 4.0)
|
46
|
+
tty-cursor (~> 0.5.0)
|
47
|
+
tty-reader (~> 0.3.0)
|
48
|
+
tty-reader (0.3.0)
|
49
|
+
tty-cursor (~> 0.5.0)
|
50
|
+
tty-screen (~> 0.6.4)
|
51
|
+
wisper (~> 2.0.0)
|
52
|
+
tty-screen (0.6.4)
|
53
|
+
unicode-display_width (1.4.0)
|
54
|
+
wisper (2.0.0)
|
55
|
+
|
56
|
+
PLATFORMS
|
57
|
+
ruby
|
58
|
+
|
59
|
+
DEPENDENCIES
|
60
|
+
bundler (~> 1.16)
|
61
|
+
pltt!
|
62
|
+
pry
|
63
|
+
rake (~> 10.0)
|
64
|
+
|
65
|
+
BUNDLED WITH
|
66
|
+
1.16.2
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2018 Stefan Wienert
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Pltt
|
2
|
+
|
3
|
+
Pltt is a Gitlab Time Tracker for the command line. It mimicks the interface of [kriskbx/gitlab-time-tracker]( https://github.com/kriskbx/gitlab-time-tracker ) and is compatible to the config and frame database. Thus, it works as a drop-in-replacement.
|
4
|
+
|
5
|
+
Goals/Pros:
|
6
|
+
|
7
|
+
* Fast interface, even though it's ruby, the boot time is faster right now
|
8
|
+
* More friendly interface, error persistent, e.g. forgotten stoppings, issue creation with question-response cycles
|
9
|
+
* More robust interface with Gitlab:
|
10
|
+
* Not possible to book on non-existend or closed issues
|
11
|
+
* Time Entries are booked on stop by default, so no time shifting
|
12
|
+
* pltt status shows issue body, milestone etc. too
|
13
|
+
|
14
|
+
## Installation
|
15
|
+
|
16
|
+
Install it yourself as:
|
17
|
+
|
18
|
+
$ gem install pltt
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
### Starting Time Tracking
|
23
|
+
|
24
|
+
```bash
|
25
|
+
# start without issue id -> shows a selection menu of 30 most recent issues in project
|
26
|
+
pltt start
|
27
|
+
|
28
|
+
# start with issue id -> validates issue exists and is not closed
|
29
|
+
pltt start 123
|
30
|
+
|
31
|
+
# create new issue with interactive question for issue creation
|
32
|
+
# issue will be created instantly, not on sync
|
33
|
+
# You can enter issue title, select labels, and description
|
34
|
+
pltt create
|
35
|
+
|
36
|
+
# Starts time tracking with
|
37
|
+
pltt resume
|
38
|
+
```
|
39
|
+
|
40
|
+
### Stopping, Synching and Maintenance
|
41
|
+
|
42
|
+
```bash
|
43
|
+
# stops time tracking & syncs to gitlab
|
44
|
+
# 2 interactive questions can easly fix missing started entries
|
45
|
+
# can adjust start time and duration (minutes)
|
46
|
+
pltt stop
|
47
|
+
|
48
|
+
# Edit current entry in EDITOR
|
49
|
+
pltt edit
|
50
|
+
pltt edit 19ad20
|
51
|
+
|
52
|
+
# Cancel = delete current running entry
|
53
|
+
pltt cancel
|
54
|
+
|
55
|
+
# normally not needed, as sync is made after stop, only in case of error
|
56
|
+
pltt sync
|
57
|
+
```
|
58
|
+
|
59
|
+
### Reporting / General
|
60
|
+
|
61
|
+
```bash
|
62
|
+
# show all issues in project as table
|
63
|
+
pltt list
|
64
|
+
pltt list --my
|
65
|
+
pltt list --label Bug
|
66
|
+
```
|
67
|
+
|
68
|
+
## Development
|
69
|
+
|
70
|
+
Missing before release:
|
71
|
+
|
72
|
+
* [x] gtt start with no arguments shows the list of open issues to select one from
|
73
|
+
* [x] gtt create can optionally create a MR + branch
|
74
|
+
* [x] gtt stop / sync note creation
|
75
|
+
* [ ] First-Start Guide, Generator which creates .gtt.yml in a project, gets the project url from .git/config
|
76
|
+
* [ ] Timezone
|
77
|
+
* [ ] Frame Cleanup, everything older than X month can delete
|
78
|
+
|
79
|
+
Missing, but not planned soon, as not needed by us:
|
80
|
+
|
81
|
+
* [ ] Logging/reporting of all bookings
|
82
|
+
* [ ] No Booking on Merge requests implemented
|
83
|
+
* [ ] No delete implemented, as cancel is enough. deleting frames is also not very useful, when they are already synced to Gitlab
|
84
|
+
|
85
|
+
## Contributing
|
86
|
+
|
87
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/pludoni/pltt.
|
88
|
+
|
89
|
+
## License
|
90
|
+
|
91
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "pltt"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/exe/pltt
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
dir = File.join(File.dirname(File.realdirpath(__FILE__)), '..')
|
3
|
+
|
4
|
+
if RUBY_VERSION < '1.9.2'
|
5
|
+
$stderr.puts 'your ruby is too old!'
|
6
|
+
exit 1
|
7
|
+
end
|
8
|
+
|
9
|
+
$LOAD_PATH.unshift File.join(dir, 'lib')
|
10
|
+
|
11
|
+
ENV['BUNDLE_GEMFILE'] ||= File.join(dir, 'Gemfile')
|
12
|
+
|
13
|
+
require 'pltt'
|
14
|
+
require 'bundler/setup'
|
15
|
+
require 'pltt/runner'
|
data/lib/pltt.rb
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'oj'
|
3
|
+
require_relative '../entry'
|
4
|
+
require_relative '../colorize'
|
5
|
+
|
6
|
+
class Pltt::Actions::Base
|
7
|
+
def self.run(*args)
|
8
|
+
new.run(*args)
|
9
|
+
end
|
10
|
+
|
11
|
+
def config
|
12
|
+
self.class.config
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.config
|
16
|
+
return @config if @config
|
17
|
+
master = File.expand_path('~/.gtt/config.yml')
|
18
|
+
unless File.exist?(master)
|
19
|
+
raise ".gtt/config.yml existiert nicht!"
|
20
|
+
end
|
21
|
+
config = YAML.load_file(master)
|
22
|
+
locale = File.join(Dir.pwd, '.gtt.yml')
|
23
|
+
if File.exist?(locale)
|
24
|
+
config = config.merge(YAML.load_file(locale))
|
25
|
+
end
|
26
|
+
config['frame_dir'] ||= '~/.gtt/frames/'
|
27
|
+
config['gitlab_url'] ||= config['url'].sub(%r{/api/v4/?}, '')
|
28
|
+
@config = config
|
29
|
+
end
|
30
|
+
|
31
|
+
def current_entry
|
32
|
+
max = Time.now - 3600 * 24 * 7
|
33
|
+
recent_entries = all_frames.select { |i| File.mtime(i) > max }
|
34
|
+
recent_entries.each do |entry|
|
35
|
+
e = load_entry(entry)
|
36
|
+
return e if e.current?
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
def load_entry(path_to_frame)
|
42
|
+
File.read(path_to_frame).yield_self { |i| Oj.load(i) }.yield_self(&Pltt::Entry.method(:new))
|
43
|
+
end
|
44
|
+
|
45
|
+
def all_frames
|
46
|
+
Dir[File.join(File.expand_path(config['frame_dir']), '*.json')]
|
47
|
+
end
|
48
|
+
|
49
|
+
def exit_if_running!
|
50
|
+
if current_entry
|
51
|
+
puts "Already started!".red
|
52
|
+
puts current_entry.status
|
53
|
+
exit 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def exit_if_not_running!
|
58
|
+
unless current_entry
|
59
|
+
puts "Not started!".red
|
60
|
+
exit 1
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def gitlab_api
|
65
|
+
@gitlab_api ||=
|
66
|
+
begin
|
67
|
+
require_relative '../gitlab_wrapper'
|
68
|
+
Pltt::GitlabWrapper.new(config['url'], config['token'], config['project'])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def sync_all_unsaved_entries
|
73
|
+
gitlab_api
|
74
|
+
max = Time.now - 3600 * 24 * 7
|
75
|
+
recent_entries = all_frames.select { |i| File.mtime(i) > max }
|
76
|
+
recent_entries.each do |e|
|
77
|
+
entry = load_entry(e)
|
78
|
+
next if entry.synced? || entry.stop.nil?
|
79
|
+
sync!(entry)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def sync!(entry)
|
84
|
+
c = entry
|
85
|
+
minutes = c.duration_seconds.round / 60
|
86
|
+
require 'pry'
|
87
|
+
|
88
|
+
min_part = minutes % 60
|
89
|
+
hour_part = minutes / 60
|
90
|
+
|
91
|
+
gitlab_time_format =
|
92
|
+
case [hour_part > 0, min_part > 0]
|
93
|
+
when [true, true] then "#{hour_part}h#{min_part}m"
|
94
|
+
when [false, true] then "#{min_part}m"
|
95
|
+
when [true, false] then "#{hour_part}m"
|
96
|
+
else return
|
97
|
+
end
|
98
|
+
puts "Synching: #{gitlab_time_format.inspect} on #{c.project}##{c.iid}"
|
99
|
+
gitlab_api.add_time_spent_on_issue(c.project, c.iid, gitlab_time_format)
|
100
|
+
|
101
|
+
note_id = Gitlab.issue_notes(entry.project, entry.iid).auto_paginate.max_by { |i| i.created_at }.id
|
102
|
+
c.add_note(note_id, c.duration_seconds.round)
|
103
|
+
c.persist!
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
require 'tty-prompt'
|
3
|
+
class Pltt::Actions::Create < Pltt::Actions::Base
|
4
|
+
def run
|
5
|
+
puts "New issue in project #{config['project'].green}:"
|
6
|
+
prompt = TTY::Prompt.new
|
7
|
+
title = prompt.ask('Enter issue title:') do |q|
|
8
|
+
q.required true
|
9
|
+
end
|
10
|
+
description = prompt.multiline("Description").join("\n")
|
11
|
+
labels = gitlab_api.labels.map(&:name)
|
12
|
+
selected_labels = if labels.length > 0
|
13
|
+
prompt.multi_select("Select labels", labels, per_page: 20)
|
14
|
+
else
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
issue = gitlab_api.create_issue(title, description, selected_labels)
|
18
|
+
_entry = Pltt::Entry.create_new_for_gitlab_issue(config['project'], issue)
|
19
|
+
|
20
|
+
branch_name = "#{issue.iid}-#{issue.title.downcase.gsub(/[\W]+/, '-')}"
|
21
|
+
if prompt.yes?("Automatically create a branch #{branch_name} and check out locally?")
|
22
|
+
gitlab_api.create_branch_and_merge_request(branch_name, issue)
|
23
|
+
system 'git fetch'
|
24
|
+
system "git checkout #{branch_name}"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
class Pltt::Actions::Edit < Pltt::Actions::Base
|
3
|
+
def run(id)
|
4
|
+
if id
|
5
|
+
raise NotImplementedError
|
6
|
+
else
|
7
|
+
exit_if_not_running!
|
8
|
+
c = current_entry
|
9
|
+
c.frame_path
|
10
|
+
|
11
|
+
exec ENV['EDITOR'] || 'vim', c.frame_path
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
# rubocop:disable Naming/UncommunicativeMethodParamName
|
3
|
+
class Pltt::Actions::List < Pltt::Actions::Base
|
4
|
+
def run(my: false, label: nil)
|
5
|
+
require 'terminal-table'
|
6
|
+
require 'pry'
|
7
|
+
|
8
|
+
table = Terminal::Table.new
|
9
|
+
gitlab_api.issues(scope: my ? 'assigned-to-me' : 'all', label: label).each do |issue|
|
10
|
+
table.add_row [
|
11
|
+
issue.iid.to_s.magenta,
|
12
|
+
issue.title.green + "\n#{issue.web_url.dark_gray}",
|
13
|
+
issue.state.gray,
|
14
|
+
issue.milestone&.title,
|
15
|
+
issue.labels.map { |i| "[~#{i}]" }.join
|
16
|
+
]
|
17
|
+
end
|
18
|
+
puts table
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
class Pltt::Actions::Resume < Pltt::Actions::Base
|
3
|
+
def run
|
4
|
+
require 'pry'
|
5
|
+
exit_if_running!
|
6
|
+
|
7
|
+
last_one = all_frames.sort_by { |i| File.mtime(i) }.reverse.lazy.
|
8
|
+
map { |i| load_entry(i) }.
|
9
|
+
select { |i| i.project == config['project'] }.
|
10
|
+
take(5).max_by { |i| i.stop }
|
11
|
+
|
12
|
+
unless last_one
|
13
|
+
puts "No previous entry found for #{config['project']}!".red
|
14
|
+
exit 1
|
15
|
+
end
|
16
|
+
|
17
|
+
new_entry = Pltt::Entry.from_resume(last_one)
|
18
|
+
new_entry.persist!
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
class Pltt::Actions::Start < Pltt::Actions::Base
|
3
|
+
def run(iid)
|
4
|
+
exit_if_running!
|
5
|
+
|
6
|
+
issue = nil
|
7
|
+
if iid
|
8
|
+
issue = gitlab_api.issue(iid.to_i)
|
9
|
+
puts "Issue: #{issue.title.green}"
|
10
|
+
else
|
11
|
+
require 'tty-prompt'
|
12
|
+
prompt = TTY::Prompt.new
|
13
|
+
recent = gitlab_api.issues.take(30)
|
14
|
+
issue = prompt.select("Select issue to start on", per_page: 20) do |menu|
|
15
|
+
recent.each do |this_issue|
|
16
|
+
menu.choice "#{this_issue.iid.to_s.magenta} #{this_issue.title}", this_issue
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
start_by_issue(issue)
|
21
|
+
rescue StandardError => e
|
22
|
+
puts "Issue #{issue.iid} not found in project #{config['project']}".red
|
23
|
+
puts e.inspect
|
24
|
+
exit 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_by_issue(issue)
|
28
|
+
if issue.closed?
|
29
|
+
puts "This issue is closed"
|
30
|
+
exit 1
|
31
|
+
end
|
32
|
+
Pltt::Entry.create_new_for_gitlab_issue(config['project'], issue)
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
class Pltt::Actions::Status < Pltt::Actions::Base
|
3
|
+
def run
|
4
|
+
exit_if_not_running!
|
5
|
+
puts current_entry.status
|
6
|
+
|
7
|
+
if (iid = current_entry.resource['id'])
|
8
|
+
issue = gitlab_api.issue(iid)
|
9
|
+
puts "-------------------------------------------".black
|
10
|
+
puts <<~DOC
|
11
|
+
#{issue.title.green} (##{iid})
|
12
|
+
#{issue.time_stats.human_total_time_spent&.dark_gray} #{issue.assignees.map { |i| "@#{i['username']}".blue }.join(' ')}
|
13
|
+
#{issue.labels.map { |i| "[~#{i}]".red }.join(' ')} #{issue.milestone&.title&.magenta}
|
14
|
+
|
15
|
+
#{issue.description}
|
16
|
+
DOC
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative './base'
|
2
|
+
require 'tty-prompt'
|
3
|
+
# rubocop:disable Style/NegatedIf
|
4
|
+
class Pltt::Actions::Stop < Pltt::Actions::Base
|
5
|
+
def run
|
6
|
+
exit_if_not_running!
|
7
|
+
c = current_entry
|
8
|
+
|
9
|
+
minutes = (c.duration_seconds / 60).round
|
10
|
+
puts "Currently running for #{minutes} min"
|
11
|
+
prompt = TTY::Prompt.new
|
12
|
+
too_large = minutes > 480
|
13
|
+
if !prompt.no?("Was started on #{c.start.localtime.to_s.green}, fix beginning?")
|
14
|
+
time = prompt.ask("Enter beginning *time* only (HH:MM)") do |q|
|
15
|
+
q.required true
|
16
|
+
q.validate(/\A\d+:\d+\Z/)
|
17
|
+
q.convert :string
|
18
|
+
end
|
19
|
+
h, m = time.split(':').map(&:to_i)
|
20
|
+
c.start = Time.new(c.start.year, c.start.month, c.start.day, h, m)
|
21
|
+
end
|
22
|
+
minutes = (c.duration_seconds / 60).round
|
23
|
+
puts "Currently running for #{minutes} min"
|
24
|
+
if too_large || !prompt.no?("Fix duration before saving? (#{minutes}min)")
|
25
|
+
puts "Error: To many minutes, must be not greater than 8h (480min)" if too_large
|
26
|
+
new_minutes = prompt.ask("New Minutes, beginning from #{c.start.localtime}") do |q|
|
27
|
+
q.required true
|
28
|
+
q.convert :int
|
29
|
+
end
|
30
|
+
stop = (c.start + new_minutes * 60).utc
|
31
|
+
else
|
32
|
+
stop = Time.now.utc
|
33
|
+
end
|
34
|
+
c.stop = stop
|
35
|
+
|
36
|
+
c.persist!
|
37
|
+
|
38
|
+
sync_all_unsaved_entries
|
39
|
+
rescue StandardError => e
|
40
|
+
puts "Issue #{c.id} not found in project #{config['project']}".red
|
41
|
+
puts e.inspect
|
42
|
+
exit 1
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,93 @@
|
|
1
|
+
class String
|
2
|
+
def dark_gray
|
3
|
+
"\e[90m#{self}\e[0m"
|
4
|
+
end
|
5
|
+
|
6
|
+
def black
|
7
|
+
"\e[30m#{self}\e[0m"
|
8
|
+
end
|
9
|
+
|
10
|
+
def red
|
11
|
+
"\e[31m#{self}\e[0m"
|
12
|
+
end
|
13
|
+
|
14
|
+
def green
|
15
|
+
"\e[32m#{self}\e[0m"
|
16
|
+
end
|
17
|
+
|
18
|
+
def brown
|
19
|
+
"\e[33m#{self}\e[0m"
|
20
|
+
end
|
21
|
+
|
22
|
+
def blue
|
23
|
+
"\e[34m#{self}\e[0m"
|
24
|
+
end
|
25
|
+
|
26
|
+
def magenta
|
27
|
+
"\e[35m#{self}\e[0m"
|
28
|
+
end
|
29
|
+
|
30
|
+
def cyan
|
31
|
+
"\e[36m#{self}\e[0m"
|
32
|
+
end
|
33
|
+
|
34
|
+
def gray
|
35
|
+
"\e[37m#{self}\e[0m"
|
36
|
+
end
|
37
|
+
|
38
|
+
def gray39
|
39
|
+
"\e[39m#{self}\e[0m"
|
40
|
+
end
|
41
|
+
|
42
|
+
def bg_black
|
43
|
+
"\e[40m#{self}\e[0m"
|
44
|
+
end
|
45
|
+
|
46
|
+
def bg_red
|
47
|
+
"\e[41m#{self}\e[0m"
|
48
|
+
end
|
49
|
+
|
50
|
+
def bg_green
|
51
|
+
"\e[42m#{self}\e[0m"
|
52
|
+
end
|
53
|
+
|
54
|
+
def bg_brown
|
55
|
+
"\e[43m#{self}\e[0m"
|
56
|
+
end
|
57
|
+
|
58
|
+
def bg_blue
|
59
|
+
"\e[44m#{self}\e[0m"
|
60
|
+
end
|
61
|
+
|
62
|
+
def bg_magenta
|
63
|
+
"\e[45m#{self}\e[0m"
|
64
|
+
end
|
65
|
+
|
66
|
+
def bg_cyan
|
67
|
+
"\e[46m#{self}\e[0m"
|
68
|
+
end
|
69
|
+
|
70
|
+
def bg_gray
|
71
|
+
"\e[47m#{self}\e[0m"
|
72
|
+
end
|
73
|
+
|
74
|
+
def bold
|
75
|
+
"\e[1m#{self}\e[22m"
|
76
|
+
end
|
77
|
+
|
78
|
+
def italic
|
79
|
+
"\e[3m#{self}\e[23m"
|
80
|
+
end
|
81
|
+
|
82
|
+
def underline
|
83
|
+
"\e[4m#{self}\e[24m"
|
84
|
+
end
|
85
|
+
|
86
|
+
def blink
|
87
|
+
"\e[5m#{self}\e[25m"
|
88
|
+
end
|
89
|
+
|
90
|
+
def reverse_color
|
91
|
+
"\e[7m#{self}\e[27m"
|
92
|
+
end
|
93
|
+
end
|
data/lib/pltt/entry.rb
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
class Pltt::Entry
|
2
|
+
attr_reader :id, :project, :start, :stop, :resource
|
3
|
+
attr_writer :start, :stop
|
4
|
+
|
5
|
+
def self.from_resume(other_entry)
|
6
|
+
new('project' => other_entry.project, 'resource' => other_entry.resource, 'start' => Time.now.utc.iso8601)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.create_new_for_gitlab_issue(project, issue)
|
10
|
+
entry = Pltt::Entry.new('project' => project, 'resource' => { 'id' => issue.iid, 'type' => 'issue' }, 'start' => Time.now.utc.iso8601)
|
11
|
+
entry.persist!
|
12
|
+
entry
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(json)
|
16
|
+
@id = json['id']
|
17
|
+
@project = json['project']
|
18
|
+
@resource = json['resource']
|
19
|
+
@notes = json['notes'] || []
|
20
|
+
@start = Time.iso8601(json['start']) if json['start']
|
21
|
+
@stop = if json['stop']
|
22
|
+
Time.iso8601(json['stop'])
|
23
|
+
else
|
24
|
+
false
|
25
|
+
end
|
26
|
+
@_json = json
|
27
|
+
end
|
28
|
+
|
29
|
+
def current?
|
30
|
+
!@stop
|
31
|
+
end
|
32
|
+
|
33
|
+
def status
|
34
|
+
duration = duration_time.strftime("%H:%M:%S")
|
35
|
+
<<~DOC
|
36
|
+
#{@project}##{iid}, #{duration.green} (id: #{@id})
|
37
|
+
#{url.gray}
|
38
|
+
DOC
|
39
|
+
end
|
40
|
+
|
41
|
+
def duration_time
|
42
|
+
Time.at(duration_seconds).utc
|
43
|
+
end
|
44
|
+
|
45
|
+
def duration_seconds
|
46
|
+
(@stop || Time.now.utc) - @start.utc
|
47
|
+
end
|
48
|
+
|
49
|
+
def url
|
50
|
+
"#{Pltt::Actions::Base.config['gitlab_url']}/#{@project}/issues/#{iid}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def frame_path
|
54
|
+
@frame_path ||= File.join(File.expand_path(Pltt::Actions::Base.config['frame_dir']), @id + ".json")
|
55
|
+
end
|
56
|
+
|
57
|
+
def cancel!
|
58
|
+
if File.exist?(frame_path)
|
59
|
+
puts "Entry deleted"
|
60
|
+
File.unlink(frame_path)
|
61
|
+
else
|
62
|
+
puts "Entry already deleted!"
|
63
|
+
exit 1
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def persist!
|
68
|
+
require 'oj'
|
69
|
+
Oj.mimic_JSON
|
70
|
+
unless @id
|
71
|
+
require 'hashids'
|
72
|
+
@id = Hashids.new('', 9).encode(@start.to_i)
|
73
|
+
end
|
74
|
+
output = JSON.pretty_generate(id: @id,
|
75
|
+
project: @project,
|
76
|
+
resource: @resource,
|
77
|
+
notes: @notes,
|
78
|
+
start: @start && @start.iso8601,
|
79
|
+
stop: @stop && @stop.iso8601)
|
80
|
+
File.write(frame_path, output)
|
81
|
+
unless @stop
|
82
|
+
puts "Started:"
|
83
|
+
end
|
84
|
+
puts status
|
85
|
+
end
|
86
|
+
|
87
|
+
def add_note(id, time)
|
88
|
+
@notes ||= []
|
89
|
+
@notes << { id: id, time: time }
|
90
|
+
end
|
91
|
+
|
92
|
+
def iid
|
93
|
+
@resource['id']
|
94
|
+
end
|
95
|
+
|
96
|
+
def synced?
|
97
|
+
@notes && @notes.length > 0
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
class Pltt::GitlabWrapper
|
2
|
+
def initialize(url, token, project)
|
3
|
+
require 'gitlab'
|
4
|
+
@project = project
|
5
|
+
|
6
|
+
Gitlab.endpoint = url
|
7
|
+
Gitlab.private_token = token
|
8
|
+
end
|
9
|
+
|
10
|
+
def issues(scope: 'assigned-to-me', order_by: 'updated_at', state: 'opened', label: nil)
|
11
|
+
Gitlab.issues(@project, state: state, order_by: order_by, scope: scope, labels: label ? label : nil).auto_paginate
|
12
|
+
end
|
13
|
+
|
14
|
+
def issue(id)
|
15
|
+
Gitlab.issue(@project, id)
|
16
|
+
end
|
17
|
+
|
18
|
+
def create_issue(title, description, labels)
|
19
|
+
user_id = Gitlab.user.id
|
20
|
+
Gitlab.create_issue(@project, title, description: description, labels: labels.join(','), assignee_ids: [user_id])
|
21
|
+
end
|
22
|
+
|
23
|
+
def labels
|
24
|
+
Gitlab.labels(@project)
|
25
|
+
end
|
26
|
+
|
27
|
+
def create_branch_and_merge_request(branch_name, issue)
|
28
|
+
Gitlab.create_branch(@project, branch_name, 'master')
|
29
|
+
Gitlab.create_merge_request(@project, "Resolve #{issue.title}",
|
30
|
+
source_branch: branch_name,
|
31
|
+
target_branch: 'master',
|
32
|
+
description: "Closes ##{issue.iid}",
|
33
|
+
remove_source_branch: true)
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
def add_time_spent_on_issue(project, issue_id, duration)
|
38
|
+
Gitlab.add_time_spent_on_issue(project, issue_id, duration)
|
39
|
+
end
|
40
|
+
end
|
data/lib/pltt/runner.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'thor'
|
2
|
+
|
3
|
+
class Pltt::Runner < Thor
|
4
|
+
desc "resume", "resume last issue in current project"
|
5
|
+
def resume
|
6
|
+
require_relative './actions/resume'
|
7
|
+
Pltt::Actions::Resume.run
|
8
|
+
end
|
9
|
+
|
10
|
+
desc "create", "create new issue in current project"
|
11
|
+
def create
|
12
|
+
require_relative './actions/create'
|
13
|
+
Pltt::Actions::Create.run
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "start [ID]", "start tracking for issue #ID"
|
17
|
+
def start(id = nil)
|
18
|
+
require_relative './actions/start'
|
19
|
+
Pltt::Actions::Start.run(id)
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "stop", "Stop"
|
23
|
+
def stop
|
24
|
+
require_relative './actions/stop'
|
25
|
+
Pltt::Actions::Stop.run
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "list", "List all project issues"
|
29
|
+
option :my, type: :boolean
|
30
|
+
option :label, type: :string
|
31
|
+
def list
|
32
|
+
require_relative './actions/list'
|
33
|
+
Pltt::Actions::List.run(my: options[:my], label: options[:label])
|
34
|
+
end
|
35
|
+
|
36
|
+
desc "status", "Status"
|
37
|
+
def status
|
38
|
+
require_relative './actions/status'
|
39
|
+
Pltt::Actions::Status.run
|
40
|
+
end
|
41
|
+
|
42
|
+
desc "edit [ID = CURRENT]", "start tracking for issue #ID"
|
43
|
+
def edit(id = nil)
|
44
|
+
require_relative './actions/edit'
|
45
|
+
Pltt::Actions::Edit.run(id)
|
46
|
+
end
|
47
|
+
|
48
|
+
desc "cancel", "cancel current entry"
|
49
|
+
def cancel
|
50
|
+
require_relative './actions/base'
|
51
|
+
if (c = Pltt::Actions::Base.new.current_entry)
|
52
|
+
c.cancel!
|
53
|
+
else
|
54
|
+
puts "No running entry to cancel"
|
55
|
+
exit 1
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'sync', 'sync all unsaved entries'
|
60
|
+
def sync
|
61
|
+
require_relative './actions/base'
|
62
|
+
Pltt::Actions::Base.new.sync_all_unsaved_entries
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
Pltt::Runner.start(ARGV)
|
data/lib/pltt/version.rb
ADDED
data/pltt.gemspec
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
lib = File.expand_path("../lib", __FILE__)
|
2
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
+
require "pltt/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "pltt"
|
7
|
+
spec.version = Pltt::VERSION
|
8
|
+
spec.authors = ["Stefan Wienert"]
|
9
|
+
spec.email = ["info@stefanwienert.de"]
|
10
|
+
|
11
|
+
spec.summary = %{}
|
12
|
+
spec.description = %{}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
17
|
+
f.match(%r{^(test|spec|features)/})
|
18
|
+
end
|
19
|
+
spec.bindir = "exe"
|
20
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency 'gitlab', '~> 4.4.0'
|
24
|
+
spec.add_dependency 'hashids'
|
25
|
+
spec.add_dependency 'oj'
|
26
|
+
spec.add_dependency 'terminal-table', '>= 1.8.0'
|
27
|
+
spec.add_dependency 'thor'
|
28
|
+
spec.add_dependency 'tty-prompt'
|
29
|
+
spec.add_development_dependency "bundler", "~> 1.16"
|
30
|
+
spec.add_development_dependency "pry"
|
31
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,197 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pltt
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0.beta
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Stefan Wienert
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2018-06-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: gitlab
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 4.4.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 4.4.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: hashids
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: oj
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: terminal-table
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 1.8.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 1.8.0
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: thor
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: tty-prompt
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :runtime
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: bundler
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - "~>"
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '1.16'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - "~>"
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '1.16'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: pry
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: rake
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - "~>"
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '10.0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - "~>"
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '10.0'
|
139
|
+
description: ''
|
140
|
+
email:
|
141
|
+
- info@stefanwienert.de
|
142
|
+
executables:
|
143
|
+
- pltt
|
144
|
+
extensions: []
|
145
|
+
extra_rdoc_files: []
|
146
|
+
files:
|
147
|
+
- ".agignore"
|
148
|
+
- ".gitignore"
|
149
|
+
- ".rubocop.yml"
|
150
|
+
- Gemfile
|
151
|
+
- Gemfile.lock
|
152
|
+
- LICENSE.txt
|
153
|
+
- README.md
|
154
|
+
- Rakefile
|
155
|
+
- bin/console
|
156
|
+
- bin/setup
|
157
|
+
- exe/pltt
|
158
|
+
- lib/pltt.rb
|
159
|
+
- lib/pltt/actions/base.rb
|
160
|
+
- lib/pltt/actions/create.rb
|
161
|
+
- lib/pltt/actions/edit.rb
|
162
|
+
- lib/pltt/actions/list.rb
|
163
|
+
- lib/pltt/actions/resume.rb
|
164
|
+
- lib/pltt/actions/start.rb
|
165
|
+
- lib/pltt/actions/status.rb
|
166
|
+
- lib/pltt/actions/stop.rb
|
167
|
+
- lib/pltt/colorize.rb
|
168
|
+
- lib/pltt/entry.rb
|
169
|
+
- lib/pltt/gitlab_wrapper.rb
|
170
|
+
- lib/pltt/runner.rb
|
171
|
+
- lib/pltt/version.rb
|
172
|
+
- pltt.gemspec
|
173
|
+
homepage: ''
|
174
|
+
licenses:
|
175
|
+
- MIT
|
176
|
+
metadata: {}
|
177
|
+
post_install_message:
|
178
|
+
rdoc_options: []
|
179
|
+
require_paths:
|
180
|
+
- lib
|
181
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
182
|
+
requirements:
|
183
|
+
- - ">="
|
184
|
+
- !ruby/object:Gem::Version
|
185
|
+
version: '0'
|
186
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
187
|
+
requirements:
|
188
|
+
- - ">"
|
189
|
+
- !ruby/object:Gem::Version
|
190
|
+
version: 1.3.1
|
191
|
+
requirements: []
|
192
|
+
rubyforge_project:
|
193
|
+
rubygems_version: 2.7.7
|
194
|
+
signing_key:
|
195
|
+
specification_version: 4
|
196
|
+
summary: ''
|
197
|
+
test_files: []
|