git_pivotal_tracker_x 0.1.1
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.
- data/.rvmrc +1 -0
- data/Gemfile +18 -0
- data/LICENSE +21 -0
- data/README.md +123 -0
- data/Rakefile +54 -0
- data/VERSION +1 -0
- data/bin/commit-msg +13 -0
- data/bin/git-bug +7 -0
- data/bin/git-chore +7 -0
- data/bin/git-feature +7 -0
- data/bin/git-finish +7 -0
- data/bin/git-info +7 -0
- data/bin/git-story +7 -0
- data/cucumber.yml +8 -0
- data/features/diagnostics.feature +15 -0
- data/features/getting_started.feature +35 -0
- data/features/hooks/aruba.rb +3 -0
- data/features/step_definitions/git_steps.rb +14 -0
- data/features/support/env.rb +1 -0
- data/git_pivotal_tracker_x.gemspec +97 -0
- data/lib/git_pivotal_tracker.rb +9 -0
- data/lib/git_pivotal_tracker/base.rb +112 -0
- data/lib/git_pivotal_tracker/finish.rb +51 -0
- data/lib/git_pivotal_tracker/info.rb +19 -0
- data/lib/git_pivotal_tracker/story.rb +59 -0
- data/spec/fixtures/finish_story.xml +17 -0
- data/spec/fixtures/no_stories.xml +3 -0
- data/spec/fixtures/one_story.xml +19 -0
- data/spec/fixtures/project.xml +37 -0
- data/spec/fixtures/start_story.xml +17 -0
- data/spec/fixtures/story.xml +18 -0
- data/spec/git_pivotal_tracker/base_spec.rb +235 -0
- data/spec/git_pivotal_tracker/finish_spec.rb +100 -0
- data/spec/git_pivotal_tracker/info_spec.rb +18 -0
- data/spec/git_pivotal_tracker/story_spec.rb +130 -0
- data/spec/spec_helper.rb +27 -0
- metadata +188 -0
@@ -0,0 +1,112 @@
|
|
1
|
+
module GitPivotalTracker
|
2
|
+
class Base
|
3
|
+
GIT_DIR = ENV['GIT_DIR'] || '.git'
|
4
|
+
|
5
|
+
attr_reader :options, :repository
|
6
|
+
|
7
|
+
def initialize(*args)
|
8
|
+
directories = Dir.pwd.split(::File::SEPARATOR)
|
9
|
+
begin
|
10
|
+
break if File.directory?(File.join(directories, GIT_DIR))
|
11
|
+
end while directories.pop
|
12
|
+
|
13
|
+
raise "No #{GIT_DIR} directory found" if directories.empty?
|
14
|
+
root = File.join(directories, GIT_DIR)
|
15
|
+
@repository = Grit::Repo.new(root)
|
16
|
+
|
17
|
+
new_hook_path = File.join(root, 'hooks', 'commit-msg')
|
18
|
+
unless File.executable?(new_hook_path)
|
19
|
+
puts "Installing commit-msg hook..."
|
20
|
+
old_hook_path = File.join(File.dirname(__FILE__), '..', '..', 'bin', 'commit-msg')
|
21
|
+
FileUtils.cp(old_hook_path, new_hook_path, :preserve => true)
|
22
|
+
end
|
23
|
+
|
24
|
+
@options = {}
|
25
|
+
parse_gitconfig
|
26
|
+
parse_argv(*args)
|
27
|
+
end
|
28
|
+
|
29
|
+
def run!
|
30
|
+
unless options[:api_token] && options[:project_id]
|
31
|
+
puts "Pivotal Tracker API Token and Project ID are required"
|
32
|
+
return 1
|
33
|
+
end
|
34
|
+
|
35
|
+
PivotalTracker::Client.token = options[:api_token]
|
36
|
+
PivotalTracker::Client.use_ssl = options[:use_ssl]
|
37
|
+
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def integration_branch
|
44
|
+
current_branch_suffix || options[:integration_branch] || 'master'
|
45
|
+
end
|
46
|
+
|
47
|
+
def current_branch_suffix
|
48
|
+
if current_branch =~ /.*-\d+?-(.*)/ and @repository.branches.any? { |branch| branch.name == $1 }
|
49
|
+
$1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def current_branch
|
54
|
+
@current_branch ||= repository.head.name
|
55
|
+
end
|
56
|
+
|
57
|
+
def story_id
|
58
|
+
if current_branch =~ /-(\d+)-/
|
59
|
+
$1
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def project
|
64
|
+
@project ||= PivotalTracker::Project.find(options[:project_id])
|
65
|
+
end
|
66
|
+
|
67
|
+
def story
|
68
|
+
@story ||= project.stories.find(story_id)
|
69
|
+
end
|
70
|
+
|
71
|
+
def log(message)
|
72
|
+
puts message if options[:verbose]
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def parse_gitconfig
|
78
|
+
options[:api_token] = repository.config['pivotal.api-token']
|
79
|
+
options[:project_id] = repository.config['pivotal.project-id']
|
80
|
+
options[:integration_branch] = repository.config['pivotal.integration-branch']
|
81
|
+
options[:only_mine] = repository.config['pivotal.only-mine']
|
82
|
+
options[:include_rejected] = repository.config['pivotal.include-rejected']
|
83
|
+
options[:fast_forward] = repository.config['pivotal.fast-forward']
|
84
|
+
options[:rebase] = repository.config['pivotal.rebase']
|
85
|
+
options[:full_name] = repository.config['pivotal.full-name'] || repository.config['user.name']
|
86
|
+
options[:verbose] = repository.config['pivotal.verbose']
|
87
|
+
options[:use_ssl] = repository.config['pivotal.use-ssl']
|
88
|
+
options[:delete_branch] = repository.config['pivotal.delete-branch']
|
89
|
+
end
|
90
|
+
|
91
|
+
def parse_argv(*args)
|
92
|
+
OptionParser.new do |opts|
|
93
|
+
opts.banner = "Usage: git <feature|chore|bug> [options]"
|
94
|
+
opts.on("-t", "--api-token=", "Pivotal Tracker API key") { |k| options[:api_token] = k }
|
95
|
+
opts.on("-p", "--project-id=", "Pivotal Tracker project id") { |p| options[:project_id] = p }
|
96
|
+
opts.on("-b", "--integration-branch=", "The branch to merge finished stories back down onto") { |b| options[:integration_branch] = b }
|
97
|
+
opts.on("-n", "--full-name=", "Your Pivotal Tracker full name") { |n| options[:full_name] = n }
|
98
|
+
|
99
|
+
|
100
|
+
opts.on("-D", "--delete-branch", "Delete store branch after merging") { |d| options[:delete_branch] = d }
|
101
|
+
opts.on("-I", "--include-rejected", "Include rejected stories as well as unstarted ones") { |i| options[:include_rejected] = i }
|
102
|
+
opts.on("-O", "--only-mine", "Only include stories that are assigned to me") { |o| options[:only_mine] = o }
|
103
|
+
opts.on("-F", "--fast-forward", "Merge topic branch with fast forward") { |f| options[:fast_forward] = f }
|
104
|
+
opts.on("-S", "--use-ssl", "Use SSL for connection to Pivotal Tracker") { |s| options[:use_ssl] = s }
|
105
|
+
opts.on("-R", "--rebase", "Fetch and rebase the integration branch before merging") { |r| options[:rebase] = r }
|
106
|
+
opts.on("-V", "--verbose", "Verbose command logging") { |v| options[:verbose] = v }
|
107
|
+
opts.on_tail("-h", "--help", "This usage guide") { put opts.to_s; exit 0 }
|
108
|
+
end.parse!(args)
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module GitPivotalTracker
|
2
|
+
class Finish < Base
|
3
|
+
|
4
|
+
def run!
|
5
|
+
return 1 if super
|
6
|
+
|
7
|
+
unless story_id
|
8
|
+
puts "Branch name must contain a Pivotal Tracker story id"
|
9
|
+
return 1
|
10
|
+
end
|
11
|
+
|
12
|
+
if options[:rebase]
|
13
|
+
puts "Fetching origin and rebasing #{current_branch}"
|
14
|
+
log repository.git.checkout({:raise => true}, integration_branch)
|
15
|
+
log repository.git.pull({:raise => true})
|
16
|
+
log repository.git.rebase({:raise => true}, integration_branch, current_branch)
|
17
|
+
end
|
18
|
+
|
19
|
+
puts "Merging #{current_branch} into #{integration_branch}"
|
20
|
+
log repository.git.checkout({:raise => true}, integration_branch)
|
21
|
+
|
22
|
+
merge_options = {:raise => true}
|
23
|
+
merge_options[:no_ff] = true unless options[:fast_forward]
|
24
|
+
log repository.git.merge(merge_options, current_branch)
|
25
|
+
|
26
|
+
puts "Pushing #{integration_branch}"
|
27
|
+
log repository.git.push({:raise => true}, 'origin', integration_branch)
|
28
|
+
|
29
|
+
puts "Marking Story #{story_id} as finished..."
|
30
|
+
if story.update(:current_state => finished_state)
|
31
|
+
delete_current_branch if options[:delete_branch]
|
32
|
+
puts "Success"
|
33
|
+
return 0
|
34
|
+
else
|
35
|
+
puts "Unable to mark Story #{story_id} as finished"
|
36
|
+
return 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def finished_state
|
43
|
+
story.story_type == "chore" ? "accepted" : "finished"
|
44
|
+
end
|
45
|
+
|
46
|
+
def delete_current_branch
|
47
|
+
puts "Deleting #{current_branch}"
|
48
|
+
log repository.git.branch({:raise => true, :d => true}, current_branch)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module GitPivotalTracker
|
2
|
+
class Info < Base
|
3
|
+
|
4
|
+
def run!
|
5
|
+
return 1 if super
|
6
|
+
|
7
|
+
unless story_id
|
8
|
+
puts "Branch name must contain a Pivotal Tracker story id"
|
9
|
+
return 1
|
10
|
+
end
|
11
|
+
|
12
|
+
puts "URL: #{story.url}"
|
13
|
+
puts "Story: #{story.name}"
|
14
|
+
puts "Description: #{story.description}"
|
15
|
+
|
16
|
+
return 0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module GitPivotalTracker
|
2
|
+
class Story < Base
|
3
|
+
|
4
|
+
def run!
|
5
|
+
return 1 if super
|
6
|
+
|
7
|
+
puts "Retrieving latest #{type} from Pivotal Tracker"
|
8
|
+
|
9
|
+
unless story = fetch_story
|
10
|
+
puts "No #{type} available!"
|
11
|
+
return 1
|
12
|
+
end
|
13
|
+
|
14
|
+
puts "URL: #{story.url}"
|
15
|
+
puts "Story: #{story.name}"
|
16
|
+
|
17
|
+
print "Enter branch name [#{branch_suffix story}]: "
|
18
|
+
suffix = gets.chomp
|
19
|
+
suffix = branch_suffix(story) if suffix == ""
|
20
|
+
|
21
|
+
branch = "#{story.story_type}-#{story.id}-#{suffix}"
|
22
|
+
puts "Checking out a new branch '#{branch}'"
|
23
|
+
log repository.git.checkout({:b => true, :raise => true}, branch)
|
24
|
+
|
25
|
+
puts "Updating #{type} status in Pivotal Tracker..."
|
26
|
+
if story.update(:owned_by => options[:full_name], :current_state => :started)
|
27
|
+
puts "Success"
|
28
|
+
return 0
|
29
|
+
else
|
30
|
+
puts "Unable to mark #{type} as started"
|
31
|
+
return 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def type
|
36
|
+
self.class.name.downcase.split(/::/).last
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def fetch_story
|
42
|
+
state = options[:include_rejected] ? "unstarted,rejected" : "unstarted"
|
43
|
+
conditions = { :current_state => state, :limit => 1 }
|
44
|
+
conditions[:owned_by] = "\"#{options[:full_name]}\"" if options[:only_mine]
|
45
|
+
conditions[:story_type] = type unless type == 'story'
|
46
|
+
project.stories.all(conditions).first
|
47
|
+
end
|
48
|
+
|
49
|
+
def branch_suffix(story)
|
50
|
+
story.name.sub(/^\W+/, '').sub(/\W+$/, '').gsub(/\W+/, '_').downcase
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
class Bug < Story; end
|
55
|
+
|
56
|
+
class Feature < Story; end
|
57
|
+
|
58
|
+
class Chore < Story; end
|
59
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<story>
|
3
|
+
<name> Pause the film!</name>
|
4
|
+
<description>As a moderator,
|
5
|
+
I can pause the film
|
6
|
+
In order to allow another activity to take place (discussion, etc).</description>
|
7
|
+
<story_type>feature</story_type>
|
8
|
+
<estimate>2</estimate>
|
9
|
+
<current_state>finished</current_state>
|
10
|
+
<requested_by>Ben Lindsey</requested_by>
|
11
|
+
<owned_by>Ben Lindsey</owned_by>
|
12
|
+
<labels>moderate,2_needs_design</labels>
|
13
|
+
<project_id>123</project_id>
|
14
|
+
<other_id></other_id>
|
15
|
+
<integration_id></integration_id>
|
16
|
+
<created_at>2011-07-14T23:06:28+00:00</created_at>
|
17
|
+
</story>
|
@@ -0,0 +1,19 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<stories type="array" count="1" total="2" limit="1">
|
3
|
+
<story>
|
4
|
+
<id type="integer">1234567890</id>
|
5
|
+
<project_id type="integer">123</project_id>
|
6
|
+
<story_type>feature</story_type>
|
7
|
+
<url>http://www.pivotaltracker.com/story/show/1234567890</url>
|
8
|
+
<estimate type="integer">2</estimate>
|
9
|
+
<current_state>unstarted</current_state>
|
10
|
+
<description>As a moderator,
|
11
|
+
I can pause the film
|
12
|
+
In order to allow another activity to take place (discussion, etc).</description>
|
13
|
+
<name> Pause the film!</name>
|
14
|
+
<requested_by>Ben Lindsey</requested_by>
|
15
|
+
<created_at type="datetime">2011/07/14 23:06:28 UTC</created_at>
|
16
|
+
<updated_at type="datetime">2011/07/14 23:13:24 UTC</updated_at>
|
17
|
+
<labels>moderate,2_needs_design</labels>
|
18
|
+
</story>
|
19
|
+
</stories>
|
@@ -0,0 +1,37 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<project>
|
3
|
+
<id>123</id>
|
4
|
+
<name>Test Project</name>
|
5
|
+
<iteration_length type="integer">1</iteration_length>
|
6
|
+
<week_start_day>Monday</week_start_day>
|
7
|
+
<point_scale>0,1,2,3,5,8</point_scale>
|
8
|
+
<account>Carbon Five</account>
|
9
|
+
<start_date type="date">2011/07/18</start_date>
|
10
|
+
<first_iteration_start_time type="datetime">2011/07/18 07:00:00 UTC</first_iteration_start_time>
|
11
|
+
<current_iteration_number type="integer">1</current_iteration_number>
|
12
|
+
<enable_tasks type="boolean">true</enable_tasks>
|
13
|
+
<velocity_scheme>Average of 3 iterations</velocity_scheme>
|
14
|
+
<current_velocity>10</current_velocity>
|
15
|
+
<initial_velocity>10</initial_velocity>
|
16
|
+
<number_of_done_iterations_to_show>12</number_of_done_iterations_to_show>
|
17
|
+
<labels>1_needs_definition,2_needs_design,discuss,moderate</labels>
|
18
|
+
<last_activity_at type="datetime">2011/07/14 23:16:29 UTC</last_activity_at>
|
19
|
+
<allow_attachments>true</allow_attachments>
|
20
|
+
<public>false</public>
|
21
|
+
<use_https>false</use_https>
|
22
|
+
<bugs_and_chores_are_estimatable>false</bugs_and_chores_are_estimatable>
|
23
|
+
<commit_mode>false</commit_mode>
|
24
|
+
<memberships type="array">
|
25
|
+
<membership>
|
26
|
+
<id>1058581</id>
|
27
|
+
<person>
|
28
|
+
<email>ben@carbonfive.com</email>
|
29
|
+
<name>Ben Lindsey</name>
|
30
|
+
<initials>BL</initials>
|
31
|
+
</person>
|
32
|
+
<role>Owner</role>
|
33
|
+
</membership>
|
34
|
+
</memberships>
|
35
|
+
<integrations type="array">
|
36
|
+
</integrations>
|
37
|
+
</project>
|
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<story>
|
3
|
+
<name> Pause the film!</name>
|
4
|
+
<description>As a moderator,
|
5
|
+
I can pause the film
|
6
|
+
In order to allow another activity to take place (discussion, etc).</description>
|
7
|
+
<story_type>feature</story_type>
|
8
|
+
<estimate>2</estimate>
|
9
|
+
<current_state>started</current_state>
|
10
|
+
<requested_by>Ben Lindsey</requested_by>
|
11
|
+
<owned_by>Ben Lindsey</owned_by>
|
12
|
+
<labels>moderate,2_needs_design</labels>
|
13
|
+
<project_id>123</project_id>
|
14
|
+
<other_id></other_id>
|
15
|
+
<integration_id></integration_id>
|
16
|
+
<created_at>2011-07-14T23:06:28+00:00</created_at>
|
17
|
+
</story>
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<story>
|
3
|
+
<id>1234567890</id>
|
4
|
+
<name> Pause the film!</name>
|
5
|
+
<description>As a moderator,
|
6
|
+
I can pause the film
|
7
|
+
In order to allow another activity to take place (discussion, etc).</description>
|
8
|
+
<story_type>feature</story_type>
|
9
|
+
<estimate>2</estimate>
|
10
|
+
<current_state>started</current_state>
|
11
|
+
<requested_by>Ben Lindsey</requested_by>
|
12
|
+
<owned_by>Ben Lindsey</owned_by>
|
13
|
+
<labels>moderate,2_needs_design</labels>
|
14
|
+
<project_id>123</project_id>
|
15
|
+
<other_id></other_id>
|
16
|
+
<integration_id></integration_id>
|
17
|
+
<created_at>2011-07-14T23:06:28+00:00</created_at>
|
18
|
+
</story>
|
@@ -0,0 +1,235 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), '..', 'spec_helper')
|
2
|
+
|
3
|
+
describe GitPivotalTracker::Base do
|
4
|
+
describe "#parse_argv" do
|
5
|
+
|
6
|
+
context "by default" do
|
7
|
+
before do
|
8
|
+
stub_git_config
|
9
|
+
subject = GitPivotalTracker::Base.new
|
10
|
+
end
|
11
|
+
|
12
|
+
it "leaves integration_branch nil" do
|
13
|
+
subject.options[:integration_branch].should be_nil
|
14
|
+
end
|
15
|
+
|
16
|
+
it "leaves fast_forward nil" do
|
17
|
+
subject.options[:fast_forward].should be_nil
|
18
|
+
end
|
19
|
+
|
20
|
+
it "leaves rebase nil" do
|
21
|
+
subject.options[:rebase].should be_nil
|
22
|
+
end
|
23
|
+
|
24
|
+
it "leaves verbose nil" do
|
25
|
+
subject.options[:verbose].should be_nil
|
26
|
+
end
|
27
|
+
|
28
|
+
it "leaves use_ssl nil" do
|
29
|
+
subject.options[:use_ssl].should be_nil
|
30
|
+
end
|
31
|
+
|
32
|
+
it "leaves full_name nil" do
|
33
|
+
subject.options[:full_name].should be_nil
|
34
|
+
end
|
35
|
+
|
36
|
+
it "leaves include_rejected nil" do
|
37
|
+
subject.options[:include_rejected].should be_nil
|
38
|
+
end
|
39
|
+
|
40
|
+
it "leaves only_mine nil" do
|
41
|
+
subject.options[:only_mine].should be_nil
|
42
|
+
end
|
43
|
+
|
44
|
+
it "leaves delete_branch nil" do
|
45
|
+
subject.options[:delete_branch].should be_nil
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "sets the api_token" do
|
50
|
+
GitPivotalTracker::Base.new("--api-token", "8a8a8a8").options[:api_token].should == '8a8a8a8'
|
51
|
+
GitPivotalTracker::Base.new("-t", "8a8a8a8").options[:api_token].should == '8a8a8a8'
|
52
|
+
end
|
53
|
+
|
54
|
+
it "sets the project_id" do
|
55
|
+
GitPivotalTracker::Base.new("--project-id", "123").options[:project_id].should == '123'
|
56
|
+
GitPivotalTracker::Base.new("-p", "123").options[:project_id].should == '123'
|
57
|
+
end
|
58
|
+
|
59
|
+
it "sets the integration_branch" do
|
60
|
+
GitPivotalTracker::Base.new("--integration-branch", "development").options[:integration_branch].should == 'development'
|
61
|
+
GitPivotalTracker::Base.new("-b", "development").options[:integration_branch].should == 'development'
|
62
|
+
end
|
63
|
+
|
64
|
+
it "sets full_name" do
|
65
|
+
GitPivotalTracker::Base.new("--full-name", "Full Name").options[:full_name].should == 'Full Name'
|
66
|
+
GitPivotalTracker::Base.new("-n", "Full Name").options[:full_name].should == 'Full Name'
|
67
|
+
end
|
68
|
+
|
69
|
+
it "sets include_rejected" do
|
70
|
+
GitPivotalTracker::Base.new("--include-rejected").options[:include_rejected].should be
|
71
|
+
GitPivotalTracker::Base.new("-I").options[:include_rejected].should be
|
72
|
+
end
|
73
|
+
|
74
|
+
it "sets only_mine" do
|
75
|
+
GitPivotalTracker::Base.new("--only-mine").options[:only_mine].should be
|
76
|
+
GitPivotalTracker::Base.new("-O").options[:only_mine].should be
|
77
|
+
end
|
78
|
+
|
79
|
+
it "sets fast_forward" do
|
80
|
+
GitPivotalTracker::Base.new("--fast-forward").options[:fast_forward].should be
|
81
|
+
GitPivotalTracker::Base.new("-F").options[:fast_forward].should be
|
82
|
+
end
|
83
|
+
|
84
|
+
it "sets use_ssl" do
|
85
|
+
GitPivotalTracker::Base.new("--use-ssl").options[:use_ssl].should be
|
86
|
+
GitPivotalTracker::Base.new("-S").options[:use_ssl].should be
|
87
|
+
end
|
88
|
+
|
89
|
+
it "sets rebase" do
|
90
|
+
GitPivotalTracker::Base.new("--rebase").options[:rebase].should be
|
91
|
+
GitPivotalTracker::Base.new("-R").options[:rebase].should be
|
92
|
+
end
|
93
|
+
|
94
|
+
it "sets verbose" do
|
95
|
+
GitPivotalTracker::Base.new("--verbose").options[:verbose].should be
|
96
|
+
GitPivotalTracker::Base.new("-V").options[:verbose].should be
|
97
|
+
end
|
98
|
+
|
99
|
+
it "sets delete_branch" do
|
100
|
+
GitPivotalTracker::Base.new("--delete-branch").options[:delete_branch].should be
|
101
|
+
GitPivotalTracker::Base.new("-D").options[:delete_branch].should be
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
describe "#parse_gitconfig" do
|
106
|
+
context "with a full-name" do
|
107
|
+
before do
|
108
|
+
stub_git_config 'pivotal.full-name' => 'Full Name', 'user.name' => 'User Name'
|
109
|
+
subject = GitPivotalTracker::Base.new
|
110
|
+
end
|
111
|
+
|
112
|
+
it "sets the full_name to the full name" do
|
113
|
+
subject.options[:full_name].should == 'Full Name'
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
context "with no full-name" do
|
118
|
+
before do
|
119
|
+
stub_git_config({
|
120
|
+
'user.name' => 'User Name',
|
121
|
+
'pivotal.integration-branch' => 'development',
|
122
|
+
'pivotal.only-mine' => 1,
|
123
|
+
'pivotal.include-rejected' => 1,
|
124
|
+
'pivotal.fast-forward' => 1,
|
125
|
+
'pivotal.rebase' => 1,
|
126
|
+
'pivotal.verbose' => 1,
|
127
|
+
'pivotal.use-ssl' => 1
|
128
|
+
})
|
129
|
+
subject = GitPivotalTracker::Base.new
|
130
|
+
end
|
131
|
+
|
132
|
+
it "sets use_ssl" do
|
133
|
+
subject.options[:use_ssl].should be
|
134
|
+
end
|
135
|
+
|
136
|
+
it "sets the api_token" do
|
137
|
+
subject.options[:api_token].should == '8a8a8a8'
|
138
|
+
end
|
139
|
+
|
140
|
+
it "sets the project_id" do
|
141
|
+
subject.options[:project_id].should == '123'
|
142
|
+
end
|
143
|
+
|
144
|
+
it "sets only_mine" do
|
145
|
+
subject.options[:only_mine].should be
|
146
|
+
end
|
147
|
+
|
148
|
+
it "sets include_rejected" do
|
149
|
+
subject.options[:include_rejected].should be
|
150
|
+
end
|
151
|
+
|
152
|
+
it "sets fast_forward" do
|
153
|
+
subject.options[:fast_forward].should be
|
154
|
+
end
|
155
|
+
|
156
|
+
it "sets rebase" do
|
157
|
+
subject.options[:rebase].should be
|
158
|
+
end
|
159
|
+
|
160
|
+
it "sets verbose" do
|
161
|
+
subject.options[:verbose].should be
|
162
|
+
end
|
163
|
+
|
164
|
+
it "sets the full_name to the user name" do
|
165
|
+
subject.options[:full_name].should == 'User Name'
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe ".new" do
|
171
|
+
context "given an invalid git root" do
|
172
|
+
before do
|
173
|
+
@current_dir = Dir.pwd
|
174
|
+
Dir.chdir("/")
|
175
|
+
end
|
176
|
+
|
177
|
+
it "fails to initialize" do
|
178
|
+
expect { GitPivotalTracker::Base.new }.to raise_error "No .git directory found"
|
179
|
+
end
|
180
|
+
|
181
|
+
after do
|
182
|
+
Dir.chdir @current_dir
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
context "given no commit-msg hook" do
|
187
|
+
let(:file_name) { ".git/hooks/commit-msg" }
|
188
|
+
|
189
|
+
before do
|
190
|
+
File.delete file_name if File.exists? file_name
|
191
|
+
GitPivotalTracker::Base.new
|
192
|
+
end
|
193
|
+
|
194
|
+
it "installs the hook" do
|
195
|
+
File.executable?(file_name).should be
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
describe "#run!" do
|
201
|
+
context "given a config with an api token and a project id" do
|
202
|
+
before do
|
203
|
+
stub_git_config
|
204
|
+
subject = GitPivotalTracker::Base.new
|
205
|
+
PivotalTracker::Client.should_receive(:token=).with('8a8a8a8')
|
206
|
+
end
|
207
|
+
|
208
|
+
it "succeeds" do
|
209
|
+
subject.run!.should be_nil
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
context "given the config has no api token" do
|
214
|
+
before do
|
215
|
+
stub_git_config 'pivotal.api-token' => nil
|
216
|
+
subject = GitPivotalTracker::Base.new
|
217
|
+
end
|
218
|
+
|
219
|
+
it "fails" do
|
220
|
+
subject.run!.should == 1
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
context "given the config has no project id" do
|
225
|
+
before do
|
226
|
+
stub_git_config 'pivotal.project-id' => nil
|
227
|
+
subject = GitPivotalTracker::Base.new
|
228
|
+
end
|
229
|
+
|
230
|
+
it "fails" do
|
231
|
+
subject.run!.should == 1
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|