logstash/tools/release/generate_release_notes.rb
Andres Rodriguez 4255a8fd1c
Rubocop: Enable SpaceAround cops (#15196)
* Enable SpaceARoundBlockParameters
* Enable SpaceAroundEqualsInParameterDefault
* Enable SpaceAroundKeyword
* Enable SpaceAroundOperators
* Enable SpaceBeforeBlockBraces, which yields no changes
2023-07-18 21:11:57 -04:00

133 lines
5.8 KiB
Ruby
Executable file

#!/usr/bin/env ruby
# Licensed to Elasticsearch B.V. under one or more contributor
# license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright
# ownership. Elasticsearch B.V. licenses this file to you under
# the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
# Example:
# ruby generate_release_notes.rb 6.4 6.4.1
#
# This:
# * compares the lock file of two commits
# * for each plugin version bumped show CHANGELOG.md of the bumped version
require 'tempfile'
require 'yaml'
require 'json'
require 'net/http'
RELEASE_NOTES_PATH = "docs/static/releasenotes.asciidoc"
release_branch = ARGV[0]
previous_release_tag = ARGV[1]
user = ARGV[2]
token = ARGV[3]
report = []
`git checkout #{release_branch}`
current_release = YAML.load(IO.read("versions.yml"))["logstash"]
current_release_dashes = current_release.tr(".", "-")
release_notes = IO.read(RELEASE_NOTES_PATH).split("\n")
current_release_heading = "* <<logstash-#{current_release_dashes},Logstash #{current_release}>>"
release_notes.insert(5, current_release_heading) unless release_notes[5].eql?(current_release_heading)
coming_tag_index = release_notes.find_index {|line| line.match(/^coming\[#{current_release}\]/) }
coming_tag_index += 1 if coming_tag_index
release_notes_entry_index = coming_tag_index || release_notes.find_index {|line| line.match(/^\[\[logstash/) }
report << "[[logstash-#{current_release_dashes}]]" unless release_notes.any? { |line| line.match(/^\[\[logstash-#{current_release_dashes}/) }
report << "=== Logstash #{current_release} Release Notes\n" unless release_notes.any? { |line| line.match(/^=== Logstash #{current_release}/)}
plugin_changes = {}
report << "---------- GENERATED CONTENT STARTS HERE ------------"
report << "=== Logstash Pull Requests with label v#{current_release}\n"
uri = URI.parse("https://api.github.com/search/issues?q=repo:elastic/logstash+is:pr+is:closed+label:v#{current_release}&sort=created&order=asc")
pull_requests = JSON.parse(Net::HTTP.get(uri))
pull_requests['items'].each do |prs|
report << "* #{prs['title']} #{prs['html_url']}[##{prs['number']}]"
end
report << ""
report << "=== Logstash Commits between #{release_branch} and #{previous_release_tag}\n"
report << "Computed with \"git log --pretty=format:'%h -%d %s (%cr) <%an>' --abbrev-commit --date=relative v#{previous_release_tag}..#{release_branch}\""
report << ""
logstash_prs = `git log --pretty=format:'%h -%d %s (%cr) <%an>' --abbrev-commit --date=relative v#{previous_release_tag}..#{release_branch}`
report << logstash_prs
report << "\n=== Logstash Plugin Release Changelogs ==="
report << "Computed from \"git diff v#{previous_release_tag}..#{release_branch} *.release\""
result = `git diff v#{previous_release_tag}..#{release_branch} *.release`.split("\n")
result.each do |line|
# example "+ logstash-input-syslog (3.4.1)"
if match = line.match(/\+\s+(?<plugin>logstash-.+?-.+?)\s+\((?<version>\d+\.\d+.\d+).*?\)/)
plugin_changes[match[:plugin]] ||= []
plugin_changes[match[:plugin]] << match[:version]
elsif match = line.match(/\-\s+(?<plugin>logstash-.+?-.+?)\s+\((?<version>\d+\.\d+.\d+).*?\)/)
plugin_changes[match[:plugin]] ||= []
plugin_changes[match[:plugin]].unshift(match[:version])
else
# ..
end
end
report << "Changed plugin versions:"
plugin_changes.each {|p, v| report << "#{p}: #{v.first} -> #{v.last}" }
report << "---------- GENERATED CONTENT ENDS HERE ------------\n"
report << "==== Plugins\n"
plugin_changes.each do |plugin, versions|
_, type, name = plugin.split("-")
header = "*#{name.capitalize} #{type.capitalize} - #{versions.last}*"
start_changelog_file = Tempfile.new(plugin + 'start')
end_changelog_file = Tempfile.new(plugin + 'end')
changelog = `curl https://raw.githubusercontent.com/logstash-plugins/#{plugin}/v#{versions.last}/CHANGELOG.md`.split("\n")
report << "#{header}\n"
changelog.each do |line|
break if line.match(/^## #{versions.first}/)
next if line.match(/^##/)
line.gsub!(/^\+/, "")
line.gsub!(/ #(?<number>\d+)\s*$/, " https://github.com/logstash-plugins/#{plugin}/issues/\\k<number>[#\\k<number>]")
line.gsub!(/\[#(?<number>\d+)\]\((?<url>[^)]*)\)/, "\\k<url>[#\\k<number>]")
line.gsub!(/^\s+-/, "*")
report << line
end
report << ""
start_changelog_file.unlink
end_changelog_file.unlink
end
release_notes.insert(release_notes_entry_index, report.join("\n").gsub(/\n{3,}/, "\n\n"))
IO.write(RELEASE_NOTES_PATH, release_notes.join("\n"))
puts "Creating commit.."
branch_name = "update_release_notes_#{Time.now.to_i}"
`git checkout -b #{branch_name}`
`git commit docs/static/releasenotes.asciidoc -m "Update release notes for #{current_release}"`
puts "Pushing commit.."
`git remote set-url origin https://x-access-token:#{token}@github.com/elastic/logstash.git`
`git push origin #{branch_name}`
puts "Creating Pull Request"
pr_title = "Release notes for #{current_release}"
result = `curl -H "Authorization: token #{token}" -d '{"title":"#{pr_title}","base":"#{release_branch}", "head":"#{branch_name}", "draft": true}' https://api.github.com/repos/elastic/logstash/pulls`
puts result
pr_number = JSON.parse(result)["number"]
puts `curl -X POST -H "Accept: application/vnd.github.v3+json" -H "Authorization: token #{token}" https://api.github.com/repos/elastic/logstash/issues/#{pr_number}/assignees -d '{"assignees":["#{user}"]}'`
puts "Done"