gradesfirst 0.2.1 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/.gitignore +1 -0
  2. data/Gemfile +1 -2
  3. data/Gemfile.lock +2 -6
  4. data/gradesfirst.gemspec +2 -2
  5. data/lib/gradesfirst.rb +1 -0
  6. data/lib/gradesfirst/cli.rb +7 -29
  7. data/lib/gradesfirst/cli_helper.rb +33 -0
  8. data/lib/gradesfirst/command.rb +7 -0
  9. data/lib/gradesfirst/commit_message_command.rb +1 -1
  10. data/lib/gradesfirst/task_add_command.rb +51 -0
  11. data/lib/gradesfirst/task_cli.rb +48 -0
  12. data/lib/gradesfirst/task_command.rb +38 -30
  13. data/lib/gradesfirst/task_delete_command.rb +64 -0
  14. data/lib/gradesfirst/task_list_command.rb +40 -0
  15. data/lib/gradesfirst/task_move_command.rb +64 -0
  16. data/lib/gradesfirst/task_toggle_command.rb +65 -0
  17. data/lib/http_magic.rb +2 -258
  18. data/lib/http_magic/api.rb +233 -0
  19. data/lib/http_magic/request.rb +93 -0
  20. data/lib/http_magic/uri.rb +74 -0
  21. data/lib/pivotal_tracker.rb +1 -1
  22. data/test/branch_command_test.rb +8 -21
  23. data/test/cli_test.rb +51 -34
  24. data/test/command_test.rb +5 -7
  25. data/test/commit_message_command_test.rb +37 -45
  26. data/test/fixtures/task.json +10 -0
  27. data/test/fixtures/task_added.txt +6 -0
  28. data/test/fixtures/task_deleted.txt +6 -0
  29. data/test/fixtures/task_moved.txt +6 -0
  30. data/test/fixtures/task_toggled.txt +6 -0
  31. data/test/fixtures/tasks.txt +2 -2
  32. data/test/http_magic/{get_test.rb → api/get_test.rb} +1 -1
  33. data/test/http_magic/api/post_test.rb +34 -0
  34. data/test/http_magic/request_test.rb +63 -0
  35. data/test/http_magic/uri_test.rb +28 -55
  36. data/test/support/pivotal_test_helper.rb +110 -0
  37. data/test/support/request_expectation.rb +33 -0
  38. data/test/task_add_command_test.rb +54 -0
  39. data/test/task_delete_command_test.rb +57 -0
  40. data/test/task_list_command_test.rb +18 -0
  41. data/test/task_move_command_test.rb +66 -0
  42. data/test/task_toggle_command_test.rb +58 -0
  43. data/test/test_helper.rb +35 -19
  44. metadata +29 -7
  45. data/test/pivotal_tracker_test.rb +0 -46
  46. data/test/task_command_test.rb +0 -52
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  *.gem
2
2
  *.swp
3
3
  .rvmrc
4
+ *.swo
data/Gemfile CHANGED
@@ -2,8 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gem 'rake'
4
4
  gem 'minitest', '~> 4.7.0'
5
- gem 'thor', '~> 0.14.6'
5
+ gem 'thor', '~> 0.18.1'
6
6
  gem 'webmock', '~> 1.16.0'
7
- gem 'mocha'
8
7
  gem 'pry'
9
8
  gem 'pry-debugger'
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.14.6)
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.14.6)
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.2.1"
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.14.6')
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
@@ -1,2 +1,3 @@
1
1
  module GradesFirst
2
+ TAB = ' '
2
3
  end
@@ -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/task_command'
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.new)
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.new)
24
+ execute(GradesFirst::CommitMessageCommand)
23
25
  end
24
26
 
25
- desc 'task', GradesFirst::TaskCommand.description
26
- def task
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
@@ -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]+$/
@@ -15,7 +15,7 @@ module GradesFirst
15
15
 
16
16
  # Performs the gf commit-message Thor command.
17
17
  def execute
18
- @story = PivotalTracker.stories[story_id].get
18
+ @story = current_story
19
19
  end
20
20
 
21
21
  # Output response of the gf commit-message Thor command in the standard
@@ -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
- # Description of the gf branch Thor command that will be used in the
9
- # command line help.
10
- def self.description
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
- # Performs the gf tasks Thor command.
15
- def execute
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
- # Generates the comand line output response. The output of the task command
24
- # is a list of the tasks associated with the PivotalTracker story associated
25
- # with the current branch.
26
- def response
27
- if @tasks.nil?
28
- error_message
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
- private
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
- def error_message
40
- 'Tasks cannot be retrieved for this branch.'
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 story_line
44
- " #{@story['name']} (#{@story['url']})\n\n"
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