troo 0.0.11 → 0.0.12
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/.simplecov +3 -0
- data/Gemfile.lock +4 -1
- data/README.md +7 -7
- data/Rakefile +2 -2
- data/config/en.yml +2 -0
- data/features/support/env.rb +0 -4
- data/lib/troo.rb +14 -26
- data/lib/troo/api/client.rb +28 -6
- data/lib/troo/api/endpoints.rb +42 -30
- data/lib/troo/api/response.rb +5 -0
- data/lib/troo/cli/main.rb +3 -0
- data/lib/troo/cli/wizard.rb +71 -0
- data/lib/troo/configuration.rb +29 -15
- data/lib/troo/debug.rb +9 -0
- data/lib/troo/decorators/resource.rb +8 -4
- data/lib/troo/launcher.rb +22 -12
- data/lib/troo/models/board.rb +2 -2
- data/lib/troo/models/card.rb +2 -2
- data/lib/troo/models/member.rb +1 -1
- data/lib/troo/models/refresh.rb +2 -2
- data/lib/troo/remote/list.rb +1 -1
- data/lib/troo/remote/member.rb +1 -1
- data/lib/troo/remote/persistence/board.rb +6 -10
- data/lib/troo/remote/persistence/card.rb +6 -10
- data/lib/troo/remote/persistence/comment.rb +6 -10
- data/lib/troo/remote/persistence/list.rb +6 -10
- data/lib/troo/remote/persistence/move_card.rb +6 -10
- data/lib/troo/troo.rb +3 -2
- data/lib/troo/version.rb +1 -1
- data/test/lib/troo/api/endpoints_test.rb +12 -22
- data/test/lib/troo/cli/commands/status_test.rb +1 -1
- data/test/lib/troo/cli/wizard_test.rb +44 -0
- data/test/lib/troo/configuration_test.rb +39 -0
- data/test/lib/troo/decorators/resource_test.rb +2 -1
- data/test/lib/troo/models/member_test.rb +1 -1
- data/test/support/fake_trello/fake_response.rb +1 -2
- data/test/support/fake_trello/server.rb +22 -14
- data/test/test_helper.rb +0 -5
- data/troo.gemspec +1 -0
- metadata +20 -6
- data/config/trello_api.yml +0 -19
- data/lib/troo/decorators/member.rb +0 -12
- data/test/lib/troo/decorators/member_test.rb +0 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7f4539888216b2fee0e90cc5a1cffd97a20e8d6d
|
|
4
|
+
data.tar.gz: e35fc3a74a984d5f3eb0a76f4331d69fe85f5f78
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a90ddbf943db77a1544cf98590ba2d4fe2eb491edcfe99cbf254a2f792e88cfa6e7150bf9a71f230e5355e2d140f7a58ed19ede803a7d9db51cd06ca36bcf4db
|
|
7
|
+
data.tar.gz: 94686af4d0318e6fea58e6392ea4475dcb060a2ea00cd81af47168dca8fe5c227351f8053a72b9bdf0f0e019be16d64c9cf988e2c6bc9d33589ec2afedc6ec08
|
data/.simplecov
ADDED
data/Gemfile.lock
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
troo (0.0.
|
|
4
|
+
troo (0.0.12)
|
|
5
5
|
addressable
|
|
6
6
|
curses (= 1.0.1)
|
|
7
7
|
dispel
|
|
8
8
|
json
|
|
9
|
+
launchy
|
|
9
10
|
oauth
|
|
10
11
|
ohm (= 1.3.2)
|
|
11
12
|
ohm-contrib (= 1.2)
|
|
@@ -76,6 +77,8 @@ GEM
|
|
|
76
77
|
minitest (>= 3.0)
|
|
77
78
|
ice_nine (0.11.0)
|
|
78
79
|
json (1.8.1)
|
|
80
|
+
launchy (2.4.2)
|
|
81
|
+
addressable (~> 2.3)
|
|
79
82
|
listen (2.7.1)
|
|
80
83
|
celluloid (>= 0.15.2)
|
|
81
84
|
celluloid-io (>= 0.15.0)
|
data/README.md
CHANGED
|
@@ -29,6 +29,12 @@ Or install it yourself as:
|
|
|
29
29
|
|
|
30
30
|
You will need user authentication tokens to access your Trello account.
|
|
31
31
|
|
|
32
|
+
### Setup Wizard
|
|
33
|
+
|
|
34
|
+
Simply run `troo wizard` and follow the on screen instructions.
|
|
35
|
+
|
|
36
|
+
### Manually
|
|
37
|
+
|
|
32
38
|
1) Sign in to Trello in the normal way.
|
|
33
39
|
|
|
34
40
|
2) Create your developer key at Trello:
|
|
@@ -89,12 +95,6 @@ You will need user authentication tokens to access your Trello account.
|
|
|
89
95
|
|
|
90
96
|
troo version
|
|
91
97
|
|
|
92
|
-
## Todo
|
|
93
|
-
|
|
94
|
-
- Fix multitude of sins.
|
|
95
|
-
- Write cucumber integration tests.
|
|
96
|
-
- Convert dates/times to Time.iso8601().
|
|
97
|
-
|
|
98
98
|
## Testing
|
|
99
99
|
|
|
100
100
|
I've put a simple fake server together so that I'm not hitting the Trello API continuously. You can activate and use this too.
|
|
@@ -115,7 +115,7 @@ I've put a simple fake server together so that I'm not hitting the Trello API co
|
|
|
115
115
|
4) Run `server.rb`:
|
|
116
116
|
|
|
117
117
|
cd ./test/support/fake_trello
|
|
118
|
-
|
|
118
|
+
./server.rb
|
|
119
119
|
|
|
120
120
|
5) Have fun.
|
|
121
121
|
|
data/Rakefile
CHANGED
|
@@ -19,7 +19,7 @@ if File.exist?(Dir.home + '/.trooconf')
|
|
|
19
19
|
|
|
20
20
|
Rake::Task['cucumber'].execute
|
|
21
21
|
else
|
|
22
|
-
warn "\nConfiguration cannot be found, please run
|
|
23
|
-
"init
|
|
22
|
+
warn "\nConfiguration cannot be found, please run `troo " \
|
|
23
|
+
"init` or `./bin/troo init` first.\n"
|
|
24
24
|
exit(1)
|
|
25
25
|
end
|
data/config/en.yml
CHANGED
data/features/support/env.rb
CHANGED
data/lib/troo.rb
CHANGED
|
@@ -5,50 +5,38 @@ require_relative 'troo/version'
|
|
|
5
5
|
|
|
6
6
|
module Troo
|
|
7
7
|
ConfigurationNotFound = Class.new(StandardError)
|
|
8
|
-
|
|
8
|
+
ConfigurationAborted = Class.new(StandardError)
|
|
9
|
+
ExpiredAccessToken = Class.new(StandardError)
|
|
9
10
|
EndpointNotFound = Class.new(StandardError)
|
|
10
11
|
|
|
11
|
-
# @param []
|
|
12
12
|
# @param [String]
|
|
13
|
-
# @
|
|
13
|
+
# @param [String]
|
|
14
|
+
# @return [Troo::Configuration]
|
|
14
15
|
def self.configuration(file = Dir.home + '/.trooconf', env = 'default')
|
|
15
16
|
unless File.exist?(file)
|
|
16
|
-
warn "\nConfiguration cannot be found, please run
|
|
17
|
-
"init
|
|
18
|
-
file =
|
|
17
|
+
warn "\nConfiguration cannot be found, please run `troo " \
|
|
18
|
+
"init` or `./bin/troo init` first.\n"
|
|
19
|
+
file = root_path + '/config/trooconf.yml'
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
@configuration ||= Troo::Configuration.load(file, env)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
|
-
# @
|
|
25
|
-
# @return []
|
|
26
|
-
def self.endpoints(version = 'version_1')
|
|
27
|
-
@endpoints ||= Troo::API::Endpoints
|
|
28
|
-
.load(configuration_path + '/trello_api.yml', version)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
# @return []
|
|
25
|
+
# @return [TrueClass]
|
|
32
26
|
def self.logger
|
|
33
27
|
@logger ||= Logger
|
|
34
|
-
.new(
|
|
28
|
+
.new(root_path + '/logs/troo.log').tap do |log|
|
|
35
29
|
log.formatter = proc do |mode, time, prog, msg|
|
|
36
|
-
"#{time.iso8601} #{
|
|
30
|
+
"\n" + Esc.green + "#{time.iso8601}:" + Esc.reset + " #{msg}\n"
|
|
37
31
|
end
|
|
38
32
|
end
|
|
39
33
|
end
|
|
40
34
|
|
|
35
|
+
def self.root_path
|
|
36
|
+
File.expand_path('../..', __FILE__)
|
|
37
|
+
end
|
|
38
|
+
|
|
41
39
|
# RestClient.log = log_dir + '/restclient.log'
|
|
42
40
|
|
|
43
41
|
Database.connect(configuration)
|
|
44
|
-
|
|
45
|
-
private
|
|
46
|
-
|
|
47
|
-
def self.configuration_path
|
|
48
|
-
File.dirname(__FILE__) + '/../config'
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def self.log_path
|
|
52
|
-
File.dirname(__FILE__) + '/../logs'
|
|
53
|
-
end
|
|
54
42
|
end
|
data/lib/troo/api/client.rb
CHANGED
|
@@ -40,15 +40,25 @@ module Troo
|
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
def empty_response?
|
|
43
|
-
parsed_response.empty?
|
|
43
|
+
return log(true) if parsed_response.empty?
|
|
44
|
+
false
|
|
44
45
|
end
|
|
45
46
|
|
|
46
47
|
def error_response?
|
|
47
|
-
response.is_a?(ErrorResponse)
|
|
48
|
+
return log(true) if response.is_a?(ErrorResponse)
|
|
49
|
+
false
|
|
48
50
|
end
|
|
49
51
|
|
|
50
52
|
def parsed_response
|
|
51
|
-
@parsed ||= Yajl::Parser.parse(
|
|
53
|
+
@parsed ||= Yajl::Parser.parse(response_body)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def response_body
|
|
57
|
+
data = response.body
|
|
58
|
+
File.open(filename, 'w') do |file_handle|
|
|
59
|
+
file_handle.write(data)
|
|
60
|
+
end
|
|
61
|
+
data
|
|
52
62
|
end
|
|
53
63
|
|
|
54
64
|
def response
|
|
@@ -69,7 +79,7 @@ module Troo
|
|
|
69
79
|
end
|
|
70
80
|
|
|
71
81
|
def urn
|
|
72
|
-
Troo.
|
|
82
|
+
Troo::API::Endpoints.interpolate(endpoint, interpolation)
|
|
73
83
|
end
|
|
74
84
|
|
|
75
85
|
def missing_parameters?
|
|
@@ -80,8 +90,9 @@ module Troo
|
|
|
80
90
|
Troo.configuration.allow_remote
|
|
81
91
|
end
|
|
82
92
|
|
|
83
|
-
def log
|
|
84
|
-
Troo.logger.debug(formatted_messages) if log?
|
|
93
|
+
def log(retval = nil)
|
|
94
|
+
Troo.logger.debug("\n" + formatted_messages) if log?
|
|
95
|
+
retval
|
|
85
96
|
end
|
|
86
97
|
|
|
87
98
|
def log?
|
|
@@ -115,6 +126,17 @@ module Troo
|
|
|
115
126
|
'Response' => response.body
|
|
116
127
|
}
|
|
117
128
|
end
|
|
129
|
+
|
|
130
|
+
def filename
|
|
131
|
+
filename = [Troo.root_path + '/tmp/', endpoint.to_s]
|
|
132
|
+
filename << '_' << external_id if external_id
|
|
133
|
+
filename << '.json'
|
|
134
|
+
filename.join
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def external_id
|
|
138
|
+
interpolation[:external_id]
|
|
139
|
+
end
|
|
118
140
|
end
|
|
119
141
|
end
|
|
120
142
|
end
|
data/lib/troo/api/endpoints.rb
CHANGED
|
@@ -1,45 +1,57 @@
|
|
|
1
1
|
module Troo
|
|
2
2
|
module API
|
|
3
3
|
class Endpoints
|
|
4
|
-
include Virtus.value_object
|
|
5
|
-
|
|
6
|
-
values do
|
|
7
|
-
attribute :board_by_id
|
|
8
|
-
attribute :boards_all
|
|
9
|
-
attribute :card_by_id
|
|
10
|
-
attribute :cards_by_board_id
|
|
11
|
-
attribute :cards_by_list_id
|
|
12
|
-
attribute :comments_by_board_id
|
|
13
|
-
attribute :comments_by_card_id
|
|
14
|
-
attribute :comments_by_list_id
|
|
15
|
-
attribute :create_board
|
|
16
|
-
attribute :create_card
|
|
17
|
-
attribute :create_comment
|
|
18
|
-
attribute :create_list
|
|
19
|
-
attribute :list_by_id
|
|
20
|
-
attribute :lists_by_board_id
|
|
21
|
-
attribute :member_by_id
|
|
22
|
-
attribute :members_by_board_id
|
|
23
|
-
attribute :move_card_board
|
|
24
|
-
attribute :move_card_list
|
|
25
|
-
end
|
|
26
|
-
|
|
27
4
|
class << self
|
|
28
|
-
# @param [
|
|
29
|
-
# @param [
|
|
30
|
-
# @return [
|
|
31
|
-
def
|
|
32
|
-
new(
|
|
5
|
+
# @param [Symbol]
|
|
6
|
+
# @param [Hash]
|
|
7
|
+
# @return [String, EndpointNotFound]
|
|
8
|
+
def interpolate(endpoint, value = {})
|
|
9
|
+
new(endpoint, value).interpolate
|
|
33
10
|
end
|
|
34
11
|
end
|
|
35
12
|
|
|
13
|
+
# @param [Symbol]
|
|
14
|
+
# @param [Hash]
|
|
15
|
+
# @return [Troo::API::Endpoints]
|
|
16
|
+
def initialize(endpoint, value = {})
|
|
17
|
+
@endpoint, @value = endpoint, value
|
|
18
|
+
end
|
|
19
|
+
|
|
36
20
|
# @param [Symbol]
|
|
37
21
|
# @param [Hash]
|
|
38
22
|
# @return [String, EndpointNotFound]
|
|
39
|
-
def interpolate
|
|
40
|
-
|
|
23
|
+
def interpolate
|
|
24
|
+
endpoints.fetch(endpoint) % value
|
|
25
|
+
rescue KeyError
|
|
41
26
|
fail EndpointNotFound
|
|
42
27
|
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
attr_reader :endpoint, :value
|
|
32
|
+
|
|
33
|
+
def endpoints
|
|
34
|
+
{
|
|
35
|
+
boards_all: '/members/me/boards',
|
|
36
|
+
board_by_id: '/boards/%{external_id}',
|
|
37
|
+
card_by_id: '/cards/%{external_id}',
|
|
38
|
+
list_by_id: '/lists/%{external_id}',
|
|
39
|
+
member_by_id: '/members/%{external_id}',
|
|
40
|
+
cards_by_board_id: '/boards/%{external_id}/cards',
|
|
41
|
+
cards_by_list_id: '/lists/%{external_id}/cards',
|
|
42
|
+
comments_by_board_id: '/boards/%{external_id}/actions',
|
|
43
|
+
comments_by_card_id: '/cards/%{external_id}/actions',
|
|
44
|
+
comments_by_list_id: '/lists/%{external_id}/actions',
|
|
45
|
+
lists_by_board_id: '/boards/%{external_id}/lists',
|
|
46
|
+
members_by_board_id: '/boards/%{external_id}/members',
|
|
47
|
+
create_board: '/boards',
|
|
48
|
+
create_card: '/cards',
|
|
49
|
+
create_comment: '/cards/%{external_id}/actions/comments',
|
|
50
|
+
create_list: '/lists',
|
|
51
|
+
move_card_list: '/cards/%{external_id}/idList',
|
|
52
|
+
move_card_board: '/cards/%{external_id}/idBoard',
|
|
53
|
+
}
|
|
54
|
+
end
|
|
43
55
|
end
|
|
44
56
|
end
|
|
45
57
|
end
|
data/lib/troo/api/response.rb
CHANGED
|
@@ -18,11 +18,16 @@ module Troo
|
|
|
18
18
|
|
|
19
19
|
# @return [Response, ErrorResponse]
|
|
20
20
|
def build
|
|
21
|
+
raise ExpiredAccessToken if expired?
|
|
21
22
|
ok? ? Response.new(attributes) : ErrorResponse.new(attributes)
|
|
22
23
|
end
|
|
23
24
|
|
|
24
25
|
private
|
|
25
26
|
|
|
27
|
+
def expired?
|
|
28
|
+
code == '401'
|
|
29
|
+
end
|
|
30
|
+
|
|
26
31
|
def ok?
|
|
27
32
|
code == '200'
|
|
28
33
|
end
|
data/lib/troo/cli/main.rb
CHANGED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
module Troo
|
|
2
|
+
module CLI
|
|
3
|
+
class Wizard < ThorFixes
|
|
4
|
+
package_name 'wizard'
|
|
5
|
+
default_task :start
|
|
6
|
+
|
|
7
|
+
# @return [String]
|
|
8
|
+
desc 'start', 'Run the configuration wizard to get started.'
|
|
9
|
+
def start
|
|
10
|
+
say Troo::Formatter.wordwrap(welcome_message)
|
|
11
|
+
|
|
12
|
+
proceed?
|
|
13
|
+
step_one!
|
|
14
|
+
|
|
15
|
+
say Troo::Formatter.wordwrap(step_one_message)
|
|
16
|
+
|
|
17
|
+
proceed?
|
|
18
|
+
step_two!
|
|
19
|
+
|
|
20
|
+
say 'All done! Run `troo` for further commands.'
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
private
|
|
24
|
+
|
|
25
|
+
def connect_url(api_key)
|
|
26
|
+
"https://trello.com/1/connect?key=#{api_key}" \
|
|
27
|
+
"&name=troo&response_type=token&scope=read,write"
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def generate_url
|
|
31
|
+
'https://trello.com/1/appKey/generate'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def config
|
|
35
|
+
@config ||= Troo::Configuration.new
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def proceed?
|
|
39
|
+
raise ConfigurationAborted unless yes?(user_input('Proceed?'))
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def step_one!
|
|
43
|
+
Launchy.open(generate_url)
|
|
44
|
+
config.api_key = ask(user_input('Key:'))
|
|
45
|
+
config.api_token = ask(user_input('Secret:'))
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def step_two!
|
|
49
|
+
Launchy.open(connect_url(config.api_key))
|
|
50
|
+
config.api_oauth_token = ask(user_input('Token:'))
|
|
51
|
+
config.save(Dir.home + '/.trooconf', 'default')
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def welcome_message
|
|
55
|
+
"Welcome to Troo. This wizard will help you configure your " \
|
|
56
|
+
"API credentials for Trello. First, you'll need to sign in " \
|
|
57
|
+
"to Trello in the normal way. Copy the API key and paste " \
|
|
58
|
+
"when prompted, then do the same for the secret.\n"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def step_one_message
|
|
62
|
+
"Thank you. You must now allow this application to use " \
|
|
63
|
+
"Trello account. Copy and paste the token when prompted.\n"
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
def user_input(value)
|
|
67
|
+
[Esc.yellow, value, Esc.reset].join
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
data/lib/troo/configuration.rb
CHANGED
|
@@ -1,33 +1,47 @@
|
|
|
1
1
|
module Troo
|
|
2
2
|
class Configuration
|
|
3
|
-
include Virtus.
|
|
3
|
+
include Virtus.model
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
attribute :logs, Boolean, default: false
|
|
15
|
-
end
|
|
5
|
+
attribute :api_key
|
|
6
|
+
attribute :api_token
|
|
7
|
+
attribute :api_oauth_token
|
|
8
|
+
attribute :api_oauth_token_secret
|
|
9
|
+
attribute :allow_remote, Boolean, default: true
|
|
10
|
+
attribute :logs, Boolean, default: false
|
|
11
|
+
attribute :name, String, default: 'My Default Configuration'
|
|
12
|
+
attribute :api_url, String, default: 'https://api.trello.com/1'
|
|
13
|
+
attribute :database, Integer, default: 1
|
|
16
14
|
|
|
17
15
|
class << self
|
|
18
|
-
# @param []
|
|
19
16
|
# @param [String]
|
|
20
|
-
# @
|
|
17
|
+
# @param [String]
|
|
18
|
+
# @return [Troo::Configuration]
|
|
21
19
|
def load(file, env)
|
|
22
20
|
new(YAML.load_file(file)[env])
|
|
23
21
|
end
|
|
24
22
|
end
|
|
25
23
|
|
|
26
|
-
# @
|
|
24
|
+
# @param [String]
|
|
25
|
+
# @param [String]
|
|
26
|
+
# @return [TrueClass, FalseClass]
|
|
27
|
+
def save(file, env)
|
|
28
|
+
return true if File.open(file, 'w') do |file|
|
|
29
|
+
file.write configuration_yaml(env)
|
|
30
|
+
end
|
|
31
|
+
false
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# @return [String]
|
|
27
35
|
def view
|
|
28
36
|
attributes.map do |label, value|
|
|
29
37
|
Preference.view(label: label, value: value)
|
|
30
38
|
end.join("\n")
|
|
31
39
|
end
|
|
40
|
+
|
|
41
|
+
private
|
|
42
|
+
|
|
43
|
+
def configuration_yaml(env = 'default')
|
|
44
|
+
{ env => self.attributes }.to_yaml
|
|
45
|
+
end
|
|
32
46
|
end
|
|
33
47
|
end
|