time_log_robot 0.2.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +6 -11
- data/bin/time_log_robot +1 -115
- data/lib/time_log_robot/version.rb +1 -1
- data/lib/time_log_robot.rb +186 -38
- data/time_log_robot.gemspec +1 -3
- metadata +2 -37
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d5097db263a7073c5b5c858536dabfe61ced24e
|
4
|
+
data.tar.gz: 381891c32f3499ecbcb611395db2294f1018b923
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 03c8d6335b209654b4b4f37c18b894cce613639d40e4167e5a8aefb79f02f6f40f64a0a6ba8eaf1c468a8cf1087ffdd1f162fd597b6a4e04af09f2693bfd2fbd
|
7
|
+
data.tar.gz: 791e6755bfd9a6a6768eba806a709c94713f1d273d8215dbb4d37f6d7d19c15eac1e3420e9280e10661de07d9013a103f6d9fae7e53ac5b8f5f0e9fca1e2f907
|
data/Gemfile.lock
CHANGED
@@ -1,30 +1,25 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
time_log_robot (0.
|
5
|
-
activesupport (>= 4.2.6)
|
6
|
-
|
7
|
-
httparty (>= 0.13.0)
|
8
|
-
json (= 1.8.1)
|
4
|
+
time_log_robot (0.3.0)
|
5
|
+
activesupport (~> 4.2, >= 4.2.6)
|
6
|
+
httparty (~> 0.13, >= 0.13.0)
|
9
7
|
|
10
8
|
GEM
|
11
9
|
remote: https://rubygems.org/
|
12
10
|
specs:
|
13
|
-
activesupport (
|
14
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
11
|
+
activesupport (4.2.7.1)
|
15
12
|
i18n (~> 0.7)
|
13
|
+
json (~> 1.7, >= 1.7.7)
|
16
14
|
minitest (~> 5.1)
|
15
|
+
thread_safe (~> 0.3, >= 0.3.4)
|
17
16
|
tzinfo (~> 1.1)
|
18
17
|
ansi (1.5.0)
|
19
18
|
builder (3.2.2)
|
20
19
|
codeclimate-test-reporter (0.6.0)
|
21
20
|
simplecov (>= 0.7.1, < 1.0.0)
|
22
21
|
coderay (1.1.1)
|
23
|
-
commander (4.4.0)
|
24
|
-
highline (~> 1.7.2)
|
25
|
-
concurrent-ruby (1.0.2)
|
26
22
|
docile (1.1.5)
|
27
|
-
highline (1.7.8)
|
28
23
|
httparty (0.14.0)
|
29
24
|
multi_xml (>= 0.5.2)
|
30
25
|
i18n (0.7.0)
|
data/bin/time_log_robot
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require 'commander/import'
|
4
3
|
require 'time_log_robot'
|
5
4
|
require 'time_log_robot/entry'
|
6
5
|
require 'time_log_robot/reporter'
|
@@ -14,117 +13,4 @@ require 'time_log_robot/jira/payload_builder'
|
|
14
13
|
require 'time_log_robot/jira/work_logger'
|
15
14
|
require 'yaml'
|
16
15
|
|
17
|
-
|
18
|
-
program :version, TimeLogRobot::VERSION
|
19
|
-
program :description, 'Logs work from a time tracker tool to a project
|
20
|
-
management tool. Currently only supports Toggl and JIRA.'
|
21
|
-
|
22
|
-
program :help, 'Author', 'Mark J. Lehman <markopolo@gmail.com>'
|
23
|
-
|
24
|
-
global_option('-i', '--inputs_help', 'Learn how and where to find the inputs you need to get this working')
|
25
|
-
|
26
|
-
command :run do |c|
|
27
|
-
c.syntax = 'time_log_robot run [options]'
|
28
|
-
|
29
|
-
c.description = 'Logs your time with optional since (default is the previous Saturday).'
|
30
|
-
|
31
|
-
c.example 'usage', 'time_log_robot run'
|
32
|
-
c.example 'shorthand', 'time_log_robot'
|
33
|
-
c.example 'with optional parameter "since"', 'time_log_robot run --since "2015-10-21"'
|
34
|
-
|
35
|
-
c.option '-m', '--mapping', 'Description to JIRA key mapping file is located by default at `~/.time_log_robot_mapping.yml`. Use this flag if you have a mapping file eslewhere and would like to define the path to point to your file instead.'
|
36
|
-
|
37
|
-
c.option '--overwrite', 'Your settings are automatically written to a file - `~/.time_log_robot_settings.yml` - to be used again the next time you invoke the robot. Use this flag if you need to overwrite those settings.'
|
38
|
-
|
39
|
-
c.option '-s', '--since STRING', String, 'The date from which to log time entries. Must be in YYYY-MM-DD format. Default is the previous Saturday.'
|
40
|
-
|
41
|
-
c.action do |args, options|
|
42
|
-
if options.inputs_help
|
43
|
-
print_inputs_help
|
44
|
-
else
|
45
|
-
create_settings_file_if_nonexistent
|
46
|
-
|
47
|
-
fetch_envars_from_config unless options.overwrite
|
48
|
-
|
49
|
-
missing_envars = get_missing_envars
|
50
|
-
if options.mapping
|
51
|
-
missing_envars['MAPPING_FILE_PATH'] = get_envar('MAPPING_FILE_PATH')
|
52
|
-
end
|
53
|
-
|
54
|
-
since = DateTime.parse(options.since).to_s unless options.since.nil?
|
55
|
-
|
56
|
-
TimeLogRobot.start(since)
|
57
|
-
|
58
|
-
write_missing_envars(missing_envars) if missing_envars.any?
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
def print_inputs_help
|
64
|
-
TimeLogRobot.envars_help.each_pair do |envar, help_text|
|
65
|
-
puts envar
|
66
|
-
puts help_text
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def get_missing_envars
|
71
|
-
missing_envars = {}
|
72
|
-
|
73
|
-
TimeLogRobot.envars.each do |key|
|
74
|
-
next if key == 'MAPPING_FILE_PATH' || ENV[key]
|
75
|
-
missing_envars[key] = get_envar(key)
|
76
|
-
end
|
77
|
-
|
78
|
-
return missing_envars
|
79
|
-
end
|
80
|
-
|
81
|
-
def get_envar(key)
|
82
|
-
env_value = ask "Enter your #{key}: " do |char|
|
83
|
-
char.echo = '*' if key =~ /password|token/i
|
84
|
-
end
|
85
|
-
env_value.strip! unless should_not_strip?(key)
|
86
|
-
ENV[key] = env_value
|
87
|
-
if ENV[key].length == 0
|
88
|
-
puts 'Invalid input. This is a required field.'
|
89
|
-
exit
|
90
|
-
end
|
91
|
-
ENV[key]
|
92
|
-
end
|
93
|
-
|
94
|
-
def should_not_strip?(key)
|
95
|
-
%w(JIRA_PASSWORD).include? key
|
96
|
-
end
|
97
|
-
|
98
|
-
def fetch_envars_from_config
|
99
|
-
return unless envars = YAML.load_file(settings_file_path)
|
100
|
-
envars.each_pair do |key, value|
|
101
|
-
value.strip! unless should_not_strip?(key)
|
102
|
-
ENV[key.upcase] = value
|
103
|
-
end
|
104
|
-
end
|
105
|
-
|
106
|
-
def write_missing_envars(missing_envars={})
|
107
|
-
puts "\nTo avoid entering setup information each time, the following configuration has been stored in `#{settings_file_path}`:"
|
108
|
-
missing_envars.each_pair do |key, value|
|
109
|
-
if key =~ /password|token/i
|
110
|
-
puts "\t#{key}=[FILTERED]"
|
111
|
-
else
|
112
|
-
puts "\t#{key}=#{value}"
|
113
|
-
end
|
114
|
-
|
115
|
-
data = YAML.load_file(settings_file_path) || {}
|
116
|
-
data[key.downcase] = value
|
117
|
-
File.open(settings_file_path, 'w') { |f| YAML.dump(data, f) }
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def create_settings_file_if_nonexistent
|
122
|
-
File.new(settings_file_path, "w+") unless File.file?(settings_file_path)
|
123
|
-
end
|
124
|
-
|
125
|
-
def settings_file_path
|
126
|
-
File.join(ENV['HOME'], '.time_log_robot_settings.yml')
|
127
|
-
end
|
128
|
-
|
129
|
-
# set default action for gem
|
130
|
-
default_command :run
|
16
|
+
TimeLogRobot.run(ARGV)
|
data/lib/time_log_robot.rb
CHANGED
@@ -1,57 +1,205 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'optparse/date'
|
3
|
+
require 'ostruct'
|
1
4
|
require 'json'
|
2
5
|
require 'httparty'
|
3
6
|
|
4
7
|
module TimeLogRobot
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
+
class << self
|
9
|
+
def run(args)
|
10
|
+
options = TimeLogRobot.parse(args)
|
8
11
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
create_settings_file_if_nonexistent
|
13
|
+
|
14
|
+
fetch_envars_from_config unless options.overwrite
|
15
|
+
|
16
|
+
missing_envars = get_missing_envars
|
17
|
+
if options.mapping
|
18
|
+
missing_envars['MAPPING_FILE_PATH'] = get_envar('MAPPING_FILE_PATH')
|
19
|
+
end
|
20
|
+
|
21
|
+
since = options.since.to_time unless options.since.nil?
|
22
|
+
|
23
|
+
TimeLogRobot.start(since)
|
16
24
|
|
17
|
-
|
18
|
-
if since.nil?
|
19
|
-
Toggl::Report.fetch
|
20
|
-
else
|
21
|
-
Toggl::Report.fetch(since: since)
|
25
|
+
write_missing_envars(missing_envars) if missing_envars.any?
|
22
26
|
end
|
23
|
-
end
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
+
def parse(args)
|
29
|
+
options = OpenStruct.new
|
30
|
+
options.mapping = nil
|
31
|
+
options.overwrite = false
|
32
|
+
options.since = nil
|
33
|
+
|
34
|
+
opt_parser = OptionParser.new do |opts|
|
35
|
+
opts.separator ''
|
36
|
+
opts.banner = 'Usage: time_log_robot [options]'
|
37
|
+
|
38
|
+
opts.separator ''
|
39
|
+
opts.separator 'Specific options:'
|
40
|
+
|
41
|
+
opts.separator ''
|
42
|
+
opts.on('-m', '--mapping PATH', String,
|
43
|
+
'Description to JIRA key mapping file is located by default at',
|
44
|
+
'`~/.time_log_robot_mapping.yml`. Use this flag if you have a', 'mapping file elsewhere and would like to define the path to', 'point to your file instead.') do |mapping|
|
45
|
+
options.mapping = mapping
|
46
|
+
end
|
47
|
+
|
48
|
+
opts.separator ''
|
49
|
+
opts.on('-o', '--overwrite',
|
50
|
+
'Your settings are automatically written to a file -',
|
51
|
+
'`~/.time_log_robot_settings.yml` - to be used again the next', 'time you invoke the robot. Use this flag if you need to', 'overwrite those settings.') do |overwrite|
|
52
|
+
options.overwrite = overwrite
|
53
|
+
end
|
28
54
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
55
|
+
opts.separator ''
|
56
|
+
opts.on('-s', '--since DATE', Date,
|
57
|
+
'The date from which to log time entries.',
|
58
|
+
'Must be in YYYY-MM-DD format.',
|
59
|
+
'Default is the previous Saturday.') do |date|
|
60
|
+
options.since = date
|
61
|
+
end
|
33
62
|
|
34
|
-
|
35
|
-
|
63
|
+
opts.separator ''
|
64
|
+
opts.separator 'Common options:'
|
36
65
|
|
37
|
-
|
38
|
-
|
66
|
+
opts.on_tail('-i', '--inputs_help',
|
67
|
+
'Learn how and where to find the inputs you need to get', 'this working') do
|
68
|
+
print_inputs_help
|
69
|
+
exit
|
70
|
+
end
|
39
71
|
|
40
|
-
|
72
|
+
opts.on_tail('-h', '--help', 'Show this message') do
|
73
|
+
puts opts
|
74
|
+
exit
|
75
|
+
end
|
41
76
|
|
42
|
-
|
77
|
+
opts.on_tail('-v', '--version', 'Show version') do
|
78
|
+
puts TimeLogRobot::VERSION
|
79
|
+
exit
|
80
|
+
end
|
81
|
+
end
|
43
82
|
|
44
|
-
|
45
|
-
|
83
|
+
opt_parser.parse!(args)
|
84
|
+
options
|
85
|
+
end
|
86
|
+
|
87
|
+
def get_missing_envars
|
88
|
+
missing_envars = {}
|
89
|
+
|
90
|
+
TimeLogRobot.envars.each do |key|
|
91
|
+
next if key == 'MAPPING_FILE_PATH' || ENV[key]
|
92
|
+
missing_envars[key] = get_envar(key)
|
93
|
+
end
|
94
|
+
|
95
|
+
return missing_envars
|
96
|
+
end
|
97
|
+
|
98
|
+
def get_envar(key)
|
99
|
+
print "Enter your #{key}: "
|
100
|
+
env_value = gets.chomp
|
101
|
+
env_value.strip! unless should_not_strip?(key)
|
102
|
+
ENV[key] = env_value
|
103
|
+
if ENV[key].length == 0
|
104
|
+
puts 'Invalid input. This is a required field.'
|
105
|
+
exit
|
106
|
+
end
|
107
|
+
ENV[key]
|
108
|
+
end
|
109
|
+
|
110
|
+
def should_not_strip?(key)
|
111
|
+
%w(JIRA_PASSWORD).include? key
|
112
|
+
end
|
46
113
|
|
47
|
-
|
48
|
-
|
114
|
+
def fetch_envars_from_config
|
115
|
+
return unless envars = YAML.load_file(settings_file_path)
|
116
|
+
envars.each_pair do |key, value|
|
117
|
+
value.strip! unless should_not_strip?(key)
|
118
|
+
ENV[key.upcase] = value
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def write_missing_envars(missing_envars={})
|
123
|
+
puts "\nTo avoid entering setup information each time, the following configuration has been stored in `#{settings_file_path}`:"
|
124
|
+
missing_envars.each_pair do |key, value|
|
125
|
+
if key =~ /password|token/i
|
126
|
+
puts "\t#{key}=[FILTERED]"
|
127
|
+
else
|
128
|
+
puts "\t#{key}=#{value}"
|
129
|
+
end
|
49
130
|
|
50
|
-
|
51
|
-
|
131
|
+
data = YAML.load_file(settings_file_path) || {}
|
132
|
+
data[key.downcase] = value
|
133
|
+
File.open(settings_file_path, 'w') { |f| YAML.dump(data, f) }
|
134
|
+
end
|
135
|
+
end
|
52
136
|
|
53
|
-
|
54
|
-
|
55
|
-
|
137
|
+
def create_settings_file_if_nonexistent
|
138
|
+
File.new(settings_file_path, "w+") unless File.file?(settings_file_path)
|
139
|
+
end
|
140
|
+
|
141
|
+
def settings_file_path
|
142
|
+
File.join(ENV['HOME'], '.time_log_robot_settings.yml')
|
143
|
+
end
|
144
|
+
|
145
|
+
def print_inputs_help
|
146
|
+
TimeLogRobot.envars_help.each_pair do |envar, help_text|
|
147
|
+
puts envar
|
148
|
+
puts help_text
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def root
|
153
|
+
File.dirname __dir__
|
154
|
+
end
|
155
|
+
|
156
|
+
def start(since)
|
157
|
+
report = fetch_time_report(since)
|
158
|
+
JIRA::WorkLogger.log_all(
|
159
|
+
service: report[:service],
|
160
|
+
time_entries: report[:entries]
|
161
|
+
)
|
162
|
+
end
|
163
|
+
|
164
|
+
def fetch_time_report(since)
|
165
|
+
if since.nil?
|
166
|
+
Toggl::Report.fetch
|
167
|
+
else
|
168
|
+
Toggl::Report.fetch(since: since)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
def envars
|
173
|
+
envars_help.keys
|
174
|
+
end
|
175
|
+
|
176
|
+
def envars_help
|
177
|
+
{
|
178
|
+
'MAPPING_FILE_PATH' =>
|
179
|
+
"This is the path to your mapping file. By default, this file is named `.time_log_robot_mapping.yml` and lives in your home directory.\n\n",
|
180
|
+
|
181
|
+
'TOGGL_TOKEN' =>
|
182
|
+
"In your Toggl account, go to your profile page and look for the API token at the bottom.\n\n",
|
183
|
+
|
184
|
+
'TOGGL_WORKSPACE_ID' =>
|
185
|
+
"This is a little trickier. Your workspaces usually only show a human-readable name to you in Toggl's UI, and here you need the workspace machine ID. But you can do a curl request to find it like this (replacing TOGGL_TOKEN with your token from above):
|
186
|
+
|
187
|
+
\tcurl -v -u TOGGL_TOKEN:api_token \ -X GET https://www.toggl.com/api/v8/workspaces
|
188
|
+
|
189
|
+
Look at the result and find the id given for the workspace you want to use.\n\n",
|
190
|
+
|
191
|
+
'TOGGL_USER_AGENT' =>
|
192
|
+
"This is your Toggl username, usually your email.\n\n",
|
193
|
+
|
194
|
+
'TOGGL_DEFAULT_LOG_TAG' =>
|
195
|
+
"This is the tag name you would like to use for tagging your Toggl time entries as they are logged to JIRA.\n\n",
|
196
|
+
|
197
|
+
'JIRA_USERNAME' =>
|
198
|
+
"This is your JIRA username, which can be found in your JIRA user profile.\n\n",
|
199
|
+
|
200
|
+
'JIRA_PASSWORD' =>
|
201
|
+
"I know there's a lot of jargon, but some of these are pretty self-explanatory\n"
|
202
|
+
}
|
203
|
+
end
|
56
204
|
end
|
57
205
|
end
|
data/time_log_robot.gemspec
CHANGED
@@ -27,7 +27,5 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_development_dependency 'codeclimate-test-reporter', '~> 0.5'
|
28
28
|
|
29
29
|
spec.add_runtime_dependency 'activesupport', '~> 4.2', '>= 4.2.6'
|
30
|
-
spec.add_runtime_dependency '
|
31
|
-
spec.add_runtime_dependency 'httparty', '~> 0.13', '>= 0.13.0'
|
32
|
-
spec.add_runtime_dependency 'json', '1.8.1'
|
30
|
+
spec.add_runtime_dependency 'httparty', '~> 0.13', '>= 0.13.0'
|
33
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: time_log_robot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark J. Lehman
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: pry
|
@@ -114,26 +114,6 @@ dependencies:
|
|
114
114
|
- - ">="
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: 4.2.6
|
117
|
-
- !ruby/object:Gem::Dependency
|
118
|
-
name: commander
|
119
|
-
requirement: !ruby/object:Gem::Requirement
|
120
|
-
requirements:
|
121
|
-
- - "~>"
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
version: '4.1'
|
124
|
-
- - ">="
|
125
|
-
- !ruby/object:Gem::Version
|
126
|
-
version: 4.1.6
|
127
|
-
type: :runtime
|
128
|
-
prerelease: false
|
129
|
-
version_requirements: !ruby/object:Gem::Requirement
|
130
|
-
requirements:
|
131
|
-
- - "~>"
|
132
|
-
- !ruby/object:Gem::Version
|
133
|
-
version: '4.1'
|
134
|
-
- - ">="
|
135
|
-
- !ruby/object:Gem::Version
|
136
|
-
version: 4.1.6
|
137
117
|
- !ruby/object:Gem::Dependency
|
138
118
|
name: httparty
|
139
119
|
requirement: !ruby/object:Gem::Requirement
|
@@ -154,20 +134,6 @@ dependencies:
|
|
154
134
|
- - ">="
|
155
135
|
- !ruby/object:Gem::Version
|
156
136
|
version: 0.13.0
|
157
|
-
- !ruby/object:Gem::Dependency
|
158
|
-
name: json
|
159
|
-
requirement: !ruby/object:Gem::Requirement
|
160
|
-
requirements:
|
161
|
-
- - '='
|
162
|
-
- !ruby/object:Gem::Version
|
163
|
-
version: 1.8.1
|
164
|
-
type: :runtime
|
165
|
-
prerelease: false
|
166
|
-
version_requirements: !ruby/object:Gem::Requirement
|
167
|
-
requirements:
|
168
|
-
- - '='
|
169
|
-
- !ruby/object:Gem::Version
|
170
|
-
version: 1.8.1
|
171
137
|
description: Automate time logging from tools like Toggl to project management software
|
172
138
|
such as JIRA
|
173
139
|
email:
|
@@ -227,4 +193,3 @@ summary: Automate work time logging
|
|
227
193
|
test_files:
|
228
194
|
- test/test_helper.rb
|
229
195
|
- test/time_log_robot/jira/issue_key_parser_test.rb
|
230
|
-
has_rdoc:
|