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
data/lib/pgit/project.rb
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require 'pgit'
|
|
2
|
+
|
|
3
|
+
module PGit
|
|
4
|
+
class Project < PGit::Pivotal::IndividualRequest
|
|
5
|
+
include ActiveModel::Validations
|
|
6
|
+
include PGit::Helpers::QueryMethods
|
|
7
|
+
extend PGit::Helpers::QueryMethods
|
|
8
|
+
|
|
9
|
+
validates_with PGit::Validators::ProjectValidator
|
|
10
|
+
|
|
11
|
+
attr_writer :api_token, :id, :path
|
|
12
|
+
attr_reader :path, :api_token, :id, :configuration, :kind
|
|
13
|
+
attr_query :id, :path, :api_token
|
|
14
|
+
|
|
15
|
+
def initialize(configuration=:no_config_given,
|
|
16
|
+
proj={},
|
|
17
|
+
&block)
|
|
18
|
+
yield self if block_given?
|
|
19
|
+
@query_hash = proj
|
|
20
|
+
@configuration = configuration
|
|
21
|
+
@cmds = proj.fetch('commands') { Array.new }
|
|
22
|
+
set_default_queries
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def commands=(some_commands)
|
|
26
|
+
@cmds = some_commands
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def commands
|
|
30
|
+
build_commands(@cmds)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def to_hash
|
|
34
|
+
{
|
|
35
|
+
"path" => path,
|
|
36
|
+
"api_token" => api_token,
|
|
37
|
+
"id" => id,
|
|
38
|
+
"commands" => commands.map {|cmd| cmd.to_hash}
|
|
39
|
+
}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def save!
|
|
43
|
+
ensure_given_queries
|
|
44
|
+
raise PGit::Error::User, errors.full_messages.first unless valid?
|
|
45
|
+
|
|
46
|
+
remove_old_copy { configuration.projects = configuration.projects << self }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def remove!
|
|
50
|
+
remove_old_copy
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def exists?
|
|
54
|
+
configuration.projects.find {|p| p.path == path}
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def sublink
|
|
58
|
+
"projects/#{id}"
|
|
59
|
+
end
|
|
60
|
+
private
|
|
61
|
+
|
|
62
|
+
def remove_old_copy
|
|
63
|
+
configuration.projects = configuration.projects.reject {|p| p.path == path}
|
|
64
|
+
yield if block_given?
|
|
65
|
+
configuration.save!
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def build_commands(cmds)
|
|
69
|
+
cmds.map do |cmd|
|
|
70
|
+
if cmd.respond_to?(:name) && cmd.respond_to?(:steps)
|
|
71
|
+
cmd
|
|
72
|
+
else
|
|
73
|
+
cmd.map { |k,v| PGit::Command.new(k, v, self) }.first
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require 'pgit'
|
|
2
|
+
|
|
3
|
+
#TODO: Find a way to make execute! just be a call on children tasks
|
|
4
|
+
module PGit
|
|
5
|
+
class Project
|
|
6
|
+
class Add
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
attr_reader :adder
|
|
10
|
+
def initialize(app)
|
|
11
|
+
@app = app
|
|
12
|
+
raise PGit::Error::User, 'Project path already exists. See `pgit proj update --help.`' if app.exists?
|
|
13
|
+
|
|
14
|
+
@reuse_adder = PGit::Project::ReuseApiTokenAdder.new(app.project, app.projects)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def execute!
|
|
18
|
+
@reuse_adder.execute!
|
|
19
|
+
@adder = PGit::Project::InteractiveAdder.new(@reuse_adder.project)
|
|
20
|
+
|
|
21
|
+
adder.execute!
|
|
22
|
+
adder.save!
|
|
23
|
+
|
|
24
|
+
puts "Successfully added the project!"
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require 'forwardable'
|
|
2
|
+
|
|
3
|
+
module PGit
|
|
4
|
+
class Project
|
|
5
|
+
class Application
|
|
6
|
+
extend Forwardable
|
|
7
|
+
def_delegators :@project, :exists?, :save!
|
|
8
|
+
def_delegators :@config, :projects
|
|
9
|
+
attr_reader :project
|
|
10
|
+
|
|
11
|
+
def initialize(global_opts, opts, args)
|
|
12
|
+
@config = PGit::Configuration.new
|
|
13
|
+
@project = PGit::Project.new(@config) do |p|
|
|
14
|
+
p.path = opts["path"]
|
|
15
|
+
p.api_token = opts["api_token"]
|
|
16
|
+
p.id = opts["id"]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'pgit'
|
|
2
|
+
require 'forwardable'
|
|
3
|
+
|
|
4
|
+
module PGit
|
|
5
|
+
class Project
|
|
6
|
+
class InteractiveAdder
|
|
7
|
+
extend Forwardable
|
|
8
|
+
|
|
9
|
+
def_delegators :@project, :save!
|
|
10
|
+
attr_reader :project
|
|
11
|
+
|
|
12
|
+
def initialize(project)
|
|
13
|
+
@project = project
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def execute!
|
|
17
|
+
if project.api_token == :no_api_token_given
|
|
18
|
+
puts "What's the project api_token?"
|
|
19
|
+
project.api_token = STDIN.gets.chomp
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
get_projects
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def get_projects
|
|
26
|
+
projects = PGit::Pivotal::Projects.new(api_token: project.api_token).get!
|
|
27
|
+
question = Interactive::Question.new do |q|
|
|
28
|
+
q.question = "Which project do you want to associate with the working directory?"
|
|
29
|
+
q.options = [projects]
|
|
30
|
+
q.columns = [:index, :name]
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
question.ask do |response|
|
|
34
|
+
if response.whole_number?
|
|
35
|
+
project.id = projects[response.to_i].id
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'interactive'
|
|
2
|
+
module PGit
|
|
3
|
+
class Project
|
|
4
|
+
class Remove
|
|
5
|
+
include Interactive
|
|
6
|
+
|
|
7
|
+
attr_reader :project, :projects
|
|
8
|
+
def initialize(app)
|
|
9
|
+
@project = app.project
|
|
10
|
+
@projects = app.projects
|
|
11
|
+
|
|
12
|
+
raise PGit::Error::User, "#{@project.path} is not in the configuration file." unless @project.exists?
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def execute!
|
|
16
|
+
confirm.ask_and_wait_for_valid_response do |confirm_response|
|
|
17
|
+
if confirm_response.yes?
|
|
18
|
+
puts "Removing #{path} from the configuration file..."
|
|
19
|
+
project.remove!
|
|
20
|
+
puts "Removed."
|
|
21
|
+
elsif confirm_response.no?
|
|
22
|
+
puts "Cancelling..."
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def confirm
|
|
30
|
+
Question.new do |c|
|
|
31
|
+
c.question = "Are you sure you want to remove #{path} from the configuration file?"
|
|
32
|
+
c.options = [:yes, :no]
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def path
|
|
37
|
+
@project.path
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'pgit'
|
|
2
|
+
|
|
3
|
+
module PGit
|
|
4
|
+
class Project
|
|
5
|
+
class ReuseApiTokenAdder
|
|
6
|
+
include Interactive
|
|
7
|
+
|
|
8
|
+
attr_reader :projects, :project
|
|
9
|
+
def initialize(project_to_add_to, projects_in_config)
|
|
10
|
+
@project = project_to_add_to
|
|
11
|
+
@projects = projects_in_config
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def execute!
|
|
15
|
+
return false if @projects.empty?
|
|
16
|
+
|
|
17
|
+
reuse_question.ask_and_wait_for_valid_response do |reuse_response|
|
|
18
|
+
if reuse_response.yes?
|
|
19
|
+
which_to_reuse_question.ask_and_wait_for_valid_response do |which_response|
|
|
20
|
+
if which_response.whole_number?
|
|
21
|
+
project.api_token = projects[which_response.to_i].api_token
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def reuse_question
|
|
31
|
+
Question.new do |q|
|
|
32
|
+
q.question = "Do you want to reuse an api token?"
|
|
33
|
+
q.options = [:yes, :no]
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def which_to_reuse_question
|
|
38
|
+
Question.new do |q|
|
|
39
|
+
q.question = "Which one?"
|
|
40
|
+
q.options = [projects.map do |proj|
|
|
41
|
+
OpenStruct.new(api_token: proj.api_token, path: proj.path)
|
|
42
|
+
end, :cancel]
|
|
43
|
+
q.columns = [:index, :api_token, :path]
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
module PGit
|
|
2
|
+
class ResponseHandler
|
|
3
|
+
attr_reader :question
|
|
4
|
+
def execute!
|
|
5
|
+
if response_can_be_handled?
|
|
6
|
+
@question.ask do |response|
|
|
7
|
+
@response_handlers.each {|handler| handler.new(options(response)).execute! }
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def response_can_be_handled?
|
|
13
|
+
true
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
data/lib/pgit/root.rb
ADDED
data/lib/pgit/status.rb
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
class PGit::Status
|
|
2
|
+
def initialize(global_options, options, args)
|
|
3
|
+
end
|
|
4
|
+
|
|
5
|
+
def execute!
|
|
6
|
+
current_branch = PGit::CurrentBranch.new
|
|
7
|
+
raise PGit::Error::User, 'The current branch is not associated with a story. Does not have a story id.' unless current_branch.story_id
|
|
8
|
+
story = PGit::Pivotal::Story.new(current_branch.story_id)
|
|
9
|
+
story_hash = story.get!
|
|
10
|
+
table = Terminal::Table.new do |t|
|
|
11
|
+
t.rows = story_hash.to_a
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
puts table
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -3,9 +3,9 @@ module PGit
|
|
|
3
3
|
class Application
|
|
4
4
|
def initialize(global_options, options, arguments)
|
|
5
5
|
if story_id = options[:start]
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
story = PGit::Pivotal::Story.new(story_id)
|
|
7
|
+
story.get!
|
|
8
|
+
|
|
9
9
|
name_parser = PGit::StoryBranch::NameParser.new(story)
|
|
10
10
|
story_branch = PGit::StoryBranch.new(name_parser)
|
|
11
11
|
|
|
File without changes
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
class PGit::StoryBranch::StoryIdParser
|
|
2
|
+
def initialize(branch_name)
|
|
3
|
+
@branch_name = branch_name
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
def parse
|
|
7
|
+
raise PGit::Error::User, "The current branch is not associated with a story. Does not have a story id." unless @branch_name.match(/\d+$/)
|
|
8
|
+
|
|
9
|
+
@branch_name.match(/\d+$/)[0]
|
|
10
|
+
end
|
|
11
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require 'pgit'
|
|
2
|
+
|
|
3
|
+
module PGit
|
|
4
|
+
module Validators
|
|
5
|
+
class ProjectValidator < ActiveModel::Validator
|
|
6
|
+
def validate(project)
|
|
7
|
+
project.get!
|
|
8
|
+
|
|
9
|
+
unless project.respond_to?(:kind)
|
|
10
|
+
project.errors[:curl] << "is not able to do the request. Please check your internet connection."
|
|
11
|
+
end
|
|
12
|
+
#
|
|
13
|
+
if project.respond_to?(:kind) && project.kind == 'error'
|
|
14
|
+
project.errors[:base] << "Project api_token or id is not valid."
|
|
15
|
+
puts project.errors.full_messages
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
data/lib/pgit/version.rb
CHANGED
data/lib/pivotal
ADDED
|
File without changes
|
data/pgit.gemspec
CHANGED
|
@@ -20,7 +20,12 @@ spec = Gem::Specification.new do |s|
|
|
|
20
20
|
s.add_development_dependency('rspec', '~> 3.1')
|
|
21
21
|
s.add_development_dependency('coveralls', '~> 0.7')
|
|
22
22
|
s.add_development_dependency('simplecov', '~> 0.9')
|
|
23
|
+
s.add_development_dependency('pry-byebug', '~> 3.0.1')
|
|
24
|
+
s.add_development_dependency('byebug', '~> 3.5.1')
|
|
23
25
|
s.add_runtime_dependency('gli','2.12.2')
|
|
26
|
+
s.add_runtime_dependency('activemodel','~> 4.2.0')
|
|
27
|
+
s.add_runtime_dependency('rainbow', '~> 2.0.0')
|
|
28
|
+
s.add_runtime_dependency('interactive', '~> 0.6.0')
|
|
24
29
|
s.license = 'MIT'
|
|
25
30
|
s.requirements << 'At least one project that uses Pivotal Tracker and Git'
|
|
26
31
|
s.requirements << 'cURL, at least 7.35.0'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
[{"kind":"iteration","number":15,"project_id":1228944,"team_strength":1,"stories":[{"kind":"story","id":90501214,"project_id":1228944,"name":"fix bug where calling project.get! defines methods on ALL projects. Use define_singleton_method.","story_type":"bug","current_state":"accepted","accepted_at":"2015-03-17T22:08:23Z","requested_by_id":1121520,"owned_by_id":1121520,"owner_ids":[1121520],"labels":[],"created_at":"2015-03-17T13:02:11Z","updated_at":"2015-03-17T22:12:28Z","url":"https://www.pivotaltracker.com/story/show/90501214"},{"kind":"story","id":90285028,"project_id":1228944,"name":"pgit proj asks if you want to reuse an api_token","description":"`Do you want to reuse an api_token? [y/n]`\n - y\n - `Which one? (1/2/c)\n - 1. /some/path: token\n - 2. /some/other/path: another_token\n ","story_type":"feature","current_state":"accepted","estimate":1,"accepted_at":"2015-03-18T01:11:47Z","requested_by_id":1121520,"owner_ids":[],"labels":[{"kind":"label","id":10378716,"project_id":1228944,"name":"project","created_at":"2015-01-05T11:42:35Z","updated_at":"2015-01-05T11:42:35Z"}],"created_at":"2015-03-13T14:29:42Z","updated_at":"2015-03-18T02:18:32Z","url":"https://www.pivotaltracker.com/story/show/90285028"},{"kind":"story","id":90566322,"project_id":1228944,"name":"pgit install no longer attempts to save an example config file in favor of using pgit proj add","story_type":"chore","current_state":"accepted","accepted_at":"2015-03-18T01:11:48Z","requested_by_id":1121520,"owned_by_id":1121520,"owner_ids":[1121520],"labels":[{"kind":"label","id":10378716,"project_id":1228944,"name":"project","created_at":"2015-01-05T11:42:35Z","updated_at":"2015-01-05T11:42:35Z"}],"created_at":"2015-03-18T01:07:29Z","updated_at":"2015-03-18T02:18:41Z","url":"https://www.pivotaltracker.com/story/show/90566322"},{"kind":"story","id":85418516,"project_id":1228944,"name":"pgit project rm","description":"Which project do you want to remove? [0/1/q]\n0 -- /Developer/blah\n1 -- /Developer/blah/blah\nq -- quit\n\nAre you sure you want to remove \"/Developer/blah\"? [y/c/q]\n\nIf user answers yes, proceed, \"Removing /Developer/blah as a PGit project.\"\nif user answers cancel, go back to first question\nIf user answers quit, then say you're quitting and quit.","story_type":"feature","current_state":"accepted","estimate":1,"accepted_at":"2015-03-20T00:22:35Z","requested_by_id":1121520,"owned_by_id":1121520,"owner_ids":[1121520],"labels":[{"kind":"label","id":10378716,"project_id":1228944,"name":"project","created_at":"2015-01-05T11:42:35Z","updated_at":"2015-01-05T11:42:35Z"}],"created_at":"2015-01-05T11:26:32Z","updated_at":"2015-03-20T00:22:34Z","url":"https://www.pivotaltracker.com/story/show/85418516"},{"kind":"story","id":90748872,"project_id":1228944,"name":"pgit story should display list of stories for the current and backlog iterations.","description":"`pgit story`, by default, will display a list of stories for the current iteration. It will ask, which story are you interested in? [0/1/2/3/4/5/c]\n 0 -- [feature-type] [points] [title] [assignment]\n 1 -- [feature-type] [points] [title] [assignment]\nIt should display information about the story, color coded.\n\n\n","story_type":"feature","current_state":"started","estimate":2,"requested_by_id":1121520,"owned_by_id":1121520,"owner_ids":[1121520],"labels":[{"kind":"label","id":10420512,"project_id":1228944,"name":"story","created_at":"2015-01-08T12:25:39Z","updated_at":"2015-01-08T12:25:39Z"}],"created_at":"2015-03-20T00:56:29Z","updated_at":"2015-03-22T12:35:20Z","url":"https://www.pivotaltracker.com/story/show/90748872"}],"start":"2015-03-16T04:00:00Z","finish":"2015-03-23T04:00:00Z"},{"kind":"iteration","number":16,"project_id":1228944,"team_strength":1,"stories":[],"start":"2015-03-23T04:00:00Z","finish":"2015-03-30T04:00:00Z"},{"kind":"iteration","number":17,"project_id":1228944,"team_strength":1,"stories":[{"kind":"story","id":90833342,"project_id":1228944,"name":"make getting project ids easier when adding a project","description":"```{\"kind\":\"me\",\"id\":1121520,\"name\":\"Edderic\",\"initials\":\"ED\",\"username\":\"edderic\",\"time_zone\":{\"kind\":\"time_zone\",\"olson_name\":\"America/Los_Angeles\",\"offset\":\"-07:00\"},\"api_token\":\"302ebab4f92dcc77dbee9d18bf09e576\",\"has_google_identity\":true,\"projects\":[{\"kind\":\"membership_summary\",\"id\":3492008,\"project_id\":915432,\"project_name\":\"ideabind\",\"project_color\":\"155f8b\",\"role\":\"owner\",\"last_viewed_at\":\"2015-02-10T01:26:35Z\"},{\"kind\":\"membership_summary\",\"id\":3570108,\"project_id\":932970,\"project_name\":\"palace\",\"project_color\":\"ee61f0\",\"role\":\"owner\",\"last_viewed_at\":\"2013-12-04T19:48:46Z\"},{\"kind\":\"membership_summary\",\"id\":3593330,\"project_id\":938010,\"project_name\":\"Ojibss\",\"project_color\":\"b800bb\",\"role\":\"owner\",\"last_viewed_at\":\"2013-10-28T15:25:44Z\"},{\"kind\":\"membership_summary\",\"id\":3662734,\"project_id\":953934,\"project_name\":\"QuidPlays\",\"project_color\":\"00a3d6\",\"role\":\"owner\",\"last_viewed_at\":\"2013-11-11T10:14:36Z\"},{\"kind\":\"membership_summary\",\"id\":3699234,\"project_id\":961764,\"project_name\":\"Granuvolver\",\"project_color\":\"d82b00\",\"role\":\"owner\",\"last_viewed_at\":\"2014-01-15T19:37:38Z\"},{\"kind\":\"membership_summary\",\"id\":3801016,\"project_id\":985420,\"project_name\":\"Adjust Brightness Script\",\"project_color\":\"ffc100\",\"role\":\"owner\",\"last_viewed_at\":\"2014-01-05T02:54:46Z\"},{\"kind\":\"membership_summary\",\"id\":4064208,\"project_id\":1041282,\"project_name\":\"Training\",\"project_color\":\"818182\",\"role\":\"owner\",\"last_viewed_at\":\"2014-03-20T00:57:48Z\"},{\"kind\":\"membership_summary\",\"id\":4434754,\"project_id\":1120660,\"project_name\":\"Cooking Assistant\",\"project_color\":\"e46642\",\"role\":\"owner\",\"last_viewed_at\":\"2014-11-13T00:34:00Z\"},{\"kind\":\"membership_summary\",\"id\":4948554,\"project_id\":1228944,\"project_name\":\"PGit\",\"project_color\":\"8100ea\",\"role\":\"owner\",\"last_viewed_at\":\"2015-03-21T14:25:10Z\"},{\"kind\":\"membership_summary\",\"id\":5271772,\"project_id\":1300676,\"project_name\":\"Interactive\",\"project_color\":\"555555\",\"role\":\"owner\",\"last_viewed_at\":\"2015-03-21T13:15:55Z\"}],\"email\":\"edderic@gmail.com\",\"receives_in_app_notifications\":true,\"created_at\":\"2013-09-18T19:08:50Z\",\"updated_at\":\"2015-03-21T15:04:26Z\"}```","story_type":"feature","current_state":"unstarted","estimate":2,"requested_by_id":1121520,"owner_ids":[],"labels":[{"kind":"label","id":10378716,"project_id":1228944,"name":"project","created_at":"2015-01-05T11:42:35Z","updated_at":"2015-01-05T11:42:35Z"}],"created_at":"2015-03-21T15:34:55Z","updated_at":"2015-03-21T15:42:18Z","url":"https://www.pivotaltracker.com/story/show/90833342"}],"start":"2015-03-30T04:00:00Z","finish":"2015-04-06T04:00:00Z"},{"kind":"iteration","number":18,"project_id":1228944,"team_strength":1,"stories":[{"kind":"story","id":86168300,"project_id":1228944,"name":"pgit project mv --src=source_path --dest=destination_path","story_type":"feature","current_state":"unstarted","estimate":1,"requested_by_id":1121520,"owner_ids":[],"labels":[{"kind":"label","id":10378716,"project_id":1228944,"name":"project","created_at":"2015-01-05T11:42:35Z","updated_at":"2015-01-05T11:42:35Z"}],"created_at":"2015-01-15T00:18:57Z","updated_at":"2015-01-15T00:24:26Z","url":"https://www.pivotaltracker.com/story/show/86168300"}],"start":"2015-04-06T04:00:00Z","finish":"2015-04-13T04:00:00Z"},{"kind":"iteration","number":19,"project_id":1228944,"team_strength":1,"stories":[{"kind":"story","id":86169384,"project_id":1228944,"name":"pgit project show","story_type":"feature","current_state":"unstarted","estimate":1,"requested_by_id":1121520,"owner_ids":[],"labels":[],"created_at":"2015-01-15T00:29:39Z","updated_at":"2015-01-15T00:30:39Z","url":"https://www.pivotaltracker.com/story/show/86169384"},{"kind":"story","id":86366000,"project_id":1228944,"name":"Move models into their own folder","story_type":"chore","current_state":"unstarted","requested_by_id":1121520,"owner_ids":[],"labels":[],"created_at":"2015-01-17T14:11:49Z","updated_at":"2015-02-01T22:57:23Z","url":"https://www.pivotaltracker.com/story/show/86366000"},{"kind":"story","id":86365990,"project_id":1228944,"name":"Move Command-Line classes to their own folder","story_type":"chore","current_state":"unstarted","requested_by_id":1121520,"owner_ids":[],"labels":[],"created_at":"2015-01-17T14:10:57Z","updated_at":"2015-02-01T22:57:25Z","url":"https://www.pivotaltracker.com/story/show/86365990"}],"start":"2015-04-13T04:00:00Z","finish":"2015-04-20T04:00:00Z"}]
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe PGit::Bilateral::HandleBack do
|
|
4
|
+
describe '#execute!' do
|
|
5
|
+
it 'should call #reask on the parent_question' do
|
|
6
|
+
stories = double('stories')
|
|
7
|
+
question = instance_double('Interactive::Question', reask!: nil)
|
|
8
|
+
response = instance_double('Interactive::Response', back?: true)
|
|
9
|
+
options = {response: response, parent_question: question, stories: stories}
|
|
10
|
+
|
|
11
|
+
back_handler = PGit::Bilateral::HandleBack.new(options)
|
|
12
|
+
back_handler.execute!
|
|
13
|
+
|
|
14
|
+
expect(question).to have_received(:reask!)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it 'should not call #reask on the parent question if response is not back' do
|
|
18
|
+
stories = double('stories')
|
|
19
|
+
question = instance_double('Interactive::Question', reask!: nil)
|
|
20
|
+
response = instance_double('Interactive::Response', back?: false)
|
|
21
|
+
options = {response: response, parent_question: question, stories: stories}
|
|
22
|
+
|
|
23
|
+
back_handler = PGit::Bilateral::HandleBack.new(options)
|
|
24
|
+
back_handler.execute!
|
|
25
|
+
|
|
26
|
+
expect(question).not_to have_received(:reask!)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe PGit::Bilateral::HandleChooseStory do
|
|
4
|
+
it 'should create the branch' do
|
|
5
|
+
some_story = double('PGit::Story')
|
|
6
|
+
chosen_story = double('PGit::Story')
|
|
7
|
+
options = {response: '1', stories: [some_story, chosen_story]}
|
|
8
|
+
story_branch = double('PGit::StoryBranch', start: true)
|
|
9
|
+
|
|
10
|
+
name_parser = double('PGit::StoryBranch::NameParser')
|
|
11
|
+
allow(PGit::StoryBranch::NameParser).to receive(:new).with(chosen_story).and_return(name_parser)
|
|
12
|
+
allow(PGit::StoryBranch).to receive(:new).with(name_parser).and_return(story_branch)
|
|
13
|
+
handle_choose_story = PGit::Bilateral::HandleChooseStory.new(options)
|
|
14
|
+
|
|
15
|
+
expect(story_branch).to have_received(:start)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe PGit::Bilateral::Story do
|
|
4
|
+
describe 'scope is bad scope' do
|
|
5
|
+
it 'should raise an error' do
|
|
6
|
+
project = instance_double('PGit::Project', id: 12345, api_token: 'someapitoken')
|
|
7
|
+
options = { scope: 'blah' }
|
|
8
|
+
query = {scope: :current}
|
|
9
|
+
story_1 = instance_double('PGit::Story',
|
|
10
|
+
story_type: 'chore',
|
|
11
|
+
estimate: 2,
|
|
12
|
+
name: 'some story',
|
|
13
|
+
current_state: 'unstarted')
|
|
14
|
+
story_2 = instance_double('PGit::Story',
|
|
15
|
+
story_type: 'feature',
|
|
16
|
+
estimate: 3,
|
|
17
|
+
name: 'some other story',
|
|
18
|
+
current_state: 'unstarted')
|
|
19
|
+
stories = [story_1, story_2]
|
|
20
|
+
iteration_1 = double('PGit::Pivotal::Iteration', stories: stories)
|
|
21
|
+
iterations = [iteration_1]
|
|
22
|
+
iterations_obj = double('PGit::Pivotal::Iterations', get!: iterations)
|
|
23
|
+
allow(PGit::Pivotal::Iterations).
|
|
24
|
+
to receive(:new).with(query).and_return(iterations_obj)
|
|
25
|
+
config = double('config', :question= => nil, :options= => nil, :columns= => nil)
|
|
26
|
+
question = instance_double('Interactive::Question', ask: nil)
|
|
27
|
+
allow(Interactive::Question).to receive(:new).and_yield(config).and_return(question)
|
|
28
|
+
expect{ PGit::Bilateral::Story.new(options) }.to raise_error(PGit::Error::User, 'Invalid options. See `pgit iteration -h` for valid options.')
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
describe '#execute!' do
|
|
33
|
+
describe 'scope is done' do
|
|
34
|
+
it 'should show the done ones' do
|
|
35
|
+
project = instance_double('PGit::Project', id: 12345, api_token: 'someapitoken')
|
|
36
|
+
options = { scope: :done }
|
|
37
|
+
query = {scope: :done}
|
|
38
|
+
story_1 = instance_double('PGit::Story',
|
|
39
|
+
story_type: 'chore',
|
|
40
|
+
estimate: 2,
|
|
41
|
+
name: 'some story',
|
|
42
|
+
current_state: 'accepted')
|
|
43
|
+
story_2 = instance_double('PGit::Story',
|
|
44
|
+
story_type: 'feature',
|
|
45
|
+
estimate: 3,
|
|
46
|
+
name: 'some other story',
|
|
47
|
+
current_state: 'accepted')
|
|
48
|
+
stories = [story_1, story_2]
|
|
49
|
+
iteration_1 = double('PGit::Pivotal::Iteration', stories: stories)
|
|
50
|
+
iterations = [iteration_1]
|
|
51
|
+
iterations_obj = double('PGit::Pivotal::Iterations', get!: iterations)
|
|
52
|
+
allow(PGit::Pivotal::Iterations).
|
|
53
|
+
to receive(:new).with(query).and_return(iterations_obj)
|
|
54
|
+
config = double('config', :question= => nil, :options= => nil, :columns= => nil)
|
|
55
|
+
question = instance_double('Interactive::Question', ask: nil)
|
|
56
|
+
allow(Interactive::Question).to receive(:new).and_yield(config).and_return(question)
|
|
57
|
+
interactive_story = PGit::Bilateral::Story.new(options)
|
|
58
|
+
interactive_story.execute!
|
|
59
|
+
|
|
60
|
+
expect(config).to have_received(:question=).with("Which story do you want to branch-ify?")
|
|
61
|
+
expect(config).to have_received(:options=).with([stories, :back])
|
|
62
|
+
expect(config).to have_received(:columns=).with([:index, :story_type, :estimate, :name, :current_state])
|
|
63
|
+
expect(question).to have_received(:ask)
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
describe 'scope is backlog' do
|
|
68
|
+
it 'should show the backlog stories' do
|
|
69
|
+
project = instance_double('PGit::Project', id: 12345, api_token: 'someapitoken')
|
|
70
|
+
options = { scope: :backlog }
|
|
71
|
+
query = {scope: :backlog}
|
|
72
|
+
story_1 = instance_double('PGit::Story',
|
|
73
|
+
story_type: 'chore',
|
|
74
|
+
estimate: 2,
|
|
75
|
+
name: 'some story',
|
|
76
|
+
current_state: 'unstarted')
|
|
77
|
+
story_2 = instance_double('PGit::Story',
|
|
78
|
+
story_type: 'feature',
|
|
79
|
+
estimate: 3,
|
|
80
|
+
name: 'some other story',
|
|
81
|
+
current_state: 'unstarted')
|
|
82
|
+
stories = [story_1, story_2]
|
|
83
|
+
iteration_1 = double('PGit::Pivotal::Iteration', stories: stories)
|
|
84
|
+
iterations = [iteration_1]
|
|
85
|
+
iterations_obj = double('PGit::Pivotal::Iterations', get!: iterations)
|
|
86
|
+
allow(PGit::Pivotal::Iterations).
|
|
87
|
+
to receive(:new).with(query).and_return(iterations_obj)
|
|
88
|
+
config = double('config', :question= => nil, :options= => nil, :columns= => nil)
|
|
89
|
+
question = instance_double('Interactive::Question', ask: nil)
|
|
90
|
+
response = instance_double('Interactive::Response', valid?: true)
|
|
91
|
+
allow(question).to receive(:ask).and_yield(response)
|
|
92
|
+
allow(Interactive::Question).to receive(:new).and_yield(config).and_return(question)
|
|
93
|
+
handle_choose_story = instance_double('PGit::Bilateral::HandleChooseStory',
|
|
94
|
+
execute!: nil)
|
|
95
|
+
interactive_story = PGit::Bilateral::Story.new(options)
|
|
96
|
+
response_options = {response: response, stories: stories, parent_question: interactive_story.question}
|
|
97
|
+
allow(PGit::Bilateral::HandleChooseStory).to receive(:new).with(response_options).
|
|
98
|
+
and_return(handle_choose_story)
|
|
99
|
+
interactive_story.execute!
|
|
100
|
+
|
|
101
|
+
expect(config).to have_received(:question=).with("Which story do you want to branch-ify?")
|
|
102
|
+
expect(config).to have_received(:options=).with([stories, :back])
|
|
103
|
+
expect(config).to have_received(:columns=).with([:index, :story_type, :estimate, :name, :current_state])
|
|
104
|
+
expect(question).to have_received(:ask)
|
|
105
|
+
expect(handle_choose_story).to have_received(:execute!)
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe 'scope is current' do
|
|
110
|
+
it 'should show a list of stories for the current iteration' do
|
|
111
|
+
project = instance_double('PGit::Project', id: 12345, api_token: 'someapitoken')
|
|
112
|
+
options = { scope: :current }
|
|
113
|
+
query = {scope: :current}
|
|
114
|
+
story_1 = instance_double('PGit::Story',
|
|
115
|
+
story_type: 'chore',
|
|
116
|
+
estimate: 2,
|
|
117
|
+
name: 'some story',
|
|
118
|
+
current_state: 'unstarted')
|
|
119
|
+
story_2 = instance_double('PGit::Story',
|
|
120
|
+
story_type: 'feature',
|
|
121
|
+
estimate: 3,
|
|
122
|
+
name: 'some other story',
|
|
123
|
+
current_state: 'unstarted')
|
|
124
|
+
stories = [story_1, story_2]
|
|
125
|
+
iteration_1 = double('PGit::Pivotal::Iteration', stories: stories)
|
|
126
|
+
iterations = [iteration_1]
|
|
127
|
+
iterations_obj = double('PGit::Pivotal::Iterations', get!: iterations)
|
|
128
|
+
allow(PGit::Pivotal::Iterations).
|
|
129
|
+
to receive(:new).with(query).and_return(iterations_obj)
|
|
130
|
+
config = double('config', :question= => nil, :options= => nil, :columns= => nil)
|
|
131
|
+
question = instance_double('Interactive::Question', ask: nil)
|
|
132
|
+
allow(Interactive::Question).to receive(:new).and_yield(config).and_return(question)
|
|
133
|
+
interactive_story = PGit::Bilateral::Story.new(options)
|
|
134
|
+
interactive_story.execute!
|
|
135
|
+
|
|
136
|
+
expect(config).to have_received(:question=).with("Which story do you want to branch-ify?")
|
|
137
|
+
expect(config).to have_received(:options=).with([stories, :back])
|
|
138
|
+
expect(config).to have_received(:columns=).with([:index, :story_type, :estimate, :name, :current_state])
|
|
139
|
+
expect(question).to have_received(:ask)
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
describe 'scope is current_backlog' do
|
|
144
|
+
it 'show a list of stories for the current and backlog iteration' do
|
|
145
|
+
project = instance_double('PGit::Project', id: 12345, api_token: 'someapitoken')
|
|
146
|
+
|
|
147
|
+
options = { scope: :current_backlog }
|
|
148
|
+
query = {scope: :current_backlog}
|
|
149
|
+
story_1 = instance_double('PGit::Story',
|
|
150
|
+
story_type: 'chore',
|
|
151
|
+
estimate: 2,
|
|
152
|
+
name: 'some story',
|
|
153
|
+
current_state: 'unstarted')
|
|
154
|
+
story_2 = instance_double('PGit::Story',
|
|
155
|
+
story_type: 'feature',
|
|
156
|
+
estimate: 3,
|
|
157
|
+
name: 'some other story',
|
|
158
|
+
current_state: 'unstarted')
|
|
159
|
+
stories = [story_1, story_2]
|
|
160
|
+
iteration_1 = double('PGit::Pivotal::Iteration', stories: stories)
|
|
161
|
+
iterations = [iteration_1]
|
|
162
|
+
iterations_obj = double('PGit::Pivotal::Iterations', get!: iterations)
|
|
163
|
+
allow(PGit::Pivotal::Iterations).
|
|
164
|
+
to receive(:new).with(query).and_return(iterations_obj)
|
|
165
|
+
config = double('config', :question= => nil, :options= => nil, :columns= => nil)
|
|
166
|
+
question = instance_double('Interactive::Question', ask: nil)
|
|
167
|
+
allow(Interactive::Question).to receive(:new).and_yield(config).and_return(question)
|
|
168
|
+
interactive_story = PGit::Bilateral::Story.new(options)
|
|
169
|
+
interactive_story.execute!
|
|
170
|
+
|
|
171
|
+
expect(config).to have_received(:question=).with("Which story do you want to branch-ify?")
|
|
172
|
+
expect(config).to have_received(:options=).with([stories, :back])
|
|
173
|
+
expect(config).to have_received(:columns=).with([:index, :story_type, :estimate, :name, :current_state])
|
|
174
|
+
expect(question).to have_received(:ask)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
end
|
|
178
|
+
end
|