Skip to content

Commit 1cba868

Browse files
committed
Impl changelog_generator.rb
1 parent 2bf7df4 commit 1cba868

File tree

2 files changed

+136
-0
lines changed

2 files changed

+136
-0
lines changed

_tools/changelog_generator/README.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# changelog_generator
2+
Generate changelog entry
3+
4+
## Requirements
5+
* Ruby
6+
* git
7+
* [gh](https://github.com/cli/cli)
8+
9+
## Usage
10+
```bash
11+
$ ruby changelog_generator.rb --help
12+
Usage: changelog_generagtor [options]
13+
--before=BEFORE Before tag or sha1 (default: latest tag)
14+
--after=AFTER After tag or sha1 (default: HEAD)
15+
```
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
# frozen_string_literal: true
2+
3+
require "optparse"
4+
require "json"
5+
6+
# @return [String]
7+
def latest_tag
8+
`git tag`.each_line.map(&:strip).max_by { |tag| Gem::Version.create(tag.delete_prefix("v")) }
9+
end
10+
11+
# @param before [String]
12+
# @param after [String]
13+
# @return [Array<Integer>]
14+
def search_pr_numbers(before:, after:)
15+
commits = `git rev-list --merges --right-only #{before}...#{after}`.each_line.map(&:strip)
16+
commits.map do |commit|
17+
commit_message = `git show -q #{commit}`
18+
commit_message =~ /Merge pull request #([0-9]+)/
19+
Regexp.last_match(1).to_i
20+
end
21+
end
22+
23+
before = nil
24+
after = nil
25+
26+
opt = OptionParser.new
27+
opt.on("--before=BEFORE", "Before tag or sha1 (default: latest tag)") { |v| before = v }
28+
opt.on("--after=AFTER", "After tag or sha1 (default: HEAD)") { |v| after = v }
29+
30+
opt.parse!(ARGV)
31+
32+
before ||= latest_tag
33+
after ||= "HEAD"
34+
35+
pr_numbers = search_pr_numbers(before:, after:)
36+
all_prs = pr_numbers.map do |pr_number|
37+
pr = JSON.parse(`gh pr view --json number,title,author,labels,url #{pr_number}`)
38+
pr["label_names"] = pr["labels"].map { |label| label["name"] }
39+
pr
40+
end
41+
42+
# @param prs [Array<Hash>]
43+
#
44+
# @return [String]
45+
def generate_category_changelog(prs)
46+
lines = []
47+
found_pr_numbers = []
48+
prs = prs.dup
49+
50+
["breaking change", "bug", "enhancement"].each do |label|
51+
label_prs = prs.find_all { |pr| pr["label_names"].include?(label) }
52+
53+
next if label_prs.empty?
54+
55+
case label
56+
when "breaking change"
57+
lines << "### :bomb: Breaking changes"
58+
when "bug"
59+
lines << "### Bugfixes"
60+
when "enhancement"
61+
lines << "### New Features"
62+
end
63+
64+
label_prs.each do |pr|
65+
lines < generate_changelog_line(pr)
66+
found_pr_numbers << pr["number"]
67+
end
68+
69+
found_pr_numbers.push(*label_prs.map { |pr| pr["number"] })
70+
71+
prs.reject! { |pr| found_pr_numbers.include?(pr["number"]) }
72+
73+
lines << ""
74+
end
75+
76+
other_prs = prs.reject do |pr|
77+
found_pr_numbers.include?(pr["number"]) || pr["label_names"].include?("chore")
78+
end
79+
80+
lines << "### Other changes"
81+
other_prs.each do |pr|
82+
lines << generate_changelog_line(pr)
83+
end
84+
found_pr_numbers.push(*other_prs.map { |pr| pr["number"] })
85+
lines << ""
86+
87+
return "* No changes\n\n" if found_pr_numbers.empty?
88+
89+
"#{lines.join("\n")}\n"
90+
end
91+
92+
# @param pr [Hash]
93+
#
94+
# @return [String]
95+
def generate_changelog_line(pr)
96+
author = pr["author"]["login"].delete_prefix("app/")
97+
98+
"* #{pr["title"]} by @#{author} in #{pr["url"]}"
99+
end
100+
101+
changelog_body = +""
102+
103+
changelog_body << "## Go\n"
104+
go_prs = all_prs.find_all { |pr| pr["label_names"].include?("go") }
105+
changelog_body << generate_category_changelog(go_prs)
106+
107+
changelog_body << "## Ruby\n"
108+
ruby_prs = all_prs.find_all { |pr| pr["label_names"].include?("ruby") }
109+
changelog_body << generate_category_changelog(ruby_prs)
110+
111+
changelog_body << "## ruby_h_to_go\n"
112+
ruby_h_to_go_prs = all_prs.find_all { |pr| pr["label_names"].include?("ruby_h_to_go") }
113+
changelog_body << generate_category_changelog(ruby_h_to_go_prs)
114+
115+
changelog_body << "## Other\n"
116+
other_prs = all_prs.reject { |pr| pr["label_names"].any? { |label| %w[go ruby ruby_h_to_go chore].include?(label) } }
117+
changelog_body << generate_category_changelog(other_prs)
118+
119+
changelog_body << "**Full Changelog**: https://github.com/ruby-go-gem/go-gem-wrapper/compare/#{before}...#{after}"
120+
121+
puts changelog_body

0 commit comments

Comments
 (0)