Skip to content

Commit 01fdaad

Browse files
authored
Merge pull request #197 from ruby-go-gem/feature/changelog_generator
Create release on GitHub Actions
2 parents 5219720 + f6a2535 commit 01fdaad

File tree

5 files changed

+192
-27
lines changed

5 files changed

+192
-27
lines changed

.github/release.yml

Lines changed: 0 additions & 27 deletions
This file was deleted.

.github/workflows/release.yml

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
name: Create releases
2+
3+
on:
4+
push:
5+
tags:
6+
- "v*"
7+
8+
jobs:
9+
publish:
10+
runs-on: ubuntu-latest
11+
12+
steps:
13+
- uses: actions/checkout@v4
14+
15+
- uses: ruby/setup-ruby@v1
16+
with:
17+
ruby-version: ruby
18+
bundler-cache: true
19+
20+
- name: Generate changelog
21+
run: |
22+
bundle exec rake changelog[,${TAG_NAME}] > /tmp/changelog.md
23+
env:
24+
TAG_NAME: ${{ github.ref_name }}
25+
26+
- name: Release
27+
uses: softprops/action-gh-release@v2
28+
with:
29+
body_path: /tmp/changelog.md

Rakefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ task :release do
1414
end
1515
end
1616

17+
desc "Generate changelog entry"
18+
task :changelog, [:before, :after] do |_, params|
19+
args = []
20+
args << "--before #{params.before}" if params.before
21+
args << "--after #{params.after}" if params.after
22+
23+
sh "ruby _tools/changelog_generator/changelog_generator.rb #{args.join(" ")}"
24+
end
25+
1726
task build_all: %w[ruby:build_all go:build_all go_gem:test ruby_h_to_go:test patch_for_go_gem:test]
1827

1928
task default: :build_all

_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: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
# frozen_string_literal: true
2+
3+
require "optparse"
4+
require "json"
5+
6+
# @return [String]
7+
def search_git_tags
8+
`git tag`.each_line.map(&:strip).sort_by { |tag| Gem::Version.create(tag.delete_prefix("v")) }.reverse
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+
after ||= "HEAD"
33+
34+
unless before
35+
git_tags = search_git_tags
36+
37+
if after == "HEAD"
38+
# Use latest tag
39+
before = git_tags[0]
40+
else
41+
index = git_tags.index(after)
42+
before =
43+
if index
44+
# Use 1 previous tag of index
45+
git_tags[index + 1]
46+
else
47+
# Use latest tag
48+
git_tags[0]
49+
end
50+
end
51+
end
52+
53+
pr_numbers = search_pr_numbers(before:, after:)
54+
all_prs = pr_numbers.map do |pr_number|
55+
pr = JSON.parse(`gh pr view --json number,title,author,labels,url #{pr_number}`)
56+
pr["label_names"] = pr["labels"].map { |label| label["name"] }
57+
pr
58+
end
59+
60+
# @param prs [Array<Hash>]
61+
#
62+
# @return [String]
63+
def generate_category_changelog(prs) # rubocop:disable Metrics/AbcSize,Metrics/CyclomaticComplexity,Metrics/MethodLength,Metrics/PerceivedComplexity
64+
lines = []
65+
found_pr_numbers = []
66+
prs = prs.dup
67+
68+
["breaking change", "bug", "enhancement"].each do |label|
69+
label_prs = prs.find_all { |pr| pr["label_names"].include?(label) }
70+
71+
next if label_prs.empty?
72+
73+
case label
74+
when "breaking change"
75+
lines << "### :bomb: Breaking changes"
76+
when "bug"
77+
lines << "### Bugfixes"
78+
when "enhancement"
79+
lines << "### New Features"
80+
end
81+
82+
label_prs.each do |pr|
83+
lines < generate_changelog_line(pr)
84+
found_pr_numbers << pr["number"]
85+
end
86+
87+
found_pr_numbers.push(*label_prs.map { |pr| pr["number"] })
88+
89+
prs.reject! { |pr| found_pr_numbers.include?(pr["number"]) }
90+
91+
lines << ""
92+
end
93+
94+
other_prs = prs.reject do |pr|
95+
found_pr_numbers.include?(pr["number"]) || pr["label_names"].include?("chore")
96+
end
97+
98+
lines << "### Other changes"
99+
other_prs.each do |pr|
100+
lines << generate_changelog_line(pr)
101+
end
102+
found_pr_numbers.push(*other_prs.map { |pr| pr["number"] })
103+
lines << ""
104+
105+
return "* No changes\n\n" if found_pr_numbers.empty?
106+
107+
"#{lines.join("\n")}\n"
108+
end
109+
110+
# @param pull_request [Hash]
111+
#
112+
# @return [String]
113+
def generate_changelog_line(pull_request)
114+
author = pull_request["author"]["login"].delete_prefix("app/")
115+
116+
"* #{pull_request["title"]} by @#{author} in #{pull_request["url"]}"
117+
end
118+
119+
changelog_body = +""
120+
121+
changelog_body << "## Go\n"
122+
go_prs = all_prs.find_all { |pr| pr["label_names"].include?("go") }
123+
changelog_body << generate_category_changelog(go_prs)
124+
125+
changelog_body << "## Ruby\n"
126+
ruby_prs = all_prs.find_all { |pr| pr["label_names"].include?("ruby") }
127+
changelog_body << generate_category_changelog(ruby_prs)
128+
129+
changelog_body << "## ruby_h_to_go\n"
130+
ruby_h_to_go_prs = all_prs.find_all { |pr| pr["label_names"].include?("ruby_h_to_go") }
131+
changelog_body << generate_category_changelog(ruby_h_to_go_prs)
132+
133+
changelog_body << "## Other\n"
134+
other_prs = all_prs.reject { |pr| pr["label_names"].any? { |label| %w[go ruby ruby_h_to_go chore].include?(label) } }
135+
changelog_body << generate_category_changelog(other_prs)
136+
137+
changelog_body << "**Full Changelog**: https://github.com/ruby-go-gem/go-gem-wrapper/compare/#{before}...#{after}"
138+
139+
puts changelog_body

0 commit comments

Comments
 (0)