pivotal-github 0.9.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2cf1d7330fa22931ced51a6ce0baee166398bb85
4
- data.tar.gz: 84637ffaa50fb94a614f009e7574751009dcfb4a
3
+ metadata.gz: 3b1327c6aeb3947b802849284a92b1f8f613454f
4
+ data.tar.gz: d149aee10919ff595cec2185b42981cd022fec2b
5
5
  SHA512:
6
- metadata.gz: 84860bbddad7a50082bbe3e1033705ce6106639f3a2eafe326d71e6aabebec630e4edee4b06cd91e6f34d43ece0f5b6b57df4928d9f9f8bcef7dbb4eda0bdfb8
7
- data.tar.gz: 126f27130bf770caf84c099a644dd098b4aff6c1f5e4e60795e414d3ada2b314c7ebeacb048b071f12cd6b22deaf1959cc5f467eda8055f3e3932b28624634e9
6
+ metadata.gz: ec6de0af73b760f7db2cf8f966df795cc69af8564cac7c637a3e23803603c98a25c8e7be8a08fb7f836389364d6207343ce0a93e0de0afa11bffc4ac1a120977
7
+ data.tar.gz: 43737ee77614a033099f5097694f70ac78da05b41b32a37d79e75650dadbfdc63f70d552f27a9afee529be5e02fc337668dea0532f8c640f3d2274c7248b8062
@@ -0,0 +1 @@
1
+ faed06d1e5f6dfd030e451c34b24ab68
@@ -0,0 +1 @@
1
+ 745955
data/Gemfile CHANGED
@@ -3,6 +3,8 @@ ruby '2.0.0'
3
3
 
4
4
  gem 'rspec', '~> 2.13.0'
5
5
  gem 'httparty', '~> 0.10.0'
6
+ gem 'git'
7
+ gem 'nokogiri'
6
8
 
7
9
  # Specify your gem's dependencies in pivotal-github.gemspec
8
10
  gemspec
data/README.md CHANGED
@@ -125,6 +125,23 @@ As with `git story-merge`, by default `git story-pull-request` exits with a warn
125
125
  -o, --override override unfinished story warning
126
126
  -h, --help this usage guide
127
127
 
