pgit 0.0.4 → 1.0.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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/.agignore +3 -0
  3. data/.travis.yml +1 -0
  4. data/README.markdown +32 -9
  5. data/Rakefile +12 -0
  6. data/bin/pgit +167 -25
  7. data/lib/pgit.rb +40 -10
  8. data/lib/pgit/bilateral/handle_back.rb +22 -0
  9. data/lib/pgit/bilateral/handle_choose_story.rb +31 -0
  10. data/lib/pgit/bilateral/story.rb +44 -0
  11. data/lib/pgit/command.rb +83 -0
  12. data/lib/pgit/command/add.rb +36 -0
  13. data/lib/pgit/command/application.rb +21 -0
  14. data/lib/pgit/command/edit.rb +36 -0
  15. data/lib/pgit/command/remove.rb +36 -0
  16. data/lib/pgit/command/run.rb +32 -0
  17. data/lib/pgit/command/show.rb +53 -0
  18. data/lib/pgit/configuration.rb +27 -3
  19. data/lib/pgit/current_project.rb +9 -45
  20. data/lib/pgit/current_project/validator.rb +2 -1
  21. data/lib/pgit/error/external.rb +11 -0
  22. data/lib/pgit/error/user.rb +12 -0
  23. data/lib/pgit/helpers/heredoc.rb +17 -0
  24. data/lib/pgit/helpers/query_methods.rb +63 -0
  25. data/lib/pgit/helpers/string_extensions.rb +29 -0
  26. data/lib/pgit/installer/bash_auto_completion.rb +57 -0
  27. data/lib/pgit/pivotal/collection_request.rb +21 -0
  28. data/lib/pgit/pivotal/individual_request.rb +47 -0
  29. data/lib/pgit/pivotal/iteration.rb +6 -0
  30. data/lib/pgit/pivotal/iterations.rb +15 -0
  31. data/lib/pgit/pivotal/project.rb +6 -0
  32. data/lib/pgit/pivotal/projects.rb +20 -0
  33. data/lib/pgit/pivotal/query.rb +8 -0
  34. data/lib/pgit/pivotal/request.rb +33 -0
  35. data/lib/pgit/pivotal/request/query.rb +25 -0
  36. data/lib/pgit/pivotal/story.rb +38 -0
  37. data/lib/pgit/pivotal_request_validator.rb +1 -1
  38. data/lib/pgit/project.rb +78 -0
  39. data/lib/pgit/project/add.rb +28 -0
  40. data/lib/pgit/project/application.rb +21 -0
  41. data/lib/pgit/project/interactive_adder.rb +41 -0
  42. data/lib/pgit/project/remove.rb +41 -0
  43. data/lib/pgit/project/reuse_api_token_adder.rb +48 -0
  44. data/lib/pgit/response_handler.rb +16 -0
  45. data/lib/pgit/root.rb +5 -0
  46. data/lib/pgit/status.rb +16 -0
  47. data/lib/pgit/story_branch/application.rb +3 -3
  48. data/lib/pgit/{name_parser.rb → story_branch/name_parser.rb} +0 -0
  49. data/lib/pgit/story_branch/story_id_parser.rb +11 -0
  50. data/lib/pgit/validators/project_validator.rb +20 -0
  51. data/lib/pgit/version.rb +1 -1
  52. data/lib/pivotal +0 -0
  53. data/pgit.gemspec +5 -0
  54. data/spec/fixtures/iterations +1 -0
  55. data/spec/pgit/bilateral/handle_back_spec.rb +29 -0
  56. data/spec/pgit/bilateral/handle_choose_story_spec.rb +17 -0
  57. data/spec/pgit/bilateral/story_spec.rb +178 -0
  58. data/spec/pgit/command/add_spec.rb +68 -0
  59. data/spec/pgit/command/application_spec.rb +110 -0
  60. data/spec/pgit/command/edit_spec.rb +61 -0
  61. data/spec/pgit/command/remove_spec.rb +76 -0
  62. data/spec/pgit/command/run_spec.rb +49 -0
  63. data/spec/pgit/command/show_spec.rb +95 -0
  64. data/spec/pgit/command_spec.rb +299 -0
  65. data/spec/pgit/configuration_spec.rb +121 -18
  66. data/spec/pgit/current_project/validator_spec.rb +2 -1
  67. data/spec/pgit/current_project_spec.rb +20 -71
  68. data/spec/pgit/{external_error_spec.rb → error/external_spec.rb} +3 -3
  69. data/spec/pgit/error/user_spec.rb +17 -0
  70. data/spec/pgit/helpers/heredoc_spec.rb +33 -0
  71. data/spec/pgit/helpers/query_methods_spec.rb +24 -0
  72. data/spec/pgit/helpers/string_extensions_spec.rb +49 -0
  73. data/spec/pgit/installer/bash_auto_completion_spec.rb +134 -0
  74. data/spec/pgit/pivotal/individual_request_spec.rb +32 -0
  75. data/spec/pgit/pivotal/iteration_spec.rb +19 -0
  76. data/spec/pgit/pivotal/iterations_spec.rb +37 -0
  77. data/spec/pgit/pivotal/project_spec.rb +9 -0
  78. data/spec/pgit/pivotal/projects_spec.rb +48 -0
  79. data/spec/pgit/pivotal/request/query_spec.rb +24 -0
  80. data/spec/pgit/pivotal/story_spec.rb +113 -0
  81. data/spec/pgit/pivotal_request_validator_spec.rb +3 -3
  82. data/spec/pgit/project/add_spec.rb +52 -0
  83. data/spec/pgit/project/application_spec.rb +69 -0
  84. data/spec/pgit/project/interactive_adder_spec.rb +45 -0
  85. data/spec/pgit/project/remove_spec.rb +86 -0
  86. data/spec/pgit/project/reuse_api_token_adder_spec.rb +41 -0
  87. data/spec/pgit/project_spec.rb +513 -0
  88. data/spec/pgit/status_spec.rb +40 -0
  89. data/spec/pgit/story_branch/application_spec.rb +5 -8
  90. data/spec/pgit/story_branch/name_parser_spec.rb +3 -3
  91. data/spec/pgit/story_branch/story_id_parser_spec.rb +17 -0
  92. data/spec/pgit/validators/project_validator_spec.rb +39 -0
  93. metadata +146 -21
  94. data/lib/pgit/configuration/layout_error.rb +0 -9
  95. data/lib/pgit/configuration/missing_attributes_error.rb +0 -10
  96. data/lib/pgit/configuration/not_found_error.rb +0 -10
  97. data/lib/pgit/configuration/project_missing_error.rb +0 -10
  98. data/lib/pgit/configuration/validator.rb +0 -41
  99. data/lib/pgit/current_project/no_paths_match_working_dir_error.rb +0 -10
  100. data/lib/pgit/external_error.rb +0 -9
  101. data/lib/pgit/installer/configuration.rb +0 -34
  102. data/lib/pgit/story.rb +0 -44
  103. data/spec/pgit/configuration/missing_attributes_error_spec.rb +0 -30
  104. data/spec/pgit/configuration/not_found_error_spec.rb +0 -17
  105. data/spec/pgit/configuration/project_missing_error_spec.rb +0 -30
  106. data/spec/pgit/configuration/validator_spec.rb +0 -79
  107. data/spec/pgit/current_project/no_paths_match_working_dir_error_spec.rb +0 -17
  108. data/spec/pgit/installer/configuration_spec.rb +0 -162
  109. data/spec/pgit/story_spec.rb +0 -35
