diff options
-rwxr-xr-x | _support/changelog | 243 | ||||
-rw-r--r-- | changelogs/unreleased/.keep | 0 | ||||
-rw-r--r-- | changelogs/unreleased/pks-lfs-pointers-latency.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/pks-remotes-voting.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/remove_ff_gitaly_go_user_revert.yml | 5 | ||||
-rw-r--r-- | changelogs/unreleased/wc-no-housekeeping-cleanup.yml | 5 | ||||
-rw-r--r-- | danger/changelog/Dangerfile | 141 |
7 files changed, 43 insertions, 361 deletions
diff --git a/_support/changelog b/_support/changelog deleted file mode 100755 index 4abb9da2c..000000000 --- a/_support/changelog +++ /dev/null @@ -1,243 +0,0 @@ -#!/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/changelogs/unreleased/.keep b/changelogs/unreleased/.keep deleted file mode 100644 index e69de29bb..000000000 --- a/changelogs/unreleased/.keep +++ /dev/null diff --git a/changelogs/unreleased/pks-lfs-pointers-latency.yml b/changelogs/unreleased/pks-lfs-pointers-latency.yml deleted file mode 100644 index f56bebcb6..000000000 --- a/changelogs/unreleased/pks-lfs-pointers-latency.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'blob: Improve latency and memory consumption for LFS pointers' -merge_request: 3483 -author: -type: performance diff --git a/changelogs/unreleased/pks-remotes-voting.yml b/changelogs/unreleased/pks-remotes-voting.yml deleted file mode 100644 index fffe31aed..000000000 --- a/changelogs/unreleased/pks-remotes-voting.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: 'remote: Vote when adding and removing remotes' -merge_request: 3508 -author: -type: added diff --git a/changelogs/unreleased/remove_ff_gitaly_go_user_revert.yml b/changelogs/unreleased/remove_ff_gitaly_go_user_revert.yml deleted file mode 100644 index 4c8633b75..000000000 --- a/changelogs/unreleased/remove_ff_gitaly_go_user_revert.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Remove gitaly feature flag gitaly_go_user_revert -merge_request: 3516 -author: -type: changed diff --git a/changelogs/unreleased/wc-no-housekeeping-cleanup.yml b/changelogs/unreleased/wc-no-housekeeping-cleanup.yml deleted file mode 100644 index e2da5d9b8..000000000 --- a/changelogs/unreleased/wc-no-housekeeping-cleanup.yml +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: Don't run housekeeping in Cleanup RPC -merge_request: 3502 -author: -type: fixed diff --git a/danger/changelog/Dangerfile b/danger/changelog/Dangerfile index 1a7029768..56efe44de 100644 --- a/danger/changelog/Dangerfile +++ b/danger/changelog/Dangerfile @@ -1,33 +1,33 @@ -# frozen_string_literal: true require 'yaml' +def lint_commit(commit) + trailer = commit.message.match(/^Changelog:\s*(?<category>\w+)/) + + return :missing if trailer.nil? || trailer[:category].nil? + + category = trailer[:category] + + return :valid if CATEGORIES.include?(category) + + self.fail( + "Commit #{commit.sha} uses an invalid changelog category: #{category}" + ) + + :invalid +end + +def presented_no_changelog_labels + NO_CHANGELOG_LABELS.map { |label| %(~"#{label}") }.join(', ') +end + NO_CHANGELOG_LABELS = [ + 'documentation', 'tooling', 'tooling::pipelines', 'tooling::workflow', 'ci-build', - 'meta', - 'documentation' + 'meta' ].freeze -SEE_DOC = "See the [changelog documentation](https://docs.gitlab.com/ee/development/changelog.html)." -CREATE_CHANGELOG_MESSAGE = <<~MSG -You can create one with: - -``` -_support/changelog -m %<mr_iid>s "%<mr_title>s" -``` - -If your merge request doesn't warrant a CHANGELOG entry, -consider adding any of the %<labels>s labels. -MSG - -SUGGEST_MR_COMMENT = <<~SUGGEST_COMMENT -```suggestion -merge_request: %<mr_iid>s -``` - -#{SEE_DOC} -SUGGEST_COMMENT CATEGORIES = YAML .load_file(File.expand_path('../../.gitlab/changelog_config.yml', __dir__)) @@ -35,102 +35,47 @@ CATEGORIES = YAML .keys .freeze -def check_changelog_trailer(commit) - trailer = commit.message.match(/^Changelog:\s*(?<category>.+)$/) +SEE_DOC = "See [the documentation](https://docs.gitlab.com/ee/development/changelog.html).".freeze - return :missing if trailer.nil? || trailer[:category].nil? +CHANGELOG_MISSING = <<~MSG.freeze +**[CHANGELOG missing](https://docs.gitlab.com/ee/development/changelog.html).** - category = trailer[:category] +To ceate a changelog, annotate one or more commits with the `Changelog` Git +trailer. If you want to annotate the latest commit, you can do so using `git +commit --amend`. If you want to annotate older or multiple commits, you need to +do so using `git rebase -i`. - return :valid if CATEGORIES.include?(category) +When adding the trailer, you can use the following values: - self.fail( - "Commit #{commit.sha} uses an invalid changelog category: #{category}" - ) +- #{CATEGORIES.join("\n- ")} - :invalid -end +For example: -def check_changelog(path) - raw_file = File.read(path) - yaml = YAML.safe_load(raw_file) +``` +This is the subject of your commit. - fail "`title` should be set, in #{gitlab.html_link(path)}! #{SEE_DOC}" if yaml["title"].nil? - fail "`type` should be set, in #{gitlab.html_link(path)}! #{SEE_DOC}" if yaml["type"].nil? +This would be the body of your commit containing some extra details. - if yaml["merge_request"].nil? - mr_line = raw_file.lines.find_index { |l| l.start_with?("merge_request:") } +Changelog: added +``` - if mr_line - markdown(format(SUGGEST_MR_COMMENT, mr_iid: gitlab.mr_json["iid"]), file: path, line: mr_line.succ) - else - message "Consider setting `merge_request` to #{gitlab.mr_json["iid"]} in #{gitlab.html_link(path)}. #{SEE_DOC}" - end - elsif yaml["merge_request"] != gitlab.mr_json["iid"] - fail "Merge request ID was not set to #{gitlab.mr_json["iid"]}! #{SEE_DOC}" - end -rescue Psych::SyntaxError, Psych::DisallowedClass, Psych::BadAlias - # YAML could not be parsed, fail the build. - fail "#{gitlab.html_link(path)} isn't valid YAML! #{SEE_DOC}" -rescue StandardError => e - warn "There was a problem trying to check the Changelog. Exception: #{e.name} - #{e.message}" -end +If your merge request doesn't warrant a CHANGELOG entry, consider adding any of +the #{presented_no_changelog_labels} labels. -def presented_no_changelog_labels - NO_CHANGELOG_LABELS.map { |label| %Q(~\\"#{label}\\") }.join(', ') -end +#{SEE_DOC} +MSG changelog_needed = (gitlab.mr_labels & NO_CHANGELOG_LABELS).empty? -changelog_found = git.added_files.find { |path| path =~ %r{\Achangelogs/unreleased/} } - -mr_title = gitlab.mr_json["title"].gsub(/^WIP: */, '') - -if git.modified_files.include?("CHANGELOG.md") - fail "**CHANGELOG.md was edited.** Please remove the additions and create a CHANGELOG entry.\n\n" + - format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: mr_title, labels: presented_no_changelog_labels) -end - -if changelog_found - check_changelog(changelog_found) -elsif changelog_needed - warn "**[CHANGELOG missing](https://docs.gitlab.com/ce/development/changelog.html).**\n\n" + - format(CREATE_CHANGELOG_MESSAGE, mr_iid: gitlab.mr_json["iid"], mr_title: mr_title, labels: presented_no_changelog_labels) -end if changelog_needed checked = 0 git.commits.each do |commit| - case check_changelog_trailer(commit) + case lint_commit(commit) when :valid, :invalid checked += 1 end end - if checked == 0 - message <<~MSG - We are in the process of rolling out a new workflow for adding changelog entries. This new workflow uses Git commit subjects and Git trailers to generate changelogs. This new approach will soon replace the current YAML based approach. - - To ease the transition process, we recommend you start using both the old and new approach in parallel. This is not required at this time, but will make it easier to transition to the new approach in the future. To do so, pick the commit that should go in the changelog and add a `Changelog` trailer to it. For example: - - ``` - This is my commit's subject line - - This is the optional commit body. - - Changelog: added - ``` - - The value of the `Changelog` trailer should be one of the following: added, fixed, changed, deprecated, removed, security, performance, other. - - For more information, take a look at the following resources: - - - `https://gitlab.com/gitlab-com/gl-infra/delivery/-/issues/1564` - - https://docs.gitlab.com/ee/api/repositories.html#generate-changelog-data - - If you'd like to see the new approach in action, take a look at the commits in [the Omnibus repository](https://gitlab.com/gitlab-org/omnibus-gitlab/-/commits/master). - MSG - end + warn(CHANGELOG_MISSING) if checked.zero? end - -# vim: ft=ruby |