trollolo 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b4ae1e203030317bbb9ec7e96f53ee12c5d81d82
4
- data.tar.gz: d8943b820b15ce09f72b6147289af3c89ba207b0
3
+ metadata.gz: 822cffbe55d2f6d6003d3efe7e5df4afd16a9bc1
4
+ data.tar.gz: 48ba1dc0d72deb98df2620cb09ac3413a64a682b
5
5
  SHA512:
6
- metadata.gz: 245e86bbe23e00552dd795479d44f271b11643ed82e9516d59541c50ce6b8bcf726de0fb0ab88ba68eb3bdab9f004e4bdb9357d4276c45b008b05855dc8069f5
7
- data.tar.gz: a732a4c652a3769e90fa3b9c17206adb8c1dc1b5736e952974073ff576de1bf1924118dfdfdf116d63701604b83db2eba4b75cb2021e5bd17d6c4aa222a09e43
6
+ metadata.gz: 80cf5c482a836eba4ed4743693cfb7c0acc459e955aa17c7e33e1b3ab3ade4fb0d2f8babb077f86829aa08ad9821256865c47b28f8ac421f14de4ccf04550753
7
+ data.tar.gz: 7974a309702986ff401670b20f24cb12c55d23e644e50bce8bbf806ae089bd0b385c6043ca64aab6598770003a5500e47bc28e04d2f6497dda5c26e246e49261
data/.travis.yml CHANGED
@@ -4,9 +4,10 @@ before_install:
4
4
  - gem update --system
5
5
  - gem --version
6
6
  rvm:
7
- - "2.0.0"
8
- - "2.1.1"
7
+ - "2.1.7"
8
+ - "2.2.3"
9
9
  script: bundle exec rspec spec/unit
10
+ sudo: false
10
11
 
11
12
  addons:
12
13
  code_climate:
data/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Trollolo Changelog
2
2
 
3
+ ## Version 0.0.7
4
+
5
+ * Add set-description command
6
+ * Add get-description command
7
+ * Add make-cover command to set an existing image as cover
8
+ * Add option to push burndown data to an API endpoint
9
+
3
10
  ## Version 0.0.6
4
11
 
5
12
  * Track cards with unplanned work separately
data/Gemfile CHANGED
@@ -5,7 +5,7 @@ gemspec
5
5
  group :test do
6
6
  gem 'codeclimate-test-reporter'
7
7
  gem 'rspec', '~> 3'
8
- gem 'aruba'
8
+ gem 'cli_tester'
9
9
  gem 'webmock'
10
10
  gem 'given_filesystem'
11
11
  gem 'byebug'
data/README.md CHANGED
@@ -91,6 +91,21 @@ This will create a new data file for the next sprint number and populate it
91
91
  with initial data taken from the Trello board. You are ready to go for the
92
92
  sprint now and can continue with calling `trollolo burndown` after each daily.
93
93
 
94
+ To push the current state of the scrum process (current day) to an api endpoint call:
95
+
96
+ trollolo burndown --push-to-api URL
97
+
98
+ Trollolo will send a json encoded POST request to `URL` with the same structure as the generated burndown yaml file.
99
+
100
+ __Note:__ If no fast lane cards are in this sprint the fast_lane structure won't appear in the json structure
101
+
102
+ The specified `URL` can contain placeholders which will be replaced:
103
+
104
+ :sprint => Current running sprint
105
+ :board => Board ID
106
+
107
+
108
+
94
109
  To generate the actual burndown chart, go to the working directory and call:
95
110
 
96
111
  trollolo plot SPRINT_NUMBER
@@ -106,6 +106,30 @@ class BurndownChart
106
106
  end
107
107
  end
108
108
 
