git-pivotal-tracker-centro 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. data/.gitignore +6 -0
  2. data/.rspec +2 -0
  3. data/.rvmrc +1 -0
  4. data/.travis.yml +3 -0
  5. data/CHANGELOG +54 -0
  6. data/Gemfile +3 -0
  7. data/Gemfile.lock +82 -0
  8. data/LICENSE +21 -0
  9. data/Rakefile +49 -0
  10. data/VERSION +1 -0
  11. data/bin/git-finish +7 -0
  12. data/bin/git-info +7 -0
  13. data/bin/git-start +8 -0
  14. data/features/finish.feature +88 -0
  15. data/features/info.feature +99 -0
  16. data/features/start.feature +113 -0
  17. data/features/step_definitions/steps.rb +119 -0
  18. data/features/support/dsl/assertions.rb +11 -0
  19. data/features/support/dsl/data.rb +11 -0
  20. data/features/support/dsl/pivotal.rb +77 -0
  21. data/features/support/env.rb +6 -0
  22. data/features/support/git-pivotal.rb +68 -0
  23. data/features/test_repo/origin.git/COMMIT_EDITMSG +1 -0
  24. data/features/test_repo/origin.git/HEAD +1 -0
  25. data/features/test_repo/origin.git/config +8 -0
  26. data/features/test_repo/origin.git/description +1 -0
  27. data/features/test_repo/origin.git/hooks/applypatch-msg.sample +15 -0
  28. data/features/test_repo/origin.git/hooks/commit-msg.sample +24 -0
  29. data/features/test_repo/origin.git/hooks/post-commit.sample +8 -0
  30. data/features/test_repo/origin.git/hooks/post-receive.sample +15 -0
  31. data/features/test_repo/origin.git/hooks/post-update.sample +8 -0
  32. data/features/test_repo/origin.git/hooks/pre-applypatch.sample +14 -0
  33. data/features/test_repo/origin.git/hooks/pre-commit.sample +46 -0
  34. data/features/test_repo/origin.git/hooks/pre-rebase.sample +169 -0
  35. data/features/test_repo/origin.git/hooks/prepare-commit-msg.sample +36 -0
  36. data/features/test_repo/origin.git/hooks/update.sample +128 -0
  37. data/features/test_repo/origin.git/index +0 -0
  38. data/features/test_repo/origin.git/info/exclude +6 -0
  39. data/features/test_repo/origin.git/logs/HEAD +1 -0
  40. data/features/test_repo/origin.git/logs/refs/heads/master +1 -0
  41. data/features/test_repo/origin.git/objects/0c/6f7b1384910d1a2f137590095f008a06c7e00c +0 -0
  42. data/features/test_repo/origin.git/objects/10/ecf2b7ce989f01f3f7266e712b48d9275f2635 +0 -0
  43. data/features/test_repo/origin.git/objects/a5/71d56305df09fb060f6ccb730b46080d305beb +0 -0
  44. data/features/test_repo/origin.git/refs/heads/master +1 -0
  45. data/features/test_repo/readme +1 -0
  46. data/git-pivotal-tracker-centro.gemspec +29 -0
  47. data/lib/commands/base.rb +120 -0
  48. data/lib/commands/bug.rb +19 -0
  49. data/lib/commands/card.rb +32 -0
  50. data/lib/commands/chore.rb +19 -0
  51. data/lib/commands/feature.rb +19 -0
  52. data/lib/commands/finish.rb +67 -0
  53. data/lib/commands/info.rb +58 -0
  54. data/lib/commands/map.rb +10 -0
  55. data/lib/commands/pick.rb +94 -0
  56. data/lib/commands/start.rb +39 -0
  57. data/lib/git-pivotal-tracker.rb +11 -0
  58. data/readme.markdown +106 -0
  59. data/spec/commands/base_spec.rb +137 -0
  60. data/spec/commands/bug_spec.rb +24 -0
  61. data/spec/commands/chore_spec.rb +24 -0
  62. data/spec/commands/feature_spec.rb +24 -0
  63. data/spec/commands/finish_spec.rb +134 -0
  64. data/spec/commands/map_spec.rb +14 -0
  65. data/spec/commands/start_spec.rb +28 -0
  66. data/spec/factories.rb +13 -0
  67. data/spec/factory.rb +26 -0
  68. data/spec/spec_helper.rb +24 -0
  69. metadata +291 -0
