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
@@ -3,7 +3,8 @@ module PGit
3
3
  class Validator
4
4
  def initialize(matching_projects)
5
5
  if matching_projects.length == 0
6
- raise PGit::CurrentProject::NoPathsMatchWorkingDirError.new
6
+ message = "None of the project paths matches the working directory"
7
+ raise PGit::Error::User, message
7
8
  end
8
9
  end
9
10
  end
@@ -0,0 +1,11 @@
1
+ module PGit
2
+ class Error
3
+ class External < PGit::Error
4
+ def initialize(message)
5
+ @message = message
6
+
7
+ super @message
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,12 @@
1
+ module PGit
2
+ class Error
3
+ class User < PGit::Error
4
+ attr_reader :message
5
+
6
+ def initialize(message = nil)
7
+ @message = message
8
+ super(@message)
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,17 @@
1
+ module PGit
2
+ module Helpers
3
+ module Heredoc
4
+ def self.remove_front_spaces(string)
5
+ space_lengths = string.split("\n").select do |s|
6
+ s.match(/\S/)
7
+ end.map {|s| s.scan(/^\s*/).first.length }
8
+
9
+ min_length = space_lengths.inject(100) do |accum, value|
10
+ accum > value ? value : accum
11
+ end
12
+
13
+ string.gsub!(/^\s{#{min_length}}/, '')
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,63 @@
1
+ module PGit
2
+ module Helpers
3
+ module QueryMethods
4
+ def set_attr(attribute)
5
+ unless instance_variable_get("@#{attribute}")
6
+ instance_variable_set("@#{attribute}", @query_hash[attribute.to_s] || yield)
7
+ end
8
+ end
9
+
10
+ def not_given(attribute)
11
+ "no_#{attribute}_given".to_sym
12
+ end
13
+
14
+ def ensure_given_queries
15
+ given_attrs.each {|attr| ensure_given_attr(attr) }
16
+ end
17
+
18
+ def ensure_given_attr(attribute)
19
+ attr = send(attribute)
20
+ raise PGit::Error::User.new(attr.to_s) if attr == not_given(attribute)
21
+ end
22
+
23
+ def attr_query(*args)
24
+ attr_has(args)
25
+ attr_given(args)
26
+ end
27
+
28
+ def set_default_attr(attribute)
29
+ set_attr(attribute) { not_given(attribute) }
30
+ end
31
+
32
+ def set_default_queries
33
+ given_attrs.each {|attr| set_default_attr(attr) }
34
+ end
35
+
36
+ # attributes that have been set to default values
37
+ def defaulted_attrs
38
+ given_attrs.reject {|attr| send("given_#{attr}?")}
39
+ end
40
+
41
+ # attributes that have corresponding #given_attr? methods
42
+ def given_attrs
43
+ methods.grep(/^given_.+\?$/).map { |m| m.to_s.gsub(/^given_/, '').gsub(/\?$/, '')}
44
+ end
45
+
46
+ def attr_has(args)
47
+ args.each do |method_name|
48
+ define_method "has_#{method_name}?" do |val|
49
+ instance_variable_get("@#{method_name}") == val
50
+ end
51
+ end
52
+ end
53
+
54
+ def attr_given(args)
55
+ args.each do |item|
56
+ define_method "given_#{item}?" do
57
+ instance_variable_get("@#{item}") != not_given(item)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,29 @@
1
+ module PGit
2
+ module Helpers
3
+ module StringExtensions
4
+ def letter?(letter)
5
+ match(/^#{letter}$/i)
6
+ end
7
+
8
+ def index?
9
+ match(/^[1-9][0-9]*$/)
10
+ end
11
+
12
+ def yes?
13
+ letter?('y')
14
+ end
15
+
16
+ def no?
17
+ letter?('n')
18
+ end
19
+
20
+ def cancel?
21
+ letter?('c')
22
+ end
23
+ end
24
+ end
25
+ end
26
+
27
+ String.class_eval do
28
+ include PGit::Helpers::StringExtensions
29
+ end
@@ -0,0 +1,57 @@
1
+ module PGit
2
+ module Installer
3
+ class BashAutoCompletion
4
+ FILENAME = "~/.pgit_auto_completion"
5
+
6
+ def self.script
7
+ autocompletion = <<-AUTOCOMPLETION
8
+ function get_pgit_commands
9
+ {
10
+ if [ -z $2 ]; then
11
+ COMPREPLY=(`pgit help -c`)
12
+ else
13
+ COMPREPLY=(`pgit help -c $2`)
14
+ fi
15
+ }
16
+ complete -F get_pgit_commands pgit
17
+ AUTOCOMPLETION
18
+
19
+ PGit::Helpers::Heredoc.remove_front_spaces(autocompletion)
20
+ end
21
+
22
+ def initialize(global_opts, opts, args)
23
+ end
24
+
25
+ def write_completer_file
26
+ expanded_path = File.expand_path(FILENAME)
27
+ f = File.open(expanded_path, 'w')
28
+ f.puts PGit::Installer::BashAutoCompletion.script
29
+ f.close
30
+
31
+ puts "Wrote autocompletion script under #{FILENAME}"
32
+ end
33
+
34
+ def source_completer_from_bashrc
35
+ if already_sourced?
36
+ puts "Already sourcing #{FILENAME} in ~/.bashrc"
37
+ else
38
+ bashrc_expanded_path = File.expand_path("~/.bashrc")
39
+ b = File.open(bashrc_expanded_path, 'a')
40
+ b.puts "source #{FILENAME}"
41
+ b.close
42
+
43
+ puts "~/.bashrc will now source #{FILENAME}"
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ def already_sourced?
50
+ expanded_bashrc = File.expand_path("~/.bashrc")
51
+ lines = File.readlines(expanded_bashrc)
52
+ already_sourced = lines.any? {|line| line.match(/source #{FILENAME}/) }
53
+ end
54
+ end
55
+ end
56
+ end
57
+
@@ -0,0 +1,21 @@
1
+ module PGit
2
+ module Pivotal
3
+ class CollectionRequest < Pivotal::Request
4
+ def get!
5
+ hashes_of_items.map do |item_hash|
6
+ individual.new {|iter| iter.hash = item_hash}
7
+ end
8
+ end
9
+
10
+ private
11
+
12
+ def individual
13
+ self.class.to_s[0...-1].constantize
14
+ end
15
+
16
+ def hashes_of_items
17
+ JSON.parse(get_request)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,47 @@
1
+ module PGit
2
+ module Pivotal
3
+ class IndividualRequest < Pivotal::Request
4
+ def initialize(&block)
5
+ yield self if block_given?
6
+ end
7
+
8
+ def put!
9
+ `curl -X PUT -H 'X-TrackerToken: #{api_token}' -H 'Content-Type: application/json' -d '#{JSON.generate(to_hash)}' #{link}`
10
+ @changed_attributes = []
11
+ end
12
+
13
+ def get!
14
+ define_methods get_request
15
+ end
16
+
17
+ def define_methods(json)
18
+ JSON.parse(json).each do |key, value|
19
+ instance_variable_set("@#{key}", value)
20
+ end
21
+ end
22
+
23
+ def to_hash
24
+ @changed_attributes.inject(Hash.new) {|accum, key| accum[key] = send(key); accum }
25
+ end
26
+
27
+ def hash=(hash)
28
+ hash.each do |key, value|
29
+ if key == 'stories'
30
+ define_singleton_method key do
31
+ value.map do |story_hash|
32
+ PGit::Pivotal::Story.new do |s|
33
+ s.hash = story_hash
34
+ end
35
+ end
36
+ end
37
+ else
38
+ define_singleton_method key do
39
+ value
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+
@@ -0,0 +1,6 @@
1
+ module PGit
2
+ module Pivotal
3
+ class Iteration < Pivotal::IndividualRequest
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,15 @@
1
+ module PGit
2
+ module Pivotal
3
+ class Iterations < Pivotal::CollectionRequest
4
+ def initialize(query='')
5
+ # TODO: use better naming
6
+ before_initialize
7
+ @query = PGit::Pivotal::Request::Query.new(query)
8
+ end
9
+
10
+ def sublink
11
+ "projects/#{@project_id}/iterations/#{@query}"
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,6 @@
1
+ module PGit
2
+ module Pivotal
3
+ class Project < PGit::Pivotal::IndividualRequest
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,20 @@
1
+ require 'pgit'
2
+
3
+ module PGit
4
+ module Pivotal
5
+ class Projects < CollectionRequest
6
+ def initialize(*args, &block)
7
+ @api_token = args.first[:api_token] unless args.empty?
8
+ yield self if block_given?
9
+ end
10
+
11
+ def api_token
12
+ @api_token ? @api_token : super
13
+ end
14
+
15
+ def sublink
16
+ 'projects'
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,8 @@
1
+ module PGit
2
+ module Pivotal
3
+ class Request
4
+ class Query
5
+ end
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,33 @@
1
+ module PGit
2
+ module Pivotal
3
+ class Request
4
+ def before_initialize
5
+ @project_id = current_project.id
6
+ end
7
+
8
+ def api_version
9
+ "v5"
10
+ end
11
+
12
+ def get_request
13
+ `curl -X GET -H 'X-TrackerToken: #{api_token}' #{link}`
14
+ end
15
+
16
+ def link
17
+ "https://www.pivotaltracker.com/services/#{api_version}/#{sublink}"
18
+ end
19
+
20
+ def api_token
21
+ current_project.api_token
22
+ end
23
+
24
+ def current_project
25
+ PGit::CurrentProject.new(configuration)
26
+ end
27
+
28
+ def configuration
29
+ PGit::Configuration.new
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,25 @@
1
+ module PGit
2
+ module Pivotal
3
+ class Request
4
+ class Query
5
+ def initialize(args={})
6
+ @args = args
7
+ end
8
+
9
+ def to_s
10
+ query_with_extra_ampersand[0...query_with_extra_ampersand.length-1]
11
+ end
12
+
13
+ private
14
+
15
+ def query_with_extra_ampersand
16
+ hash_strings.inject("?") { |accum, item| accum + item }
17
+ end
18
+
19
+ def hash_strings
20
+ @args.map { |key, value| "#{key}=#{value}&" }
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,38 @@
1
+ require 'pgit'
2
+
3
+ module PGit
4
+ module Pivotal
5
+ class Story < PGit::Pivotal::IndividualRequest
6
+ ATTRIBUTES = :estimate, :id, :project_id, :follower_ids, :group, :name, :description,
7
+ :story_type, :current_state, :accepted_at, :deadline, :requested_by_id,
8
+ :owner_ids, :labels, :label_ids, :before_id, :after_id, :integration_id,
9
+ :external_id
10
+
11
+ attr_reader *ATTRIBUTES
12
+
13
+ ATTRIBUTES.each do |attr|
14
+ define_method "#{attr}=" do |value|
15
+ @changed_attributes ||= []
16
+ @changed_attributes << attr
17
+ instance_variable_set("@#{attr}", value)
18
+ end
19
+ end
20
+
21
+ def initialize(id=:no_story_id_given, &block)
22
+ before_initialize
23
+ @changed_attributes = []
24
+ @id = id
25
+ @follower_ids = []
26
+ yield self if block_given?
27
+ end
28
+
29
+ def sublink
30
+ "projects/#{@project_id}/stories/#{id}"
31
+ end
32
+
33
+ def attributes
34
+ ATTRIBUTES
35
+ end
36
+ end
37
+ end
38
+ end
@@ -12,7 +12,7 @@ module PGit
12
12
 
13
13
  def validate
14
14
  if kind_error? || no_kind?
15
- raise PGit::ExternalError.new(@request)
15
+ raise PGit::Error::External.new(@request)
16
16
  end
17
17
  end
18
18