109
+
110
+ # Writes a POST request to url
111
+ def push_to_api(url, burndown_data)
112
+
113
+ url = url.gsub(':sprint', sprint.to_s)
114
+ .gsub(':board', board_id.to_s)
115
+
116
+ begin
117
+ uri = URI.parse(url)
118
+ push = Net::HTTP::Post.new(uri.path, { 'Content-Type' => 'application/json' })
119
+ push.body = burndown_data.to_hash.to_json
120
+
121
+ Net::HTTP.start(uri.hostname, uri.port) do |http|
122
+ http.request(push)
123
+ end
124
+ rescue StandardError => e
125
+ # Instead of catching 20 different exceptions which can be
126
+ # thrown by URI and Http::, StandardError is catched.
127
+ # Fix this if there is a better solution
128
+ raise TrolloloError.new("pushing to endpoint failed: #{e.message}")
129
+ end
130
+ end
131
+
132
+
109
133
  def burndown_data_filename
110
134
  "burndown-data-#{sprint.to_s.rjust(2,"0")}.yaml"
111
135
  end
@@ -179,6 +203,10 @@ class BurndownChart
179
203
  if options[:plot]
180
204
  BurndownChart.plot(self.sprint, options)
181
205
  end
206
+
207
+ if options.has_key?('push-to-api')
208
+ push_to_api(options['push-to-api'], data)
209
+ end
182
210
  end
183
211
 
184
212
  def create_next_sprint(burndown_dir)
data/lib/burndown_data.rb CHANGED
@@ -47,6 +47,7 @@ class BurndownData
47
47
  @unplanned_story_points = Result.new
48
48
  @unplanned_tasks = Result.new
49
49
  @fast_lane_cards = Result.new
50
+ @date_time = Time.now
50
51
  end
51
52
 
52
53
  def to_hash
data/lib/cli.rb CHANGED
@@ -169,6 +169,7 @@ EOT
169
169
  option :plot, :type => :boolean, :desc => "also plot the new data"
170
170
  option 'with-fast-lane', :desc => "Plot Fast Lane with new cards bars", :required => false, :type => :boolean
171
171
  option 'no-tasks', :desc => "Do not plot tasks line", :required => false, :type => :boolean
172
+ option 'push-to-api', :desc => 'Push collected data to api endpoint (in json)', :required => false
172
173
  def burndown
173
174
  process_global_options options
174
175
  require_trello_credentials
@@ -235,6 +236,27 @@ EOT
235
236
  puts "Home page: #{o.url}"
236
237
  end
237
238
 
239
+ desc "get-description", "Reads description"
240
+ option "card-id", :desc => "Id of card", :required => true
241
+ def get_description
242
+ process_global_options options
243
+ require_trello_credentials
244
+
245
+ trello = TrelloWrapper.new(@@settings)
246
+
247
+ puts trello.get_description(options["card-id"])
248
+ end
249
+
250
+ desc "set-description", "Writes description read from standard input"
251
+ option "card-id", :desc => "Id of card", :required => true
252
+ def set_description
253
+ process_global_options options
254
+ require_trello_credentials
255
+
256
+ trello = TrelloWrapper.new(@@settings)
257
+ trello.set_description(options["card-id"], STDIN.read)
258
+ end
259
+
238
260
  desc "organization_members", "Show organization members"
239
261
  option "org-name", :desc => "Name of organization", :required => true
240
262
  def organization_members
@@ -261,6 +283,16 @@ EOT
261
283
  trello.add_attachment(options["card-id"], filename)
262
284
  end
263
285
 
286
+ desc "make-cover <filename>", "Make existing picture the cover"
287
+ option "card-id", :desc => "Id of card", :required => true
288
+ def make_cover(filename)
289
+ process_global_options(options)
290
+ require_trello_credentials
291
+
292
+ trello = TrelloWrapper.new(@@settings)
293
+ trello.make_cover(options["card-id"], filename)
294
+ end
295
+
264
296
  private
265
297
 
266
298
  def process_global_options options
@@ -55,6 +55,31 @@ class TrelloWrapper
55
55
  card.add_attachment(File.open(filename, "rb"))
56
56
  end
57
57
 
