trollolo 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,64 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class Card
19
+
20
+ attr_accessor :sp, :tasks, :tasks_done
21
+
22
+ def self.name_to_points(card_name)
23
+ card_name =~ /^\(([\d.]+)\)/
24
+ return nil if $1.nil?
25
+ $1.to_f
26
+ end
27
+
28
+ def initialize
29
+ @sp = nil
30
+ @extra = false
31
+ end
32
+
33
+ def has_sp?
34
+ @sp != nil
35
+ end
36
+
37
+ def extra?
38
+ @extra
39
+ end
40
+
41
+ def set_extra
42
+ @extra = true
43
+ end
44
+
45
+ def self.parse json
46
+ card = Card.new
47
+
48
+ title = json["name"]
49
+ card.sp = name_to_points(title)
50
+
51
+ labels = json["labels"]
52
+ labels.each do |label|
53
+ if label["name"] == "Under waterline"
54
+ card.set_extra
55
+ end
56
+ end
57
+
58
+ card.tasks = json["badges"]["checkItems"]
59
+ card.tasks_done = json["badges"]["checkItemsChecked"]
60
+
61
+ card
62
+ end
63
+
64
+ end
@@ -0,0 +1,251 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class Cli < Thor
19
+
20
+ default_task :global
21
+
22
+ class_option :version, :type => :boolean, :desc => "Show version"
23
+ class_option :verbose, :type => :boolean, :desc => "Verbose mode"
24
+ class_option :raw, :type => :boolean, :desc => "Raw mode"
25
+ class_option "board-id", :type => :string, :desc => "id of Trello board"
26
+
27
+ def self.settings= s
28
+ @@settings = s
29
+ end
30
+
31
+ desc "global", "Global options", :hide => true
32
+ def global
33
+ if options[:version]
34
+ puts "Trollolo: #{@@settings.version}"
35
+ else
36
+ Cli.help shell
37
+ end
38
+ end
39
+
40
+ desc "get-lists", "Get lists"
41
+ option "board-id", :desc => "Id of Trello board", :required => true
42
+ def get_lists
43
+ process_global_options options
44
+ require_trello_credentials
45
+
46
+ trello = Trello.new(board_id: options["board-id"], developer_public_key: @@settings.developer_public_key, member_token: @@settings.member_token)
47
+ lists = trello.lists
48
+
49
+ if @@settings.raw
50
+ puts JSON.pretty_generate lists
51
+ else
52
+ lists.each do |list|
53
+ puts "#{list[ "name" ]}"
54
+ end
55
+ end
56
+ end
57
+
58
+ desc "get-cards", "Get cards"
59
+ option "board-id", :desc => "Id of Trello board", :required => true
60
+ def get_cards
61
+ process_global_options options
62
+ require_trello_credentials
63
+
64
+ trello = Trello.new(board_id: options["board-id"], developer_public_key: @@settings.developer_public_key, member_token: @@settings.member_token)
65
+
66
+ cards = trello.cards
67
+
68
+ if @@settings.raw
69
+ puts JSON.pretty_generate cards
70
+ else
71
+ burndown = BurndownData.new @@settings
72
+ burndown.board_id = options["board-id"]
73
+
74
+ todo_list_id = burndown.fetch_todo_list_id
75
+ doing_list_id = burndown.fetch_doing_list_id
76
+ done_list_id = burndown.fetch_done_list_id
77
+
78
+ cards_todo = Array.new
79
+ cards_doing = Array.new
80
+ cards_done = Array.new
81
+
82
+ above_waterline = true
83
+
84
+ cards.each do |card|
85
+ name = card["name"]
86
+ list = card["idList"]
87
+ puts "CARD #{name} (#{list})"
88
+
89
+ if name == "Waterline"
90
+ above_waterline = false
91
+ next
92
+ end
93
+
94
+ if Card.name_to_points(name).nil?
95
+ next
96
+ end
97
+
98
+ if list == todo_list_id && above_waterline
99
+ cards_todo.push card
100
+ elsif list == doing_list_id
101
+ cards_doing.push card
102
+ elsif list == done_list_id
103
+ cards_done.push card
104
+ end
105
+ end
106
+
107
+ story_points_todo = 0
108
+ story_points_doing = 0
109
+ story_points_done = 0
110
+
111
+ puts
112
+
113
+ puts "Todo"
114
+ cards_todo.each do |card|
115
+ puts " #{card["name"]}"
116
+ story_points_todo += Card.name_to_points(card["name"])
117
+ end
118
+
119
+ puts "Doing"
120
+ cards_doing.each do |card|
121
+ puts " #{card["name"]}"
122
+ story_points_doing += Card.name_to_points(card["name"])
123
+ end
124
+
125
+ puts "Done"
126
+ cards_done.each do |card|
127
+ puts " #{card["name"]}"
128
+ story_points_done += Card.name_to_points(card["name"])
129
+ end
130
+
131
+ puts
132
+
133
+ story_points_total = story_points_todo + story_points_doing + story_points_done
134
+
135
+ puts "Done: #{story_points_done}/#{story_points_total} (#{story_points_doing} in progress)"
136
+ end
137
+ end
138
+
139
+ desc "get-checklists", "Get checklists"
140
+ option "board-id", :desc => "Id of Trello board", :required => true
141
+ def get_checklists
142
+ process_global_options options
143
+ require_trello_credentials
144
+
145
+ trello = Trello.new(board_id: options["board-id"], developer_public_key: @@settings.developer_public_key, member_token: @@settings.member_token)
146
+
147
+ data = trello.checklists
148
+
149
+ puts JSON.pretty_generate data
150
+ end
151
+
152
+ desc "fetch-burndown-data", "Fetch data for burndown chart"
153
+ option "board-id", :desc => "Id of Trello board", :required => true
154
+ def fetch_burndown_data
155
+ process_global_options options
156
+ require_trello_credentials
157
+
158
+ burndown = BurndownData.new @@settings
159
+ burndown.board_id = options["board-id"]
160
+ burndown.fetch
161
+
162
+ puts "Story points:"
163
+ puts " Open: #{burndown.story_points.open}"
164
+ puts " Done: #{burndown.story_points.done}"
165
+ puts " Total: #{burndown.story_points.total}"
166
+ puts "Tasks:"
167
+ puts " Open: #{burndown.tasks.open}"
168
+ puts " Done: #{burndown.tasks.done}"
169
+ puts " Total: #{burndown.tasks.total}"
170
+ puts
171
+ puts "Extra story points:"
172
+ puts " Open: #{burndown.extra_story_points.open}"
173
+ puts " Done: #{burndown.extra_story_points.done}"
174
+ puts " Total: #{burndown.extra_story_points.total}"
175
+ puts "Extra tasks:"
176
+ puts " Open: #{burndown.extra_tasks.open}"
177
+ puts " Done: #{burndown.extra_tasks.done}"
178
+ puts " Total: #{burndown.extra_tasks.total}"
179
+ end
180
+
181
+ desc "burndown-init", "Initialize burndown chart"
182
+ option :output, :aliases => :o, :desc => "Output directory", :required => true
183
+ option "board-id", :desc => "Id of Trello board", :required => true
184
+ def burndown_init command=nil
185
+ process_global_options options
186
+ require_trello_credentials
187
+
188
+ chart = BurndownChart.new @@settings
189
+ puts "Preparing directory..."
190
+ chart.setup(options[:output],options["board-id"])
191
+ end
192
+
193
+ desc "burndown", "Update burndown chart"
194
+ option :output, :aliases => :o, :desc => "Output directory", :required => false
195
+ option :new_sprint, :aliases => :n, :desc => "Create new sprint"
196
+ def burndown
197
+ process_global_options options
198
+ require_trello_credentials
199
+
200
+ chart = BurndownChart.new @@settings
201
+ begin
202
+ if options[:new_sprint]
203
+ chart.create_next_sprint(options[:output] || Dir.pwd)
204
+ end
205
+ chart.update(options[:output] || Dir.pwd)
206
+ rescue TrolloloError => e
207
+ STDERR.puts e
208
+ exit 1
209
+ end
210
+ end
211
+
212
+ desc "plot", "Plot burndown chart"
213
+ def plot(sprint_number)
214
+ process_global_options options
215
+
216
+ plot_helper = File.expand_path("../../scripts/create_burndown.py", __FILE__ )
217
+ system "python #{plot_helper} #{sprint_number}"
218
+ end
219
+
220
+ private
221
+
222
+ def process_global_options options
223
+ @@settings.verbose = options[:verbose]
224
+ @@settings.raw = options[:raw]
225
+ end
226
+
227
+ def require_trello_credentials
228
+ write_back = false
229
+
230
+ if !@@settings.developer_public_key
231
+ puts "Put in Trello developer public key:"
232
+ @@settings.developer_public_key = STDIN.gets.chomp
233
+ write_back = true
234
+ end
235
+
236
+ if !@@settings.member_token
237
+ puts "Put in Trello member token:"
238
+ @@settings.member_token = STDIN.gets.chomp
239
+ write_back = true
240
+ end
241
+
242
+ if write_back
243
+ @@settings.save_config
244
+ end
245
+
246
+ if !@@settings.developer_public_key || !@@settings.member_token
247
+ STDERR.puts "Require trello credentials in config file"
248
+ exit 1
249
+ end
250
+ end
251
+ end
@@ -0,0 +1,54 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class Settings
19
+
20
+ attr_accessor :verbose, :raw
21
+ attr_accessor :developer_public_key, :member_token
22
+
23
+ def initialize config_file_path
24
+ @config_file_path = config_file_path
25
+ if File.exists? config_file_path
26
+ @config = YAML.load_file(config_file_path)
27
+
28
+ if @config
29
+ @developer_public_key = @config["developer_public_key"]
30
+ @member_token = @config["member_token"]
31
+ else
32
+ raise "Couldn't read config data from '#{config_file_path}'"
33
+ end
34
+ end
35
+
36
+ @verbose = false
37
+ @raw = false
38
+ end
39
+
40
+ def save_config
41
+ @config = {}
42
+ @config["developer_public_key"] = @developer_public_key
43
+ @config["member_token"] = @member_token
44
+
45
+ File.open(@config_file_path,"w") do |f|
46
+ f.write(@config.to_yaml)
47
+ end
48
+ end
49
+
50
+ def version
51
+ Trollolo::VERSION
52
+ end
53
+
54
+ end
@@ -0,0 +1,66 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ class Trello
19
+ class ApiError < StandardError; end
20
+
21
+ attr_accessor :board_id
22
+
23
+ attr_reader :developer_public_key, :member_token
24
+
25
+ def initialize settings
26
+ @developer_public_key = settings.fetch(:developer_public_key)
27
+ @member_token = settings.fetch(:member_token)
28
+ @board_id = settings.fetch(:board_id)
29
+ end
30
+
31
+ def lists
32
+ get "lists"
33
+ end
34
+
35
+ def cards
36
+ get "cards"
37
+ end
38
+
39
+ def checklists
40
+ get "checklists"
41
+ end
42
+
43
+ private
44
+
45
+ def resource_url resource
46
+ "/1/boards/#{board_id}/#{resource}?key=#{developer_public_key}&token=#{member_token}"
47
+ end
48
+
49
+ # FIXME: we should handle time-outs gracefully.
50
+
51
+ def get resource
52
+ resp = http_client.get resource_url(resource)
53
+ unless resp.code == "200"
54
+ raise ApiError.new("Error occured while connecting to the trello API.")
55
+ end
56
+ JSON.parse(resp.body)
57
+ rescue JSON::ParserError => e
58
+ raise ApiError.new(e)
59
+ end
60
+
61
+ def http_client
62
+ http = Net::HTTP.new "trello.com", 443
63
+ http.use_ssl = true
64
+ http
65
+ end
66
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright (c) 2013-2014 SUSE LLC
2
+ #
3
+ # This program is free software; you can redistribute it and/or
4
+ # modify it under the terms of version 3 of the GNU General Public License as
5
+ # published by the Free Software Foundation.
6
+ #
7
+ # This program is distributed in the hope that it will be useful,
8
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
9
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
+ # GNU General Public License for more details.
11
+ #
12
+ # You should have received a copy of the GNU General Public License
13
+ # along with this program; if not, contact SUSE LLC.
14
+ #
15
+ # To contact SUSE about this file by physical or electronic mail,
16
+ # you may find current contact information at www.suse.com
17
+
18
+ require "thor"
19
+ require "net/http"
20
+ require "net/https"
21
+ require "json"
22
+ require "yaml"
23
+ require "erb"
24
+
25
+ require_relative 'version'
26
+ require_relative 'cli'
27
+ require_relative 'settings'
28
+ require_relative 'trello'
29
+ require_relative 'card'
30
+ require_relative 'burndown_chart'
31
+ require_relative 'burndown_data'
32
+
33
+ class TrolloloError < StandardError
34
+ end