@@ -0,0 +1,44 @@
1
+ require 'pgit'
2
+
3
+ module PGit
4
+ module Bilateral
5
+ class Story < ResponseHandler
6
+ include Interactive
7
+ def initialize(options)
8
+ raise PGit::Error::User, "Invalid options. See `pgit iteration -h` for valid options." unless options_has_valid_scope(options)
9
+
10
+ @iterations_obj = PGit::Pivotal::Iterations.new(get_scope_hash(options))
11
+ @iterations = @iterations_obj.get!
12
+ @question = _question
13
+ @response_handlers = [PGit::Bilateral::HandleChooseStory]
14
+ end
15
+
16
+ def stories
17
+ @iterations.inject([]) { |accum, iteration| accum | iteration.stories }
18
+ end
19
+
20
+ private
21
+
22
+ def options(new_response)
23
+ {response: new_response, stories: stories, parent_question: @question}
24
+ end
25
+
26
+ def _question
27
+ Question.new do |q|
28
+ q.question = "Which story do you want to branch-ify?"
29
+ q.options = [stories, :back]
30
+ q.columns = [:index, :story_type, :estimate, :name, :current_state]
31
+ end
32
+ end
33
+
34
+ def get_scope_hash(options)
35
+ options.select {|k,v| k == :scope}
36
+ end
37
+
38
+ def options_has_valid_scope(options)
39
+ [:done, :current, :current_backlog, :backlog].inject(false) {|accum, valid_scope| accum || options.fetch(:scope).to_sym == valid_scope}
40
+
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,83 @@
1
+ module PGit
2
+ class Command
3
+ attr_reader :name, :steps, :branch_name, :current_project
4
+
5
+ def initialize(name, steps, project)
6
+ @name = name
7
+ @steps = steps
8
+ @branch_name = PGit::CurrentBranch.new.name
9
+ @current_project = project
10
+ end
11
+
12
+ def execute
13
+ @steps.each do |step|
14
+ step.gsub!(/STORY_BRANCH/, branch_name)
15
+
16
+ puts "About to execute '#{formatted_step(step)}'. Proceed? #{exec_options}"
17
+ response = STDIN.gets.chomp
18
+
19
+ if response.letter?('s')
20
+ puts formatted_action('Skipping...')
21
+ elsif response.letter?('q')
22
+ puts formatted_action("Quitting...")
23
+ break
24
+ elsif response.letter?('y')
25
+ puts "#{formatted_action('Executing')} '#{formatted_step(step)}'..."
26
+ puts `#{step}`
27
+ else
28
+ show_options
29
+ raise PGit::Error::User
30
+ end
31
+ end
32
+ rescue PGit::Error::User
33
+ retry
34
+ end
35
+
36
+ def to_h
37
+ to_hash
38
+ end
39
+
40
+ def to_hash
41
+ { name => steps }
42
+ end
43
+
44
+ def to_s
45
+ steps.inject(Rainbow("#{name}:\n").bright) {|accum, step| accum + " #{step}\n" }
46
+ end
47
+
48
+ def save!
49
+ current_project.commands.reject! {|cmd| cmd.name == name}
50
+ current_project.commands = current_project.commands << self
51
+ current_project.save!
52
+ end
53
+
54
+ def remove!
55
+ current_project.commands.reject! {|cmd| cmd.name == name}
56
+ current_project.save!
57
+ end
58
+
59
+ private
60
+
61
+ def formatted_action(action)
62
+ Rainbow(action).color(:yellow)
63
+ end
64
+
65
+ def formatted_step(step)
66
+ Rainbow(step).bright
67
+ end
68
+
69
+ def exec_options
70
+ Rainbow("[Y/s/q]").color("#FF6FEA")
71
+ end
72
+
73
+ def show_options
74
+ message = <<-LEGAL_OPTIONS
75
+ y - yes
76
+ s - skip
77
+ q - quit
78
+ LEGAL_OPTIONS
79
+
80
+ puts Rainbow(PGit::Helpers::Heredoc.remove_front_spaces(message)).red
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,36 @@
1
+ require 'forwardable'
2
+
3
+ module PGit
4
+ class Command
5
+ class Add
6
+ extend Forwardable
7
+ def_delegators :@app, :commands, :command, :args, :global_opts, :opts, :current_project
8
+ def_delegators :command, :name
9
+
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ def execute!
15
+ check_command_exists_for_add
16
+
17
+ command.save!
18
+ display_success_msg(:added, :to)
19
+ end
20
+
21
+ private
22
+
23
+ def exists?
24
+ commands.find { |c| c.name == name }
25
+ end
26
+
27
+ def display_success_msg(event, preposition)
28
+ puts "Successfully #{event} command '#{name}' #{preposition} the current project!"
29
+ end
30
+
31
+ def check_command_exists_for_add
32
+ raise PGit::Error::User.new "Command '#{name}' already exists in the current project. If you want to update the command, see `pgit cmd edit --help`" if exists?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,21 @@
1
+ require 'forwardable'
2
+ module PGit
3
+ class Command
4
+ class Application
5
+ extend Forwardable
6
+ def_delegators :@current_project, :commands
7
+
8
+ attr_reader :global_opts, :opts, :args, :current_project, :command
9
+ def initialize(global_opts, opts, args)
10
+ configuration = PGit::Configuration.new
11
+ @current_project = PGit::CurrentProject.new(configuration)
12
+ @global_opts = global_opts
13
+ @command = PGit::Command.new(opts.fetch("name") { :no_name_provided },
14
+ opts.fetch("steps") { [:no_steps_provided] },
15
+ @current_project)
16
+ @args = args
17
+ @opts = opts
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,36 @@
1
+ require 'forwardable'
2
+
3
+ module PGit
4
+ class Command
5
+ class Edit
6
+ extend Forwardable
7
+ def_delegators :@app, :commands, :command, :args, :global_opts, :opts
8
+ def_delegators :command, :name
9
+
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ def execute!
15
+ check_command_exists_for_update
16
+
17
+ command.save!
18
+ display_success_msg
19
+ end
20
+
21
+ private
22
+
23
+ def exists?
24
+ commands.find { |c| c.name == name }
25
+ end
26
+
27
+ def display_success_msg
28
+ puts "Successfully edited command '#{name}' of the current project!"
29
+ end
30
+
31
+ def check_command_exists_for_update
32
+ raise PGit::Error::User.new "Cannot edit a command that does not exist in the current project. See `pgit cmd add --help` if you want to add a new command" unless exists?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,36 @@
1
+ require 'forwardable'
2
+
3
+ module PGit
4
+ class Command
5
+ class Remove
6
+ extend Forwardable
7
+ def_delegators :@app, :commands, :command, :args, :global_opts, :opts, :current_project
8
+ def_delegators :command, :name
9
+
10
+ def initialize(app)
11
+ @app = app
12
+ end
13
+
14
+ def execute!
15
+ check_command_exists_for_remove
16
+
17
+ command.remove!
18
+ display_success_msg
19
+ end
20
+
21
+ private
22
+
23
+ def exists?
24
+ commands.find { |c| c.name == name }
25
+ end
26
+
27
+ def display_success_msg
28
+ puts "Successfully removed command '#{name}' from the current project!"
29
+ end
30
+
31
+ def check_command_exists_for_remove
32
+ raise PGit::Error::User.new "Cannot remove a command that does not exist in the current project. See `pgit cmd add --help` if you want to add a new command" unless exists?
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,32 @@
1
+ require 'forwardable'
2
+
3
+ module PGit
4
+ class Command
5
+ class Run
6
+ extend Forwardable
7
+ def_delegators :@app, :commands, :args, :global_opts, :opts, :current_project
8
+
9
+ def initialize(app)
10
+ @app = app
11
+ end
12
+
13
+ def execute!
14
+ error_message = "Command '#{search}' does not exist. Run 'pgit cmd show' to see the available custom commands."
15
+ raise PGit::Error::User, error_message unless command
16
+
17
+ command.execute
18
+ end
19
+
20
+ private
21
+
22
+ def search
23
+ raise PGit::Error::User, "Run expects a command_name argument." if args.empty?
24
+ args.first
25
+ end
26
+
27
+ def command
28
+ commands.find {|c| c.name == args.first}
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,53 @@
1
+ require 'delegate'
2
+ require 'rainbow'
3
+ require 'forwardable'
4
+
5
+ module PGit
6
+ class Command
7
+ class Show
8
+ extend Forwardable
9
+ def_delegators :@app, :commands, :args, :global_opts, :opts
10
+
11
+ def initialize(app)
12
+ @app = app
13
+ end
14
+
15
+ def execute!
16
+ error_message = "No commands are listed for this project. Run `pgit cmd add --help` for more info."
17
+ raise PGit::Error::User, error_message if commands.empty?
18
+
19
+ if search.empty?
20
+ show_all_of_current_project
21
+ else
22
+ show_one
23
+ end
24
+ end
25
+
26
+ def search
27
+ args.first || []
28
+ end
29
+
30
+ private
31
+
32
+ def show_all_of_current_project
33
+ puts "Listing custom commands of the current project..."
34
+ puts
35
+ commands.each { |c| puts c.to_s }
36
+ puts
37
+ end
38
+
39
+ def command
40
+ commands.find { |c| c.name == search }
41
+ end
42
+
43
+ def show_one
44
+ raise PGit::Error::User, "Command '#{search}' not found for this project" unless command
45
+
46
+ puts "Listing custom command '#{Rainbow(command.name).bright}' of the current project..."
47
+ puts
48
+ puts command.to_s
49
+ puts
50
+ end
51
+ end
52
+ end
53
+ end
@@ -25,12 +25,36 @@ module PGit
25
25
  }