58
+ def make_cover(card_id, image_name)
59
+ attachment_id = attachment_id_by_name(card_id, image_name)
60
+ raise("Error: The attachment with the name '#{image_name}' was not found") if !attachment_id
61
+ client.put("/cards/#{card_id}/idAttachmentCover?value=#{attachment_id}")
62
+ end
63
+
64
+ def attachment_id_by_name(card_id, image_name)
65
+ json = JSON.parse(client.get("/cards/#{card_id}/attachments?fields=name"))
66
+ attachment = json.find{ |e| e["name"] == image_name }
67
+ if attachment
68
+ attachment["id"]
69
+ else
70
+ nil
71
+ end
72
+ end
73
+
74
+ def get_description(card_id)
75
+ card = Trello::Card.find(card_id)
76
+ card.desc
77
+ end
78
+
79
+ def set_description(card_id, description)
80
+ client.put("/cards/#{card_id}/desc?value=#{description}")
81
+ end
82
+
58
83
  private
59
84
 
60
85
  def init_trello
data/lib/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Trollolo
2
2
 
3
- VERSION = "0.0.6"
3
+ VERSION = "0.0.7"
4
4
 
5
5
  end
@@ -1,6 +1,7 @@
1
1
  require_relative 'integration_spec_helper'
2
2
 
3
3
  include GivenFilesystemSpecHelpers
4
+ include CliTester
4
5
 
5
6
  def trollolo_cmd
6
7
  File.expand_path('../wrapper/trollolo_wrapper',__FILE__)
@@ -17,37 +18,35 @@ end
17
18
  describe "command line" do
18
19
 
19
20
  it "processes help option" do
20
- run "trollolo -h"
21
- assert_exit_status_and_partial_output 0, "Commands:"
22
- assert_partial_output "trollolo help", all_output
23
- assert_partial_output "Options:", all_output
21
+ result = run_command(args: ["-h"])
22
+ expect(result).to exit_with_success(/Commands:/)
23
+ expect(result.stdout).to match("trollolo help")
24
+ expect(result.stdout).to match("Options:")
24
25
  end
25
26
 
26
27
  it "throws error on invalid command" do
27
- run "#{trollolo_cmd} invalid_command"
28
- assert_exit_status 1
28
+ result = run_command(cmd: trollolo_cmd, args: ["invalid_command"])
29
+ expect(result).to exit_with_error(1, "Could not find command \"invalid_command\".\n")
29
30
  end
30
-
31
+
31
32
  it "asks for authorization data" do
32
- run "#{credentials_input_wrapper} get-cards --board-id=myboardid"
33
- assert_exit_status 0
33
+ expect(run_command(cmd: credentials_input_wrapper, args: ["get-cards", "--board-id=myboardid"])).to exit_with_success("")
34
34
  end
35
35
 
36
36
  describe "burndown chart" do
37
37
  use_given_filesystem
38
-
38
+
39
39
  it "inits burndown directory" do
40
40
  path = given_directory
41
- run "#{trollolo_cmd} burndown-init -o #{path} --board-id=myboardid"
42
- assert_exit_status 0
41
+ result = run_command(cmd: trollolo_cmd, args: ["burndown-init", "-o", "#{path}", "--board-id=myboardid"])
42
+ expect(result).to exit_with_success(/Preparing/)
43
43
  end
44
-
44
+
45
45
  it "fails, if burndown data is not found" do
46
46
  path = given_directory
