time_log_robot 0.2.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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:
|