github_changes 0.1.5 → 0.1.6
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 +4 -4
- data/lib/changelog_generator/generator.rb +142 -78
- data/lib/changelog_generator/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7eed4d44163ee873a8bd9f54545c684bf198e0f
|
4
|
+
data.tar.gz: 906288c0ad3c375f17600004a0ad4fa03beac063
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f31590bde945802712fe14e6e6d9034bf2bfac72f0733bf371940f595ca222c437b12cfe9c65aaa97a324077a238cb66c36e2a4b4f7684c858b2ed94d9de7b9
|
7
|
+
data.tar.gz: 3d3d0c25c8b89f3bd800416c1448084af4459c0c1aed78a95b53d2f4376bd33a7563dd70af7e5b8dfb49545e6e65c8a4f2715fdaed8f3174ded879191b1a38f7
|
@@ -15,7 +15,7 @@ module ChangelogGenerator
|
|
15
15
|
self.user = user
|
16
16
|
self.repo_name = repo
|
17
17
|
self.from_ref = from_ref
|
18
|
-
self.to_ref = to_ref || "
|
18
|
+
self.to_ref = to_ref || "now"
|
19
19
|
self.label_filter = label_filter
|
20
20
|
end
|
21
21
|
|
@@ -33,92 +33,20 @@ module ChangelogGenerator
|
|
33
33
|
|
34
34
|
private
|
35
35
|
|
36
|
-
def
|
37
|
-
|
38
|
-
`#{cmd}`
|
39
|
-
end
|
40
|
-
|
41
|
-
def clone_or_fetch_repo(user, repo, path)
|
42
|
-
output = nil
|
43
|
-
|
44
|
-
if Dir.exist? path
|
45
|
-
output = run "cd #{path} && git fetch"
|
46
|
-
else
|
47
|
-
output = run "git clone --bare \"https://#{ENV['GITHUB_TOKEN']}@github.com/#{user}/#{repo}.git\" \"#{path}\""
|
48
|
-
end
|
49
|
-
|
50
|
-
unless $?.exitstatus == 0
|
36
|
+
def generate_changelog(user, repo, start_ref, end_ref, label_filter = nil)
|
37
|
+
unless check_github_response() { github.repos.get(user, repo) }
|
51
38
|
abort "Unable to access repo `#{user}/#{repo}`. Please ensure correct spelling. If this repo is private you must ensure to configure me with a suitable GitHub oath token."
|
52
39
|
end
|
53
40
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
def is_ref?(ref)
|
58
|
-
return false unless ref !~ /^\s*$/
|
59
|
-
run "git show \"#{ref}\""
|
60
|
-
$?.exitstatus == 0
|
61
|
-
end
|
62
|
-
|
63
|
-
def ref_before(date_string)
|
64
|
-
output = run("git rev-list -1 --all --before=\"#{date_string}\"").chomp
|
65
|
-
$?.exitstatus == 0 ? output : nil
|
66
|
-
end
|
67
|
-
|
68
|
-
def ref_after(date_string)
|
69
|
-
output = run("git rev-list --all --after=\"#{date_string}\" | tail -1").chomp
|
70
|
-
$?.exitstatus == 0 ? output : nil
|
71
|
-
end
|
72
|
-
|
73
|
-
def find_ref(string)
|
74
|
-
return string if is_ref? string
|
75
|
-
string = yield(string)
|
76
|
-
is_ref?(string) ? string : nil
|
77
|
-
end
|
78
|
-
|
79
|
-
def find_shas_or_abort(start_ref, end_ref)
|
80
|
-
start_sha = find_ref(start_ref) { |s| ref_after(s) }
|
81
|
-
end_sha = find_ref(end_ref) { |s| ref_before(s) }
|
82
|
-
|
83
|
-
unless start_sha
|
84
|
-
abort "Unable to parse `#{start_ref}` as a reference or date. Please specify a git tag, branch, or SHA. You can also specify a date like `last week` or `5 days ago`"
|
85
|
-
end
|
86
|
-
unless end_sha
|
87
|
-
abort "Unable to parse `#{end_ref}` as a reference or date. Please specify a git tag, branch, or SHA. You can also specify a date like `last week` or `5 days ago` or `January 1, 1999`"
|
88
|
-
end
|
89
|
-
|
90
|
-
return start_sha, end_sha
|
91
|
-
end
|
92
|
-
|
93
|
-
def pull_request_numbers(start_sha, end_sha)
|
94
|
-
log_command = "git log #{start_sha}..#{end_sha}"
|
95
|
-
log = `#{log_command} --grep "Merge pull" --reverse | grep "Merge pull request #"`
|
96
|
-
pull_nums = log.split("\n").map { |p| p.match(/.*#(\d+) .*/)[1].to_i }
|
97
|
-
end
|
98
|
-
|
99
|
-
def filter_prs_by_label(github, user, repo, pull_nums, label_filter)
|
100
|
-
pull_nums.select do |n|
|
101
|
-
issue = github.issues.get user, repo, n
|
102
|
-
label_names = issue.labels.map { |l| l.name }
|
103
|
-
label_names.include?(label_filter)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
def generate_changelog(user, repo, start_ref, end_ref, label_filter = nil)
|
108
|
-
path = "clones/#{user}/#{repo}.git"
|
109
|
-
|
110
|
-
clone_or_fetch_repo(user, repo, path)
|
111
|
-
FileUtils.cd(path) # Below methods assuming we are in git repo
|
112
|
-
start_sha, end_sha = find_shas_or_abort(start_ref, end_ref)
|
113
|
-
pull_nums = pull_request_numbers(start_sha, end_sha)
|
114
|
-
pull_nums = filter_prs_by_label(github, user, repo, pull_nums, label_filter) if label_filter
|
41
|
+
start_sha, start_time, end_sha = parse_references(start_ref, end_ref)
|
42
|
+
pull_nums = pull_request_numbers(start_sha, start_time, end_sha)
|
43
|
+
pull_nums = filter_prs_by_label(pull_nums)
|
115
44
|
abort "No PRs found matching criteria" if pull_nums.empty?
|
116
45
|
|
117
46
|
pulls = pull_nums.map { |p| github.pull_requests.get(user, repo, p) }
|
118
47
|
pulls = pulls.map { |p| PullRequest.from_github_pr(p) }
|
119
48
|
# puts JSON.pretty_generate(pulls.first.body.to_hash)
|
120
49
|
|
121
|
-
# puts "Finding connected issues:"
|
122
50
|
pulls.each do |pull|
|
123
51
|
issue_nums = connected_issues_from_pr(pull)
|
124
52
|
github_issues = issue_nums.map { |n| github.issues.get(user, repo, n) }
|
@@ -163,6 +91,87 @@ module ChangelogGenerator
|
|
163
91
|
value
|
164
92
|
end
|
165
93
|
|
94
|
+
def run(cmd)
|
95
|
+
# puts "Running: #{cmd}"
|
96
|
+
`#{cmd}`
|
97
|
+
end
|
98
|
+
|
99
|
+
def find_ref_for_string(string)
|
100
|
+
ref = check_github_response() { github.git_data.references.get user, repo_name, URI::encode("heads/#{string}") }
|
101
|
+
ref ||= check_github_response() { github.git_data.references.get user, repo_name, URI::encode("tags/#{string}") }
|
102
|
+
return ref
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_commit_sha_for_ref_string(string)
|
106
|
+
ref = find_ref_for_string string
|
107
|
+
return nil unless ref && ref.object && ref.object.type && ref.object.sha
|
108
|
+
|
109
|
+
case ref.object.type
|
110
|
+
when "commit"
|
111
|
+
ref.object.sha
|
112
|
+
when "tag"
|
113
|
+
tag = check_github_response() { github.git_data.tags.get user, repo_name, URI::encode(ref.object.sha) }
|
114
|
+
tag ? tag.object.sha : nil
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def find_commit_sha_for_string(string)
|
119
|
+
return nil unless string && string.strip.length > 0
|
120
|
+
|
121
|
+
# Search references first becomes branches/tags seem more likely than commit SHA
|
122
|
+
sha = find_commit_sha_for_ref_string string
|
123
|
+
return sha if sha
|
124
|
+
|
125
|
+
# Maybe it is a commit SHA?
|
126
|
+
commit = check_github_response() { github.repos.commits.get user, repo_name, URI::encode(string) }
|
127
|
+
return commit.sha if commit
|
128
|
+
end
|
129
|
+
|
130
|
+
def parse_string_as_time(string)
|
131
|
+
Chronic.parse(string)
|
132
|
+
end
|
133
|
+
|
134
|
+
def commit_before(date)
|
135
|
+
response = check_github_response() { github.repos.commits.list user, repo_name, until: date.iso8601, :per_page => 1 }
|
136
|
+
return nil unless response
|
137
|
+
return response.first.sha
|
138
|
+
end
|
139
|
+
|
140
|
+
def end_sha(end_string)
|
141
|
+
ref = find_commit_sha_for_string(end_string)
|
142
|
+
return ref if ref
|
143
|
+
|
144
|
+
time = parse_string_as_time(end_string)
|
145
|
+
return nil unless time
|
146
|
+
|
147
|
+
commit_before(time)
|
148
|
+
end
|
149
|
+
|
150
|
+
def parse_references(start_ref, end_ref)
|
151
|
+
end_sha = end_sha(end_ref)
|
152
|
+
# We can start on a SHA or Time
|
153
|
+
start_sha = find_commit_sha_for_string(start_ref)
|
154
|
+
start_time = parse_string_as_time(start_ref)
|
155
|
+
|
156
|
+
unless start_sha || start_time
|
157
|
+
abort "Unable to parse `#{start_ref}` as a reference or date. Please specify a git tag, branch, or SHA. You can also specify a date like `last week` or `5 days ago`"
|
158
|
+
end
|
159
|
+
unless end_sha
|
160
|
+
abort "Unable to parse `#{end_ref}` as a reference or date. Please specify a git tag, branch, or SHA. You can also specify a date like `last week` or `5 days ago` or `January 1, 1999`"
|
161
|
+
end
|
162
|
+
|
163
|
+
return start_sha, start_time, end_sha
|
164
|
+
end
|
165
|
+
|
166
|
+
def filter_prs_by_label(pull_nums)
|
167
|
+
return pull_nums unless label_filter && label_filter.strip.length > 0
|
168
|
+
pull_nums.select do |n|
|
169
|
+
issue = github.issues.get user, repo_name, n
|
170
|
+
label_names = issue.labels.map { |l| l.name }
|
171
|
+
label_names.include?(label_filter)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
166
175
|
def changelog_from_pr(pr)
|
167
176
|
default = "- #{pr['title']}"
|
168
177
|
|
@@ -175,11 +184,66 @@ module ChangelogGenerator
|
|
175
184
|
matcher['changes'].strip
|
176
185
|
end
|
177
186
|
|
187
|
+
def pull_num_from_commit(commit)
|
188
|
+
message = commit.commit.message
|
189
|
+
match = message.match(/merge pull request #(\d+)/i)
|
190
|
+
return nil unless match
|
191
|
+
match[1]
|
192
|
+
end
|
193
|
+
|
178
194
|
def connected_issues_from_pr(pr)
|
179
195
|
body = pr.body
|
180
196
|
return [] unless body
|
181
197
|
|
182
198
|
body.scan(/((connect|connects|fix|fixes|address|addresses):?\s*(to)?:?\s*#(?<number>\d+))/im).reject(&:nil?).map(&:last).flatten
|
183
199
|
end
|
200
|
+
|
201
|
+
# Page through all commits in the range collecting PR numbers
|
202
|
+
def pull_request_numbers(start_sha, start_time, end_sha)
|
203
|
+
pull_nums = []
|
204
|
+
|
205
|
+
if start_sha
|
206
|
+
# First we do a compare
|
207
|
+
response = check_github_response() { github.repos.commits.compare user, repo_name, start_sha, end_sha }
|
208
|
+
abort "Unable to compare from #{from_ref} to #{to_ref}. Tried `#{start_sha}..#{end_sha}`" unless response
|
209
|
+
if response
|
210
|
+
commits = response.commits
|
211
|
+
if response.total_commits < 250 # This API won't return more than 250 - we have to go pagination mode below for that
|
212
|
+
return commits.reduce([]) do |memo, commit|
|
213
|
+
pull_num = pull_num_from_commit(commit)
|
214
|
+
memo << pull_num if pull_num
|
215
|
+
memo
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
response = check_github_response() { github.repos.commits.list user, repo_name, sha: end_sha, :per_page => 100 }
|
222
|
+
abort "Something went wrong fetching commit information" unless response
|
223
|
+
pull_nums = []
|
224
|
+
loop do
|
225
|
+
done = false
|
226
|
+
commits = response.body
|
227
|
+
commits.each do |commit|
|
228
|
+
if (!start_sha && start_time) && start_time > Chronic.parse(commit.commit.committer.date)
|
229
|
+
done = true
|
230
|
+
break
|
231
|
+
end
|
232
|
+
|
233
|
+
pull_num = pull_num_from_commit(commit)
|
234
|
+
pull_nums << pull_num if pull_num
|
235
|
+
|
236
|
+
if start_sha && commit.sha == start_sha
|
237
|
+
done = true
|
238
|
+
break
|
239
|
+
end
|
240
|
+
end
|
241
|
+
break if done
|
242
|
+
break unless response.has_next_page?
|
243
|
+
response = response.next_page
|
244
|
+
end
|
245
|
+
|
246
|
+
pull_nums
|
247
|
+
end
|
184
248
|
end
|
185
249
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: github_changes
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Cody Rayment
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-04-02 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|