47
- run "#{trollolo_cmd} burndown -o #{path}"
48
- assert_exit_status 1
49
- assert_partial_output "burndown-data-01.yaml' not found", all_stderr
47
+ result = run_command(cmd: trollolo_cmd, args: ["burndown", "-o", "#{path}"])
48
+ expect(result).to exit_with_error(1, /burndown-data-01.yaml' not found/)
50
49
  end
51
50
  end
52
-
51
+
53
52
  end
@@ -1,6 +1,7 @@
1
1
  require_relative "integration_spec_helper"
2
2
 
3
3
  include GivenFilesystemSpecHelpers
4
+ include CliTester
4
5
 
5
6
  HELPER_SCRIPT = File.expand_path("../../../scripts/create_burndown.py", __FILE__)
6
7
 
@@ -12,9 +13,8 @@ describe "create_burndown.py" do
12
13
  given_file("burndown-data-23.yaml", from: "create_burndown_helper/burndown-data-23.yaml")
13
14
  end
14
15
 
15
- cmd = "#{HELPER_SCRIPT} 23 --output=#{@working_dir} --no-head"
16
- run(cmd)
17
- assert_exit_status(0)
16
+ result = run_command(cmd: HELPER_SCRIPT, args: ["23", "--output=#{@working_dir}", "--no-head"])
17
+ expect(result).to exit_with_success("")
18
18
  expect(File.join(@working_dir, "burndown-23.png")).
19
19
  to be_same_image_as("create_burndown_helper/burndown-23.png")
20
20
  end
@@ -24,9 +24,8 @@ describe "create_burndown.py" do
24
24
  given_file("burndown-data-31.yaml", from: "create_burndown_helper/burndown-data-31.yaml")
25
25
  end
26
26
 
27
- cmd = "#{HELPER_SCRIPT} 31 --output=#{@working_dir} --no-head"
28
- run(cmd)
29
- assert_exit_status(0)
27
+ result = run_command(cmd: HELPER_SCRIPT, args: ["31", "--output=#{@working_dir}", "--no-head"])
28
+ expect(result).to exit_with_success("")
30
29
  expect(File.join(@working_dir, "burndown-31.png")).
31
30
  to be_same_image_as("create_burndown_helper/burndown-31.png")
32
31
  end
@@ -36,9 +35,8 @@ describe "create_burndown.py" do
36
35
  given_file("burndown-data-35.yaml", from: "create_burndown_helper/burndown-data-35.yaml")
37
36
  end
38
37
 
39
- cmd = "#{HELPER_SCRIPT} 35 --output=#{@working_dir} --no-head"
40
- run(cmd)
41
- assert_exit_status(0)
38
+ result = run_command(cmd: HELPER_SCRIPT, args: ["35", "--output=#{@working_dir}", "--no-head"])
39
+ expect(result).to exit_with_success("")
42
40
  expect(File.join(@working_dir, "burndown-35.png")).
43
41
  to be_same_image_as("create_burndown_helper/burndown-35.png")
44
42
  end
@@ -48,9 +46,9 @@ describe "create_burndown.py" do
48
46
  given_file("burndown-data-08.yaml", from: "create_burndown_helper/burndown-data-08.yaml")
49
47
  end
50
48
 
51
- cmd = "#{HELPER_SCRIPT} 08 --output=#{@working_dir} --no-tasks --with-fast-lane --no-head"
52
- run(cmd)
53
- assert_exit_status(0)
49
+ result = run_command(cmd: HELPER_SCRIPT,
50
+ args: ["08", "--output=#{@working_dir}", "--no-tasks", "--with-fast-lane", "--no-head"])
51
+ expect(result).to exit_with_success("")
54
52
  expect(File.join(@working_dir, "burndown-08.png")).
55
53
  to be_same_image_as("create_burndown_helper/burndown-08.png")
56
54
  end
@@ -1,5 +1,6 @@
1
1
  require_relative '../../lib/trollolo'
2
2
  require 'given_filesystem/spec_helpers'
3
+ require 'cli_tester'
3
4
 
4
5
  bin_path = File.expand_path( "../../../bin/", __FILE__ )
5
6
 
@@ -3,10 +3,24 @@ require_relative 'spec_helper'
3
3
  include GivenFilesystemSpecHelpers
4
4
 
5
5
  describe BurndownChart do
6
+
7
+ subject { BurndownChart.new(dummy_settings) }
8
+
9
+ let(:burndown_data) do
10
+ burndown_data = BurndownData.new(dummy_settings)
11
+ burndown_data.story_points.open = 16
12
+ burndown_data.story_points.done = 7
13
+ burndown_data.tasks.open = 10
14
+ burndown_data.tasks.done = 11
15
+ burndown_data.date_time = DateTime.parse('2014-05-30')
16
+ burndown_data
17
+ end
18
+
6
19
  before(:each) do
7
20
  @settings = dummy_settings
8
21
  @burndown_data = BurndownData.new(@settings)
9
22
  @chart = BurndownChart.new(@settings)
23
+ allow(BurndownData).to receive(:new).and_return(burndown_data)
10
24
  full_board_mock
11
25
  end
12
26
 
@@ -312,6 +326,21 @@ EOT
312
326
  expect(File.read(write_path)).to eq expected_file_content
313
327
  end
314
328
  end
329
+
330
+ describe '#push_to_api' do
331
+ let(:sample_url) { 'http://api.somesite.org/push/1/days' }
332
+ let(:malformed_url) { 'http//api.malformed..urrii/@@@@' }
333
+
334
+ it 'check if it raises an expection on malformed url' do
335
+ expect { subject.push_to_api(malformed_url, burndown_data) }
336
+ .to raise_error(TrolloloError)
337
+ end
338
+
339
+ it 'push data to api endpoint' do
340
+ stub_request(:post, sample_url).with(body: @chart.data.to_hash.to_json).to_return(status: 200)
341
+ subject.push_to_api(sample_url, @chart.data)
342
+ end
343
+ end
315
344
  end
316
345
 
317
346
  describe "commands" do
@@ -96,4 +96,45 @@ EOT
96
96
  @cli.get_checklists
97
97
  }.to output(expected_output).to_stdout
