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.
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