128
+ ### git story-accept
129
+
130
+ `git story-accept` examines the repository log and changes every **Delivered** story to **Accepted**. This makes it possible to accept a pull request by merging into master and then mark all the associated stories **Accepted** by running `git story-accept`. This saves having to manually keep track of the correspondences.
131
+
132
+ The purpose of `git story-accept` is to accept stories that have been merged into `master`, so by default it works only on the master branch. This requirement can be overridden by the `--override` option.
133
+
134
+ In order to avoid reading the entire Git log every time it's run, by default `git story-accept` stops immediately after finding a story that has already been accepted. The assumption is that `git story-accept` is run immediately after merging a pull request into a master branch that is always up-to-date, so that there are no delivered but unaccepted stories further down in the log.
135
+
136
+ `git story-accept` requires the existence of `.api_token` and `.project_id` files containing the Pivotal Tracker API token and project id, respectively. The user is prompted to create them if they are not present. (They aren't read from the command line using `gets` due to an incompatibility with options passing.)
137
+
138
+ #### Options
139
+
140
+ Usage: git story-accept
141
+ -o, --override override master branch requirement
142
+ -a, --all process all stories (entire log)
143
+ -h, --help this usage guide
144
+
128
145
  ### story-open
129
146
 
130
147
  The `story-open` command (no `git`) opens the current story in the default browser (OS X–only):
@@ -134,13 +151,14 @@ The `story-open` command (no `git`) opens the current story in the default brows
134
151
 
135
152
  ## Configuration
136
153
 
137
- In order to use the `pivotal-github` gem, you need to configure a post-receive hook for your repository. At GitHub, navigate to `Settings > Service Hooks > Pivotal Tracker` and paste in your Pivotal Tracker API token. (To find your Pivotal Tracker API token, go to your user profile and scroll to the bottom.) Be sure to check the **Active** box to activate the post-receive hook. At Bitbucket, click on the gear icon to view the settings, click on `Services`, select `Pivotal Tracker`, and paste in your Pivotal Tracker API key.
154
+ In order to use the `pivotal-github` gem, you need to configure a post-receive hook for your repository. At GitHub, navigate to `Settings > Service Hooks > Pivotal Tracker` and paste in your Pivotal Tracker API token. (To find your Pivotal Tracker API token, go to your user profile and scroll to the bottom.) Be sure to check the **Active** box to activate the post-receive hook. At Bitbucket, click on the gear icon to view the settings, click on `Services`, select `Pivotal Tracker`, and paste in your Pivotal Tracker API key. In addition, the `git story-accept` command requires the existence of `.api_token` and `.project_id` files containing the Pivotal Tracker API token and project id, respectively.
138
155
 
139
156
  The `pivotal-github` command names follow the Git convention of being verbose (e.g., unlike Subversion, Git doesn't natively support `co` for `checkout`), but I recommend setting up aliases as necessary. Here are some suggestions, formatted so that they can be pasted directly into a terminal window:
140
157
 
141
158
  git config --global alias.sc story-commit
142
159
  git config --global alias.sm story-merge
143
160
  git config --global alias.spr story-pull-request
161
+ git config --global alias.sa story-accept
144
162
 
145
163
  I also recommend setting up an alias for `git push-branch` from [git-utils](https://github.com/mhartl/git-utils):
146
164
 
@@ -161,12 +179,13 @@ A single-developer workflow would then look like this:
161
179
  $ git sync
162
180
  $ git rebase master
163
181
  $ git sm
182
+ $ git sa
164
183
 
165
- Here `git sync` is also from [git-utils](https://github.com/mhartl/git-utils).
184
+ Here `git sync` is from [git-utils](https://github.com/mhartl/git-utils).
166
185
 
167
186
  ## Workflow with integrated code reivew
168
187
 
169
- The `pivotal-github` gem is degined to support a workflow involving integrated code review, which has the usual benefits: at least two pairs of eyes see any committed code, and at least two brains know basically what the committed code does. The cost is that having a second developer involved can slow you down. I suggest using your judgment to determine which workflow makes the most sense on a story-by-story basis.
188
+ The `pivotal-github` gem is designed to support a workflow involving integrated code review, which has the usual benefits: at least two pairs of eyes see any committed code, and at least two brains know basically what the committed code does. The cost is that having a second developer involved can slow you down. I suggest using your judgment to determine which workflow makes the most sense on a story-by-story basis.
170
189
 
171
190
  Here's the process in detail:
172
191
 
@@ -192,7 +211,7 @@ Rather than immediately submitting a pull request, Alice can also continue by br
192
211
  ### Developer #2 (Bob)
193
212
 
194
213
  1. Select **Pull Requests** at GitHub and review the pull request diffs
195
- 2. If acceptable, merge the branch by clicking on the button at GitHub, and optionally accept the story at Pivotal Tracker
214
+ 2. If acceptable, merge the pull request into master, run `git pull` on `master` to pull in the changes, and run `git story-accept` to mark the corresponding stories accepted
196
215
  3. If not acceptable, manually change the state at Pivotal Tracker to **Rejected** and leave a note (at GitHub or at Pivotal Tracker) indicating the reason
197
216
  4. If the branch can't be automatically merged, mark the story as **Rejected**
198
217
 
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
3
+ require 'pivotal-github/story_accept'
4
+
5
+ exit Command.run!(StoryAccept, ARGV.dup)
@@ -5,3 +5,4 @@ require "pivotal-github/story_commit"
5
5
  require "pivotal-github/story_merge"
6
6
  require "pivotal-github/story_open"
7
7
  require "pivotal-github/story_pull_request"
8
+ require "pivotal-github/story_accept"
@@ -0,0 +1,105 @@
1
+ require 'pivotal-github/command'
2
+ require 'git'
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'nokogiri'
6
+
7
+ class StoryAccept < Command
8
+
9
+ def parser
10
+ OptionParser.new do |opts|
11
+ opts.banner = "Usage: git story-accept"
12
+ opts.on("-o", "--override", "override master branch requirement") do |opt|
13
+ self.options.override = opt
14
+ end
15
+ opts.on("-a", "--all", "process all stories (entire log)") do |opt|
16
+ self.options.all = opt
17
+ end
18
+ opts.on_tail("-h", "--help", "this usage guide") do
19
+ puts opts.to_s; exit 0
20
+ end
21
+ end
22
+ end
23
+
24
+ # Returns the ids to accept.
25
+ # These ids are of the form [Delivers #<story id>] or
26
+ # [Delivers #<story id> #<another story id>].
27
+ def ids_to_accept
28
+ delivered_regex = /\[Deliver(?:s|ed) (.*?)\]/
29
+ Git.open('.').log.inject([]) do |delivered_ids, commit|
30
+ message = commit.message
31
+ delivered = message.scan(delivered_regex).flatten
32
+ commit_ids = delivered.inject([]) do |ids, element|
33
+ ids.concat(element.scan(/[0-9]{8,}/).flatten)
34
+ ids
35
+ end
36
+ commit_ids.each do |commit_id|
37
+ return delivered_ids if already_accepted?(commit_id) && !options['all']
38
+ delivered_ids << commit_id
39
+ delivered_ids.uniq!
40
+ end
41
+ delivered_ids
42
+ end
43
+ end
44
+
45
+ # Returns true if a story has already been accepted.
46
+ def already_accepted?(story_id)
47
+ data = { 'X-TrackerToken' => api_token,
48
+ 'Content-type' => "application/xml" }
49
+ response = Net::HTTP.start(story_uri.host, story_uri.port) do |http|
50
+ http.get(story_uri.path, data)
51
+ end
52
+ Nokogiri::XML(response.body).at_css('current_state').content == "accepted"
53
+ end
54
+
55
+ def api_token
56
+ api_filename = '.api_token'
57
+ if File.exist?(api_filename)
58
+ @api_token ||= File.read(api_filename).strip
59
+ else
60
+ puts "Please create a file called '#{api_filename}'"
61
+ puts "containing your Pivotal Tracker API token."
62
+ exit 1
63
+ end
64
+ end
65
+
66
+ def project_id
67
+ project_id_filename = '.project_id'
68
+ if File.exist?(project_id_filename)
69
+ @project_id_filename ||= File.read(project_id_filename)
70
+ else
71
+ puts "Please create a file called '#{project_id}'"
72
+ puts "containing the Pivotal Tracker project number."
73
+ exit 1
74
+ end
75
+ end
76
+
77
+ # Changes a story's state to **Accepted**.
78
+ def accept!(story_id)
79
+ accepted = "<story><current_state>accepted</current_state></story>"
80
+ data = { 'X-TrackerToken' => api_token,
81
+ 'Content-type' => "application/xml" }
82
+ Net::HTTP.start(story_uri.host, story_uri.port) do |http|
83
+ http.put(story_uri.path, accepted, data)
84
+ end
85
+ end
86
+
87
+ def run!
88
+ if story_branch != 'master' && !options['override']
89
+ puts "Runs only on the master branch by default"
90
+ puts "Use --override to override"
91
+ exit 1
92
+ end
93
+ ids_to_accept.each { |id| accept!(id) }
94
+ end
95
+
96
+ private
97
+
98
+ def api_base
99
+ 'http://www.pivotaltracker.com/services/v3'
100
+ end
101
+
102
+ def story_uri
103
+ URI.parse("#{api_base}/projects/#{project_id}/stories/#{story_id}")
104
+ end
105
+ end
@@ -1,5 +1,5 @@
1
1
  module Pivotal
2
2
  module Github
3
- VERSION = "0.9.1"
3
+ VERSION = "1.0.0"
4
4
  end
5
5
  end
@@ -0,0 +1,56 @@
1
+ require 'spec_helper'
2
+
3
+ describe StoryAccept do
4
+
5
+ let(:command) { StoryAccept.new(['-o', '-a']) }
6
+ before do
7
+ command.stub(:story_branch).and_return('62831853-tau-manifesto')
8
+ command.stub(:already_accepted?).and_return(false)
9
+ end
10
+ subject { command }
11
+
12
+ it { should respond_to(:ids_to_accept) }
13
+
14
+ describe "ids_to_accept" do
15
+ let(:ids) { command.ids_to_accept }
16
+ subject { ids }
17
+
18
+ it { should_not be_empty }
19
+ it { should include("51204529") }
20
+ it { should include("51106181") }
21
+ it { should include("50566167") }
22
+
23
+ it "should not have duplicate ids" do
24
+ expect(ids).to eq ids.uniq
25
+ end
26
+ end
27
+
28
+
29
+ its(:api_token) { should_not be_empty }
30
+
31
+ describe "accept!" do
32
+ before do
33
+ command.stub(:accept!)
34
+ end
35
+
36
+ it "should accept each id" do
37
+ number_accepted = command.ids_to_accept.length
38
+ command.should_receive(:accept!).exactly(number_accepted).times
39
+ command.run!
40
+ end
41
+ end
42
+
43
+ describe "when stopping upon reading the first accepted id" do
44
+ let(:command) { StoryAccept.new(['-o']) }
45
+ before do
46
+ command.stub(:story_branch).and_return('62831853-tau-manifesto')
47
+ command.stub(:already_accepted?).and_return(false)
48
+ command.stub(:already_accepted?).with("50566167").and_return(true)
49
+ end
50
+ subject { command }
51
+
52
+ its(:ids_to_accept) { should include("51204529") }
53
+ its(:ids_to_accept) { should include("51106181") }
54
+ its(:ids_to_accept) { should_not include("50566167") }
55
+ end
56
+ end
metadata CHANGED
@@ -1,19 +1,20 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pivotal-github
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Hartl
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-06-09 00:00:00.000000000 Z
11
+ date: 2013-06-18 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Add commands for Pivotal Tracker-GitHub integration
14
14
  email:
15
15
  - michael@michaelhartl.com
16
16
  executables:
17
+ - git-story-accept
17
18
  - git-story-commit
18
19
  - git-story-merge
19
20
  - git-story-pull-request
@@ -21,7 +22,9 @@ executables:
21
22
  extensions: []
22
23
  extra_rdoc_files: []
23
24
  files:
25
+ - .api_token
24
26
  - .gitignore
27
+ - .project_id
25
28
  - .rspec
26
29
  - .ruby-gemset
27
30
  - .ruby-version
@@ -29,6 +32,7 @@ files:
29
32
  - LICENSE.txt
30
33
  - README.md
31
34
  - Rakefile
35
+ - bin/git-story-accept
32
36
  - bin/git-story-commit
33
37
  - bin/git-story-merge
34
38
  - bin/git-story-pull-request
@@ -37,6 +41,7 @@ files:
37
41
  - lib/pivotal-github/command.rb
38
42
  - lib/pivotal-github/finished_command.rb
39
43
  - lib/pivotal-github/options.rb
44
+ - lib/pivotal-github/story_accept.rb
40
45
  - lib/pivotal-github/story_commit.rb
41
46
  - lib/pivotal-github/story_merge.rb
42
47
  - lib/pivotal-github/story_open.rb
@@ -44,6 +49,7 @@ files:
44
49
  - lib/pivotal-github/version.rb
45
50
  - pivotal-github.gemspec
46
51
  - spec/commands/command_spec.rb
52
+ - spec/commands/story_accept_spec.rb
47
53
  - spec/commands/story_commit_spec.rb
48
54
  - spec/commands/story_merge_spec.rb
49
55
  - spec/commands/story_open_spec.rb
@@ -75,6 +81,7 @@ specification_version: 4
75
81
  summary: See the README for full documentation
76
82
  test_files:
77
83
  - spec/commands/command_spec.rb
84
+ - spec/commands/story_accept_spec.rb
78
85
  - spec/commands/story_commit_spec.rb
79
86
  - spec/commands/story_merge_spec.rb
80
87
  - spec/commands/story_open_spec.rb