gradesfirst 0.2.1 → 0.3.0
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.
- data/.gitignore +1 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +2 -6
- data/gradesfirst.gemspec +2 -2
- data/lib/gradesfirst.rb +1 -0
- data/lib/gradesfirst/cli.rb +7 -29
- data/lib/gradesfirst/cli_helper.rb +33 -0
- data/lib/gradesfirst/command.rb +7 -0
- data/lib/gradesfirst/commit_message_command.rb +1 -1
- data/lib/gradesfirst/task_add_command.rb +51 -0
- data/lib/gradesfirst/task_cli.rb +48 -0
- data/lib/gradesfirst/task_command.rb +38 -30
- data/lib/gradesfirst/task_delete_command.rb +64 -0
- data/lib/gradesfirst/task_list_command.rb +40 -0
- data/lib/gradesfirst/task_move_command.rb +64 -0
- data/lib/gradesfirst/task_toggle_command.rb +65 -0
- data/lib/http_magic.rb +2 -258
- data/lib/http_magic/api.rb +233 -0
- data/lib/http_magic/request.rb +93 -0
- data/lib/http_magic/uri.rb +74 -0
- data/lib/pivotal_tracker.rb +1 -1
- data/test/branch_command_test.rb +8 -21
- data/test/cli_test.rb +51 -34
- data/test/command_test.rb +5 -7
- data/test/commit_message_command_test.rb +37 -45
- data/test/fixtures/task.json +10 -0
- data/test/fixtures/task_added.txt +6 -0
- data/test/fixtures/task_deleted.txt +6 -0
- data/test/fixtures/task_moved.txt +6 -0
- data/test/fixtures/task_toggled.txt +6 -0
- data/test/fixtures/tasks.txt +2 -2
- data/test/http_magic/{get_test.rb → api/get_test.rb} +1 -1
- data/test/http_magic/api/post_test.rb +34 -0
- data/test/http_magic/request_test.rb +63 -0
- data/test/http_magic/uri_test.rb +28 -55
- data/test/support/pivotal_test_helper.rb +110 -0
- data/test/support/request_expectation.rb +33 -0
- data/test/task_add_command_test.rb +54 -0
- data/test/task_delete_command_test.rb +57 -0
- data/test/task_list_command_test.rb +18 -0
- data/test/task_move_command_test.rb +66 -0
- data/test/task_toggle_command_test.rb +58 -0
- data/test/test_helper.rb +35 -19
- metadata +29 -7
- data/test/pivotal_tracker_test.rb +0 -46
- data/test/task_command_test.rb +0 -52
@@ -0,0 +1,93 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module HttpMagic
|
5
|
+
# Encapsulating class to hold all of the infrastructure to make the actual
|
6
|
+
# requests to the api. It receives at a minimum a HttpMagic::Uri object which
|
7
|
+
# manages the url building.
|
8
|
+
#
|
9
|
+
# == Example
|
10
|
+
#
|
11
|
+
# uri_object = HttpMagic::Uri.new('http://example.com')
|
12
|
+
#
|
13
|
+
# request = Request.new(uri_object)
|
14
|
+
#
|
15
|
+
# request.get
|
16
|
+
# => { 'name' => 'Foo Bar' }
|
17
|
+
class Request
|
18
|
+
def initialize(uri, options = {})
|
19
|
+
@uri = uri
|
20
|
+
@data = options[:data]
|
21
|
+
@options = {
|
22
|
+
headers: options[:headers] || {}
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete
|
27
|
+
parse_response http.delete(@uri.urn, @options[:headers])
|
28
|
+
end
|
29
|
+
|
30
|
+
# Makes a GET request to the url provided by the Uri object and returns the
|
31
|
+
# resulting JSON data as a Ruby hash.
|
32
|
+
#
|
33
|
+
# == Example
|
34
|
+
#
|
35
|
+
# uri_object = HttpMagic::Uri.new('http://example.com')
|
36
|
+
#
|
37
|
+
# request = Request.new(uri_object)
|
38
|
+
#
|
39
|
+
# request.get
|
40
|
+
# => { 'name' => 'Foo Bar' }
|
41
|
+
def get
|
42
|
+
parse_response http.request_get(@uri.urn, @options[:headers])
|
43
|
+
end
|
44
|
+
|
45
|
+
# Makes a POST request to the url provided by the Uri object and returns the
|
46
|
+
# resulting JSON data as a Ruby hash. If data was provided as an optional
|
47
|
+
# initialization parameter, then that is also POSTed.
|
48
|
+
#
|
49
|
+
# == Example
|
50
|
+
#
|
51
|
+
# uri_object = HttpMagic::Uri.new('http://example.com')
|
52
|
+
#
|
53
|
+
# request = Request.new(uri_object, data: { name: 'New Foo' })
|
54
|
+
#
|
55
|
+
# request.post
|
56
|
+
def post
|
57
|
+
if !@data.empty?
|
58
|
+
@options[:headers].merge!( 'Content-Type' => 'application/json' )
|
59
|
+
end
|
60
|
+
|
61
|
+
parse_response http.request_post(@uri.urn, @data.to_json, @options[:headers])
|
62
|
+
end
|
63
|
+
|
64
|
+
def put
|
65
|
+
if !@data.empty?
|
66
|
+
@options[:headers].merge!( 'Content-Type' => 'application/json' )
|
67
|
+
end
|
68
|
+
|
69
|
+
parse_response http.request_put(@uri.urn, @data.to_json, @options[:headers])
|
70
|
+
end
|
71
|
+
|
72
|
+
private
|
73
|
+
|
74
|
+
def http
|
75
|
+
return @http unless @http.nil?
|
76
|
+
@http = Net::HTTP.new(@uri.domain, 443)
|
77
|
+
@http.use_ssl = true
|
78
|
+
@http
|
79
|
+
end
|
80
|
+
|
81
|
+
def parse_response(response)
|
82
|
+
if response && response.is_a?(Net::HTTPSuccess)
|
83
|
+
if response.body && response.content_type == 'application/json'
|
84
|
+
JSON.parse(response.body)
|
85
|
+
else
|
86
|
+
response.body.to_s
|
87
|
+
end
|
88
|
+
else
|
89
|
+
nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
|
2
|
+
module HttpMagic
|
3
|
+
# Helper class that holds the parts of the URI and provides methods to put
|
4
|
+
# them together.
|
5
|
+
#
|
6
|
+
# == Example
|
7
|
+
#
|
8
|
+
# uri = HttpMagic::Uri.new('example.com')
|
9
|
+
# uri.build
|
10
|
+
# => "https://example.com/"
|
11
|
+
#
|
12
|
+
# uri.namespace = 'api/v2'
|
13
|
+
# uri.build
|
14
|
+
# => "https://example.com/api/v2"
|
15
|
+
#
|
16
|
+
# uri.parts = ['path']
|
17
|
+
# uri.build
|
18
|
+
# => "https://example.com/api/v2/path"
|
19
|
+
#
|
20
|
+
class Uri
|
21
|
+
attr_accessor :namespace, :parts
|
22
|
+
|
23
|
+
attr_reader :domain
|
24
|
+
|
25
|
+
def initialize(domain)
|
26
|
+
@domain = domain
|
27
|
+
@parts = []
|
28
|
+
end
|
29
|
+
|
30
|
+
# Builds a full uniform resource identifier.
|
31
|
+
#
|
32
|
+
# == Example
|
33
|
+
#
|
34
|
+
# uri = HttpMagic::Uri.new('example.com')
|
35
|
+
# uri.namespace = 'api/v1'
|
36
|
+
# uri.parts = %w(foo bar)
|
37
|
+
#
|
38
|
+
# uri.urn
|
39
|
+
# => "https://example.com/api/v1/foo/bar"
|
40
|
+
def build
|
41
|
+
"#{url}#{urn}"
|
42
|
+
end
|
43
|
+
|
44
|
+
# Uniform resource locator based on @domain value.
|
45
|
+
#
|
46
|
+
# == Example
|
47
|
+
#
|
48
|
+
# uri = HttpMagic::Uri.new('example.com')
|
49
|
+
#
|
50
|
+
# uri.url
|
51
|
+
# => "https://example.com/"
|
52
|
+
#
|
53
|
+
# uri.url(false)
|
54
|
+
# => "https://example.com"
|
55
|
+
def url
|
56
|
+
"https://#{@domain}"
|
57
|
+
end
|
58
|
+
|
59
|
+
# Uniform resource name for a resource.
|
60
|
+
#
|
61
|
+
# == Example
|
62
|
+
#
|
63
|
+
# uri = HttpMagic::Uri.new('example.com')
|
64
|
+
# uri.namespace = 'api/v1'
|
65
|
+
# uri.parts = %w(foo bar)
|
66
|
+
#
|
67
|
+
# uri.urn
|
68
|
+
# => "/api/v1/foo/bar"
|
69
|
+
def urn
|
70
|
+
resource_name = [@namespace, @parts].flatten.compact.join('/')
|
71
|
+
"/#{resource_name}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
data/lib/pivotal_tracker.rb
CHANGED
data/test/branch_command_test.rb
CHANGED
@@ -1,32 +1,19 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require 'pivotal_tracker'
|
2
3
|
require 'gradesfirst/branch_command'
|
4
|
+
require 'pivotal_tracker'
|
3
5
|
|
4
6
|
describe GradesFirst::BranchCommand do
|
5
7
|
before do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
)
|
11
|
-
|
12
|
-
stub_pivotal_request(
|
13
|
-
:get,
|
14
|
-
'stories/57348714',
|
15
|
-
body: fixture_file('story_foo.json')
|
16
|
-
)
|
17
|
-
|
18
|
-
PivotalTracker.api_token = 'test_token'
|
19
|
-
git_branch_output = fixture_file('git_branch.txt')
|
20
|
-
@command = GradesFirst::BranchCommand.new
|
21
|
-
@command.stub :git_branch, git_branch_output do
|
22
|
-
@command.execute
|
8
|
+
expect_requests stub_bar_story_request, stub_foo_story_request do
|
9
|
+
git_branch_output = fixture_file('git_branch.txt')
|
10
|
+
@command = GradesFirst::BranchCommand.new
|
11
|
+
@command.stub :git_branch, git_branch_output, &call_execute
|
23
12
|
end
|
24
13
|
end
|
25
14
|
|
26
|
-
|
27
|
-
|
28
|
-
assert_equal fixture_file('gf_branch.txt'), @command.response
|
29
|
-
end
|
15
|
+
specify '#response responds with Pivotal enhancements' do
|
16
|
+
assert_equal fixture_file('gf_branch.txt'), @command.response
|
30
17
|
end
|
31
18
|
|
32
19
|
end
|
data/test/cli_test.rb
CHANGED
@@ -2,52 +2,69 @@ require 'test_helper'
|
|
2
2
|
require 'gradesfirst/cli'
|
3
3
|
|
4
4
|
describe GradesFirst::CLI do
|
5
|
-
def command_not_found(command)
|
6
|
-
"Could not find task \"#{command}\".\n"
|
7
|
-
end
|
8
5
|
|
9
|
-
def
|
10
|
-
|
11
|
-
|
12
|
-
end
|
6
|
+
def assert_command_hooked_up(shell_command, klass)
|
7
|
+
assert_includes klass.instance_methods, :execute
|
8
|
+
assert_includes klass.instance_methods, :response
|
13
9
|
|
14
|
-
|
15
|
-
|
16
|
-
|
10
|
+
execute_arity = klass.instance_method(:execute).arity
|
11
|
+
if execute_arity < 0
|
12
|
+
execute_arity += 1
|
13
|
+
execute_arity = execute_arity.abs
|
17
14
|
end
|
15
|
+
expected_execute_parameters = Array.new(execute_arity, Object)
|
16
|
+
|
17
|
+
expected_output = 'Expected Response'
|
18
|
+
command_instance = Minitest::Mock.new.
|
19
|
+
expect(:execute, nil, expected_execute_parameters).
|
20
|
+
expect(:response, expected_output)
|
18
21
|
|
19
|
-
|
20
|
-
|
21
|
-
GradesFirst::CLI.start
|
22
|
+
stdout, stderr = capture_io do
|
23
|
+
klass.stub :new, command_instance do
|
24
|
+
GradesFirst::CLI.start Shellwords.split(shell_command)
|
22
25
|
end
|
23
|
-
refute_includes output, command_not_found('branch')
|
24
26
|
end
|
27
|
+
|
28
|
+
assert_equal '', stderr, "Error reported to standard error by CLI command \"#{shell_command}\""
|
29
|
+
assert_match expected_output, stdout, "Incorrect output from CLI command \"#{shell_command}\""
|
30
|
+
command_instance.verify
|
25
31
|
end
|
26
32
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
33
|
+
specify 'branch command is hooked up' do
|
34
|
+
assert_command_hooked_up 'branch', GradesFirst::BranchCommand
|
35
|
+
end
|
31
36
|
|
32
|
-
|
33
|
-
|
34
|
-
GradesFirst::CLI.start %w{ commit-message }
|
35
|
-
end
|
36
|
-
refute_includes output, command_not_found('commit-message')
|
37
|
-
end
|
37
|
+
specify 'commit-message command is hooked up' do
|
38
|
+
assert_command_hooked_up 'commit-message', GradesFirst::CommitMessageCommand
|
38
39
|
end
|
39
40
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
41
|
+
# Waiting on fix for subcommands with default command.
|
42
|
+
# https://github.com/erikhuda/thor/pull/374
|
43
|
+
#specify 'task command is hooked up to default list subcommand' do
|
44
|
+
# assert_command_hooked_up 'task', GradesFirst::TaskListCommand
|
45
|
+
#end
|
44
46
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
47
|
+
specify 'task add command is hooked up' do
|
48
|
+
assert_command_hooked_up(
|
49
|
+
'task add "This is a task."',
|
50
|
+
GradesFirst::TaskAddCommand
|
51
|
+
)
|
52
|
+
end
|
53
|
+
|
54
|
+
specify 'task delete command is hooked up' do
|
55
|
+
assert_command_hooked_up('task delete 1', GradesFirst::TaskDeleteCommand)
|
56
|
+
end
|
57
|
+
|
58
|
+
specify 'task list command is hooked up' do
|
59
|
+
assert_command_hooked_up 'task list', GradesFirst::TaskListCommand
|
60
|
+
end
|
61
|
+
|
62
|
+
specify 'task move command is hooked up' do
|
63
|
+
assert_command_hooked_up('task move 5 1', GradesFirst::TaskMoveCommand)
|
64
|
+
end
|
65
|
+
|
66
|
+
specify 'task toggle command is hooked up' do
|
67
|
+
assert_command_hooked_up('task toggle 1', GradesFirst::TaskToggleCommand)
|
51
68
|
end
|
52
69
|
|
53
70
|
end
|
data/test/command_test.rb
CHANGED
@@ -2,13 +2,11 @@ require 'test_helper'
|
|
2
2
|
require 'gradesfirst/command'
|
3
3
|
|
4
4
|
describe GradesFirst::Command do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
end
|
5
|
+
specify '#story_id pulls the story id from the branch' do
|
6
|
+
assert '123', GradesFirst::Command.new.send(:story_id, 'abc/123')
|
7
|
+
end
|
9
8
|
|
10
|
-
|
11
|
-
|
12
|
-
end
|
9
|
+
specify '#story_id returns nil if not story id' do
|
10
|
+
assert_nil GradesFirst::Command.new.send(:story_id, 'abc')
|
13
11
|
end
|
14
12
|
end
|
@@ -1,62 +1,54 @@
|
|
1
1
|
require 'test_helper'
|
2
|
+
require 'pivotal_tracker'
|
2
3
|
require 'gradesfirst/commit_message_command'
|
4
|
+
require 'pivotal_tracker'
|
3
5
|
|
4
6
|
describe GradesFirst::CommitMessageCommand do
|
5
|
-
before do
|
6
|
-
stub_pivotal_request(
|
7
|
-
:get,
|
8
|
-
'stories/29384793',
|
9
|
-
body: fixture_file('story_bar.json')
|
10
|
-
)
|
11
|
-
|
12
|
-
PivotalTracker.api_token = 'test_token'
|
13
|
-
end
|
14
|
-
|
15
7
|
describe '#response' do
|
16
|
-
it '
|
8
|
+
it 'responds with formatted commit message' do
|
17
9
|
command = GradesFirst::CommitMessageCommand.new
|
18
|
-
|
19
|
-
command.
|
20
|
-
assert_equal fixture_file('commit_message.txt'), command.response
|
10
|
+
expect_requests stub_bar_story_request do
|
11
|
+
command.stub :current_branch, "test/#{bar_story_id}", &call_execute
|
21
12
|
end
|
13
|
+
assert_equal fixture_file('commit_message.txt'), command.response
|
22
14
|
end
|
23
15
|
end
|
24
|
-
end
|
25
16
|
|
26
|
-
describe '
|
27
|
-
|
28
|
-
|
29
|
-
|
17
|
+
describe '#constrain_line_length' do
|
18
|
+
def test_string
|
19
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce vitae.'
|
20
|
+
end
|
30
21
|
|
31
|
-
|
32
|
-
|
33
|
-
|
22
|
+
def test_string_ending_with_a_letter
|
23
|
+
'Lorem ipsum dolor sit amet'
|
24
|
+
end
|
34
25
|
|
35
|
-
|
36
|
-
|
37
|
-
|
26
|
+
def test_string_with_line_feeds_at_30
|
27
|
+
"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit.\nFusce vitae."
|
28
|
+
end
|
38
29
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
30
|
+
it 'adds new lines at natural breaks when length is exceeded' do
|
31
|
+
command = GradesFirst::CommitMessageCommand.new
|
32
|
+
assert_equal(
|
33
|
+
test_string_with_line_feeds_at_30,
|
34
|
+
command.send(:constrain_line_length, test_string, 30)
|
35
|
+
)
|
36
|
+
end
|
46
37
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
38
|
+
it 'does nothing when length is not exceeded' do
|
39
|
+
command = GradesFirst::CommitMessageCommand.new
|
40
|
+
assert_equal(
|
41
|
+
test_string,
|
42
|
+
command.send(:constrain_line_length, test_string, 80)
|
43
|
+
)
|
44
|
+
end
|
54
45
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
46
|
+
it 'does not wrap when ending with a letter' do
|
47
|
+
command = GradesFirst::CommitMessageCommand.new
|
48
|
+
assert_equal(
|
49
|
+
test_string_ending_with_a_letter,
|
50
|
+
command.send(:constrain_line_length, test_string_ending_with_a_letter, 80)
|
51
|
+
)
|
52
|
+
end
|
61
53
|
end
|
62
54
|
end
|