diff options
author | Jacob Vosmaer (GitLab) <jacob@gitlab.com> | 2018-05-17 13:12:33 +0300 |
---|---|---|
committer | Jacob Vosmaer (GitLab) <jacob@gitlab.com> | 2018-05-17 13:12:33 +0300 |
commit | aa862d7937c802dfea18f190e8ae4d7f9d4f224b (patch) | |
tree | ba1f54cddf895d3114ac6711786563920b53f222 | |
parent | 0e8cb5ad07960952a94c7eb0ec3167cccd7ae9ec (diff) | |
parent | 1dc8d51ea225b0385e22d9182a6b0d5de5d4291e (diff) |
Merge branch 'zj-changelog-merge-conflicts' into 'master'
Generate changelog and its entries
See merge request gitlab-org/gitaly!719
-rw-r--r-- | CHANGELOG.md | 9 | ||||
-rw-r--r-- | Dangerfile | 33 | ||||
-rwxr-xr-x | _support/changelog | 243 | ||||
-rwxr-xr-x | _support/generate_changelog | 66 | ||||
-rwxr-xr-x | _support/release | 18 | ||||
-rw-r--r-- | changelogs/unreleased/gitaly-ruby-debug-log.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/gitaly-ruby-round-robin.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/zj-changelog-merge-conflicts.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/zj-move-create-repo-code.yml | 5 |
9 files changed, 352 insertions, 37 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md index adbb71c2f..58a968991 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,5 @@ # Gitaly changelog -UNRELEASED - -- Use round robin load balancing instead of 'pick first' for gitaly-ruby - https://gitlab.com/gitlab-org/gitaly/merge_requests/700 -- Unvendor Repository#create implementation - https://gitlab.com/gitlab-org/gitaly/merge_requests/713 -- Add gitaly-ruby installation debug log messages - https://gitlab.com/gitlab-org/gitaly/merge_requests/710 - v0.100.0 - Fix WikiFindPage when the page has invalidly-encoded content diff --git a/Dangerfile b/Dangerfile index 3afa7a26d..ee7e37498 100644 --- a/Dangerfile +++ b/Dangerfile @@ -1,30 +1,35 @@ -CHANGELOG_FILE = "CHANGELOG.md" +require 'yaml' +require 'json' -def check_changelog - unless git.modified_files.include?(CHANGELOG_FILE) - warn("This MR is missing a CHANGELOG entry") +fail("Please provide a MR description") if gitlab.mr_body.empty? + +def check_changelog(path) + if git.modified_files.include?("CHANGELOG.md") + fail("CHANGELOG.md was edited. Please remove the additions and create an entry with _support/changelog") return end - patch = git.diff_for_file(CHANGELOG_FILE).patch - unless patch.match?(/^\+- #{Regexp.quote(gitlab.mr_title)}\n/) - fail('Changelog entry should match the MR title') - end + if git.added_files.include?(path) + warn("No changelog entry was generated, please do so by executing _support/changelog") + else + yaml = YAML.safe_load(yaml) - unless patch.match?(/^\+\s+#{Regexp.quote(gitlab.mr_json['web_url'])}\n/) - fail('Changelog entry URL does not match the web url') + unless yaml['merge_request'] == gitlab.mr["iid"] + fail("Merge request ID was set to #{yaml['merge_request']}, expected #{gitlab.mr['iid']}") + end + + unless yaml['title'] == gitlab.mr_title + fail('Changelog entry should match the MR title') + end end end -check_changelog - -fail("Please provide a MR description") if gitlab.mr_body.empty? +check_changelog(File.join('changelogs', 'unreleased', "#{gitlab.branch_for_base}.yml}")) VENDOR_JSON = 'vendor/vendor.json' fail("Expected #{VENDOR_JSON} to exist") unless File.exist?(VENDOR_JSON) if git.modified_files.include?(VENDOR_JSON) - require 'json' parsed_json = JSON.parse(File.read(VENDOR_JSON)) proto = parsed_json["package"]&.find { |h| h["path"].start_with?("gitlab.com/gitlab-org/gitaly-proto") } diff --git a/_support/changelog b/_support/changelog new file mode 100755 index 000000000..4abb9da2c --- /dev/null +++ b/_support/changelog @@ -0,0 +1,243 @@ +#!/usr/bin/env ruby +# +# Generate a changelog entry file in the correct location. +# +# Automatically stages the file and amends the previous commit if the `--amend` +# argument is used. +# +# Lifted from gitlab-org/gitlab-ce + +require 'optparse' +require 'yaml' + +Options = Struct.new( + :amend, + :author, + :dry_run, + :force, + :merge_request, + :title, + :type +) +INVALID_TYPE = -1 + +class ChangelogOptionParser + Type = Struct.new(:name, :description) + TYPES = [ + Type.new('added', 'New feature'), + Type.new('fixed', 'Bug fix'), + Type.new('changed', 'Feature change'), + Type.new('deprecated', 'New deprecation'), + Type.new('removed', 'Feature removal'), + Type.new('security', 'Security fix'), + Type.new('performance', 'Performance improvement'), + Type.new('other', 'Other') + ].freeze + TYPES_OFFSET = 1 + + class << self + def parse(argv) + options = Options.new + + parser = OptionParser.new do |opts| + opts.banner = "Usage: #{__FILE__} [options] [title]\n\n" + + # Note: We do not provide a shorthand for this in order to match the `git + # commit` interface + opts.on('--amend', 'Amend the previous commit') do |value| + options.amend = value + end + + opts.on('-f', '--force', 'Overwrite an existing entry') do |value| + options.force = value + end + + opts.on('-m', '--merge-request [integer]', Integer, 'Merge Request ID') do |value| + options.merge_request = value + end + + opts.on('-n', '--dry-run', "Don't actually write anything, just print") do |value| + options.dry_run = value + end + + opts.on('-u', '--git-username', 'Use Git user.name configuration as the author') do |value| + options.author = git_user_name if value + end + + opts.on('-t', '--type [string]', String, "The category of the change, valid options are: #{TYPES.map(&:name).join(', ')}") do |value| + options.type = parse_type(value) + end + + opts.on('-h', '--help', 'Print help message') do + $stdout.puts opts + exit + end + end + + parser.parse!(argv) + + # Title is everything that remains, but let's clean it up a bit + options.title = argv.join(' ').strip.squeeze(' ').tr("\r\n", '') + + options + end + + def read_type + read_type_message + + type = TYPES[$stdin.getc.to_i - TYPES_OFFSET] + assert_valid_type!(type) + + type.name + end + + private + + def parse_type(name) + type_found = TYPES.find do |type| + type.name == name + end + type_found ? type_found.name : INVALID_TYPE + end + + def read_type_message + $stdout.puts "\n>> Please specify the index for the category of your change:" + TYPES.each_with_index do |type, index| + $stdout.puts "#{index + TYPES_OFFSET}. #{type.description}" + end + $stdout.print "\n?> " + end + + def assert_valid_type!(type) + unless type + $stderr.puts "Invalid category index, please select an index between 1 and #{TYPES.length}" + exit 1 + end + end + + def git_user_name + %x{git config user.name}.strip + end + end +end + +class ChangelogEntry + attr_reader :options + + def initialize(options) + @options = options + + assert_feature_branch! + assert_title! + assert_new_file! + + # Read type from $stdin unless is already set + options.type ||= ChangelogOptionParser.read_type + assert_valid_type! + + $stdout.puts "\e[32mcreate\e[0m #{file_path}" + $stdout.puts contents + + unless options.dry_run + write + amend_commit if options.amend + end + end + + private + + def contents + yaml_content = YAML.dump( + 'title' => title, + 'merge_request' => options.merge_request, + 'author' => options.author, + 'type' => options.type + ) + remove_trailing_whitespace(yaml_content) + end + + def write + File.write(file_path, contents) + end + + def amend_commit + %x{git add #{file_path}} + exec("git commit --amend") + end + + def fail_with(message) + $stderr.puts "\e[31merror\e[0m #{message}" + exit 1 + end + + def assert_feature_branch! + return unless branch_name == 'master' + + fail_with "Create a branch first!" + end + + def assert_new_file! + return unless File.exist?(file_path) + return if options.force + + fail_with "#{file_path} already exists! Use `--force` to overwrite." + end + + def assert_title! + return if options.title.length > 0 || options.amend + + fail_with "Provide a title for the changelog entry or use `--amend`" \ + " to use the title from the previous commit." + end + + def assert_valid_type! + return unless options.type && options.type == INVALID_TYPE + + fail_with 'Invalid category given!' + end + + def title + if options.title.empty? + last_commit_subject + else + options.title + end + end + + def last_commit_subject + %x{git log --format="%s" -1}.strip + end + + def file_path + File.join( + unreleased_path, + branch_name.gsub(/[^\w-]/, '-') << '.yml' + ) + end + + def unreleased_path + path = File.join('changelogs', 'unreleased') + path = File.join('ee', path) if ee? + + path + end + + def ee? + @ee ||= File.exist?(File.expand_path('../CHANGELOG-EE.md', __dir__)) + end + + def branch_name + @branch_name ||= %x{git symbolic-ref --short HEAD}.strip + end + + def remove_trailing_whitespace(yaml_content) + yaml_content.gsub(/ +$/, '') + end +end + +if $0 == __FILE__ + options = ChangelogOptionParser.parse(ARGV) + ChangelogEntry.new(options) +end + +# vim: ft=ruby diff --git a/_support/generate_changelog b/_support/generate_changelog new file mode 100755 index 000000000..89bbcd719 --- /dev/null +++ b/_support/generate_changelog @@ -0,0 +1,66 @@ +#!/usr/bin/env ruby +# Generates the changelog from the yaml entries in changelogs/unreleased + +require 'yaml' +require 'fileutils' + +class ChangelogEntry + attr_reader :title, :merge_request, :type, :author + + def initialize(file_path) + yaml = YAML.safe_load(File.read(file_path)) + + @title = yaml['title'] + @merge_request = yaml['merge_request'] + @type = yaml['type'] + @author = yaml['author'] + end + + def to_s + str = "" + str << "- #{title}\n" + str << " https://gitlab.com/gitlab-org/gitaly/merge_requests/#{merge_request}\n" + str << " Contributed by #{author}\n" if author + + str + end +end + +ROOT_DIR = File.expand_path('../..', __FILE__) +UNRELEASED_ENTRIES = File.join(ROOT_DIR, 'changelogs', 'unreleased') +CHANGELOG_FILE = File.join(ROOT_DIR, 'CHANGELOG.md') + +def main(version) + entries = [] + Dir["#{UNRELEASED_ENTRIES}/*.yml"].each do |yml| + entries << ChangelogEntry.new(yml) + FileUtils.rm(yml) + end + + lines = [] + types = entries.map(&:type).uniq.sort + types.each do |type| + lines << "#{type.capitalize}\n" + + entries.each do |e| + next unless e.type == type + + lines << e.to_s + end + end + + current_changelog = File.read(CHANGELOG_FILE).lines + header = current_changelog.shift(2) + + new_changelog = [header, "v#{version}\n\n", lines, "\n", current_changelog].flatten.join + + File.write(CHANGELOG_FILE, new_changelog) +end + +unless ARGV.count == 1 + warn "Usage: #{$0} VERSION" + warn "Specify version as x.y.z" + abort +end + +main(ARGV.first) diff --git a/_support/release b/_support/release index 81e006135..2ff2061e0 100755 --- a/_support/release +++ b/_support/release @@ -35,7 +35,10 @@ def main(version) tag_name = "v#{version}" write_version_file(version) - update_changelog(tag_name) + + run!(%W[_support/generate_changelog #{version}]) + run!(%w[git add changelogs CHANGELOG.md]) + version_msg = "Version #{version}" run!(%W[git commit -m #{version_msg}]) run!(%W[git tag -a -m #{version_msg} #{tag_name}]) @@ -57,19 +60,6 @@ def write_version_file(version) run!(%W[git add #{version_file}]) end -def update_changelog(version_string) - changelog = 'CHANGELOG.md' - content = IO.read(changelog).lines - unreleased_line = "UNRELEASED\n" - version_index = content.find_index { |l| l == unreleased_line } - if version_index.nil? - abort "no #{unreleased_line.inspect} line found in #{changelog}" - end - content[version_index] = version_string + "\n" - IO.write(changelog, content.join) - run!(%W[git add #{changelog}]) -end - def error(msg) warn "#{$0}: #{msg}" end diff --git a/changelogs/unreleased/gitaly-ruby-debug-log.yml b/changelogs/unreleased/gitaly-ruby-debug-log.yml new file mode 100644 index 000000000..e35765ced --- /dev/null +++ b/changelogs/unreleased/gitaly-ruby-debug-log.yml @@ -0,0 +1,5 @@ +--- +title: Add gitaly-ruby installation debug log messages +merge_request: 710 +author: +type: changed diff --git a/changelogs/unreleased/gitaly-ruby-round-robin.yml b/changelogs/unreleased/gitaly-ruby-round-robin.yml new file mode 100644 index 000000000..b0b03f8b4 --- /dev/null +++ b/changelogs/unreleased/gitaly-ruby-round-robin.yml @@ -0,0 +1,5 @@ +--- +title: Use round robin load balancing instead of 'pick first' for gitaly-ruby +merge_request: +author: +type: fixed diff --git a/changelogs/unreleased/zj-changelog-merge-conflicts.yml b/changelogs/unreleased/zj-changelog-merge-conflicts.yml new file mode 100644 index 000000000..9e093680d --- /dev/null +++ b/changelogs/unreleased/zj-changelog-merge-conflicts.yml @@ -0,0 +1,5 @@ +--- +title: Generate changelog when releasing a tag to prevent merge conflicts +merge_request: +author: +type: other diff --git a/changelogs/unreleased/zj-move-create-repo-code.yml b/changelogs/unreleased/zj-move-create-repo-code.yml new file mode 100644 index 000000000..6f5729339 --- /dev/null +++ b/changelogs/unreleased/zj-move-create-repo-code.yml @@ -0,0 +1,5 @@ +--- +title: Unvendor Repository#create implementation +merge_request: 713 +author: +type: other |