pivotal-github 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/Gemfile +7 -0
- data/LICENSE.txt +22 -0
- data/README.md +170 -0
- data/Rakefile +1 -0
- data/bin/git-story-commit +5 -0
- data/bin/git-story-merge +5 -0
- data/bin/git-story-pull +6 -0
- data/bin/git-story-push +3 -0
- data/lib/pivotal-github.rb +4 -0
- data/lib/pivotal-github/command.rb +52 -0
- data/lib/pivotal-github/options.rb +33 -0
- data/lib/pivotal-github/story_commit.rb +83 -0
- data/lib/pivotal-github/version.rb +5 -0
- data/pivotal-github.gemspec +19 -0
- data/spec/commands/story_commit_spec.rb +97 -0
- data/spec/options/options_spec.rb +54 -0
- data/spec/spec_helper.rb +9 -0
- metadata +71 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Michael Hartl
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,170 @@
|
|
1
|
+
# pivotal-github
|
2
|
+
|
3
|
+
**NOTE:** This gem is as-yet unreleased.
|
4
|
+
|
5
|
+
This gem facilitates a Pivotal Tracker–GitHub workflow inspired by [Logical Reality](http://lrdesign.com/).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'pivotal-github'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install pivotal-github
|
20
|
+
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
The `pivotal-github` gem adds several additional Git commands to the local environment.
|
25
|
+
|
26
|
+
### git story-commit
|
27
|
+
|
28
|
+
`git story-commit` makes a standard `git commit` with the story number added to the commit message. This automatically adds a link at Pivotal Tracker between the story and the diff at GitHub.
|
29
|
+
|
30
|
+
For example, when on a branch called `6283185-add-markdown-support`, the `git story-commit` command automatically adds `[#6283185]` to the commit message:
|
31
|
+
|
32
|
+
$ git story-commit -am "Add foo bars"
|
33
|
+
[6283185-add-markdown-support 6f56414] [#6283185] Add foo bars
|
34
|
+
|
35
|
+
|
36
|
+
Here's the full usage info:
|
37
|
+
|
38
|
+
$ git story-commit -h
|
39
|
+
Usage: git story-commit [options]
|
40
|
+
-m, --message MESSAGE add a commit message (including story #)
|
41
|
+
-f, --finish mark story as finished
|
42
|
+
-d, --deliver mark story as delivered
|
43
|
+
-a, --all commit all changed files
|
44
|
+
-h, --help this usage guide
|
45
|
+
|
46
|
+
Additionally, `git story-commit` accepts any options valid for `git commit`.
|
47
|
+
|
48
|
+
### git story-push
|
49
|
+
|
50
|
+
`git story push` creates a remote branch at `origin` with the name of the current branch:
|
51
|
+
|
52
|
+
$ git story-push
|
53
|
+
* [new branch] 6283185-add-markdown-support -> 6283185-add-markdown-support
|
54
|
+
|
55
|
+
this usage guide
|
56
|
+
|
57
|
+
`git story-push` accepts any options valid for `git push`.
|
58
|
+
|
59
|
+
### git story-pull
|
60
|
+
|
61
|
+
`git story-pull` syncs the local `master` with the remote `master`. On a branch called `6283185-add-markdown-support`, `git story-pull` is equivalent to the following:
|
62
|
+
|
63
|
+
$ git checkout master
|
64
|
+
$ git pull
|
65
|
+
$ git checkout 6283185-add-markdown-support
|
66
|
+
|
67
|
+
The purpose of `git story-pull` it to prepare the local story branch for rebasing against `master`:
|
68
|
+
|
69
|
+
$ git story-pull
|
70
|
+
$ git rebase master
|
71
|
+
|
72
|
+
This is essentially equivalent to
|
73
|
+
|
74
|
+
$ git fetch
|
75
|
+
$ git rebase origin/master
|
76
|
+
|
77
|
+
but I don't like having `master` and `origin/master` be different since it forces you to remember to run `git pull` on `master` some time down the line.
|
78
|
+
|
79
|
+
### git story-merge
|
80
|
+
|
81
|
+
`git story-merge` merges the current branch into `master`. On a branch called `6283185-add-markdown-support`, `git story-merge` is equivalent to the following:
|
82
|
+
|
83
|
+
$ git checkout master
|
84
|
+
$ git merge 6283185-add-markdown-support
|
85
|
+
|
86
|
+
## Configuration
|
87
|
+
|
88
|
+
In order to use the `pivotal-github` gem, you need to configure a [post-receive hook for Pivotal Tracker at GitHub](https://www.pivotaltracker.com/help/api?version=v3#github_hooks) for your repository. (To find your Pivotal Tracker API token, go to your user profile and scroll to the bottom.)
|
89
|
+
|
90
|
+
The `pivotal-github` command names follow the Git convention of being verbose (it's telling that, unlike Subversion, Git doesn't natively support `co` for `checkout`), but I recommend setting up aliases as necessary. Here are some suggestions:
|
91
|
+
|
92
|
+
$ git config --global alias.sc story-commit
|
93
|
+
$ git config --global alias.sp story-push
|
94
|
+
$ git config --global alias.sl story-pull
|
95
|
+
$ git config --global alias.sm story-merge
|
96
|
+
|
97
|
+
A single-developer workflow would then look like this:
|
98
|
+
|
99
|
+
$ git co -b 6283185-add-markdown-support
|
100
|
+
$ git sp
|
101
|
+
<work>
|
102
|
+
$ git sc -am "Added foo"
|
103
|
+
$ git push
|
104
|
+
<more work>
|
105
|
+
$ git sc -am "Added bar"
|
106
|
+
<complete story>
|
107
|
+
$ git sc -f -am "Added baz"
|
108
|
+
$ git push
|
109
|
+
$ git sl
|
110
|
+
$ git rebase master
|
111
|
+
$ git sm
|
112
|
+
|
113
|
+
Note that this workflow uses `git sp` (and subsequent invocations of `git push`) only to create a remote storage backup. The principal purpose of `git story-push` is to support the integrated code review workflow described below.
|
114
|
+
|
115
|
+
## Workflow
|
116
|
+
|
117
|
+
The `pivotal-github` gem is degined to support a workflow that involves integrated code review, which has the usual advantages: at least two pairs of eyes see any committed code, and at least two brains know basically what the committed code does. Here's the process in detail:
|
118
|
+
|
119
|
+
### Developer #1 (Alice)
|
120
|
+
|
121
|
+
1. Start an issue at [Pivotal Tracker](http://pivotaltracker.com/)
|
122
|
+
2. Create a branch in the local Git repository containing the story number and a brief description: `git checkout -b 6283185-add-markdown-support`
|
123
|
+
3. Create a remote branch at [GitHub](http://github.com/) using `git story-push`
|
124
|
+
3. Use `git story-commit` to make commits, which includes the story number in the commit message: `git story-commit -am "Add syntax highlighting"`
|
125
|
+
4. Continue pushing up after each commit using `git push` as usual
|
126
|
+
4. When done with the story, add `-f` to mark the story as finished: `git story-commit -f -am "Add paragraph breaks"`
|
127
|
+
4. Rebase against `master` using `git story-pull` followed by `git rebase master` or `git rebase master --interactive` (optionally squashing commit messages as described in the article [A Git Workflow for Agile Teams](http://reinh.com/blog/2009/03/02/a-git-workflow-for-agile-teams.html))
|
128
|
+
4. Push up with `git push`
|
129
|
+
6. At the GitHub page for the repo, select "Branches" and submit a pull request
|
130
|
+
7. **(experimental)** Add a story of type Chore to Pivotal Tracker and assign it to Developer #2 (Bob)
|
131
|
+
|
132
|
+
|
133
|
+
### Developer #2 (Bob)
|
134
|
+
|
135
|
+
1. Review the pull request diffs
|
136
|
+
2. If acceptable, merge the branch
|
137
|
+
3. If not acceptable, manually change the state at Pivotal Tracker to Rejected
|
138
|
+
4. **(experimental)** If there are conflicts, make a Chore to resolve the conflicts and assign it to Alice
|
139
|
+
|
140
|
+
Until Bob accepts the pull request, Alice can continue working on new stories, taking care to branch off of the current branch if she needs its changes to continue. Note that the commits will appear on the story as soon as Alice creates a remote branch (and as she pushes to it), but it won't be marked 'finished' or 'delivered' until Bob merges the pull request into `master`.
|
141
|
+
|
142
|
+
## Merge conflicts
|
143
|
+
|
144
|
+
This section contains some suggestions for resolving merge conflicts. First, set up a visual merge tool by installing [diffmerge](http://www.sourcegear.com/diffmerge/). Then add the following to the `.gitconfig` file in your home directory:
|
145
|
+
|
146
|
+
[mergetool "diffmerge"]
|
147
|
+
cmd = diffmerge --merge --result=$MERGED $LOCAL $BASE $REMOTE
|
148
|
+
trustExitCode = false
|
149
|
+
|
150
|
+
When the branch can't automatically be merged at GitHub, follow these steps:
|
151
|
+
|
152
|
+
### Devleloper #1 (Alice)
|
153
|
+
|
154
|
+
1. While on the story branch, run `git story-pull`
|
155
|
+
2. Rebase against `master` with `git rebase master` **or** merge with `master` using `git merge master`
|
156
|
+
4. Either handle resulting conflicts by hand or use the visual merge tool: `git mergetool`
|
157
|
+
5. Commit the change: `git commit -a`
|
158
|
+
6. Push up the modified branch: `git push`
|
159
|
+
7. **(experimental)** Add a Chore to revisit the pull request and assign to Developer #2 (Bob)
|
160
|
+
|
161
|
+
|
162
|
+
Now Bob should be able to merge in the pull request automatically using the nice big green button at GitHub.
|
163
|
+
|
164
|
+
## Contributing
|
165
|
+
|
166
|
+
1. Fork it
|
167
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
168
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
169
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
170
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/bin/git-story-merge
ADDED
data/bin/git-story-pull
ADDED
data/bin/git-story-push
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
class Command
|
2
|
+
attr_accessor :args, :cmd, :options, :known_options, :unknown_options
|
3
|
+
|
4
|
+
def initialize(args = [])
|
5
|
+
self.args = args
|
6
|
+
parse
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse
|
10
|
+
raise "Define in derived class"
|
11
|
+
end
|
12
|
+
|
13
|
+
def current_branch
|
14
|
+
`git rev-parse --abbrev-ref HEAD`.strip
|
15
|
+
end
|
16
|
+
|
17
|
+
def story_id
|
18
|
+
current_branch.scan(/\d+/).first
|
19
|
+
end
|
20
|
+
|
21
|
+
def options
|
22
|
+
@options ||= parse
|
23
|
+
end
|
24
|
+
|
25
|
+
# Runs a command
|
26
|
+
# If the argument array contains '--debug', returns the command that would
|
27
|
+
# have been run
|
28
|
+
def self.run!(command_class, args)
|
29
|
+
debug = args.delete('--debug')
|
30
|
+
command = command_class.new(args)
|
31
|
+
if debug
|
32
|
+
puts command.cmd
|
33
|
+
return 1
|
34
|
+
else
|
35
|
+
command.run!
|
36
|
+
return 0
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
# Returns an argument string based on given arguments
|
43
|
+
# The main trick is to add in quotes for option
|
44
|
+
# arguments when necessary.
|
45
|
+
# For example, ['-a', '-m', 'foo bar'] becomes
|
46
|
+
# '-a -m "foo bar"'
|
47
|
+
def argument_string(args)
|
48
|
+
args.inject([]) do |opts, opt|
|
49
|
+
opts << (opt =~ /^-/ ? opt : opt.inspect)
|
50
|
+
end.join(' ')
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module Options
|
4
|
+
|
5
|
+
# Returns a list of options unknown to a particular options parser
|
6
|
+
# For example, if '-a' is a known option but '-b' and '-c' are not,
|
7
|
+
# unknown_options(parser, ['-a', '-b', '-c']) returns ['-b', '-c'].
|
8
|
+
# It also preserves arguments, so
|
9
|
+
# unknown_options(parser, ['-a', '-b', '-c', 'foo bar']) returns
|
10
|
+
# ['-b', '-c', 'foo bar'].
|
11
|
+
def self.unknown_options(parser, args)
|
12
|
+
unknown = []
|
13
|
+
recursive_parse = Proc.new do |arg_list|
|
14
|
+
begin
|
15
|
+
parser.parse!(arg_list)
|
16
|
+
rescue OptionParser::InvalidOption => e
|
17
|
+
unknown.concat(e.args)
|
18
|
+
while !arg_list.empty? && arg_list.first[0] != "-"
|
19
|
+
unknown << arg_list.shift
|
20
|
+
end
|
21
|
+
recursive_parse.call(arg_list)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
recursive_parse.call(args.dup)
|
25
|
+
unknown
|
26
|
+
end
|
27
|
+
|
28
|
+
# Returns a list of options with unknown options removed
|
29
|
+
def self.known_options(parser, args)
|
30
|
+
unknown = unknown_options(parser, args)
|
31
|
+
args.reject { |arg| unknown.include?(arg) }
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'pivotal-github/options'
|
4
|
+
require 'pivotal-github/command'
|
5
|
+
|
6
|
+
class StoryCommit < Command
|
7
|
+
|
8
|
+
def parse
|
9
|
+
options = OpenStruct.new
|
10
|
+
parser = OptionParser.new do |opts|
|
11
|
+
opts.banner = "Usage: git story-commit [options]"
|
12
|
+
opts.on("-m", "--message MESSAGE",
|
13
|
+
"add a commit message (including story #)") do |m|
|
14
|
+
options.message = m
|
15
|
+
end
|
16
|
+
opts.on("-f", "--finish", "mark story as finished") do |f|
|
17
|
+
options.finish = f
|
18
|
+
end
|
19
|
+
opts.on("-d", "--deliver", "mark story as delivered") do |d|
|
20
|
+
options.deliver = d
|
21
|
+
end
|
22
|
+
opts.on("-a", "--all", "commit all changed files") do |a|
|
23
|
+
options.all = a
|
24
|
+
end
|
25
|
+
opts.on_tail("-h", "--help", "this usage guide") do
|
26
|
+
puts opts.to_s; exit 0
|
27
|
+
end
|
28
|
+
end
|
29
|
+
self.known_options = Options::known_options(parser, args)
|
30
|
+
self.unknown_options = Options::unknown_options(parser, args)
|
31
|
+
parser.parse(known_options)
|
32
|
+
options
|
33
|
+
end
|
34
|
+
|
35
|
+
def message
|
36
|
+
if story_id.nil?
|
37
|
+
# Arranges to fall through to regular 'git commit'
|
38
|
+
options.message
|
39
|
+
else
|
40
|
+
if finish?
|
41
|
+
label = "Finishes ##{story_id}"
|
42
|
+
elsif deliver?
|
43
|
+
label = "Delivers ##{story_id}"
|
44
|
+
else
|
45
|
+
label = "##{story_id}"
|
46
|
+
end
|
47
|
+
"[#{label}] #{options.message}"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns a command appropriate for executing at the command line
|
52
|
+
# We take care to insert the story number and, if necessary, an indication
|
53
|
+
# that the commit finishes the story.
|
54
|
+
def cmd
|
55
|
+
c = ['git commit']
|
56
|
+
c << '-a' if all?
|
57
|
+
c << %(-m "#{message}") if message?
|
58
|
+
c << argument_string(unknown_options) unless unknown_options.empty?
|
59
|
+
c.join(' ')
|
60
|
+
end
|
61
|
+
|
62
|
+
def run!
|
63
|
+
system cmd
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
def finish?
|
69
|
+
options.finish
|
70
|
+
end
|
71
|
+
|
72
|
+
def deliver?
|
73
|
+
options.deliver
|
74
|
+
end
|
75
|
+
|
76
|
+
def message?
|
77
|
+
!options.message.nil?
|
78
|
+
end
|
79
|
+
|
80
|
+
def all?
|
81
|
+
options.all
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'pivotal-github/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "pivotal-github"
|
8
|
+
gem.version = Pivotal::Github::VERSION
|
9
|
+
gem.authors = ["Michael Hartl"]
|
10
|
+
gem.email = ["michael@michaelhartl.com"]
|
11
|
+
gem.description = %q{Add commands for Pivotal Tracker–GitHub integration}
|
12
|
+
gem.summary = %q{See the README for full documentation}
|
13
|
+
gem.homepage = "https://github.com/mhartl/pivotal-github"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe StoryCommit do
|
4
|
+
|
5
|
+
before { command.stub(:current_branch).and_return('6283185-tau-manifesto') }
|
6
|
+
let(:command) { StoryCommit.new(['-m', 'message', '-a', '-z', '--foo']) }
|
7
|
+
subject { command }
|
8
|
+
|
9
|
+
it { should respond_to(:cmd) }
|
10
|
+
it { should respond_to(:args) }
|
11
|
+
it { should respond_to(:options) }
|
12
|
+
it { should respond_to(:parse) }
|
13
|
+
it { should respond_to(:message) }
|
14
|
+
it { should respond_to(:story_id) }
|
15
|
+
|
16
|
+
shared_examples "record with known options" do
|
17
|
+
subject { command }
|
18
|
+
|
19
|
+
its(:cmd) { should =~ /git commit/ }
|
20
|
+
its(:message) { should_not be_empty }
|
21
|
+
its(:message?) { should be_true }
|
22
|
+
its(:all?) { should be_true }
|
23
|
+
|
24
|
+
describe "parse" do
|
25
|
+
subject { command.options }
|
26
|
+
|
27
|
+
its(:message) { should == 'message' }
|
28
|
+
its(:all) { should be_true }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "with only known options" do
|
33
|
+
let(:command) { StoryCommit.new(['-m', 'message', '-a']) }
|
34
|
+
it_should_behave_like "record with known options"
|
35
|
+
end
|
36
|
+
|
37
|
+
describe "with a compound argument" do
|
38
|
+
let(:command) { StoryCommit.new(['-am', 'message']) }
|
39
|
+
it_should_behave_like "record with known options"
|
40
|
+
end
|
41
|
+
|
42
|
+
describe "with some unknown options" do
|
43
|
+
let(:command) { StoryCommit.new(['-m', 'message', '-a', '-z', '--foo']) }
|
44
|
+
|
45
|
+
it_should_behave_like "record with known options"
|
46
|
+
|
47
|
+
it "should not raise an error" do
|
48
|
+
expect { command.parse }.not_to raise_error(OptionParser::InvalidOption)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#story_id' do
|
53
|
+
subject { command.story_id }
|
54
|
+
it { should == '6283185' }
|
55
|
+
end
|
56
|
+
|
57
|
+
describe "command with message" do
|
58
|
+
its(:cmd) do
|
59
|
+
should == %(git commit -a -m "[##{command.story_id}] message" -z --foo)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "command with no message" do
|
64
|
+
let(:command) { StoryCommit.new(['-a', '-z', '--foo']) }
|
65
|
+
its(:cmd) { should == %(git commit -a -z --foo) }
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "command with finish flag" do
|
69
|
+
let(:command) { StoryCommit.new(['-m', 'message', '-f']) }
|
70
|
+
its(:cmd) do
|
71
|
+
should == %(git commit -m "[Finishes ##{command.story_id}] message")
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "command with deliver flag" do
|
76
|
+
let(:command) { StoryCommit.new(['-m', 'message', '-d']) }
|
77
|
+
its(:cmd) do
|
78
|
+
should == %(git commit -m "[Delivers ##{command.story_id}] message")
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
describe "command with no story id" do
|
83
|
+
before { command.stub(:current_branch).and_return('tau-manifesto') }
|
84
|
+
its(:cmd) do
|
85
|
+
should == %(git commit -a -m "message" -z --foo)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "command-line command" do
|
90
|
+
let(:command) { `bin/git-story-commit -a -m "message" -z --debug` }
|
91
|
+
subject { command }
|
92
|
+
it { should =~ /git commit -a -m/ }
|
93
|
+
it { should =~ /message/ }
|
94
|
+
it { should =~ /-z/ }
|
95
|
+
it { should_not =~ /--debug/ }
|
96
|
+
end
|
97
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
|
4
|
+
describe Options do
|
5
|
+
|
6
|
+
let(:options) { OpenStruct.new }
|
7
|
+
|
8
|
+
let(:parser) do
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.banner = "Usage: git record [options]"
|
11
|
+
opts.on("-m", "--message MESSAGE",
|
12
|
+
"add a commit message (with ticket #)") do |m|
|
13
|
+
options.message = m
|
14
|
+
end
|
15
|
+
opts.on("-a", "--all", "commit all changed files") do |a|
|
16
|
+
options.all = a
|
17
|
+
end
|
18
|
+
opts.on("-f", "--finish", "mark story as finished") do |f|
|
19
|
+
options.finish = f
|
20
|
+
end
|
21
|
+
opts.on_tail("-h", "--help", "this usage guide") do
|
22
|
+
puts opts.to_s; exit 0
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
let(:args) { ['-a', '-m', '"A message"', '--finish', '-z', '--foo', 'b ar'] }
|
28
|
+
|
29
|
+
it { should respond_to(:unknown_options) }
|
30
|
+
it { should respond_to(:known_options) }
|
31
|
+
|
32
|
+
describe '#unknown_options' do
|
33
|
+
subject { Options::unknown_options(parser, args) }
|
34
|
+
|
35
|
+
it { should include('-z') }
|
36
|
+
it { should include('--foo') }
|
37
|
+
it { should include('b ar') }
|
38
|
+
it { should_not include('-a') }
|
39
|
+
it { should_not include('-m') }
|
40
|
+
it { should_not include('"A message"') }
|
41
|
+
it { should_not include('--finish') }
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#known_options' do
|
45
|
+
subject { Options::known_options(parser, args) }
|
46
|
+
|
47
|
+
it { should_not include('-z') }
|
48
|
+
it { should_not include('--foo') }
|
49
|
+
it { should_not include('b ar') }
|
50
|
+
it { should include('-a') }
|
51
|
+
it { should include('-m') }
|
52
|
+
it { should include('"A message"') }
|
53
|
+
it { should include('--finish') } end
|
54
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pivotal-github
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Michael Hartl
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-07 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Add commands for Pivotal Tracker–GitHub integration
|
15
|
+
email:
|
16
|
+
- michael@michaelhartl.com
|
17
|
+
executables:
|
18
|
+
- git-story-commit
|
19
|
+
- git-story-merge
|
20
|
+
- git-story-pull
|
21
|
+
- git-story-push
|
22
|
+
extensions: []
|
23
|
+
extra_rdoc_files: []
|
24
|
+
files:
|
25
|
+
- .gitignore
|
26
|
+
- .rspec
|
27
|
+
- Gemfile
|
28
|
+
- LICENSE.txt
|
29
|
+
- README.md
|
30
|
+
- Rakefile
|
31
|
+
- bin/git-story-commit
|
32
|
+
- bin/git-story-merge
|
33
|
+
- bin/git-story-pull
|
34
|
+
- bin/git-story-push
|
35
|
+
- lib/pivotal-github.rb
|
36
|
+
- lib/pivotal-github/command.rb
|
37
|
+
- lib/pivotal-github/options.rb
|
38
|
+
- lib/pivotal-github/story_commit.rb
|
39
|
+
- lib/pivotal-github/version.rb
|
40
|
+
- pivotal-github.gemspec
|
41
|
+
- spec/commands/story_commit_spec.rb
|
42
|
+
- spec/options/options_spec.rb
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
homepage: https://github.com/mhartl/pivotal-github
|
45
|
+
licenses: []
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
require_paths:
|
49
|
+
- lib
|
50
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
51
|
+
none: false
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 1.8.23
|
65
|
+
signing_key:
|
66
|
+
specification_version: 3
|
67
|
+
summary: See the README for full documentation
|
68
|
+
test_files:
|
69
|
+
- spec/commands/story_commit_spec.rb
|
70
|
+
- spec/options/options_spec.rb
|
71
|
+
- spec/spec_helper.rb
|