gplan 0.1.2 → 0.1.3
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.
- checksums.yaml +7 -0
- data/README.md +61 -0
- data/Rakefile +12 -0
- data/bin/gplan +2 -105
- data/fixtures/vcr_cassettes/github_pull_requests.yml +161 -0
- data/gplan-0.1.3.gem +0 -0
- data/gplan.gemspec +19 -0
- data/lib/gplan.rb +90 -0
- data/lib/printer.rb +21 -2
- data/templates/template.html.haml +2 -2
- data/test/integration/release_notes_test.rb +43 -0
- data/test/test_helper.rb +15 -0
- data/test/unit/dependency_test.rb +81 -0
- metadata +30 -13
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 43c8051408d4828bfe25d3dffa8b618da215d17d
|
4
|
+
data.tar.gz: a06bb0ad26db3c187539255259abf0c3c50a5926
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 7a194113296b337a4489607b68d4c6d3563e77e5bec0935dd70934e167c54bc0584c645fa11ec4ca5e237482f645f20653300479b6e022b1dcdb8746cf82569f
|
7
|
+
data.tar.gz: fea17a6bce3a35c00ef5379c87ba614e23044d5a3e8131900d663bad35c96f857c2ac34facf51179817186879f36f6995785f61593c8f6d65e93786a1b87defd
|
data/README.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
[](http://badge.fury.io/rb/gplan)
|
2
|
+
|
3
|
+
## What is GPlan?
|
4
|
+
|
5
|
+
GPlan started out as a simple ruby script that parsed out ticket numbers
|
6
|
+
from any git log of the current branch compared to its production branch
|
7
|
+
and puts together release notes
|
8
|
+
|
9
|
+
As of right now, it does this by combining Github Pull Requests, Github Issues and Planbox Stories.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
gem install gplan
|
14
|
+
|
15
|
+
# Create environment variables
|
16
|
+
|
17
|
+
This will be different on every OS, but for OSX, I did this...
|
18
|
+
|
19
|
+
sudo echo "
|
20
|
+
#for planbox
|
21
|
+
export PLANBOX_EMAIL=<EMAIL_ADDRESS>
|
22
|
+
export PLANBOX_TOKEN=<PASSWORD>
|
23
|
+
export GITHUB_USERNAME=<GITHUB_USERNAME>
|
24
|
+
export GITHUB_TOKEN=<GITHUB_TOKEN>" >> /etc/profile
|
25
|
+
|
26
|
+
# Configure Project
|
27
|
+
|
28
|
+
For any project you want to use this for, you will need to tell gplan what repository/branch to compare your current branch to. To do this, create a `.gplan` file in the repository's root with `<repo_name>/<branch_name>`. If one isn't set, a default of `production/master` is used.
|
29
|
+
|
30
|
+
echo "origin/master" > .gplan
|
31
|
+
|
32
|
+
OR
|
33
|
+
|
34
|
+
pass in a param that overrides this configuration. ie.. `gplan 98ih2h3583`
|
35
|
+
|
36
|
+
## Usage
|
37
|
+
|
38
|
+
1. cd to git project
|
39
|
+
2. checkout the branch that you wish to get release notes for
|
40
|
+
3. run `gplan`
|
41
|
+
4. you should now get a list of the pattern
|
42
|
+
|
43
|
+
```
|
44
|
+
ID:STATUS:TITLE:PROJECT_NAME:PROJECT_ALIAS:PR:TITLE
|
45
|
+
...
|
46
|
+
---- Unmatched PRs ----
|
47
|
+
...
|
48
|
+
PR:TITLE
|
49
|
+
```
|
50
|
+
|
51
|
+
Note: unmatched PRs are github pull requests that doesn't have a matching planbox story
|
52
|
+
|
53
|
+
## Tests
|
54
|
+
|
55
|
+
To run tests:
|
56
|
+
|
57
|
+
rake test
|
58
|
+
|
59
|
+
or just
|
60
|
+
|
61
|
+
rake
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "rake/testtask"
|
2
|
+
|
3
|
+
Rake::TestTask.new do |t|
|
4
|
+
t.libs << "test"
|
5
|
+
t.test_files = FileList['test/**/*_test.rb']
|
6
|
+
t.verbose = true
|
7
|
+
# needed for VCR
|
8
|
+
ENV['GITHUB_TOKEN'] = '123'
|
9
|
+
ENV['GITHUB_USERNAME'] = 'test'
|
10
|
+
end
|
11
|
+
|
12
|
+
task :default => :test
|
data/bin/gplan
CHANGED
@@ -2,109 +2,6 @@
|
|
2
2
|
#
|
3
3
|
# This script is used to find all of the planbox story numbers from the git log
|
4
4
|
|
5
|
-
|
6
|
-
require 'pathname'
|
7
|
-
bin_path = Pathname.new(__FILE__).realpath
|
8
|
-
$:.unshift File.expand_path('../../lib', bin_path)
|
9
|
-
Dir[bin_path + '../../lib/*.rb'].each {|file| require file }
|
5
|
+
require_relative '../lib/gplan'
|
10
6
|
|
11
|
-
|
12
|
-
|
13
|
-
PB_STORY_REGEX=/\[(?:fixes)? *#*([0-9]*)\]/i
|
14
|
-
GH_PR_REGEX=/Merge pull request #(\d*)/i
|
15
|
-
|
16
|
-
@repo_overide = ARGV.select{|i| i[/^(?!-)/]}.first
|
17
|
-
@params = ARGV.select{|i| i[/^-/]}
|
18
|
-
@PRINT_HTML = @params.include? "-h"
|
19
|
-
|
20
|
-
@gh_release_array = []
|
21
|
-
@pb_release_array = []
|
22
|
-
@combined = []
|
23
|
-
|
24
|
-
def combine_results
|
25
|
-
@pb_release_array.each do |pb_story|
|
26
|
-
@gh_release_array.each do |gh_pr|
|
27
|
-
if gh_pr['pb_id'] and gh_pr['pb_id'].to_i == pb_story["id"]
|
28
|
-
gh_pr.delete('id') # doing this so we don't overide the pb id
|
29
|
-
pb_story = pb_story.merge gh_pr
|
30
|
-
@gh_release_array.delete gh_pr
|
31
|
-
break
|
32
|
-
end
|
33
|
-
end
|
34
|
-
@combined << pb_story
|
35
|
-
end
|
36
|
-
|
37
|
-
# add the remaining unmatched PRs
|
38
|
-
@gh_release_array.each do |gh_pr|
|
39
|
-
@combined << gh_pr
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# used to pull story numbers from pull request titles
|
44
|
-
def pull_pb_numbers_from_prs
|
45
|
-
@gh_release_array.each do |gh_pr|
|
46
|
-
pb_ids = gh_pr['title'].scan(PB_STORY_REGEX).flatten.uniq
|
47
|
-
if !pb_ids.empty?
|
48
|
-
gh_pr.merge!({"pb_id" => pb_ids.first.to_i}) # making an assumption that there is only 1 pb story number
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def pull_dependency(story)
|
54
|
-
return if story['blocks'].nil?
|
55
|
-
|
56
|
-
# find dependency based on blocks
|
57
|
-
story['blocks'].each do |block|
|
58
|
-
if block.match(/(^(#+|\s+)?dependen(t|cy|cies|cys))/i)
|
59
|
-
return block
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
# else find dependency based on labels
|
64
|
-
if story['labels'].to_s.match /Has Dependency/i
|
65
|
-
return "has a dependency label"
|
66
|
-
end
|
67
|
-
return nil
|
68
|
-
end
|
69
|
-
|
70
|
-
def setup_repository
|
71
|
-
if @repo_overide # allow you to pass in a SHA or remote/branch to target against. This can be useful when generating release notes after a deployment
|
72
|
-
@target = @repo_overide
|
73
|
-
else
|
74
|
-
conf_file =Dir.pwd+"/.gplan"
|
75
|
-
if File.exists?(conf_file)
|
76
|
-
File.open(conf_file, "r") do |f|
|
77
|
-
#target should be repository/branch
|
78
|
-
@target = f.each_line.first.chomp
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
# Set the default branch if one is not set
|
83
|
-
@target = "production/master" unless @target
|
84
|
-
@repo = @target.split("/").first
|
85
|
-
begin
|
86
|
-
`git fetch #{@repo}`
|
87
|
-
rescue
|
88
|
-
puts "unable to fetch #{@repo}, checking git log anyways..."
|
89
|
-
end
|
90
|
-
end
|
91
|
-
|
92
|
-
# MAIN
|
93
|
-
|
94
|
-
setup_repository
|
95
|
-
list= `git log #{@target}..`
|
96
|
-
|
97
|
-
pb_story_ids = list.scan(PB_STORY_REGEX).flatten.uniq
|
98
|
-
gh_pr_ids = list.scan(GH_PR_REGEX).flatten.uniq
|
99
|
-
|
100
|
-
@gh_release_array = Github.new.get_release_notes_array gh_pr_ids
|
101
|
-
@pb_release_array = Planbox.get_release_notes_array pb_story_ids
|
102
|
-
|
103
|
-
pull_pb_numbers_from_prs
|
104
|
-
combine_results
|
105
|
-
|
106
|
-
if @PRINT_HTML
|
107
|
-
Printer.html @combined
|
108
|
-
else
|
109
|
-
Printer.print @combined
|
110
|
-
end
|
7
|
+
Gplan.new(ARGV).generate_release_notes
|
@@ -0,0 +1,161 @@
|
|
1
|
+
---
|
2
|
+
http_interactions:
|
3
|
+
- request:
|
4
|
+
method: get
|
5
|
+
uri: https://api.github.com/repos/username/repo/issues/1?access_token=123
|
6
|
+
body:
|
7
|
+
encoding: US-ASCII
|
8
|
+
string: ''
|
9
|
+
headers:
|
10
|
+
User-Agent:
|
11
|
+
- TheJefe
|
12
|
+
Content-Type:
|
13
|
+
- application/json
|
14
|
+
Accept:
|
15
|
+
- application/json
|
16
|
+
response:
|
17
|
+
status:
|
18
|
+
code: 200
|
19
|
+
message: OK
|
20
|
+
headers:
|
21
|
+
Server:
|
22
|
+
- GitHub.com
|
23
|
+
Date:
|
24
|
+
- Sun, 05 Apr 2015 02:55:26 GMT
|
25
|
+
Content-Type:
|
26
|
+
- application/json; charset=utf-8
|
27
|
+
Content-Length:
|
28
|
+
- '2282'
|
29
|
+
Status:
|
30
|
+
- 200 OK
|
31
|
+
X-Ratelimit-Limit:
|
32
|
+
- '5000'
|
33
|
+
X-Ratelimit-Remaining:
|
34
|
+
- '4984'
|
35
|
+
X-Ratelimit-Reset:
|
36
|
+
- '1428204696'
|
37
|
+
Cache-Control:
|
38
|
+
- private, max-age=60, s-maxage=60
|
39
|
+
Last-Modified:
|
40
|
+
- Fri, 03 Apr 2015 19:40:47 GMT
|
41
|
+
Etag:
|
42
|
+
- '"a1ab6d6b8c492b97d573ff676b8a2d4a"'
|
43
|
+
X-Oauth-Scopes:
|
44
|
+
- gist, repo
|
45
|
+
X-Accepted-Oauth-Scopes:
|
46
|
+
- ''
|
47
|
+
Vary:
|
48
|
+
- Accept, Authorization, Cookie, X-GitHub-OTP
|
49
|
+
- Accept-Encoding
|
50
|
+
X-Github-Media-Type:
|
51
|
+
- github.v3
|
52
|
+
X-Xss-Protection:
|
53
|
+
- 1; mode=block
|
54
|
+
X-Frame-Options:
|
55
|
+
- deny
|
56
|
+
Content-Security-Policy:
|
57
|
+
- default-src 'none'
|
58
|
+
Access-Control-Allow-Credentials:
|
59
|
+
- 'true'
|
60
|
+
Access-Control-Expose-Headers:
|
61
|
+
- ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,
|
62
|
+
X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
|
63
|
+
Access-Control-Allow-Origin:
|
64
|
+
- '*'
|
65
|
+
X-Github-Request-Id:
|
66
|
+
- 62EC2E61:6B93:43993F:5520A41E
|
67
|
+
Strict-Transport-Security:
|
68
|
+
- max-age=31536000; includeSubdomains; preload
|
69
|
+
X-Content-Type-Options:
|
70
|
+
- nosniff
|
71
|
+
X-Served-By:
|
72
|
+
- 7f48e2f7761567e923121f17538d7a6d
|
73
|
+
body:
|
74
|
+
encoding: UTF-8
|
75
|
+
string: '{"url":"https://api.github.com/repos/username/repo/issues/1","labels_url":"https://api.github.com/repos/username/repo/issues/1/labels{/name}","comments_url":"https://api.github.com/repos/username/repo/issues/1/comments","events_url":"https://api.github.com/repos/username/repo/issues/1/events","html_url":"https://github.com/username/repo/pull/1","id":66143574,"number":1,"title":"
|
76
|
+
first pull request","user":{"login":"JohnSmith","id":1527103,"avatar_url":"https://avatars.githubusercontent.com/u/1527103?v=3","gravatar_id":"","url":"https://api.github.com/users/JohnSmith","html_url":"https://github.com/JohnSmith","followers_url":"https://api.github.com/users/JohnSmith/followers","following_url":"https://api.github.com/users/JohnSmith/following{/other_user}","gists_url":"https://api.github.com/users/JohnSmith/gists{/gist_id}","starred_url":"https://api.github.com/users/JohnSmith/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JohnSmith/subscriptions","organizations_url":"https://api.github.com/users/JohnSmith/orgs","repos_url":"https://api.github.com/users/JohnSmith/repos","events_url":"https://api.github.com/users/JohnSmith/events{/privacy}","received_events_url":"https://api.github.com/users/JohnSmith/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/username/repo/labels/Has%20Dependency","name":"Has
|
77
|
+
Dependency","color":"207de5"},{"url":"https://api.github.com/repos/username/repo/labels/in%20progress","name":"in
|
78
|
+
progress","color":"ededed"},{"url":"https://api.github.com/repos/username/repo/labels/WIP","name":"WIP","color":"eb6420"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-04-03T13:08:40Z","updated_at":"2015-04-03T13:08:59Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/username/repo/pulls/1","html_url":"https://github.com/username/repo/pull/1","diff_url":"https://github.com/username/repo/pull/1.diff","patch_url":"https://github.com/username/repo/pull/1.patch"},"body":"Depends
|
79
|
+
on #2126 ","closed_by":null}'
|
80
|
+
http_version:
|
81
|
+
recorded_at: Sun, 05 Apr 2015 02:55:26 GMT
|
82
|
+
- request:
|
83
|
+
method: get
|
84
|
+
uri: https://api.github.com/repos/username/repo/issues/2?access_token=123
|
85
|
+
body:
|
86
|
+
encoding: US-ASCII
|
87
|
+
string: ''
|
88
|
+
headers:
|
89
|
+
User-Agent:
|
90
|
+
- TheJefe
|
91
|
+
Content-Type:
|
92
|
+
- application/json
|
93
|
+
Accept:
|
94
|
+
- application/json
|
95
|
+
response:
|
96
|
+
status:
|
97
|
+
code: 200
|
98
|
+
message: OK
|
99
|
+
headers:
|
100
|
+
Server:
|
101
|
+
- GitHub.com
|
102
|
+
Date:
|
103
|
+
- Sun, 05 Apr 2015 02:55:27 GMT
|
104
|
+
Content-Type:
|
105
|
+
- application/json; charset=utf-8
|
106
|
+
Content-Length:
|
107
|
+
- '2282'
|
108
|
+
Status:
|
109
|
+
- 200 OK
|
110
|
+
X-Ratelimit-Limit:
|
111
|
+
- '5000'
|
112
|
+
X-Ratelimit-Remaining:
|
113
|
+
- '4983'
|
114
|
+
X-Ratelimit-Reset:
|
115
|
+
- '1428204696'
|
116
|
+
Cache-Control:
|
117
|
+
- private, max-age=60, s-maxage=60
|
118
|
+
Last-Modified:
|
119
|
+
- Fri, 03 Apr 2015 19:40:47 GMT
|
120
|
+
Etag:
|
121
|
+
- '"a1ab6d6b8c492b97d573ff676b8a2d4a"'
|
122
|
+
X-Oauth-Scopes:
|
123
|
+
- gist, repo
|
124
|
+
X-Accepted-Oauth-Scopes:
|
125
|
+
- ''
|
126
|
+
Vary:
|
127
|
+
- Accept, Authorization, Cookie, X-GitHub-OTP
|
128
|
+
- Accept-Encoding
|
129
|
+
X-Github-Media-Type:
|
130
|
+
- github.v3
|
131
|
+
X-Xss-Protection:
|
132
|
+
- 1; mode=block
|
133
|
+
X-Frame-Options:
|
134
|
+
- deny
|
135
|
+
Content-Security-Policy:
|
136
|
+
- default-src 'none'
|
137
|
+
Access-Control-Allow-Credentials:
|
138
|
+
- 'true'
|
139
|
+
Access-Control-Expose-Headers:
|
140
|
+
- ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset,
|
141
|
+
X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval
|
142
|
+
Access-Control-Allow-Origin:
|
143
|
+
- '*'
|
144
|
+
X-Github-Request-Id:
|
145
|
+
- 62EC2E61:6B93:4399A5:5520A41F
|
146
|
+
Strict-Transport-Security:
|
147
|
+
- max-age=31536000; includeSubdomains; preload
|
148
|
+
X-Content-Type-Options:
|
149
|
+
- nosniff
|
150
|
+
X-Served-By:
|
151
|
+
- 5aeb3f30c9e3ef6ef7bcbcddfd9a68f7
|
152
|
+
body:
|
153
|
+
encoding: UTF-8
|
154
|
+
string: '{"url":"https://api.github.com/repos/username/repo/issues/2","labels_url":"https://api.github.com/repos/username/repo/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/username/repo/issues/2/comments","events_url":"https://api.github.com/repos/username/repo/issues/2/events","html_url":"https://github.com/username/repo/pull/2","id":66143574,"number":2,"title":"
|
155
|
+
second pull request","user":{"login":"JohnSmith","id":1527103,"avatar_url":"https://avatars.githubusercontent.com/u/1527103?v=3","gravatar_id":"","url":"https://api.github.com/users/JohnSmith","html_url":"https://github.com/JohnSmith","followers_url":"https://api.github.com/users/JohnSmith/followers","following_url":"https://api.github.com/users/JohnSmith/following{/other_user}","gists_url":"https://api.github.com/users/JohnSmith/gists{/gist_id}","starred_url":"https://api.github.com/users/JohnSmith/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/JohnSmith/subscriptions","organizations_url":"https://api.github.com/users/JohnSmith/orgs","repos_url":"https://api.github.com/users/JohnSmith/repos","events_url":"https://api.github.com/users/JohnSmith/events{/privacy}","received_events_url":"https://api.github.com/users/JohnSmith/received_events","type":"User","site_admin":false},"labels":[{"url":"https://api.github.com/repos/username/repo/labels/Has%20Dependency","name":"Has
|
156
|
+
Dependency","color":"207de5"},{"url":"https://api.github.com/repos/username/repo/labels/in%20progress","name":"in
|
157
|
+
progress","color":"ededed"},{"url":"https://api.github.com/repos/username/repo/labels/WIP","name":"WIP","color":"eb6420"}],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":0,"created_at":"2015-04-03T13:08:40Z","updated_at":"2015-04-03T13:08:59Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/username/repo/pulls/2","html_url":"https://github.com/username/repo/pull/2","diff_url":"https://github.com/username/repo/pull/2.diff","patch_url":"https://github.com/username/repo/pull/2.patch"},"body":"## Depends
|
158
|
+
on #2126 ","closed_by":null}'
|
159
|
+
http_version:
|
160
|
+
recorded_at: Sun, 05 Apr 2015 02:55:26 GMT
|
161
|
+
recorded_with: VCR 2.9.3
|
data/gplan-0.1.3.gem
ADDED
Binary file
|
data/gplan.gemspec
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'gplan'
|
6
|
+
s.version = '0.1.3'
|
7
|
+
s.date = '2015-04-05'
|
8
|
+
s.authors = ["Jeff Koenig"]
|
9
|
+
s.email = 'jkoenig311@gmail.com'
|
10
|
+
s.homepage = 'https://github.com/el-jefe-/gplan'
|
11
|
+
s.summary = "Creates release notes from the git log and planbox"
|
12
|
+
s.description = "Creates release notes from the git log and planbox"
|
13
|
+
s.executables = ["gplan"]
|
14
|
+
s.files = `git ls-files`.split($\)
|
15
|
+
s.require_paths = ['lib']
|
16
|
+
s.add_runtime_dependency('httparty', "~> 0.13")
|
17
|
+
s.add_runtime_dependency('haml', "~> 4.0.5")
|
18
|
+
s.add_runtime_dependency('rake',"~> 10.4.2")
|
19
|
+
end
|
data/lib/gplan.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'printer'
|
2
|
+
require 'github'
|
3
|
+
require 'planbox'
|
4
|
+
|
5
|
+
PB_STORY_REGEX=/\[(?:fixes)? *#*([0-9]*)\]/i
|
6
|
+
GH_PR_REGEX=/Merge pull request #(\d*)/i
|
7
|
+
|
8
|
+
class Gplan
|
9
|
+
|
10
|
+
def initialize params
|
11
|
+
@params = params
|
12
|
+
@repo_overide = @params.select{|i| i[/^(?!-)/]}.first
|
13
|
+
@PRINT_HTML = @params.include? "-h"
|
14
|
+
@gh_release_array = []
|
15
|
+
@pb_release_array = []
|
16
|
+
@combined = []
|
17
|
+
end
|
18
|
+
|
19
|
+
def generate_release_notes
|
20
|
+
setup_repository
|
21
|
+
list= `git log #{@target}..`
|
22
|
+
|
23
|
+
pb_story_ids = list.scan(PB_STORY_REGEX).flatten.uniq
|
24
|
+
gh_pr_ids = list.scan(GH_PR_REGEX).flatten.uniq
|
25
|
+
|
26
|
+
@gh_release_array = Github.new.get_release_notes_array gh_pr_ids
|
27
|
+
@pb_release_array = Planbox.get_release_notes_array pb_story_ids
|
28
|
+
|
29
|
+
pull_pb_numbers_from_prs
|
30
|
+
combine_results
|
31
|
+
|
32
|
+
if @PRINT_HTML
|
33
|
+
Printer.new.html @combined
|
34
|
+
else
|
35
|
+
Printer.new.print @combined
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def combine_results
|
40
|
+
@pb_release_array.each do |pb_story|
|
41
|
+
@gh_release_array.each do |gh_pr|
|
42
|
+
if gh_pr['pb_id'] and gh_pr['pb_id'].to_i == pb_story["id"]
|
43
|
+
gh_pr.delete('id') # doing this so we don't overide the pb id
|
44
|
+
pb_story = pb_story.merge gh_pr
|
45
|
+
@gh_release_array.delete gh_pr
|
46
|
+
break
|
47
|
+
end
|
48
|
+
end
|
49
|
+
@combined << pb_story
|
50
|
+
end
|
51
|
+
|
52
|
+
# add the remaining unmatched PRs
|
53
|
+
@gh_release_array.each do |gh_pr|
|
54
|
+
@combined << gh_pr
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
# used to pull story numbers from pull request titles
|
59
|
+
def pull_pb_numbers_from_prs
|
60
|
+
@gh_release_array.each do |gh_pr|
|
61
|
+
pb_ids = gh_pr['title'].scan(PB_STORY_REGEX).flatten.uniq
|
62
|
+
if !pb_ids.empty?
|
63
|
+
gh_pr.merge!({"pb_id" => pb_ids.first.to_i}) # making an assumption that there is only 1 pb story number
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def setup_repository
|
69
|
+
if @repo_overide # allow you to pass in a SHA or remote/branch to target against. This can be useful when generating release notes after a deployment
|
70
|
+
@target = @repo_overide
|
71
|
+
else
|
72
|
+
conf_file =Dir.pwd+"/.gplan"
|
73
|
+
if File.exists?(conf_file)
|
74
|
+
File.open(conf_file, "r") do |f|
|
75
|
+
#target should be repository/branch
|
76
|
+
@target = f.each_line.first.chomp
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
# Set the default branch if one is not set
|
81
|
+
@target = "production/master" unless @target
|
82
|
+
@repo = @target.split("/").first
|
83
|
+
begin
|
84
|
+
`git fetch #{@repo}`
|
85
|
+
rescue
|
86
|
+
puts "unable to fetch #{@repo}, checking git log anyways..."
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
end
|
data/lib/printer.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'haml'
|
2
2
|
|
3
|
-
|
3
|
+
class Printer
|
4
4
|
|
5
5
|
def html stories
|
6
6
|
$stories = stories
|
@@ -21,7 +21,7 @@ module Printer
|
|
21
21
|
release_notes += "PR:TITLE\n"
|
22
22
|
end
|
23
23
|
|
24
|
-
dependency =
|
24
|
+
dependency = get_dependency(story)
|
25
25
|
dependencies << "PR ##{story['number']}: " + dependency unless dependency.nil?
|
26
26
|
|
27
27
|
line = ""
|
@@ -39,6 +39,25 @@ module Printer
|
|
39
39
|
puts release_notes
|
40
40
|
end
|
41
41
|
|
42
|
+
def get_dependency(story)
|
43
|
+
|
44
|
+
# find dependency based on blocks
|
45
|
+
unless story['blocks'].nil?
|
46
|
+
story['blocks'].each do |block|
|
47
|
+
if block.match(/(^(#+(\s+)?|\s+)?depend(s|ent|ency|encies|encys))/i)
|
48
|
+
return block
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
return if story['labels'].nil?
|
54
|
+
# else find dependency based on labels
|
55
|
+
if story['labels'].to_s.match /Has Dependency/i
|
56
|
+
return "has a dependency label"
|
57
|
+
end
|
58
|
+
return nil
|
59
|
+
end
|
60
|
+
|
42
61
|
def planbox_info story
|
43
62
|
"#{story['id']}:#{story['status']}:#{story['name']}:#{story['project_name']}:#{story['project_alias']}"
|
44
63
|
end
|
@@ -23,7 +23,7 @@
|
|
23
23
|
%td
|
24
24
|
%a{href: story['html_url']}= story['number']
|
25
25
|
%td= story['title']
|
26
|
-
- block =
|
26
|
+
- block = Printer.new.get_dependency(story)
|
27
27
|
- next if block.nil?
|
28
28
|
%td= block
|
29
29
|
|
@@ -50,6 +50,6 @@
|
|
50
50
|
%td
|
51
51
|
%a{href: issue['html_url']}= issue['number']
|
52
52
|
%td= issue['milestone']['title'] if issue['milestone']
|
53
|
-
- block =
|
53
|
+
- block = Printer.new.get_dependency(story)
|
54
54
|
- next if block.nil?
|
55
55
|
%td= block
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'pry'
|
3
|
+
|
4
|
+
class ReleaseNotesTest < UnitTest
|
5
|
+
describe 'release notes' do
|
6
|
+
|
7
|
+
before do
|
8
|
+
github = Github.new
|
9
|
+
@stories = []
|
10
|
+
VCR.use_cassette("github_pull_requests") do
|
11
|
+
@stories = github.get_release_notes_array [1,2]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'can be printed to stdout' do
|
16
|
+
old_stdout = $stdout
|
17
|
+
$stdout = StringIO.new
|
18
|
+
Printer.new.print @stories
|
19
|
+
output = $stdout.string.split("\n")
|
20
|
+
$stdout = old_stdout
|
21
|
+
output.count.must_equal 12
|
22
|
+
output.last.must_equal "PR #2: Depends on #2126 "
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'can be printed to an html file' do
|
26
|
+
output = Printer.new.html @stories
|
27
|
+
output.first.must_equal "<h2>Release notes</h2>"
|
28
|
+
output.count.must_equal 55
|
29
|
+
assert output.to_s.include? "Depends on #2126"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Stubs to fake up repos and outputs
|
34
|
+
class Github < Github
|
35
|
+
def get_repo_name
|
36
|
+
'username/repo'
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def File.write file, release_notes
|
41
|
+
return release_notes.split("\n")
|
42
|
+
end
|
43
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
gem 'minitest'
|
2
|
+
gem 'vcr'
|
3
|
+
|
4
|
+
require 'minitest/autorun'
|
5
|
+
require 'gplan'
|
6
|
+
require 'printer'
|
7
|
+
require 'vcr'
|
8
|
+
|
9
|
+
VCR.configure do |config|
|
10
|
+
config.cassette_library_dir = "fixtures/vcr_cassettes"
|
11
|
+
config.hook_into :webmock # or :fakeweb
|
12
|
+
end
|
13
|
+
|
14
|
+
class UnitTest < MiniTest::Test
|
15
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DependencyTest < UnitTest
|
4
|
+
describe 'dependencies' do
|
5
|
+
|
6
|
+
describe 'show blocks' do
|
7
|
+
|
8
|
+
match_words = %w(
|
9
|
+
depends
|
10
|
+
dependent
|
11
|
+
dependency
|
12
|
+
dependencies
|
13
|
+
dependencys
|
14
|
+
)
|
15
|
+
|
16
|
+
match_words.each do |word|
|
17
|
+
it 'starting with the word #{word}' do
|
18
|
+
dependency = "#{word}\n"+
|
19
|
+
"This is a dependency"
|
20
|
+
story = stub_story_with_block dependency
|
21
|
+
Printer.new.get_dependency(story).must_equal dependency
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'starting with the word dependent' do
|
26
|
+
dependency = "Dependent on\n"+
|
27
|
+
"This is a dependency"
|
28
|
+
story = stub_story_with_block dependency
|
29
|
+
Printer.new.get_dependency(story).must_equal dependency
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'starting with spaces then the word dependent' do
|
33
|
+
dependency = " Dependent on\n"+
|
34
|
+
"This is a dependency"
|
35
|
+
story = stub_story_with_block dependency
|
36
|
+
Printer.new.get_dependency(story).must_equal dependency
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'with hashes and spaces at the beginning' do
|
40
|
+
dependency = "## Dependency\n"+
|
41
|
+
"This is a dependency"
|
42
|
+
story = stub_story_with_block dependency
|
43
|
+
Printer.new.get_dependency(story).must_equal dependency
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'dont show blocks' do
|
49
|
+
it 'when dependent is not the first word' do
|
50
|
+
dependency = "not Dependent\n"+
|
51
|
+
"This is NOT a dependency"
|
52
|
+
story = stub_story_with_block dependency
|
53
|
+
Printer.new.get_dependency(story).must_equal nil
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
describe 'dependency flag' do
|
58
|
+
|
59
|
+
it 'shown when no block is found' do
|
60
|
+
label = 'Has Dependency'
|
61
|
+
story = {
|
62
|
+
'labels' => [ label ]
|
63
|
+
}
|
64
|
+
Printer.new.get_dependency(story).must_equal "has a dependency label"
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'not shown when a block is found' do
|
68
|
+
dependency = "Dependency\n"+
|
69
|
+
"This is a dependency"
|
70
|
+
label = 'Has Dependency'
|
71
|
+
story = stub_story_with_block dependency
|
72
|
+
story['labels'] = [ label ]
|
73
|
+
Printer.new.get_dependency(story).must_equal dependency
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def stub_story_with_block dependency
|
78
|
+
{'blocks' => [ dependency ]}
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
metadata
CHANGED
@@ -1,36 +1,32 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: gplan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.3
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Jeff Koenig
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2015-
|
11
|
+
date: 2015-04-05 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: httparty
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
21
|
-
version: 0.13
|
19
|
+
version: '0.13'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: 0.13
|
26
|
+
version: '0.13'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: haml
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,11 +34,24 @@ dependencies:
|
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 4.0.5
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: 10.4.2
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 10.4.2
|
46
55
|
description: Creates release notes from the git log and planbox
|
47
56
|
email: jkoenig311@gmail.com
|
48
57
|
executables:
|
@@ -50,35 +59,43 @@ executables:
|
|
50
59
|
extensions: []
|
51
60
|
extra_rdoc_files: []
|
52
61
|
files:
|
62
|
+
- README.md
|
63
|
+
- Rakefile
|
53
64
|
- bin/gplan
|
54
65
|
- bin/releasenotes.html
|
66
|
+
- fixtures/vcr_cassettes/github_pull_requests.yml
|
67
|
+
- gplan-0.1.3.gem
|
68
|
+
- gplan.gemspec
|
55
69
|
- lib/github.rb
|
70
|
+
- lib/gplan.rb
|
56
71
|
- lib/planbox.rb
|
57
72
|
- lib/printer.rb
|
58
73
|
- templates/template.html.haml
|
74
|
+
- test/integration/release_notes_test.rb
|
75
|
+
- test/test_helper.rb
|
76
|
+
- test/unit/dependency_test.rb
|
59
77
|
homepage: https://github.com/el-jefe-/gplan
|
60
78
|
licenses: []
|
79
|
+
metadata: {}
|
61
80
|
post_install_message:
|
62
81
|
rdoc_options: []
|
63
82
|
require_paths:
|
64
83
|
- lib
|
65
84
|
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
-
none: false
|
67
85
|
requirements:
|
68
86
|
- - '>='
|
69
87
|
- !ruby/object:Gem::Version
|
70
88
|
version: '0'
|
71
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
72
|
-
none: false
|
73
90
|
requirements:
|
74
91
|
- - '>='
|
75
92
|
- !ruby/object:Gem::Version
|
76
93
|
version: '0'
|
77
94
|
requirements: []
|
78
95
|
rubyforge_project:
|
79
|
-
rubygems_version:
|
96
|
+
rubygems_version: 2.0.14
|
80
97
|
signing_key:
|
81
|
-
specification_version:
|
98
|
+
specification_version: 4
|
82
99
|
summary: Creates release notes from the git log and planbox
|
83
100
|
test_files: []
|
84
101
|
has_rdoc:
|