98
98
  end
99
+
100
+ it "gets description" do
101
+ body = <<-EOT
102
+ {
103
+ "id": "54ae8485221b1cc5b173e713",
104
+ "desc": "haml"
105
+ }
106
+ EOT
107
+ stub_request(
108
+ :get, "https://api.trello.com/1/cards/54ae8485221b1cc5b173e713?key=mykey&token=mytoken"
109
+ ).with(
110
+ :headers => {
111
+ 'Accept'=>'*/*; q=0.5, application/xml',
112
+ 'Accept-Encoding'=>'gzip, deflate',
113
+ 'User-Agent'=>'Ruby'
114
+ }
115
+ ).to_return(:status => 200, :body => body, :headers => {})
116
+ @cli.options = {"card-id" => "54ae8485221b1cc5b173e713"}
117
+ expected_output = "haml\n"
118
+ expect {
119
+ @cli.get_description
120
+ }.to output(expected_output).to_stdout
121
+ end
122
+
123
+ it "sets description" do
124
+ expect(STDIN).to receive(:read).and_return("My description")
125
+ stub_request(
126
+ :put, "https://api.trello.com/1/cards/54ae8485221b1cc5b173e713/desc?key=mykey&token=mytoken&value=My%20description"
127
+ ).with(
128
+ :headers => {
129
+ 'Accept'=>'*/*; q=0.5, application/xml',
130
+ 'Accept-Encoding'=>'gzip, deflate',
131
+ 'Content-Length'=>'0',
132
+ 'Content-Type'=>'application/x-www-form-urlencoded',
133
+ 'User-Agent'=>'Ruby'
134
+ }
135
+ ).to_return(:status => 200, :body => "", :headers => {})
136
+ @cli.options = {"card-id" => "54ae8485221b1cc5b173e713"}
137
+ @cli.set_description
138
+ expect(WebMock).to have_requested(:put, "https://api.trello.com/1/cards/54ae8485221b1cc5b173e713/desc?key=mykey&token=mytoken&value=My%20description")
139
+ end
99
140
  end
@@ -74,4 +74,41 @@ EOT
74
74
  subject.add_attachment("123", path)
75
75
  end
76
76
  end
