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