pgit 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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