77
+
78
+ describe "#make_cover" do
79
+ let(:card_id) { "c133a484cff21c7a33ff031f" }
80
+ let(:image_id) { "484cff21c7a33ff031f997a" }
81
+ let(:image_name) { "passed.jpg" }
82
+ let(:client) { double }
83
+ let(:card_attachments_body) { <<-EOF
84
+ [
85
+ {
86
+ "id":"78d86ae7f25c748559b37ca",
87
+ "name":"failed.jpg"
88
+ },
89
+ {
90
+ "id":"484cff21c7a33ff031f997a",
91
+ "name":"passed.jpg"
92
+ }
93
+ ]
94
+ EOF
95
+ }
96
+
97
+ before(:each) do
98
+ stub_request(:get, "https://api.trello.com/1/cards/#{card_id}/attachments?fields=name&key=mykey&token=mytoken").
99
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'User-Agent'=>'Ruby'}).
100
+ to_return(:status => 200, :body => card_attachments_body, :headers => {})
101
+ stub_request(:put, "https://api.trello.com/1/cards/#{card_id}/idAttachmentCover?key=mykey&token=mytoken&value=#{image_id}").
102
+ with(:headers => {'Accept'=>'*/*; q=0.5, application/xml', 'Accept-Encoding'=>'gzip, deflate', 'Content-Length'=>'0', 'Content-Type'=>'application/x-www-form-urlencoded', 'User-Agent'=>'Ruby'})
103
+ end
104
+
105
+ it "make the attachment with the file name passed.jpg the cover" do
106
+ subject.make_cover(card_id, image_name)
107
+ expect(WebMock).to have_requested(:put, "https://api.trello.com/1/cards/#{card_id}/idAttachmentCover?key=mykey&token=mytoken&value=#{image_id}")
108
+ end
109
+
110
+ it "shows an error if the file was not found in the attachment list" do
111
+ expect { subject.make_cover(card_id, "non_existing_file.jpg") }.to raise_error(/non_existing_file.jpg/)
112
+ end
113
+ end
77
114
  end
data/trollolo.gemspec CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.summary = 'Trello command line client'
13
13
  s.description = 'Trollolo is a command line tool to access Trello and support tasks like generation of burndown charts.'
14
14
 
15
+ s.required_ruby_version = '>= 2.1'
15
16
  s.required_rubygems_version = '>= 1.3.6'
16
17
  s.rubyforge_project = 'trollolo'
17
18
 
data/yes_ship_it.conf CHANGED
@@ -1,9 +1,2 @@
1
- assertions:
2
- - release_branch
3
- - working_directory
4
- - version
5
- - change_log
6
- - built_gem
7
- - published_gem
8
- - tag
9
- - pushed_tag
1
+ include:
2
+ ruby_gem
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trollolo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 0.0.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cornelius Schumacher
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-11-12 00:00:00.000000000 Z
11
+ date: 2016-01-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: thor
@@ -103,7 +103,6 @@ files:
103
103
  - spec/integration/command_line_spec.rb
104
104
  - spec/integration/create_burndown_spec.rb
105
105
  - spec/integration/integration_spec_helper.rb
106
- - spec/integration/support/aruba_hook.rb
107
106
  - spec/integration/support/custom_matchers.rb
108
107
  - spec/integration/wrapper/credentials_input_wrapper
109
108
  - spec/integration/wrapper/empty_config_trollolo_wrapper
@@ -135,7 +134,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
135
134
  requirements:
136
135
  - - ">="
137
136
  - !ruby/object:Gem::Version
138
- version: '0'
137
+ version: '2.1'
139
138
  required_rubygems_version: !ruby/object:Gem::Requirement
140
139
  requirements:
141
140
  - - ">="
@@ -1,11 +0,0 @@
1
- require 'aruba/api'
2
- require 'aruba/reporting'
3
-
4
- RSpec.configure do |config|
5
- config.include Aruba::Api
6
-
7
- config.before(:each) do
8
- restore_env
9
- clean_current_dir
10
- end
11
- end