26
26
  end
27
27
 
28
+ attr_reader :config_path, :yaml
29
+
28
30
  def initialize(config_path = '~/.pgit.rc.yml')
29
- @validator = PGit::Configuration::Validator.new(config_path)
31
+ @config_path = config_path
32
+ @expanded_path = File.expand_path(config_path)
33
+ @yaml = YAML::load_file(@expanded_path) || {}
34
+ @projs = @yaml.fetch("projects") { [] }
35
+ rescue Exception => e
36
+ if e.message.match(/No such file or directory/)
37
+ f = File.new(@expanded_path, 'w');
38
+ f.close
39
+ end
40
+ end
41
+
42
+ def projects=(new_projects)
43
+ @projs = new_projects.map {|p| p.to_hash}
44
+ end
45
+
46
+ def projects
47
+ @projs.map {|proj| PGit::Project.new(self, proj) }
48
+ end
49
+
50
+ def to_hash
51
+ { 'projects' => projects.map { |proj| proj.to_hash } }
30
52
  end
31
53
 
32
- def to_yaml
33
- @validator.yaml
54
+ def save!
55
+ file = File.new(@expanded_path, 'w')
56
+ YAML.dump(to_hash, file)
57
+ file.close
34
58
  end
35
59
  end
36
60
  end
