trollolo 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +21 -2
- data/.rubocop_todo.yml +105 -270
- data/CHANGELOG.md +10 -0
- data/CONTRIBUTING.md +6 -4
- data/Gemfile +1 -1
- data/README.md +10 -1
- data/Rakefile +4 -4
- data/bin/trollolo +2 -2
- data/lib/backup.rb +21 -23
- data/lib/burndown_chart.rb +46 -49
- data/lib/burndown_data.rb +21 -21
- data/lib/card.rb +23 -32
- data/lib/checklist.rb +13 -1
- data/lib/cli.rb +105 -110
- data/lib/column.rb +11 -10
- data/lib/empty_column.rb +2 -2
- data/lib/scrum/backlog_mover.rb +3 -3
- data/lib/scrum/card_type_detection.rb +1 -1
- data/lib/scrum/creator.rb +7 -7
- data/lib/scrum/prioritizer.rb +1 -1
- data/lib/scrum/sprint_board.rb +4 -4
- data/lib/scrum/sprint_cleaner.rb +3 -3
- data/lib/scrum/sprint_planning_board.rb +2 -4
- data/lib/scrum_board.rb +3 -3
- data/lib/settings.rb +29 -27
- data/lib/trello_service.rb +1 -1
- data/lib/trello_wrapper.rb +9 -9
- data/lib/version.rb +1 -1
- data/spec/data/card.json +19 -0
- data/spec/data/trollolorc +3 -0
- data/spec/integration/command_line_spec.rb +14 -14
- data/spec/integration/create_burndown_spec.rb +25 -25
- data/spec/integration/integration_spec_helper.rb +1 -1
- data/spec/integration/wrapper/credentials_input_wrapper +7 -11
- data/spec/integration/wrapper/empty_config_trollolo_wrapper +2 -2
- data/spec/integration/wrapper/trollolo_wrapper +2 -2
- data/spec/unit/backup_spec.rb +14 -14
- data/spec/unit/burndown_chart_spec.rb +176 -184
- data/spec/unit/burndown_data_spec.rb +21 -23
- data/spec/unit/card_spec.rb +38 -24
- data/spec/unit/cli_spec.rb +57 -57
- data/spec/unit/empty_column_spec.rb +1 -1
- data/spec/unit/retrieve_data_spec.rb +13 -13
- data/spec/unit/scrum/backlog_mover_spec.rb +8 -8
- data/spec/unit/scrum/card_type_detection_spec.rb +12 -12
- data/spec/unit/scrum/creator_spec.rb +8 -8
- data/spec/unit/scrum/prioritizer_spec.rb +19 -19
- data/spec/unit/scrum/priority_name_spec.rb +16 -16
- data/spec/unit/scrum/sprint_board_spec.rb +3 -3
- data/spec/unit/scrum/sprint_cleaner_spec.rb +15 -15
- data/spec/unit/scrum/sprint_planning_board_spec.rb +2 -2
- data/spec/unit/scrum_board_spec.rb +56 -56
- data/spec/unit/settings_spec.rb +23 -23
- data/spec/unit/spec_helper.rb +3 -3
- data/spec/unit/support/test_data_operations.rb +4 -0
- data/spec/unit/support/update_webmock_data +9 -11
- data/spec/unit/support/vcr.rb +3 -3
- data/spec/unit/support/webmocks.rb +21 -12
- data/spec/unit/trello_wrapper_spec.rb +40 -29
- data/trollolo.gemspec +3 -3
- metadata +8 -5
data/spec/unit/settings_spec.rb
CHANGED
@@ -4,58 +4,58 @@ describe Settings do
|
|
4
4
|
|
5
5
|
include GivenFilesystemSpecHelpers
|
6
6
|
|
7
|
-
context
|
7
|
+
context 'given config file' do
|
8
8
|
before(:each) do
|
9
9
|
@settings = Settings.new( File.expand_path('../../data/trollolorc', __FILE__) )
|
10
10
|
end
|
11
11
|
|
12
|
-
it
|
12
|
+
it 'is not verbose by default' do
|
13
13
|
expect(@settings.verbose).to be false
|
14
14
|
end
|
15
15
|
|
16
|
-
it
|
17
|
-
expect(@settings.developer_public_key).to eq
|
18
|
-
expect(@settings.member_token).to eq
|
16
|
+
it 'reads config file' do
|
17
|
+
expect(@settings.developer_public_key).to eq 'mykey'
|
18
|
+
expect(@settings.member_token).to eq 'mytoken'
|
19
19
|
end
|
20
20
|
|
21
|
-
context
|
22
|
-
context
|
21
|
+
context '#scrum' do
|
22
|
+
context 'when setting is missing' do
|
23
23
|
before do
|
24
24
|
@settings = Settings.new( File.expand_path('../../data/trollolorc_with_board_aliases', __FILE__) )
|
25
25
|
end
|
26
|
-
it
|
27
|
-
expect(@settings.scrum[
|
26
|
+
it 'returns default settings' do
|
27
|
+
expect(@settings.scrum['board_names']).to eq('planning' => 'Planning Board', 'sprint' => 'Sprint Board')
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
31
|
-
context
|
32
|
-
it
|
33
|
-
expect(@settings.scrum[
|
34
|
-
expect(@settings.scrum.board_names[
|
31
|
+
context 'when setting does exist' do
|
32
|
+
it 'returns name' do
|
33
|
+
expect(@settings.scrum['board_names']['sprint']).to eq('Sprint Board')
|
34
|
+
expect(@settings.scrum.board_names['planning']).to eq('Planning Board')
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
context
|
40
|
-
context
|
41
|
-
it
|
39
|
+
context '#board_aliases' do
|
40
|
+
context 'when aliases do not exist' do
|
41
|
+
it 'returns an empty Hash' do
|
42
42
|
expect(@settings.board_aliases).to eq({})
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
-
context
|
46
|
+
context 'when mapping exists' do
|
47
47
|
before do
|
48
48
|
@settings = Settings.new( File.expand_path('../../data/trollolorc_with_board_aliases', __FILE__) )
|
49
49
|
end
|
50
50
|
|
51
|
-
it
|
52
|
-
expect(@settings.board_aliases).to eq(
|
51
|
+
it 'returns the mapping' do
|
52
|
+
expect(@settings.board_aliases).to eq('MyTrelloBoard' => '53186e8391ef8671265eba9d')
|
53
53
|
end
|
54
54
|
end
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
|
-
context
|
58
|
+
context 'non-existent config file' do
|
59
59
|
use_given_filesystem
|
60
60
|
|
61
61
|
before(:each) do
|
@@ -63,9 +63,9 @@ describe Settings do
|
|
63
63
|
@settings = Settings.new(@config_file)
|
64
64
|
end
|
65
65
|
|
66
|
-
it
|
67
|
-
@settings.developer_public_key =
|
68
|
-
@settings.member_token =
|
66
|
+
it 'saves config file' do
|
67
|
+
@settings.developer_public_key = 'mypublickey'
|
68
|
+
@settings.member_token = 'mymembertoken'
|
69
69
|
@settings.save_config
|
70
70
|
|
71
71
|
expect(File.read(@config_file)).to eq "---\ndeveloper_public_key: mypublickey\nmember_token: mymembertoken\n"
|
data/spec/unit/spec_helper.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
|
-
require
|
1
|
+
require 'simplecov'
|
2
2
|
SimpleCov.start
|
3
3
|
require_relative '../../lib/trollolo'
|
4
4
|
require 'given_filesystem/spec_helpers'
|
5
5
|
require 'webmock/rspec'
|
6
6
|
require 'byebug'
|
7
7
|
require 'pry'
|
8
|
-
WebMock.disable_net_connect!(:
|
8
|
+
WebMock.disable_net_connect!(allow: 'codeclimate.com')
|
9
9
|
|
10
|
-
bin_path = File.expand_path(
|
10
|
+
bin_path = File.expand_path( '../../../bin/', __FILE__ )
|
11
11
|
|
12
12
|
if ENV['PATH'] !~ /#{bin_path}/
|
13
13
|
ENV['PATH'] = bin_path + File::PATH_SEPARATOR + ENV['PATH']
|
@@ -1,24 +1,22 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
require
|
3
|
+
require 'json'
|
4
4
|
|
5
|
-
require_relative
|
5
|
+
require_relative 'webmocks'
|
6
6
|
|
7
|
-
trollolo_bin = File.expand_path(
|
8
|
-
spec_data_dir = File.expand_path(
|
7
|
+
trollolo_bin = File.expand_path('../../../../bin/trollolo', __FILE__)
|
8
|
+
spec_data_dir = File.expand_path('../../../data', __FILE__)
|
9
9
|
|
10
|
-
STDERR.puts
|
10
|
+
STDERR.puts 'Updating web mock data'
|
11
11
|
|
12
12
|
def scrub_file(file)
|
13
13
|
json = JSON.parse(File.read(file))
|
14
|
-
if json.is_a?(Hash) && json.
|
15
|
-
json[
|
16
|
-
if card.
|
17
|
-
card["email"] = "trello@example.com"
|
18
|
-
end
|
14
|
+
if json.is_a?(Hash) && json.key?('cards')
|
15
|
+
json['cards'].each do |card|
|
16
|
+
card['email'] = 'trello@example.com' if card.key?('email')
|
19
17
|
end
|
20
18
|
end
|
21
|
-
File.open(file,
|
19
|
+
File.open(file, 'w') do |f|
|
22
20
|
f.write(JSON.pretty_generate(json))
|
23
21
|
end
|
24
22
|
end
|
data/spec/unit/support/vcr.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require 'vcr'
|
2
2
|
VCR.configure do |config|
|
3
|
-
config.cassette_library_dir =
|
3
|
+
config.cassette_library_dir = 'spec/data/vcr'
|
4
4
|
config.hook_into :webmock
|
5
5
|
end
|
6
6
|
|
7
7
|
# example needs to use real_settings if vcr_record: true is used
|
8
8
|
def real_settings
|
9
|
-
config_path = ENV[
|
9
|
+
config_path = ENV['TROLLOLO_CONFIG_PATH'] || File.expand_path('~/.trollolorc')
|
10
10
|
Settings.new(config_path)
|
11
11
|
end
|
12
12
|
|
@@ -40,7 +40,7 @@ end
|
|
40
40
|
RSpec.configure do |c|
|
41
41
|
c.around do |example|
|
42
42
|
if (cassette = example.metadata[:vcr])
|
43
|
-
|
43
|
+
raise 'you need to use real_settings to re-record vcr data' if real_settings_needed?(example)
|
44
44
|
VCR.use_cassette(cassette, record: vcr_record_mode(example)) do
|
45
45
|
example.run
|
46
46
|
end
|
@@ -7,27 +7,36 @@ def webmock_mapping
|
|
7
7
|
{
|
8
8
|
path: 'boards/53186e8391ef8671265eba9d/lists',
|
9
9
|
parameters: {
|
10
|
-
|
10
|
+
'filter' => 'open'
|
11
11
|
},
|
12
12
|
file: 'lists.json'
|
13
13
|
},
|
14
14
|
{
|
15
15
|
path: 'boards/53186e8391ef8671265eba9d',
|
16
16
|
parameters: {
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
'cards' => 'open',
|
18
|
+
'lists' => 'open',
|
19
|
+
'card_checklists' => 'all'
|
20
20
|
},
|
21
21
|
file: 'full-board.json'
|
22
22
|
},
|
23
23
|
{
|
24
24
|
path: 'boards/P4kJA4bE',
|
25
25
|
parameters: {
|
26
|
-
|
27
|
-
|
28
|
-
|
26
|
+
'cards' => 'open',
|
27
|
+
'lists' => 'open',
|
28
|
+
'card_checklists' => 'all'
|
29
29
|
},
|
30
30
|
file: 'full-board-with-accepted.json'
|
31
|
+
},
|
32
|
+
{
|
33
|
+
path: 'boards/7Zar7bNm',
|
34
|
+
parameters: {
|
35
|
+
'cards' => 'open',
|
36
|
+
'lists' => 'open',
|
37
|
+
'card_checklists' => 'all'
|
38
|
+
},
|
39
|
+
file: 'full-board.json'
|
31
40
|
}
|
32
41
|
]
|
33
42
|
end
|
@@ -40,22 +49,22 @@ def parameters_as_string(mapping, parameters = nil)
|
|
40
49
|
end
|
41
50
|
end
|
42
51
|
if !parameters.empty?
|
43
|
-
parameters_string =
|
52
|
+
parameters_string = '?' + parameters.join('&')
|
44
53
|
else
|
45
|
-
parameters_string =
|
54
|
+
parameters_string = ''
|
46
55
|
end
|
47
56
|
parameters_string
|
48
57
|
end
|
49
58
|
|
50
59
|
def mapping_url(mapping, parameters = nil)
|
51
|
-
url =
|
60
|
+
url = 'https://api.trello.com/1/' + mapping[:path]
|
52
61
|
url += parameters_as_string(mapping, parameters)
|
53
62
|
end
|
54
63
|
|
55
64
|
def full_board_mock
|
56
65
|
webmock_mapping.each do |mapping|
|
57
|
-
url = mapping_url(mapping, [
|
66
|
+
url = mapping_url(mapping, [ 'key=mykey', 'token=mytoken' ])
|
58
67
|
stub_request(:get, url)
|
59
|
-
.to_return(:
|
68
|
+
.to_return(status: 200, body: load_test_file(mapping[:file]))
|
60
69
|
end
|
61
70
|
end
|
@@ -4,12 +4,12 @@ include GivenFilesystemSpecHelpers
|
|
4
4
|
|
5
5
|
describe TrelloWrapper do
|
6
6
|
|
7
|
-
let!(:settings){ double('settings', developer_public_key:
|
7
|
+
let!(:settings){ double('settings', developer_public_key: 'mykey', member_token: 'mytoken') }
|
8
8
|
subject { described_class.new(settings) }
|
9
9
|
|
10
10
|
before do
|
11
|
-
stub_request(:get,
|
12
|
-
to_return(:
|
11
|
+
stub_request(:get, 'https://api.trello.com/1/boards/myboard?cards=open&key=mykey&lists=open&token=mytoken').
|
12
|
+
to_return(status: 200, body: load_test_file('board.json'), headers: {})
|
13
13
|
full_board_mock
|
14
14
|
end
|
15
15
|
|
@@ -30,26 +30,26 @@ describe TrelloWrapper do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'finds board via Trello' do
|
33
|
-
subject.board(
|
33
|
+
subject.board('myboard')
|
34
34
|
end
|
35
35
|
|
36
36
|
it 'instantiate ScrumBoard with trello board and settings' do
|
37
37
|
expect(ScrumBoard).to receive(:new).with(:board, subject.instance_variable_get(:@settings))
|
38
|
-
subject.board(
|
38
|
+
subject.board('myboard')
|
39
39
|
end
|
40
40
|
|
41
41
|
it 'returns instance of a ScrumBoard' do
|
42
|
-
expect(subject.board(
|
42
|
+
expect(subject.board('myboard')).to be_instance_of(ScrumBoard)
|
43
43
|
end
|
44
44
|
|
45
45
|
it 'memoize board object' do
|
46
|
-
expect(subject.board(
|
46
|
+
expect(subject.board('myboard')).to be subject.board('myboard')
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
50
|
describe '#backup' do
|
51
51
|
it 'raises an error for empty board id' do
|
52
|
-
expect { subject.backup(
|
52
|
+
expect { subject.backup('') }.to raise_error(TrolloloError)
|
53
53
|
end
|
54
54
|
|
55
55
|
it 'raises an error for nil board id' do
|
@@ -70,7 +70,7 @@ describe TrelloWrapper do
|
|
70
70
|
describe '#add_attachment' do
|
71
71
|
use_given_filesystem
|
72
72
|
|
73
|
-
it
|
73
|
+
it 'uploads attachment' do
|
74
74
|
srand(1) # Make sure multipart boundary is always the same
|
75
75
|
|
76
76
|
card_body = <<EOT
|
@@ -80,26 +80,31 @@ describe TrelloWrapper do
|
|
80
80
|
}
|
81
81
|
EOT
|
82
82
|
|
83
|
-
stub_request(:get,
|
84
|
-
with(:
|
85
|
-
to_return(:
|
83
|
+
stub_request(:get, 'https://api.trello.com/1/cards/123?key=mykey&token=mytoken').
|
84
|
+
with(headers: {'Accept' => '*/*; q=0.5, application/xml', 'Accept-Encoding' => 'gzip, deflate', 'User-Agent' => 'Ruby'}).
|
85
|
+
to_return(status: 200, body: card_body, headers: {})
|
86
86
|
|
87
|
-
|
88
|
-
|
89
|
-
|
87
|
+
headers = {'Accept' => '*/*; q=0.5, application/xml',
|
88
|
+
'Accept-Encoding' => 'gzip, deflate',
|
89
|
+
'Content-Length' => '188',
|
90
|
+
'Content-Type' => 'multipart/form-data; boundary=470924',
|
91
|
+
'User-Agent' => 'Ruby'}
|
90
92
|
|
91
|
-
|
93
|
+
stub_request(:post, 'https://api.trello.com/1/cards/123/attachments?key=mykey&token=mytoken').
|
94
|
+
with(headers: headers).to_return(status: 200, body: '', headers: {})
|
92
95
|
|
93
|
-
|
96
|
+
path = given_file('attachment-data')
|
97
|
+
|
98
|
+
subject.add_attachment('123', path)
|
94
99
|
end
|
95
100
|
end
|
96
101
|
|
97
|
-
describe
|
98
|
-
let(:card_id) {
|
99
|
-
let(:image_id) {
|
100
|
-
let(:image_name) {
|
102
|
+
describe '#make_cover' do
|
103
|
+
let(:card_id) { 'c133a484cff21c7a33ff031f' }
|
104
|
+
let(:image_id) { '484cff21c7a33ff031f997a' }
|
105
|
+
let(:image_name) { 'passed.jpg' }
|
101
106
|
let(:client) { double }
|
102
|
-
let(:card_attachments_body)
|
107
|
+
let(:card_attachments_body) do <<-EOF
|
103
108
|
[
|
104
109
|
{
|
105
110
|
"id":"78d86ae7f25c748559b37ca",
|
@@ -111,23 +116,29 @@ EOT
|
|
111
116
|
}
|
112
117
|
]
|
113
118
|
EOF
|
114
|
-
|
119
|
+
end
|
115
120
|
|
116
121
|
before(:each) do
|
117
122
|
stub_request(:get, "https://api.trello.com/1/cards/#{card_id}/attachments?fields=name&key=mykey&token=mytoken").
|
118
|
-
with(:
|
119
|
-
to_return(:
|
123
|
+
with(headers: {'Accept' => '*/*; q=0.5, application/xml', 'Accept-Encoding' => 'gzip, deflate', 'User-Agent' => 'Ruby'}).
|
124
|
+
to_return(status: 200, body: card_attachments_body, headers: {})
|
125
|
+
headers = {'Accept' => '*/*; q=0.5, application/xml',
|
126
|
+
'Accept-Encoding' => 'gzip, deflate',
|
127
|
+
'Content-Length' => '0',
|
128
|
+
'Content-Type' => 'application/x-www-form-urlencoded',
|
129
|
+
'User-Agent' => 'Ruby'}
|
130
|
+
|
120
131
|
stub_request(:put, "https://api.trello.com/1/cards/#{card_id}/idAttachmentCover?key=mykey&token=mytoken&value=#{image_id}").
|
121
|
-
with(:headers
|
132
|
+
with(headers: headers)
|
122
133
|
end
|
123
134
|
|
124
|
-
it
|
135
|
+
it 'make the attachment with the file name passed.jpg the cover' do
|
125
136
|
subject.make_cover(card_id, image_name)
|
126
137
|
expect(WebMock).to have_requested(:put, "https://api.trello.com/1/cards/#{card_id}/idAttachmentCover?key=mykey&token=mytoken&value=#{image_id}")
|
127
138
|
end
|
128
139
|
|
129
|
-
it
|
130
|
-
expect { subject.make_cover(card_id,
|
140
|
+
it 'shows an error if the file was not found in the attachment list' do
|
141
|
+
expect { subject.make_cover(card_id, 'non_existing_file.jpg') }.to raise_error(/non_existing_file.jpg/)
|
131
142
|
end
|
132
143
|
end
|
133
144
|
end
|
data/trollolo.gemspec
CHANGED
@@ -4,7 +4,7 @@ require File.expand_path('../lib/version', __FILE__)
|
|
4
4
|
Gem::Specification.new do |s|
|
5
5
|
s.name = 'trollolo'
|
6
6
|
s.version = Trollolo::VERSION
|
7
|
-
s.license = 'GPL-3'
|
7
|
+
s.license = 'GPL-3.0'
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ['Cornelius Schumacher']
|
10
10
|
s.email = ['cschum@suse.de']
|
@@ -12,7 +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.2'
|
15
|
+
s.required_ruby_version = ['>= 2.2.0', '< 2.4.2']
|
16
16
|
s.required_rubygems_version = '>= 1.3.6'
|
17
17
|
s.rubyforge_project = 'trollolo'
|
18
18
|
|
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_dependency 'ruby-trello', '~> 1.5.0'
|
21
21
|
|
22
22
|
s.files = `git ls-files`.split("\n")
|
23
|
-
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ?
|
23
|
+
s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? Regexp.last_match(1) : nil}.compact
|
24
24
|
s.require_path = 'lib'
|
25
25
|
|
26
26
|
s.files += Dir['man/*.?'] # UNIX man pages
|
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.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cornelius Schumacher
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2018-01-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -171,7 +171,7 @@ files:
|
|
171
171
|
- yes_ship_it.conf
|
172
172
|
homepage: https://github.com/openSUSE/trollolo
|
173
173
|
licenses:
|
174
|
-
- GPL-3
|
174
|
+
- GPL-3.0
|
175
175
|
metadata: {}
|
176
176
|
post_install_message:
|
177
177
|
rdoc_options: []
|
@@ -181,7 +181,10 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
181
181
|
requirements:
|
182
182
|
- - ">="
|
183
183
|
- !ruby/object:Gem::Version
|
184
|
-
version:
|
184
|
+
version: 2.2.0
|
185
|
+
- - "<"
|
186
|
+
- !ruby/object:Gem::Version
|
187
|
+
version: 2.4.2
|
185
188
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
186
189
|
requirements:
|
187
190
|
- - ">="
|
@@ -189,7 +192,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
189
192
|
version: 1.3.6
|
190
193
|
requirements: []
|
191
194
|
rubyforge_project: trollolo
|
192
|
-
rubygems_version: 2.
|
195
|
+
rubygems_version: 2.5.2.1
|
193
196
|
signing_key:
|
194
197
|
specification_version: 4
|
195
198
|
summary: Trello command line client
|