gradesfirst 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -12,11 +12,8 @@ GEM
|
|
12
12
|
debugger-ruby_core_source (~> 1.2.4)
|
13
13
|
debugger-linecache (1.2.0)
|
14
14
|
debugger-ruby_core_source (1.2.4)
|
15
|
-
metaclass (0.0.1)
|
16
15
|
method_source (0.8.2)
|
17
16
|
minitest (4.7.5)
|
18
|
-
mocha (0.14.0)
|
19
|
-
metaclass (~> 0.0.1)
|
20
17
|
pry (0.9.12.4)
|
21
18
|
coderay (~> 1.0)
|
22
19
|
method_source (~> 0.8)
|
@@ -27,7 +24,7 @@ GEM
|
|
27
24
|
rake (10.0.2)
|
28
25
|
safe_yaml (0.9.7)
|
29
26
|
slop (3.4.7)
|
30
|
-
thor (0.
|
27
|
+
thor (0.18.1)
|
31
28
|
webmock (1.16.0)
|
32
29
|
addressable (>= 2.2.7)
|
33
30
|
crack (>= 0.3.2)
|
@@ -37,9 +34,8 @@ PLATFORMS
|
|
37
34
|
|
38
35
|
DEPENDENCIES
|
39
36
|
minitest (~> 4.7.0)
|
40
|
-
mocha
|
41
37
|
pry
|
42
38
|
pry-debugger
|
43
39
|
rake
|
44
|
-
thor (~> 0.
|
40
|
+
thor (~> 0.18.1)
|
45
41
|
webmock (~> 1.16.0)
|
data/gradesfirst.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.platform = Gem::Platform::RUBY
|
3
3
|
s.name = "gradesfirst"
|
4
|
-
s.version = "0.
|
4
|
+
s.version = "0.3.0"
|
5
5
|
s.summary = "GradesFirst command line utility for developers."
|
6
6
|
s.description = "This utility will help manage the various tasks developers need to do on their workstation such as database updates."
|
7
7
|
s.license = "MIT"
|
@@ -22,6 +22,6 @@ Gem::Specification.new do |s|
|
|
22
22
|
|
23
23
|
s.require_paths = ['lib']
|
24
24
|
|
25
|
-
s.add_dependency('thor', '~> 0.
|
25
|
+
s.add_dependency('thor', '~> 0.18.1')
|
26
26
|
s.add_development_dependency('minitest', '~> 4.7.0')
|
27
27
|
end
|
data/lib/gradesfirst.rb
CHANGED
data/lib/gradesfirst/cli.rb
CHANGED
@@ -1,53 +1,31 @@
|
|
1
1
|
require 'thor'
|
2
2
|
|
3
|
+
require 'gradesfirst/cli_helper'
|
3
4
|
require 'gradesfirst/command'
|
4
5
|
require 'gradesfirst/branch_command'
|
5
6
|
require 'gradesfirst/commit_message_command'
|
6
|
-
require 'gradesfirst/
|
7
|
+
require 'gradesfirst/task_cli'
|
7
8
|
|
8
9
|
require 'pivotal_tracker'
|
9
10
|
|
10
11
|
module GradesFirst
|
11
12
|
class CLI < Thor
|
13
|
+
include GradesFirst::CliHelper
|
12
14
|
|
13
15
|
desc 'branch', GradesFirst::BranchCommand.description
|
14
16
|
def branch
|
15
17
|
set_pivotal_tracker_api_token
|
16
|
-
execute(GradesFirst::BranchCommand
|
18
|
+
execute(GradesFirst::BranchCommand)
|
17
19
|
end
|
18
20
|
|
19
21
|
desc 'commit-message', GradesFirst::CommitMessageCommand.description
|
20
22
|
def commit_message
|
21
23
|
set_pivotal_tracker_api_token
|
22
|
-
execute(GradesFirst::CommitMessageCommand
|
24
|
+
execute(GradesFirst::CommitMessageCommand)
|
23
25
|
end
|
24
26
|
|
25
|
-
desc 'task',
|
26
|
-
|
27
|
-
set_pivotal_tracker_api_token
|
28
|
-
execute(GradesFirst::TaskCommand.new)
|
29
|
-
end
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def execute(command)
|
34
|
-
command.execute
|
35
|
-
say command.response
|
36
|
-
end
|
37
|
-
|
38
|
-
def set_pivotal_tracker_api_token
|
39
|
-
file_name = "#{Dir.home}/.pivotal_tracker_api_key"
|
40
|
-
if File.exists?(file_name)
|
41
|
-
api_token = File.read(file_name)
|
42
|
-
else
|
43
|
-
api_token = ask('Enter your PivotalTracker API token:')
|
44
|
-
File.open(file_name, 'w') do |file|
|
45
|
-
file.write(api_token)
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
PivotalTracker.api_token = api_token
|
50
|
-
end
|
27
|
+
desc 'task COMMAND', 'Manage tasks related to a PivotalTracker story.'
|
28
|
+
subcommand 'task', GradesFirst::TaskCLI
|
51
29
|
|
52
30
|
Signal.trap('SIGINT') do
|
53
31
|
print "\n"
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module GradesFirst
|
2
|
+
|
3
|
+
# Helper methods used across multiple Thor CLI commands and subcommands.
|
4
|
+
module CliHelper
|
5
|
+
private
|
6
|
+
|
7
|
+
# Executes a command that conforms to the GradesFirst Command pattern
|
8
|
+
# interface.
|
9
|
+
def execute(klass, *args)
|
10
|
+
command = klass.new
|
11
|
+
command.execute(*args)
|
12
|
+
say command.response
|
13
|
+
end
|
14
|
+
|
15
|
+
# Set the PivotalTracker api token to authenticate the current user.
|
16
|
+
# If the user is access PivotalTracker for the first time then they will
|
17
|
+
# be prompted to enter their api token and it will be saved for later use.
|
18
|
+
def set_pivotal_tracker_api_token
|
19
|
+
file_name = "#{Dir.home}/.pivotal_tracker_api_key"
|
20
|
+
if File.exists?(file_name)
|
21
|
+
api_token = File.read(file_name)
|
22
|
+
else
|
23
|
+
api_token = ask('Enter your PivotalTracker API token:')
|
24
|
+
File.open(file_name, 'w') do |file|
|
25
|
+
file.write(api_token)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
PivotalTracker.api_token = api_token
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
data/lib/gradesfirst/command.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'gradesfirst'
|
2
|
+
|
1
3
|
module GradesFirst
|
2
4
|
|
3
5
|
# Base class for all command objects.
|
@@ -10,6 +12,11 @@ module GradesFirst
|
|
10
12
|
`git rev-parse --abbrev-ref HEAD`
|
11
13
|
end
|
12
14
|
|
15
|
+
# Retrieves the current story
|
16
|
+
def current_story
|
17
|
+
PivotalTracker.stories[story_id].get
|
18
|
+
end
|
19
|
+
|
13
20
|
# Extracts a PivotalTracker story id from a branch if one is present.
|
14
21
|
def story_id(branch = current_branch)
|
15
22
|
if branch =~ /[0-9]+$/
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'gradesfirst/task_command'
|
2
|
+
|
3
|
+
module GradesFirst
|
4
|
+
|
5
|
+
# Implementation of a Thor command for adding tasks to PivotalTracker stories.
|
6
|
+
class TaskAddCommand < GradesFirst::TaskCommand
|
7
|
+
# Description of the "gf task add" Thor command that will be used in
|
8
|
+
# the commandline help.
|
9
|
+
def self.description
|
10
|
+
'Add a task to a PivotalTracker story.'
|
11
|
+
end
|
12
|
+
|
13
|
+
# Performs the gf task add Thor command.
|
14
|
+
def execute(description)
|
15
|
+
@story = current_story
|
16
|
+
if @story
|
17
|
+
@success = task_add(@story, description)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Generates the command line output response. The output of the task add
|
22
|
+
# command is a completion status message which may be followed by the new
|
23
|
+
# list of tasks if the task was added successfully.
|
24
|
+
def response
|
25
|
+
task_action_response(@story, @success)
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def story_error_message
|
31
|
+
'Tasks cannot be created for this branch.'
|
32
|
+
end
|
33
|
+
|
34
|
+
def task_add(story, description)
|
35
|
+
PivotalTracker.
|
36
|
+
projects[story['project_id']].
|
37
|
+
stories[story['id']].
|
38
|
+
tasks.
|
39
|
+
post(description: description)
|
40
|
+
end
|
41
|
+
|
42
|
+
def task_error_message
|
43
|
+
'Creation of the task failed.'
|
44
|
+
end
|
45
|
+
|
46
|
+
def task_success_message
|
47
|
+
'Task was successfully added.'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'gradesfirst/cli_helper'
|
2
|
+
require 'gradesfirst/task_add_command'
|
3
|
+
require 'gradesfirst/task_delete_command'
|
4
|
+
require 'gradesfirst/task_list_command'
|
5
|
+
require 'gradesfirst/task_move_command'
|
6
|
+
require 'gradesfirst/task_toggle_command'
|
7
|
+
|
8
|
+
module GradesFirst
|
9
|
+
class TaskCLI < Thor
|
10
|
+
include GradesFirst::CliHelper
|
11
|
+
|
12
|
+
namespace :task
|
13
|
+
# Waiting on fix for subcommands with default command.
|
14
|
+
# https://github.com/erikhuda/thor/pull/374
|
15
|
+
#default_command :list
|
16
|
+
|
17
|
+
desc 'add DESCRIPTION', GradesFirst::TaskAddCommand.description
|
18
|
+
def add(description)
|
19
|
+
set_pivotal_tracker_api_token
|
20
|
+
execute(GradesFirst::TaskAddCommand, description)
|
21
|
+
end
|
22
|
+
|
23
|
+
desc 'delete POSITION', GradesFirst::TaskDeleteCommand.description
|
24
|
+
def delete(position)
|
25
|
+
set_pivotal_tracker_api_token
|
26
|
+
execute(GradesFirst::TaskDeleteCommand, position)
|
27
|
+
end
|
28
|
+
|
29
|
+
desc 'list', GradesFirst::TaskListCommand.description
|
30
|
+
def list
|
31
|
+
set_pivotal_tracker_api_token
|
32
|
+
execute(GradesFirst::TaskListCommand)
|
33
|
+
end
|
34
|
+
|
35
|
+
desc 'move FROM TO', GradesFirst::TaskMoveCommand.description
|
36
|
+
def move(from, to)
|
37
|
+
set_pivotal_tracker_api_token
|
38
|
+
execute(GradesFirst::TaskMoveCommand, from , to)
|
39
|
+
end
|
40
|
+
|
41
|
+
desc 'toggle POSITION', GradesFirst::TaskToggleCommand.description
|
42
|
+
def toggle(position)
|
43
|
+
set_pivotal_tracker_api_token
|
44
|
+
execute(GradesFirst::TaskToggleCommand, position)
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
@@ -1,47 +1,55 @@
|
|
1
1
|
require 'gradesfirst/command'
|
2
2
|
|
3
3
|
module GradesFirst
|
4
|
-
|
5
|
-
# Implementation of a Thor command for managing tasks related to a story.
|
6
4
|
class TaskCommand < GradesFirst::Command
|
5
|
+
private
|
7
6
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
'List the tasks related to a PivotalTracker story.'
|
7
|
+
def get_task_id_by_position(story, position)
|
8
|
+
task = get_task_by_position(story, position)
|
9
|
+
task['id'] if task
|
12
10
|
end
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
@story = PivotalTracker.stories[story_id].get
|
17
|
-
if @story
|
18
|
-
project_id = @story['project_id']
|
19
|
-
@tasks = PivotalTracker.projects[project_id].stories[story_id].tasks.get
|
20
|
-
end
|
12
|
+
def get_task_by_position(story, position)
|
13
|
+
get_tasks(story).find { |t| t['position'] == position.to_i }
|
21
14
|
end
|
22
15
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
else
|
30
|
-
task_list = @tasks.map do |t|
|
31
|
-
" [#{t["complete"] ? 'X' : ' '}] #{t["description"]}"
|
32
|
-
end
|
33
|
-
story_line + task_list.join("\n") + "\n"
|
34
|
-
end
|
16
|
+
def get_tasks(story)
|
17
|
+
PivotalTracker.
|
18
|
+
projects[story['project_id']].
|
19
|
+
stories[story['id']].
|
20
|
+
tasks.
|
21
|
+
get
|
35
22
|
end
|
36
23
|
|
37
|
-
|
24
|
+
def position(task)
|
25
|
+
task['position'].to_s.rjust(2)
|
26
|
+
end
|
27
|
+
|
28
|
+
def story_line(story)
|
29
|
+
"#{TAB}#{story['name']} (#{story['url']})\n\n"
|
30
|
+
end
|
38
31
|
|
39
|
-
|
40
|
-
|
32
|
+
# Generates the commandline output response for actions taken on tasks like
|
33
|
+
# add and delete.
|
34
|
+
def task_action_response(story, success)
|
35
|
+
if story.nil?
|
36
|
+
story_error_message
|
37
|
+
elsif !success
|
38
|
+
task_error_message
|
39
|
+
else
|
40
|
+
tasks = get_tasks(story)
|
41
|
+
[
|
42
|
+
TAB + task_success_message,
|
43
|
+
task_list_response(story, tasks)
|
44
|
+
].join("\n\n")
|
45
|
+
end
|
41
46
|
end
|
42
47
|
|
43
|
-
def
|
44
|
-
|
48
|
+
def task_list_response(story, tasks)
|
49
|
+
task_list = tasks.map do |t|
|
50
|
+
"#{TAB}#{position(t)}. [#{t["complete"] ? 'X' : ' '}] #{t["description"]}"
|
51
|
+
end
|
52
|
+
story_line(story) + task_list.join("\n") + "\n"
|
45
53
|
end
|
46
54
|
end
|
47
55
|
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'gradesfirst/task_command'
|
2
|
+
|
3
|
+
module GradesFirst
|
4
|
+
|
5
|
+
# Implementation of a Thor command for deleting tasks from PivotalTracker
|
6
|
+
# stories.
|
7
|
+
class TaskDeleteCommand < GradesFirst::TaskCommand
|
8
|
+
# Description of the "gf task delete" Thor command that will be used in
|
9
|
+
# the commandline help.
|
10
|
+
def self.description
|
11
|
+
'Delete a task from a PivotalTracker story.'
|
12
|
+
end
|
13
|
+
|
14
|
+
# Performs the gf task delete POSITION Thor command.
|
15
|
+
def execute(position)
|
16
|
+
@story = current_story
|
17
|
+
if @story
|
18
|
+
task_id = get_task_id_by_position(@story, position)
|
19
|
+
if task_id
|
20
|
+
@success = task_delete(@story, task_id)
|
21
|
+
else
|
22
|
+
@task_position_invalid = true
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Generates the command line output response. The output of the task delete
|
28
|
+
# command is a completion status message which may be followed by the new
|
29
|
+
# list of tasks if the task was deleted successfully.
|
30
|
+
def response
|
31
|
+
if @task_position_invalid
|
32
|
+
position_invalid_message
|
33
|
+
else
|
34
|
+
task_action_response(@story, @success)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def position_invalid_message
|
41
|
+
'Task position given does not exist.'
|
42
|
+
end
|
43
|
+
|
44
|
+
def story_error_message
|
45
|
+
'Tasks cannot be deleted for this branch.'
|
46
|
+
end
|
47
|
+
|
48
|
+
def task_delete(story, task_id)
|
49
|
+
PivotalTracker.
|
50
|
+
projects[story['project_id']].
|
51
|
+
stories[story['id']].
|
52
|
+
tasks[task_id].
|
53
|
+
delete
|
54
|
+
end
|
55
|
+
|
56
|
+
def task_error_message
|
57
|
+
'Deletion of the task failed.'
|
58
|
+
end
|
59
|
+
|
60
|
+
def task_success_message
|
61
|
+
'Task was successfully deleted.'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|