@@ -0,0 +1,137 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands::Base do
4
+
5
+ before(:each) do
6
+ @input = mock('input')
7
+ @output = mock('output')
8
+
9
+ # stub out git config requests
10
+ Commands::Base.any_instance.stubs(:get).with { |v| v =~ /git config/ }.returns("")
11
+ end
12
+
13
+ it "should set the api key with the -k option" do
14
+ @pick = Commands::Base.new("-k", "1234").with(@input, @output)
15
+ @pick.options[:api_token].should == "1234"
16
+ end
17
+
18
+ it "should set the api key with the --api-token= option" do
19
+ @pick = Commands::Base.new("--api-key=1234").with(@input, @output)
20
+ @pick.options[:api_token].should == "1234"
21
+ end
22
+
23
+ it "should set the project id with the -p option" do
24
+ @pick = Commands::Base.new("-p", "1").with(@input, @output)
25
+ @pick.options[:project_id].should == "1"
26
+ end
27
+
28
+ it "should set the project id with the --project-id= option" do
29
+ @pick = Commands::Base.new("--project-id=1").with(@input, @output)
30
+ @pick.options[:project_id].should == "1"
31
+ end
32
+
33
+ it "should set the full name with the -n option" do
34
+ @pick = Commands::Base.new("-n", "Jeff Tucker").with(@input, @output)
35
+ @pick.options[:full_name].should == "Jeff Tucker"
36
+ end
37
+
38
+ it "should set the full name with the --full-name= option" do
39
+ @pick = Commands::Base.new(@input, @output,"--full-name=Jeff Tucker")
40
+ @pick.options[:full_name].should == "Jeff Tucker"
41
+ end
42
+
43
+ it "should set the quiet flag with the -q option" do
44
+ @pick = Commands::Base.new("-q").with(@input, @output)
45
+ @pick.options[:quiet].should be_true
46
+ end
47
+
48
+ it "should set the quiet flag with the --quiet option" do
49
+ @pick = Commands::Base.new("--quiet").with(@input, @output)
50
+ @pick.options[:quiet].should be_true
51
+ end
52
+
53
+ it "should set the force flag with the -f option" do
54
+ @pick = Commands::Base.new("-f").with(@input, @output)
55
+ @pick.options[:force].should be_true
56
+ end
57
+
58
+ it "should set the force flag with the --force option" do
59
+ @pick = Commands::Base.new("--force").with(@input, @output)
60
+ @pick.options[:force].should be_true
61
+ end
62
+
63
+ it "should set the verbose flag with the -v option" do
64
+ @pick = Commands::Base.new("-v").with(@input, @output)
65
+ @pick.options[:verbose].should be_true
66
+ end
67
+
68
+ it "should set the verbose flag with the --verbose option" do
69
+ @pick = Commands::Base.new("--verbose").with(@input, @output)
70
+ @pick.options[:verbose].should be_true
71
+ end
72
+
73
+ it "should unset the verbose flag with the --no-verbose option" do
74
+ @pick = Commands::Base.new("--no-verbose").with(@input, @output)
75
+ @pick.options[:verbose].should be_false
76
+ end
77
+
78
+ it "should respect verbose from git config if it's set true (case insensitive)" do
79
+ Commands::Base.any_instance.stubs(:get).with("git config --get pivotal.verbose").returns("truE")
80
+ @pick = Commands::Base.new
81
+ @pick.options[:verbose].should be_true
82
+ end
83
+
84
+ it "should respect verbose from git config if it's set true (case insensitive)" do
85
+ Commands::Base.any_instance.stubs(:get).with("git config --get pivotal.verbose").returns("falSe")
86
+ @pick = Commands::Base.new
87
+ @pick.options[:verbose].should be_false
88
+ end
89
+
90
+ it "should be verbose by default" do
91
+ Commands::Base.any_instance.stubs(:get).with("git config --get pivotal.verbose").returns("")
92
+ @pick = Commands::Base.new
93
+ @pick.options[:verbose].should be_true
94
+ end
95
+
96
+ it "should print a message if the API token is missing" do
97
+ @output.expects(:print).with("Pivotal Tracker API Token and Project ID are required\n")
98
+
99
+ @pick = Commands::Base.new("-p", "1").with(@input, @output)
100
+ @pick.run!
101
+ end
102
+
103
+ it "should print a message if the project ID is missing" do
104
+ @output.expects(:print).with("Pivotal Tracker API Token and Project ID are required\n")
105
+
106
+ @pick = Commands::Base.new("-k", "1").with(@input, @output)
107
+ @pick.run!
108
+ end
109
+
110
+ it "should set use_ssl to true with --use-ssl" do
111
+ @pick = Commands::Base.new("--use-ssl").with(@input, @output)
112
+ @pick.options[:use_ssl].should be_true
113
+ end
114
+
115
+ it "should set use_ssl to true with -S" do
116
+ @pick = Commands::Base.new("-S").with(@input, @output)
117
+ @pick.options[:use_ssl].should be_true
118
+ end
119
+
120
+ it "should set use_ssl to false by default" do
121
+ @pick = Commands::Base.new("").with(@input, @output)
122
+ @pick.options[:use_ssl].should be_false
123
+ end
124
+
125
+ it "should respect use_ssl from git config if it's set true (case insensitive)" do
126
+ Commands::Base.any_instance.stubs(:get).with("git config --get pivotal.use-ssl").returns("truE")
127
+ @pick = Commands::Base.new
128
+ @pick.options[:use_ssl].should be_true
129
+ end
130
+
131
+ it "should respect use_ssl from git config if it's set to anything but true" do
132
+ Commands::Base.any_instance.stubs(:get).with("git config --get pivotal.use-ssl").returns("not true")
133
+ @pick = Commands::Base.new
134
+ @pick.options[:use_ssl].should be_false
135
+ end
136
+
137
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands::Bug do
4
+
5
+ before(:each) do
6
+ # stub out git config requests
7
+ Commands::Bug.any_instance.stubs(:get).with { |v| v =~ /git config/ }.returns("")
8
+
9
+ @bug = Commands::Bug.new
10
+ end
11
+
12
+ it "should specify its story type" do
13
+ @bug.type.should == "bug"
14
+ end
15
+
16
+ it "should specify a plural for its story types" do
17
+ @bug.plural_type.should == "bugs"
18
+ end
19
+
20
+ it "should specify its branch suffix" do
21
+ @bug.branch_suffix.should == "bugfix"
22
+ end
23
+
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands::Chore do
4
+
5
+ before(:each) do
6
+ # stub out git config requests
7
+ Commands::Chore.any_instance.stubs(:get).with { |v| v =~ /git config/ }.returns("")
8
+
9
+ @chore = Commands::Chore.new
10
+ end
11
+
12
+ it "should specify its story type" do
13
+ @chore.type.should == "chore"
14
+ end
15
+
16
+ it "should specify a plural for its story types" do
17
+ @chore.plural_type.should == "chores"
18
+ end
19
+
20
+ it "should specify its branch suffix" do
21
+ @chore.branch_suffix.should == "chore"
22
+ end
23
+
24
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands::Feature do
4
+
5
+ before(:each) do
6
+ # stub out git config requests
7
+ Commands::Feature.any_instance.stubs(:get).with { |v| v =~ /git config/ }.returns("")
8
+
9
+ @feature = Commands::Feature.new
10
+ end
11
+
12
+ it "should specify its story type" do
13
+ @feature.type.should == "feature"
14
+ end
15
+
16
+ it "should specify a plural for its story types" do
17
+ @feature.plural_type.should == "features"
18
+ end
19
+
20
+ it "should specify its branch suffix" do
21
+ @feature.branch_suffix.should == "feature"
22
+ end
23
+
24
+ end
@@ -0,0 +1,134 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands::Finish do
4
+
5
+ def mock_project_id
6
+ @mock_project_id ||= '4321'
7
+ end
8
+
9
+ def mock_projects
10
+ if @mock_projects.nil?
11
+ @mock_projects = mock("mock project")
12
+ @mock_projects.stubs(:stories).returns(mock_stories)
13
+ end
14
+ @mock_projects
15
+ end
16
+
17
+ def mock_stories
18
+ if @mock_stories.nil?
19
+ @mock_stories = mock("mock story list")
20
+ @mock_stories.stubs(:find).with(mock_story_id).returns(mock_story)
21
+ end
22
+ @mock_stories
23
+ end
24
+
25
+ def mock_story_id
26
+ @mock_story_id ||= 1234
27
+ end
28
+
29
+ def mock_story
30
+ if @mock_story.nil?
31
+ @mock_story = mock("mock story")
32
+ end
33
+ @mock_story
34
+ end
35
+
36
+ def branch_name
37
+ "#{mock_story_id}-feature-branch-name"
38
+ end
39
+
40
+ before(:each) do
41
+ # stub out git config requests
42
+ Commands::Finish.any_instance.stubs(:get).with { |v| v =~ /git config/ }.returns("")
43
+
44
+ PivotalTracker::Project.stubs(:find).returns(mock_projects)
45
+
46
+ @finish = Commands::Finish.new(nil, nil, "-p", mock_project_id)
47
+ @finish.stubs(:put)
48
+ @finish.stubs(:get_char).returns('y')
49
+ end
50
+
51
+ context "where the branch name does not contain a valid story id" do
52
+ before(:each) do
53
+ # stub out git status request to identify the branch
54
+ branch_name = "invalid-branch-name-without-story-id"
55
+ Commands::Finish.any_instance.stubs(:get).with { |v| v =~ /git status/ }.returns("# On branch #{branch_name}")
56
+ Commands::Finish.any_instance.stubs(:get).with { |v| v == "git symbolic-ref HEAD" }.returns(branch_name)
57
+ end
58
+
59
+ it "should return an exit status of one" do
60
+ @finish.run!.should == 1
61
+ end
62
+
63
+ it "should print an error message" do
64
+ @finish.expects(:put).with("Branch name must contain a Pivotal Tracker story id").once
65
+ @finish.run!
66
+ end
67
+ end
68
+
69
+ context "where the branch name does contain a valid story id" do
70
+ before(:each) do
71
+ # stub out git status request to identify the branch
72
+ Commands::Finish.any_instance.stubs(:get).with { |v| v =~ /git status/ }.returns("# On branch #{branch_name}")
73
+ Commands::Finish.any_instance.stubs(:get).with { |v| v == "git symbolic-ref HEAD" }.returns(branch_name)
74
+ end
75
+
76
+ it "should exit if the user does not wish to proceed" do
77
+ @finish.stubs(:get_char).returns('n')
78
+ @finish.expects(:sys).never
79
+ @finish.run!
80
+ end
81
+
82
+ it "should checkout the master branch, delete the local branch, and delete the remote branch" do
83
+ @finish.expects(:sys).with() { |value| value == "git checkout master" }
84
+ @finish.expects(:sys).with("git branch -d #{branch_name}").returns(true)
85
+ @finish.expects(:sys).with("git push origin :#{branch_name}")
86
+ mock_story.stubs(:story_type).returns("finished")
87
+ mock_story.stubs(:update)
88
+ @finish.run!
89
+ end
90
+
91
+ it "should attempt to update the story status to the stories finished_state" do
92
+ @finish.stubs(:sys).returns(true)
93
+ mock_story.stubs(:story_type).returns("finished")
94
+ mock_story.expects(:update).with(:current_state => "finished")
95
+ @finish.run!
96
+ end
97
+
98
+ it "should not delete the remote branch and update the story if the local branch could not be deleted" do
99
+ @finish.expects(:sys).with() { |value| value == "git checkout master" }
100
+ @finish.expects(:sys).with("git branch -d #{branch_name}").returns(false)
101
+ @finish.expects(:sys).with("git push origin :#{branch_name}").never
102
+ @finish.run!
103
+ end
104
+
105
+ context "and the story is successfully marked as finished in PT" do
106
+ before(:each) do
107
+ @finish.stubs(:sys).returns(true)
108
+ mock_story.stubs(:story_type).returns("finished")
109
+ mock_story.stubs(:update).with(:current_state => "finished").returns(true)
110
+ end
111
+
112
+ it "should succeed with an exist status of zero" do
113
+ @finish.run!.should == 0
114
+ end
115
+ end
116
+
117
+ context "and the story fails to be marked as finished in PT" do
118
+ before(:each) do
119
+ @finish.stubs(:sys).returns(true)
120
+ mock_story.stubs(:story_type).returns("finished")
121
+ mock_story.stubs(:update).with(:current_state => "finished").returns(false)
122
+ end
123
+
124
+ it "should fail with an exist status of one" do
125
+ @finish.run!.should == 1
126
+ end
127
+
128
+ it "should print an error message" do
129
+ @finish.expects(:put).with("Unable to mark Story #{mock_story_id} as finished").once
130
+ @finish.run!
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,14 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands::Map do
4
+
5
+ describe "#[]" do
6
+ it "retrieves values when a specific key matches a regular expression" do
7
+ subject[/^\d+$/] = "w00t"
8
+ subject["1234"].should eq("w00t")
9
+ subject["9123423423"].should eq("w00t")
10
+ subject["a9123423423"].should be_nil
11
+ subject["1234f"].should be_nil
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe Commands::Start do
4
+
5
+ describe '.for' do
6
+ it "returns the Command::Bug when the first argument is bug" do
7
+ Commands::Start.for("bug").should be_instance_of(Commands::Bug)
8
+ end
9
+
10
+ it "returns the Command::Chore when the first argument is chore" do
11
+ Commands::Start.for("chore").should be_instance_of(Commands::Chore)
12
+ end
13
+
14
+ it "returns the Command::Feature when the first argument is feature" do
15
+ Commands::Start.for("feature").should be_instance_of(Commands::Feature)
16
+ end
17
+
18
+ it "returns the Command::Card when the first argument is a card id" do
19
+ Commands::Start.for("123456").should be_instance_of(Commands::Card)
20
+ end
21
+
22
+ it "raises when the command is unknown card type" do
23
+ Commands::Start.expects(:display_usage_instructions_and_quit)
24
+ Commands::Start.for("unknown")
25
+ end
26
+ end
27
+
28
+ end
data/spec/factories.rb ADDED
@@ -0,0 +1,13 @@
1
+ require File.join(File.dirname(__FILE__), 'factory')
2
+
3
+ Factory.define :story, {
4
+ :id => 1,
5
+ :current_state => :unstarted,
6
+ :story_type => :feature,
7
+ :estimate => 1,
8
+ }
9
+
10
+ Factory.define :project, {
11
+ :id => 1,
12
+ :name => "Project"
13
+ }
data/spec/factory.rb ADDED
@@ -0,0 +1,26 @@
1
+ class Factory
2
+ class << self
3
+ def factories
4
+ @@factories ||= {}
5
+ end
6
+
7
+ def define(type, attributes)
8
+ factories[type] = attributes
9
+ end
10
+ end
11
+ end
12
+
13
+
14
+ def Factory(type, attrs = {})
15
+ defaults = Factory.factories[type]
16
+ attrs = defaults.merge(attrs)
17
+
18
+ markup = Builder::XmlMarkup.new
19
+ markup.__send__(type) do
20
+ attrs.each do |attribute, value|
21
+ markup.__send__(attribute, value.to_s)
22
+ end
23
+ end
24
+
25
+ markup.target!
26
+ end
@@ -0,0 +1,24 @@
1
+ require 'mocha'
2
+ require 'builder'
3
+
4
+ # This file was generated by the `rspec --init` command. Conventionally, all
5
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
6
+ # Require this file using `require "spec_helper.rb"` to ensure that it is only
7
+ # loaded once.
8
+ #
9
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
10
+ RSpec.configure do |config|
11
+ config.mock_with :mocha
12
+ config.treat_symbols_as_metadata_keys_with_true_values = true
13
+ config.run_all_when_everything_filtered = true
14
+ config.filter_run :focus
15
+ end
16
+
17
+ specdir = File.expand_path(File.join(File.dirname(__FILE__), '..'))
18
+ require File.join(specdir, 'lib','git-pivotal-tracker')
19
+
20
+ require File.join(File.dirname(__FILE__), 'factories')
21
+
22
+ def stub_connection_to_pivotal
23
+ RestClient::Resource.any_instance.stubs(:get).returns("")
24
+ end