togman 0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/togman +58 -0
- data/lib/mantis.rb +44 -0
- data/lib/toggl.rb +63 -0
- metadata +135 -0
data/bin/togman
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
require "rubygems"
|
3
|
+
require "patron"
|
4
|
+
require "pp"
|
5
|
+
require "json"
|
6
|
+
require 'savon'
|
7
|
+
require 'highline/import'
|
8
|
+
require 'trollop'
|
9
|
+
require 'yaml'
|
10
|
+
|
11
|
+
require 'toggl.rb'
|
12
|
+
require 'mantis.rb'
|
13
|
+
|
14
|
+
configfile = ENV['HOME'] + '/.togmanrc'
|
15
|
+
if !File.file? configfile
|
16
|
+
puts 'Cannot open ' + configfile
|
17
|
+
exit
|
18
|
+
end
|
19
|
+
|
20
|
+
config = YAML::load_file configfile
|
21
|
+
pp config
|
22
|
+
|
23
|
+
Savon.configure do |setting|
|
24
|
+
setting.log = false # disable logging
|
25
|
+
# config.log_level = :info # changing the log level
|
26
|
+
end
|
27
|
+
|
28
|
+
opts = Trollop::options do
|
29
|
+
opt :dryrun, "Preview time to be logged without saving to Mantis", :short => 'd'
|
30
|
+
end
|
31
|
+
|
32
|
+
if !opts.dryrun
|
33
|
+
pass = ask('Password:') {|q| q.echo = '*'}
|
34
|
+
end
|
35
|
+
|
36
|
+
t = Toggl.new config['toggl_api_key'], config['nonbill']
|
37
|
+
m = Mantis.new config['user'], pass, config['mantis_url']
|
38
|
+
|
39
|
+
if !opts.dryrun
|
40
|
+
t.today.each do |ims, data|
|
41
|
+
if !m.issue_exists ims
|
42
|
+
raise "Issue not found #{ims}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
total = 0
|
48
|
+
free = []
|
49
|
+
t.today.each do |ims, data|
|
50
|
+
data.each do |item|
|
51
|
+
if !opts.dryrun
|
52
|
+
m.add_note ims, item[:desc], item[:duration]
|
53
|
+
end
|
54
|
+
p ims.to_s + " " + item[:desc] + " " + item[:duration].to_s + " " + item[:orig].to_s
|
55
|
+
total += item[:duration]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
p "TOTAL: " + total.to_s
|
data/lib/mantis.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
class Mantis
|
2
|
+
def initialize (user, password, url)
|
3
|
+
@client = Savon::Client.new do |wdsl|
|
4
|
+
wdsl.document = url
|
5
|
+
end
|
6
|
+
@client.wsdl.endpoint = url
|
7
|
+
@user = user
|
8
|
+
@password = password
|
9
|
+
end
|
10
|
+
|
11
|
+
def issue_exists (issue_id)
|
12
|
+
user = @user
|
13
|
+
password = @password
|
14
|
+
issue = @client.request "mc_issue_exists" do
|
15
|
+
soap.body = <<XML
|
16
|
+
<username>#{user}</username>
|
17
|
+
<password>#{password}</password>
|
18
|
+
<issue_id>#{issue_id}</issue_id>
|
19
|
+
XML
|
20
|
+
end
|
21
|
+
|
22
|
+
issue.to_hash[:mc_issue_exists_response][:return]
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_note (issue_id, text, time_tracking)
|
26
|
+
user = @user
|
27
|
+
password = @password
|
28
|
+
res = @client.request "mc_issue_note_add" do
|
29
|
+
soap.body = <<XML
|
30
|
+
<username>#{user}</username>
|
31
|
+
<password>#{password}</password>
|
32
|
+
<issue_id>#{issue_id}</issue_id>
|
33
|
+
<note>
|
34
|
+
<text>#{text}</text>
|
35
|
+
<view_state>
|
36
|
+
<name>private</name>
|
37
|
+
<id>50</id>
|
38
|
+
</view_state>
|
39
|
+
<time_tracking>#{time_tracking}</time_tracking>
|
40
|
+
</note>
|
41
|
+
XML
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/toggl.rb
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
class Toggl
|
2
|
+
def initialize (api_key, nonbill)
|
3
|
+
@api_key = api_key
|
4
|
+
@nonbill = nonbill
|
5
|
+
|
6
|
+
@sess = Patron::Session.new
|
7
|
+
@sess.base_url = "https://www.toggl.com"
|
8
|
+
@sess.username = api_key
|
9
|
+
@sess.password = "api_token"
|
10
|
+
end
|
11
|
+
|
12
|
+
def today
|
13
|
+
from = Time.utc(Time.now.year, Time.now.month, Time.now.day).iso8601
|
14
|
+
to = Time.utc(Time.now.year, Time.now.month, Time.now.day, 23, 59, 59).iso8601
|
15
|
+
return self.entries(from, to)
|
16
|
+
end
|
17
|
+
|
18
|
+
def entries (from, to)
|
19
|
+
log = {}
|
20
|
+
res = @sess.get('/api/v5/time_entries.json?start_date=' + from + '&end_date=' + to).body
|
21
|
+
JSON.parse(res)["data"].each do |item|
|
22
|
+
raw = item["description"]
|
23
|
+
|
24
|
+
# Check all entries start with a issue number
|
25
|
+
if !res = raw.match(/^([0-9]+) (.+)$/)
|
26
|
+
raise 'Item does not have an issue number: ' + raw
|
27
|
+
end
|
28
|
+
|
29
|
+
ims = res[1]
|
30
|
+
desc = res[2]
|
31
|
+
duration = (item["duration"] / 60)
|
32
|
+
|
33
|
+
if log[ims] == nil
|
34
|
+
log[ims] = []
|
35
|
+
end
|
36
|
+
|
37
|
+
# Squash times with the same descriptions together
|
38
|
+
exists = false
|
39
|
+
log[ims].each do |exist|
|
40
|
+
if exist[:desc] == desc
|
41
|
+
exist[:duration] += duration
|
42
|
+
exists = true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# TOOD: Rounding should be on the total time for an issue.
|
47
|
+
# not per note... either need to bunch them together or
|
48
|
+
# round the final note???
|
49
|
+
|
50
|
+
free = false
|
51
|
+
if !@nonbill.member? ims.to_i
|
52
|
+
orig = duration
|
53
|
+
duration = ((duration.to_f/10).ceil*10).round
|
54
|
+
free = true
|
55
|
+
end
|
56
|
+
|
57
|
+
if !exists
|
58
|
+
log[ims].push({:desc => desc, :duration => duration, :orig => orig})
|
59
|
+
end
|
60
|
+
end
|
61
|
+
return log
|
62
|
+
end
|
63
|
+
end
|
metadata
ADDED
@@ -0,0 +1,135 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: togman
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
version: "0.1"
|
9
|
+
platform: ruby
|
10
|
+
authors:
|
11
|
+
- Benjamin Johnson
|
12
|
+
autorequire:
|
13
|
+
bindir: bin
|
14
|
+
cert_chain: []
|
15
|
+
|
16
|
+
date: 2011-10-03 00:00:00 +01:00
|
17
|
+
default_executable: bin/togman
|
18
|
+
dependencies:
|
19
|
+
- !ruby/object:Gem::Dependency
|
20
|
+
name: patron
|
21
|
+
prerelease: false
|
22
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
segments:
|
27
|
+
- 0
|
28
|
+
- 4
|
29
|
+
- 16
|
30
|
+
version: 0.4.16
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: json
|
35
|
+
prerelease: false
|
36
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
segments:
|
41
|
+
- 1
|
42
|
+
- 6
|
43
|
+
- 1
|
44
|
+
version: 1.6.1
|
45
|
+
type: :runtime
|
46
|
+
version_requirements: *id002
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: savon
|
49
|
+
prerelease: false
|
50
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
- 9
|
57
|
+
- 7
|
58
|
+
version: 0.9.7
|
59
|
+
type: :runtime
|
60
|
+
version_requirements: *id003
|
61
|
+
- !ruby/object:Gem::Dependency
|
62
|
+
name: highline
|
63
|
+
prerelease: false
|
64
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
segments:
|
69
|
+
- 1
|
70
|
+
- 6
|
71
|
+
- 2
|
72
|
+
version: 1.6.2
|
73
|
+
type: :runtime
|
74
|
+
version_requirements: *id004
|
75
|
+
- !ruby/object:Gem::Dependency
|
76
|
+
name: trollop
|
77
|
+
prerelease: false
|
78
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
segments:
|
83
|
+
- 1
|
84
|
+
- 16
|
85
|
+
- 2
|
86
|
+
version: 1.16.2
|
87
|
+
type: :runtime
|
88
|
+
version_requirements: *id005
|
89
|
+
description: ""
|
90
|
+
email:
|
91
|
+
- ben@benpjohnson.com
|
92
|
+
executables:
|
93
|
+
- togman
|
94
|
+
extensions: []
|
95
|
+
|
96
|
+
extra_rdoc_files: []
|
97
|
+
|
98
|
+
files:
|
99
|
+
- bin/togman
|
100
|
+
- lib/mantis.rb
|
101
|
+
- lib/toggl.rb
|
102
|
+
has_rdoc: true
|
103
|
+
homepage: http://benpjohnson.com
|
104
|
+
licenses: []
|
105
|
+
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
|
109
|
+
require_paths:
|
110
|
+
- lib
|
111
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
requirements:
|
113
|
+
- - ">="
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
version: "0"
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
segments:
|
123
|
+
- 1
|
124
|
+
- 3
|
125
|
+
- 6
|
126
|
+
version: 1.3.6
|
127
|
+
requirements: []
|
128
|
+
|
129
|
+
rubyforge_project:
|
130
|
+
rubygems_version: 1.3.6
|
131
|
+
signing_key:
|
132
|
+
specification_version: 3
|
133
|
+
summary: Transfer time from Toggl to Mantis
|
134
|
+
test_files: []
|
135
|
+
|