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.
- checksums.yaml +4 -4
- data/.agignore +3 -0
- data/.travis.yml +1 -0
- data/README.markdown +32 -9
- data/Rakefile +12 -0
- data/bin/pgit +167 -25
- data/lib/pgit.rb +40 -10
- data/lib/pgit/bilateral/handle_back.rb +22 -0
- data/lib/pgit/bilateral/handle_choose_story.rb +31 -0
- data/lib/pgit/bilateral/story.rb +44 -0
- data/lib/pgit/command.rb +83 -0
- data/lib/pgit/command/add.rb +36 -0
- data/lib/pgit/command/application.rb +21 -0
- data/lib/pgit/command/edit.rb +36 -0
- data/lib/pgit/command/remove.rb +36 -0
- data/lib/pgit/command/run.rb +32 -0
- data/lib/pgit/command/show.rb +53 -0
- data/lib/pgit/configuration.rb +27 -3
- data/lib/pgit/current_project.rb +9 -45
- data/lib/pgit/current_project/validator.rb +2 -1
- data/lib/pgit/error/external.rb +11 -0
- data/lib/pgit/error/user.rb +12 -0
- data/lib/pgit/helpers/heredoc.rb +17 -0
- data/lib/pgit/helpers/query_methods.rb +63 -0
- data/lib/pgit/helpers/string_extensions.rb +29 -0
- data/lib/pgit/installer/bash_auto_completion.rb +57 -0
- data/lib/pgit/pivotal/collection_request.rb +21 -0
- data/lib/pgit/pivotal/individual_request.rb +47 -0
- data/lib/pgit/pivotal/iteration.rb +6 -0
- data/lib/pgit/pivotal/iterations.rb +15 -0
- data/lib/pgit/pivotal/project.rb +6 -0
- data/lib/pgit/pivotal/projects.rb +20 -0
- data/lib/pgit/pivotal/query.rb +8 -0
- data/lib/pgit/pivotal/request.rb +33 -0
- data/lib/pgit/pivotal/request/query.rb +25 -0
- data/lib/pgit/pivotal/story.rb +38 -0
- data/lib/pgit/pivotal_request_validator.rb +1 -1
- data/lib/pgit/project.rb +78 -0
- data/lib/pgit/project/add.rb +28 -0
- data/lib/pgit/project/application.rb +21 -0
- data/lib/pgit/project/interactive_adder.rb +41 -0
- data/lib/pgit/project/remove.rb +41 -0
- data/lib/pgit/project/reuse_api_token_adder.rb +48 -0
- data/lib/pgit/response_handler.rb +16 -0
- data/lib/pgit/root.rb +5 -0
- data/lib/pgit/status.rb +16 -0
- data/lib/pgit/story_branch/application.rb +3 -3
- data/lib/pgit/{name_parser.rb → story_branch/name_parser.rb} +0 -0
- data/lib/pgit/story_branch/story_id_parser.rb +11 -0
- data/lib/pgit/validators/project_validator.rb +20 -0
- data/lib/pgit/version.rb +1 -1
- data/lib/pivotal +0 -0
- data/pgit.gemspec +5 -0
- data/spec/fixtures/iterations +1 -0
- data/spec/pgit/bilateral/handle_back_spec.rb +29 -0
- data/spec/pgit/bilateral/handle_choose_story_spec.rb +17 -0
- data/spec/pgit/bilateral/story_spec.rb +178 -0
- data/spec/pgit/command/add_spec.rb +68 -0
- data/spec/pgit/command/application_spec.rb +110 -0
- data/spec/pgit/command/edit_spec.rb +61 -0
- data/spec/pgit/command/remove_spec.rb +76 -0
- data/spec/pgit/command/run_spec.rb +49 -0
- data/spec/pgit/command/show_spec.rb +95 -0
- data/spec/pgit/command_spec.rb +299 -0
- data/spec/pgit/configuration_spec.rb +121 -18
- data/spec/pgit/current_project/validator_spec.rb +2 -1
- data/spec/pgit/current_project_spec.rb +20 -71
- data/spec/pgit/{external_error_spec.rb → error/external_spec.rb} +3 -3
- data/spec/pgit/error/user_spec.rb +17 -0
- data/spec/pgit/helpers/heredoc_spec.rb +33 -0
- data/spec/pgit/helpers/query_methods_spec.rb +24 -0
- data/spec/pgit/helpers/string_extensions_spec.rb +49 -0
- data/spec/pgit/installer/bash_auto_completion_spec.rb +134 -0
- data/spec/pgit/pivotal/individual_request_spec.rb +32 -0
- data/spec/pgit/pivotal/iteration_spec.rb +19 -0
- data/spec/pgit/pivotal/iterations_spec.rb +37 -0
- data/spec/pgit/pivotal/project_spec.rb +9 -0
- data/spec/pgit/pivotal/projects_spec.rb +48 -0
- data/spec/pgit/pivotal/request/query_spec.rb +24 -0
- data/spec/pgit/pivotal/story_spec.rb +113 -0
- data/spec/pgit/pivotal_request_validator_spec.rb +3 -3
- data/spec/pgit/project/add_spec.rb +52 -0
- data/spec/pgit/project/application_spec.rb +69 -0
- data/spec/pgit/project/interactive_adder_spec.rb +45 -0
- data/spec/pgit/project/remove_spec.rb +86 -0
- data/spec/pgit/project/reuse_api_token_adder_spec.rb +41 -0
- data/spec/pgit/project_spec.rb +513 -0
- data/spec/pgit/status_spec.rb +40 -0
- data/spec/pgit/story_branch/application_spec.rb +5 -8
- data/spec/pgit/story_branch/name_parser_spec.rb +3 -3
- data/spec/pgit/story_branch/story_id_parser_spec.rb +17 -0
- data/spec/pgit/validators/project_validator_spec.rb +39 -0
- metadata +146 -21
- data/lib/pgit/configuration/layout_error.rb +0 -9
- data/lib/pgit/configuration/missing_attributes_error.rb +0 -10
- data/lib/pgit/configuration/not_found_error.rb +0 -10
- data/lib/pgit/configuration/project_missing_error.rb +0 -10
- data/lib/pgit/configuration/validator.rb +0 -41
- data/lib/pgit/current_project/no_paths_match_working_dir_error.rb +0 -10
- data/lib/pgit/external_error.rb +0 -9
- data/lib/pgit/installer/configuration.rb +0 -34
- data/lib/pgit/story.rb +0 -44
- data/spec/pgit/configuration/missing_attributes_error_spec.rb +0 -30
- data/spec/pgit/configuration/not_found_error_spec.rb +0 -17
- data/spec/pgit/configuration/project_missing_error_spec.rb +0 -30
- data/spec/pgit/configuration/validator_spec.rb +0 -79
- data/spec/pgit/current_project/no_paths_match_working_dir_error_spec.rb +0 -17
- data/spec/pgit/installer/configuration_spec.rb +0 -162
- 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
|
-
|
|
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,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,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,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,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
|