@@ -1,56 +1,20 @@
1
- #
2
- # Decides what the "current project" is, in relation to the pwd.
3
- #
4
- # - config_yaml: has the project configurations. It has at least one
5
- # project. Each project has an (pivotal) api_token, path, and (pivotal)
6
- # id
7
- #
1
+ require 'pgit'
2
+ require 'forwardable'
8
3
 
9
4
  module PGit
10
5
  class CurrentProject
11
- def initialize(config_yaml)
12
- @current_project = find_current_project(config_yaml)
13
- end
14
-
15
- def pwd
16
- project_path = @current_project["path"]
17
- File.expand_path(project_path, __FILE__)
18
- end
19
-
20
- def id
21
- @current_project["id"]
22
- end
23
-
24
- def api_token
25
- @current_project["api_token"]
26
- end
27
-
28
- private
6
+ extend Forwardable
29
7
 
30
- def escape_slashes(project_path)
31
- project_path.gsub('/','\/')
8
+ PGit::Project.instance_methods(false).each do |m|
9
+ def_delegator :@current, m
32
10
  end
33
11
 
34
- def find_matching_projects(projects)
35
- projects.select do |project|
36
- project_path = project["path"]
37
- extended_path = File.expand_path(project_path, __FILE__)
38
- escaped_project = escape_slashes(extended_path)
39
- Dir.pwd.match(/#{escaped_project}/)
12
+ def initialize(configuration)
13
+ @current = configuration.projects.find do |p|
14
+ File.expand_path(p.path) == Dir.pwd
40
15
  end
41
- end
42
-
43
- def find_current_project(config_yaml)
44
- projects = config_yaml["projects"]
45
- matching_projects = find_matching_projects(projects)
46
-
47
- PGit::CurrentProject::Validator.new(matching_projects)
48
- find_best_match(matching_projects)
49
- end
50
16
 
51
- def find_best_match(matching_projects)
52
- matching_projects.sort! { |a,b| b["path"].length <=> a["path"].length }
53
- matching_projects.first
17
+ raise PGit::Error::User, "Current Project does not exist. See `pgit proj add -h`" unless @current
54
18
  end
55
19
  end
56
20
  end