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