git-pivotal-tracker-centro 1.0.0.rc1
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/.gitignore +6 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/.travis.yml +3 -0
- data/CHANGELOG +54 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +82 -0
- data/LICENSE +21 -0
- data/Rakefile +49 -0
- data/VERSION +1 -0
- data/bin/git-finish +7 -0
- data/bin/git-info +7 -0
- data/bin/git-start +8 -0
- data/features/finish.feature +88 -0
- data/features/info.feature +99 -0
- data/features/start.feature +113 -0
- data/features/step_definitions/steps.rb +119 -0
- data/features/support/dsl/assertions.rb +11 -0
- data/features/support/dsl/data.rb +11 -0
- data/features/support/dsl/pivotal.rb +77 -0
- data/features/support/env.rb +6 -0
- data/features/support/git-pivotal.rb +68 -0
- data/features/test_repo/origin.git/COMMIT_EDITMSG +1 -0
- data/features/test_repo/origin.git/HEAD +1 -0
- data/features/test_repo/origin.git/config +8 -0
- data/features/test_repo/origin.git/description +1 -0
- data/features/test_repo/origin.git/hooks/applypatch-msg.sample +15 -0
- data/features/test_repo/origin.git/hooks/commit-msg.sample +24 -0
- data/features/test_repo/origin.git/hooks/post-commit.sample +8 -0
- data/features/test_repo/origin.git/hooks/post-receive.sample +15 -0
- data/features/test_repo/origin.git/hooks/post-update.sample +8 -0
- data/features/test_repo/origin.git/hooks/pre-applypatch.sample +14 -0
- data/features/test_repo/origin.git/hooks/pre-commit.sample +46 -0
- data/features/test_repo/origin.git/hooks/pre-rebase.sample +169 -0
- data/features/test_repo/origin.git/hooks/prepare-commit-msg.sample +36 -0
- data/features/test_repo/origin.git/hooks/update.sample +128 -0
- data/features/test_repo/origin.git/index +0 -0
- data/features/test_repo/origin.git/info/exclude +6 -0
- data/features/test_repo/origin.git/logs/HEAD +1 -0
- data/features/test_repo/origin.git/logs/refs/heads/master +1 -0
- data/features/test_repo/origin.git/objects/0c/6f7b1384910d1a2f137590095f008a06c7e00c +0 -0
- data/features/test_repo/origin.git/objects/10/ecf2b7ce989f01f3f7266e712b48d9275f2635 +0 -0
- data/features/test_repo/origin.git/objects/a5/71d56305df09fb060f6ccb730b46080d305beb +0 -0
- data/features/test_repo/origin.git/refs/heads/master +1 -0
- data/features/test_repo/readme +1 -0
- data/git-pivotal-tracker-centro.gemspec +29 -0
- data/lib/commands/base.rb +120 -0
- data/lib/commands/bug.rb +19 -0
- data/lib/commands/card.rb +32 -0
- data/lib/commands/chore.rb +19 -0
- data/lib/commands/feature.rb +19 -0
- data/lib/commands/finish.rb +67 -0
- data/lib/commands/info.rb +58 -0
- data/lib/commands/map.rb +10 -0
- data/lib/commands/pick.rb +94 -0
- data/lib/commands/start.rb +39 -0
- data/lib/git-pivotal-tracker.rb +11 -0
- data/readme.markdown +106 -0
- data/spec/commands/base_spec.rb +137 -0
- data/spec/commands/bug_spec.rb +24 -0
- data/spec/commands/chore_spec.rb +24 -0
- data/spec/commands/feature_spec.rb +24 -0
- data/spec/commands/finish_spec.rb +134 -0
- data/spec/commands/map_spec.rb +14 -0
- data/spec/commands/start_spec.rb +28 -0
- data/spec/factories.rb +13 -0
- data/spec/factory.rb +26 -0
- data/spec/spec_helper.rb +24 -0
- metadata +291 -0
@@ -0,0 +1 @@
|
|
1
|
+
0000000000000000000000000000000000000000 10ecf2b7ce989f01f3f7266e712b48d9275f2635 Jeff Tucker <trydionel@gmail.com> 1279979728 -0400 commit (initial): A blank repo for testing
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
10ecf2b7ce989f01f3f7266e712b48d9275f2635
|
@@ -0,0 +1 @@
|
|
1
|
+
Testing repo
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "git-pivotal-tracker-centro"
|
6
|
+
s.version = IO.read("VERSION")
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Zach Dennis", "Jeff Tucker", "Sam Stokes", "John Wood"]
|
9
|
+
s.email = "john@johnpwood.net"
|
10
|
+
s.homepage = "https://github.com/centro/git-pivotal"
|
11
|
+
s.summary = "A collection of git utilities to ease integration with Pivotal Tracker."
|
12
|
+
s.description = "A collection of git utilities to ease integration with Pivotal Tracker."
|
13
|
+
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.require_paths = ["lib"]
|
18
|
+
|
19
|
+
s.add_runtime_dependency(%q<pivotal-tracker>, [">= 0"])
|
20
|
+
|
21
|
+
s.add_development_dependency(%q<rake>, [">= 0"])
|
22
|
+
s.add_development_dependency(%q<mocha>, [">= 0"])
|
23
|
+
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
24
|
+
s.add_development_dependency(%q<aruba>, [">= 0"])
|
25
|
+
s.add_development_dependency(%q<rspec>, [">= 0"])
|
26
|
+
s.add_development_dependency(%q<cucumber>, [">= 0"])
|
27
|
+
s.add_development_dependency(%q<pry>, [">= 0"])
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'pivotal-tracker'
|
3
|
+
require 'optparse'
|
4
|
+
|
5
|
+
module Commands
|
6
|
+
class Base
|
7
|
+
|
8
|
+
attr_accessor :input, :output, :options
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
@input = STDIN
|
12
|
+
@output = STDOUT
|
13
|
+
|
14
|
+
@options = {}
|
15
|
+
|
16
|
+
parse_gitconfig
|
17
|
+
parse_argv(*args)
|
18
|
+
end
|
19
|
+
|
20
|
+
def with(input, output)
|
21
|
+
tap do
|
22
|
+
@input = input
|
23
|
+
@output = output
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def put(string, newline=true)
|
28
|
+
@output.print(newline ? string + "\n" : string) unless options[:quiet]
|
29
|
+
end
|
30
|
+
|
31
|
+
def sys(cmd)
|
32
|
+
if options[:verbose]
|
33
|
+
put cmd
|
34
|
+
system cmd
|
35
|
+
else
|
36
|
+
system "#{cmd} > /dev/null 2>&1"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def get(cmd)
|
41
|
+
put cmd if options[:verbose]
|
42
|
+
`#{cmd}`
|
43
|
+
end
|
44
|
+
|
45
|
+
def get_char
|
46
|
+
input.getc
|
47
|
+
end
|
48
|
+
|
49
|
+
def run!
|
50
|
+
unless options[:api_token] && options[:project_id]
|
51
|
+
put "Pivotal Tracker API Token and Project ID are required"
|
52
|
+
return 1
|
53
|
+
end
|
54
|
+
|
55
|
+
PivotalTracker::Client.token = options[:api_token]
|
56
|
+
PivotalTracker::Client.use_ssl = options[:use_ssl]
|
57
|
+
|
58
|
+
return 0
|
59
|
+
end
|
60
|
+
|
61
|
+
protected
|
62
|
+
|
63
|
+
def on_parse(opts)
|
64
|
+
# no-op, override in sub-class to provide command specific options
|
65
|
+
end
|
66
|
+
|
67
|
+
def current_branch
|
68
|
+
@current_branch ||= get('git symbolic-ref HEAD').chomp.split('/').last
|
69
|
+
end
|
70
|
+
|
71
|
+
def project
|
72
|
+
@project ||= PivotalTracker::Project.find(options[:project_id])
|
73
|
+
end
|
74
|
+
|
75
|
+
def full_name
|
76
|
+
options[:full_name]
|
77
|
+
end
|
78
|
+
|
79
|
+
def remote
|
80
|
+
options[:remote] || "origin"
|
81
|
+
end
|
82
|
+
|
83
|
+
private
|
84
|
+
|
85
|
+
def parse_gitconfig
|
86
|
+
token = get("git config --get pivotal.api-token").strip
|
87
|
+
name = get("git config --get pivotal.full-name").strip
|
88
|
+
id = get("git config --get pivotal.project-id").strip
|
89
|
+
remote = get("git config --get pivotal.remote").strip
|
90
|
+
use_ssl = get("git config --get pivotal.use-ssl").strip
|
91
|
+
verbose = get("git config --get pivotal.verbose").strip
|
92
|
+
|
93
|
+
options[:api_token] = token unless token == ""
|
94
|
+
options[:project_id] = id unless id == ""
|
95
|
+
options[:full_name] = name unless name == ""
|
96
|
+
options[:remote] = remote unless remote == ""
|
97
|
+
options[:use_ssl] = (/^true$/i.match(use_ssl))
|
98
|
+
options[:verbose] = verbose == "" ? true : (/^true$/i.match(verbose))
|
99
|
+
end
|
100
|
+
|
101
|
+
def parse_argv(*args)
|
102
|
+
OptionParser.new do |opts|
|
103
|
+
opts.banner = "Usage: git pick [options]"
|
104
|
+
opts.on("-k", "--api-key=", "Pivotal Tracker API key") { |k| options[:api_token] = k }
|
105
|
+
opts.on("-p", "--project-id=", "Pivotal Tracker project id") { |p| options[:project_id] = p }
|
106
|
+
opts.on("-n", "--full-name=", "Pivotal Tracker full name") { |n| options[:full_name] = n }
|
107
|
+
opts.on("-S", "--use-ssl", "Use SSL for connection to Pivotal Tracker (for private repos(?))") { |s| options[:use_ssl] = s }
|
108
|
+
opts.on("-D", "--defaults", "Accept default options. No-interaction mode") { |d| options[:defaults] = d }
|
109
|
+
opts.on("-q", "--quiet", "Quiet, no-interaction mode") { |q| options[:quiet] = q }
|
110
|
+
opts.on("-v", "--[no-]verbose", "Run verbosely") { |v| options[:verbose] = v }
|
111
|
+
opts.on("-f", "--force", "Do not prompt") { |f| options[:force] = f }
|
112
|
+
|
113
|
+
on_parse(opts)
|
114
|
+
|
115
|
+
opts.on_tail("-h", "--help", "This usage guide") { put opts.to_s; exit 0 }
|
116
|
+
end.parse!(args)
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
end
|
data/lib/commands/bug.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'commands/pick'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
class Card < Pick
|
5
|
+
attr_accessor :story_id
|
6
|
+
|
7
|
+
def type
|
8
|
+
"story"
|
9
|
+
end
|
10
|
+
|
11
|
+
def plural_type
|
12
|
+
"cards"
|
13
|
+
end
|
14
|
+
|
15
|
+
def branch_suffix
|
16
|
+
if story.story_type == "bug"
|
17
|
+
"bugfix"
|
18
|
+
else
|
19
|
+
story.story_type
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
protected
|
24
|
+
|
25
|
+
def story
|
26
|
+
return @story if @story
|
27
|
+
raise ArgumentError, "No story id was given!" unless story_id
|
28
|
+
project.stories.find(story_id)
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'commands/base'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
class Finish < Base
|
5
|
+
|
6
|
+
def run!
|
7
|
+
super
|
8
|
+
|
9
|
+
unless story_id
|
10
|
+
put "Branch name must contain a Pivotal Tracker story id"
|
11
|
+
return 1
|
12
|
+
end
|
13
|
+
|
14
|
+
if confirm_should_finish_story?
|
15
|
+
topic_branch = current_branch
|
16
|
+
|
17
|
+
put "Switching to master"
|
18
|
+
sys "git checkout master"
|
19
|
+
|
20
|
+
put "Destroying local branch"
|
21
|
+
local_branch_deleted_successfully = sys "git branch -d #{topic_branch}"
|
22
|
+
|
23
|
+
if local_branch_deleted_successfully
|
24
|
+
put "Destroying remote branch"
|
25
|
+
sys "git push origin :#{topic_branch}"
|
26
|
+
|
27
|
+
put "Marking Story #{story_id} as finished..."
|
28
|
+
if !story.update(:current_state => finished_state)
|
29
|
+
put "Unable to mark Story #{story_id} as finished"
|
30
|
+
return 1
|
31
|
+
end
|
32
|
+
else
|
33
|
+
put "The local branch could not be deleted. Please make sure your changes have been merged."
|
34
|
+
return 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
return 0
|
39
|
+
end
|
40
|
+
|
41
|
+
protected
|
42
|
+
|
43
|
+
def confirm_should_finish_story?
|
44
|
+
return true if options[:force]
|
45
|
+
|
46
|
+
put "Finish story #{story_id} and delete local and remote branches? (y/N): ", false
|
47
|
+
finish_story = get_char.strip.downcase
|
48
|
+
finish_story == 'y'
|
49
|
+
end
|
50
|
+
|
51
|
+
def finished_state
|
52
|
+
if story.story_type == "chore"
|
53
|
+
"accepted"
|
54
|
+
else
|
55
|
+
"finished"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def story_id
|
60
|
+
match = current_branch[/\d+/] and match.to_i
|
61
|
+
end
|
62
|
+
|
63
|
+
def story
|
64
|
+
@story ||= project.stories.find(story_id)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'commands/base'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
class Info < Base
|
5
|
+
def initialize(*args)
|
6
|
+
@story_id = args.shift if args.first =~ /^(\d+)$/
|
7
|
+
super(*args)
|
8
|
+
end
|
9
|
+
|
10
|
+
def run!
|
11
|
+
super
|
12
|
+
|
13
|
+
unless story_id
|
14
|
+
put "No story id was supplied and you aren't on a topic branch!"
|
15
|
+
return 1
|
16
|
+
end
|
17
|
+
|
18
|
+
put "Story: #{story.name}"
|
19
|
+
put "URL: #{story.url}"
|
20
|
+
put "Labels: #{story.labels.split(',').join(', ')}" if story.labels
|
21
|
+
put "State: #{story.accepted_at ? 'accepted' : 'not accepted'}"
|
22
|
+
|
23
|
+
colwidth = 74
|
24
|
+
|
25
|
+
put "\nDescription:\n"
|
26
|
+
put wrap_text("#{story.description}\n", colwidth).gsub(/^/, ' ').chomp
|
27
|
+
|
28
|
+
if options[:comments]
|
29
|
+
put "\nComments:\n"
|
30
|
+
story.notes.all.each do |note|
|
31
|
+
@output.printf " %-37s%37s\n\n", note.author, note.noted_at.strftime("%b %e, %Y %k:%M%p")
|
32
|
+
put wrap_text(note.text, colwidth - 2).gsub(/^/, ' ')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
return 0
|
37
|
+
end
|
38
|
+
|
39
|
+
protected
|
40
|
+
|
41
|
+
def wrap_text(txt, col = 80)
|
42
|
+
txt.gsub(/(.{1,#{col}})( +|$\n?)|(.{1,#{col}})/,
|
43
|
+
"\\1\\3\n")
|
44
|
+
end
|
45
|
+
|
46
|
+
def on_parse(opts)
|
47
|
+
opts.on("-c", "--comments", "Display comments"){ |v| options[:comments] = v }
|
48
|
+
end
|
49
|
+
|
50
|
+
def story_id
|
51
|
+
@story_id || current_branch[/\d+/]
|
52
|
+
end
|
53
|
+
|
54
|
+
def story
|
55
|
+
@story ||= project.stories.find(story_id)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
data/lib/commands/map.rb
ADDED
@@ -0,0 +1,94 @@
|
|
1
|
+
require 'commands/base'
|
2
|
+
|
3
|
+
module Commands
|
4
|
+
class Pick < Base
|
5
|
+
|
6
|
+
def type
|
7
|
+
raise Error("must define in subclass")
|
8
|
+
end
|
9
|
+
|
10
|
+
def plural_type
|
11
|
+
raise Error("must define in subclass")
|
12
|
+
end
|
13
|
+
|
14
|
+
def branch_suffix
|
15
|
+
raise Error("must define in subclass")
|
16
|
+
end
|
17
|
+
|
18
|
+
def run!
|
19
|
+
response = super
|
20
|
+
return response if response > 0
|
21
|
+
|
22
|
+
if story
|
23
|
+
put "Story: #{story.name}"
|
24
|
+
put "URL: #{story.url}\n"
|
25
|
+
|
26
|
+
if confirm_should_start_story?
|
27
|
+
put "Updating #{type} status in Pivotal Tracker..."
|
28
|
+
story.update(:owned_by => options[:full_name], :current_state => :started)
|
29
|
+
|
30
|
+
if story.errors.empty?
|
31
|
+
branch_name = get_branch_name
|
32
|
+
create_branch(branch_name)
|
33
|
+
else
|
34
|
+
put "Unable to mark #{type} as started"
|
35
|
+
put "\t" + story.errors.to_a.join("\n\t")
|
36
|
+
return 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
else
|
40
|
+
put "No #{plural_type} available!"
|
41
|
+
end
|
42
|
+
|
43
|
+
return 0
|
44
|
+
end
|
45
|
+
|
46
|
+
protected
|
47
|
+
|
48
|
+
def confirm_should_start_story?
|
49
|
+
return true if options[:force]
|
50
|
+
|
51
|
+
put "Start #{type} #{story.id} - #{story.name}? (Y/n): ", false
|
52
|
+
start_story = get_char.strip.downcase
|
53
|
+
start_story == '' || start_story == 'y'
|
54
|
+
end
|
55
|
+
|
56
|
+
def story
|
57
|
+
if @story.nil?
|
58
|
+
msg = "Retrieving latest #{plural_type} from Pivotal Tracker"
|
59
|
+
msg += " for #{options[:full_name]}" if options[:only_mine]
|
60
|
+
put "#{msg}..."
|
61
|
+
|
62
|
+
conditions = { :story_type => type, :current_state => "unstarted", :limit => 1, :offset => 0 }
|
63
|
+
conditions[:owned_by] = options[:full_name] if options[:only_mine]
|
64
|
+
@story = project.stories.all(conditions).first
|
65
|
+
end
|
66
|
+
@story
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_branch_name
|
70
|
+
branch_name = ""
|
71
|
+
suggested_branch_name = "#{story.id}-#{story.name.downcase.gsub(/\s+/, "-")}"
|
72
|
+
|
73
|
+
unless options[:quiet] || options[:defaults]
|
74
|
+
put "Enter branch name [#{suggested_branch_name}]: ", false
|
75
|
+
branch_name = input.gets.chomp.strip
|
76
|
+
end
|
77
|
+
|
78
|
+
branch_name == "" ? suggested_branch_name : branch_name
|
79
|
+
end
|
80
|
+
|
81
|
+
def create_branch(branch)
|
82
|
+
if get("git branch").match(branch).nil?
|
83
|
+
put "Creating remote branch '#{branch}'"
|
84
|
+
sys "git push origin origin:refs/heads/#{branch}"
|
85
|
+
sys "git fetch origin"
|
86
|
+
|
87
|
+
put "Switched to a new branch '#{branch}'"
|
88
|
+
sys "git branch #{branch} origin/#{branch}"
|
89
|
+
sys "git checkout #{branch}"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
end
|
94
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'commands/map'
|
2
|
+
require 'commands/bug'
|
3
|
+
require 'commands/card'
|
4
|
+
require 'commands/chore'
|
5
|
+
require 'commands/feature'
|
6
|
+
|
7
|
+
module Commands
|
8
|
+
class Start
|
9
|
+
COMMAND_MAP = Map.new.merge({
|
10
|
+
"bug" => Commands::Bug,
|
11
|
+
"chore" => Commands::Chore,
|
12
|
+
"feature" => Commands::Feature,
|
13
|
+
/^\d+$/ => Commands::Card
|
14
|
+
})
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def for(*args)
|
18
|
+
identifier = args.shift
|
19
|
+
construct_instance_for(identifier, args) || display_usage_instructions_and_quit(identifier)
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def construct_instance_for(identifier, args)
|
25
|
+
if klass=COMMAND_MAP[identifier]
|
26
|
+
instance = klass.new(*args)
|
27
|
+
instance.story_id = identifier if instance.respond_to?(:story_id=)
|
28
|
+
instance
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def display_usage_instructions_and_quit(identifier)
|
33
|
+
puts "ERROR: Unknown card identifier given: '#{identifier}'. Valid options are 'bug', 'chore', 'feature', or the card number."
|
34
|
+
exit 1
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__))
|
2
|
+
|
3
|
+
require File.join('commands', 'base')
|
4
|
+
require File.join('commands', 'pick')
|
5
|
+
require File.join('commands', 'card')
|
6
|
+
require File.join('commands', 'feature')
|
7
|
+
require File.join('commands', 'bug')
|
8
|
+
require File.join('commands', 'chore')
|
9
|
+
require File.join('commands', 'finish')
|
10
|
+
require File.join('commands', 'info')
|
11
|
+
require File.join('commands', 'start')
|
data/readme.markdown
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
This is based on https://github.com/trydionel/git-pivotal but has an extended vision and set of goals to achieve.
|
2
|
+
|
3
|
+
Things like:
|
4
|
+
|
5
|
+
* Make the existing API more intuitive:
|
6
|
+
* git-bug, git-chore, git-feature should not be separate CLI commands. The common action is start, so goal here is to support "git-start _story\_type_"
|
7
|
+
* Users should be able to interact with specific stories when possible.
|
8
|
+
* e.g. "git start 123456" should start story 123456.
|
9
|
+
* being generic (interacting with next available or specific should apply to all applicable commands)
|
10
|
+
* Add more commands to interact with Pivotal:
|
11
|
+
* git comments
|
12
|
+
* git label
|
13
|
+
* git unstart
|
14
|
+
* Add verbosity and dry-run support to commands to communicate to the users what commands will be run
|
15
|
+
* Add before/after hooks extension points so people do not have to modify the project in order to do something custom.
|
16
|
+
* e.g. if you want to build a changelog as story's are finished, this should be able to be done by hooking into the "git finish" command and not require altering the code-base
|
17
|
+
* better support for handling merge conflicts (_this may be nothing more than communicating better to the user if a merge conflict happens when issuing a command_)
|
18
|
+
|
19
|
+
The main vision for this is simple: Encourage and support good practices and be flexible.
|
20
|
+
|
21
|
+
More README to come. See ISSUES for things I want to tackle in this project.
|
22
|
+
|
23
|
+
## The workflow
|
24
|
+
|
25
|
+
1. Assign the story to yourself (or have someone assign it to you)
|
26
|
+
2. From _master_, `git start <story_type>`, where story\_type is either 'bug', 'chore', 'feature', or the story number. A new branch will be created, and you will be automatically switched to it. The story will also be marked as started.
|
27
|
+
3. WRITE ALL THE CODE!, create pull request, merge into master.
|
28
|
+
4. `git finish`. This will destroy the local and remote branches, and mark the story as finished.
|
29
|
+
|
30
|
+
### git start - Starting the next available Feature/Bug/Chore
|
31
|
+
|
32
|
+
git start <story_type>
|
33
|
+
|
34
|
+
Replace story\_type in the above command to start the next available story in your Pivotal project, e.g.:
|
35
|
+
|
36
|
+
1 git-pivotal:master % git start feature
|
37
|
+
Retrieving latest features from Pivotal Tracker for John Wood...
|
38
|
+
Story: Test the tracker gem
|
39
|
+
URL: http://www.pivotaltracker.com/story/show/38895179
|
40
|
+
|
41
|
+
Start feature 38895179 - Test the tracker gem? (Y/n): Y
|
42
|
+
Updating feature status in Pivotal Tracker...
|
43
|
+
Enter branch name [38895179-test-the-tracker-gem]:
|
44
|
+
git branch
|
45
|
+
Creating remote branch '38895179-test-the-tracker-gem'
|
46
|
+
git push origin origin:refs/heads/38895179-test-the-tracker-gem
|
47
|
+
Total 0 (delta 0), reused 0 (delta 0)
|
48
|
+
To git@github.com:centro/git-pivotal.git
|
49
|
+
* [new branch] origin/HEAD -> 38895179-test-the-tracker-gem
|
50
|
+
git fetch origin
|
51
|
+
Switched to a new branch '38895179-test-the-tracker-gem'
|
52
|
+
git branch 38895179-test-the-tracker-gem origin/38895179-test-the-tracker-gem
|
53
|
+
Branch 38895179-test-the-tracker-gem set up to track remote branch 38895179-test-the-tracker-gem from origin.
|
54
|
+
git checkout 38895179-test-the-tracker-gem
|
55
|
+
Switched to branch '38895179-test-the-tracker-gem'
|
56
|
+
2 git-pivotal:38895179-test-the-tracker-gem %
|
57
|
+
|
58
|
+
### git finish
|
59
|
+
When on a feature branch, this command will close the associated story in Pivotal Tracker and remove the feature branch.
|
60
|
+
|
61
|
+
3 git-pivotal:38895179-test-the-tracker-gem % git finish
|
62
|
+
git symbolic-ref HEAD
|
63
|
+
Finish story 38895179 and delete local and remote branches? (y/N): y
|
64
|
+
Switching to master
|
65
|
+
git co master
|
66
|
+
Switched to branch 'master'
|
67
|
+
Destroying local branch
|
68
|
+
git branch -d 38895179-test-the-tracker-gem
|
69
|
+
Deleted branch 38895179-test-the-tracker-gem (was 99e52a3).
|
70
|
+
Destroying remote branch
|
71
|
+
git push origin :38895179-test-the-tracker-gem
|
72
|
+
To git@github.com:centro/git-pivotal.git
|
73
|
+
- [deleted] 38895179-test-the-tracker-gem
|
74
|
+
Marking Story 38895179 as finished...
|
75
|
+
4 git-pivotal:master %
|
76
|
+
|
77
|
+
### git info
|
78
|
+
When on a feature/bug/chore branch, this command will display the story information as recorded in Pivotal Tracker.
|
79
|
+
|
80
|
+
5 git-pivotal:1234567-testing % git info
|
81
|
+
Story: Test git pivotal
|
82
|
+
URL: http://www.pivotaltracker.com/story/show/1234567
|
83
|
+
Description: The awesome story description
|
84
|
+
6 git-pivotal:1234567-testing %
|
85
|
+
|
86
|
+
## Installation
|
87
|
+
|
88
|
+
_This section is out of date and applies to the original project. It needs to be updated._
|
89
|
+
|
90
|
+
To install git-pivotal, simply run
|
91
|
+
|
92
|
+
[sudo] gem install git-pivotal
|
93
|
+
|
94
|
+
## Configuration
|
95
|
+
|
96
|
+
Once installed, git pivotal needs three bits of info: your Pivotal Tracker API Token, your name as it appears in Pivotal Tracker and your Pivotal Tracker project id. The former two are best set as a global git config options:
|
97
|
+
|
98
|
+
git config --global pivotal.api-token 9a9a9a9a9a9a9a9a9a9a
|
99
|
+
git config --global pivotal.full-name "Jeff Tucker"
|
100
|
+
|
101
|
+
The project id is best placed within your project's git config:
|
102
|
+
|
103
|
+
git config -f .git/config pivotal.project-id 88888
|
104
|
+
|
105
|
+
If you're not interested in storing these options in git, you can pass them into git pivotal as command line arguments. See the usage guides for more details.
|
106
|
+
|