Commit 3850e498 authored by Yorick Peterse's avatar Yorick Peterse

Merge branch 'prep-new-changelog-approach' into 'master'

Update tooling/docs for the new changelog workflow

See merge request gitlab-org/gitlab!62012
parents 34af4653 448a9e7c
**NOTE:** This file is no longer used for GitLab Enterprise Edition changelog
entries. Starting with May 22nd, 2021 all changelog entries are found in
[CHANGELOG.md](CHANGELOG.md)
Please view this file on the master branch, on stable branches it's out of date.
## 13.12.0 (2021-05-22)
......
#!/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.
require 'optparse'
require 'yaml'
INVALID_TYPE = -1
module ChangelogHelpers
Abort = Class.new(StandardError)
Done = Class.new(StandardError)
MAX_FILENAME_LENGTH = 99 # GNU tar has a 99 character limit
def capture_stdout(cmd)
output = IO.popen(cmd, &:read)
fail_with "command failed: #{cmd.join(' ')}" unless $?.success?
output
end
def fail_with(message)
raise Abort, "\e[31merror\e[0m #{message}"
end
end
class ChangelogOptionParser
extend ChangelogHelpers
Options = Struct.new(
:amend,
:author,
:dry_run,
:force,
:merge_request,
:title,
:type,
:ee
)
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('-e', '--ee', 'Generate a changelog entry for GitLab EE') do |value|
options.ee = value
end
opts.on('-h', '--help', 'Print help message') do
$stdout.puts opts
raise Done.new
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
raise Abort, "Invalid category index, please select an index between 1 and #{TYPES.length}"
end
end
def git_user_name
capture_stdout(%w[git config user.name]).strip
end
end
end
class ChangelogEntry
include ChangelogHelpers
attr_reader :options
def initialize(options)
@options = options
end
def execute
assert_feature_branch!
assert_title! unless editor
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
if editor
system("#{editor} '#{file_path}'")
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 editor
ENV['EDITOR']
end
def amend_commit
fail_with "git add failed" unless system(*%W[git add #{file_path}])
Kernel.exec(*%w[git commit --amend])
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
capture_stdout(%w[git log --format=%s -1]).strip
end
def file_path
base_path = File.join(
unreleased_path,
branch_name.gsub(/[^\w-]/, '-'))
# Add padding for .yml extension
base_path[0..MAX_FILENAME_LENGTH - 5] + '.yml'
end
def unreleased_path
path = File.join('changelogs', 'unreleased')
path = File.join('ee', path) if ee?
path
end
def ee?
options.ee
end
def branch_name
@branch_name ||= capture_stdout(%w[git symbolic-ref --short HEAD]).strip
end
def remove_trailing_whitespace(yaml_content)
yaml_content.gsub(/ +$/, '')
end
end
if $0 == __FILE__
begin
options = ChangelogOptionParser.parse(ARGV)
ChangelogEntry.new(options).execute
rescue ChangelogHelpers::Abort => ex
$stderr.puts ex.message
exit 1
rescue ChangelogHelpers::Done
exit
end
end
# vim: ft=ruby
---
title: Allow issue type change for incidents
merge_request: 61363
author:
type: changed
---
title: Update button variants and alignment to align with the Pajamas Design System
and modify the avatar layout to have better flow.
merge_request: 61504
author:
type: other
---
title: Track usage of the resolve conflict UI
merge_request: 61654
author:
type: other
---
title: Remove old redirect rule for the usage trends feature
merge_request: 60485
author:
type: changed
---
title: Update group/project member tabs to comply with Pajamas design system
merge_request:
author:
type: other
---
title: Remove the feature flag for the external validation service
merge_request: 61351
author:
type: other
---
title: Add admin page for batched background migrations
merge_request: 60911
author:
type: added
---
title: Remove the redundant update for API endpoint projects/:id/statuses/:sha
merge_request: 61470
author:
type: performance
---
title: Removed packages_finder_helper_deploy_token feature flag
merge_request: 62189
author:
type: other
---
title: Lock a newly created item card in boards
merge_request: 61958
author:
type: changed
---
title: Use cache for CI::Build runners check
merge_request: 61998
author:
type: performance
---
title: Add options events to Redis HLL metrics for filtering data
merge_request: 61685
author:
type: other
---
title: Observe secondary email addresses when adding a member
merge_request: 62024
author:
type: changed
---
title: Fix pipeline graph undefined needs error
merge_request: 62027
author:
type: fixed
---
title: Remove support for /wip quick action
merge_request: 61199
author:
type: removed
---
title: Properly process stale ongoing container repository cleanups
merge_request: 62005
author:
type: fixed
---
title: Remove UnicornCheck service
merge_request: 62204
author:
type: removed
---
title: Remove Unicorn Sampler
merge_request: 62090
author:
type: removed
---
title: Execute member hooks only if an associated user is present
merge_request: 62175
author:
type: fixed
---
title: Fix blob preview error
merge_request: 62128
author:
type: fixed
---
title: Left-align certain application-wide cancel buttons to conform to the GitLab Pajamas style guide
merge_request: 61858
author:
type: changed
---
title: Ensure post-update actions are applied when assignees change
merge_request: 61897
author:
type: fixed
---
title: Fix errors in instance and group-level integration pages for some integrations
merge_request: 62054
author:
type: fixed
---
title: Resolve Time tracking report is bugged on GraphQL boards
merge_request: 62109
author:
type: fixed
---
title: Prepare ci_build_trace_sections for int8 migration
merge_request: 62098
author:
type: other
---
title: Add ease score onboarding in-product marketing email
merge_request: 61347
author:
type: changed
---
title: Prevent overflows in WebHook#backoff_count
merge_request: 62202
author:
type: fixed
---
title: Debian Group and Project Distribution Keys schema
merge_request: 60993
author: Mathieu Parent
type: added
---
title: Drop plugins directory support
merge_request: 55168
author:
type: removed
---
title: Redirect some of deprecated repository routes
merge_request: 34867
author:
type: removed
---
title: Remove some deprecated global routes
merge_request: 34295
author:
type: removed
---
title: Accelerate builds queuing using a denormalized accelerated table
merge_request: 61581
author:
type: performance
---
title: Fix atom feed with push events for multiple tags
merge_request: 62059
author:
type: fixed
---
title: Fix permission check when setting issue/merge request subscription in GraphQL
API.
merge_request: 61980
author:
type: fixed
---
title: Return 404 from branches API when repository does not exist
merge_request:
author:
type: fixed
---
title: Fixed Rails Save Bang offenses in few spec/models/* files
merge_request: 61961
author: Suraj Tripathi @surajtripathy07
type: fixed
---
title: Fixed Rails Save Bang offenses in few spec/models/* files
merge_request: 62165
author: Suraj Tripathi @surajtripathy07
type: fixed
---
title: Enable Kroki on reStructuredText and Textile documents
merge_request: 60780
author: Guillaume Grossetie
type: added
---
title: Add metrics to calculate rate of project imports
merge_request: 61775
author:
type: added
---
title: Backfill clusters_integration_prometheus.enabled
merge_request: 61502
author:
type: changed
---
title: Compress oversized Sidekiq job payload before dispatching into Redis
merge_request: 61667
author:
type: added
---
title: Contributes to https://gitlab.com/gitlab-org/gitlab/-/issues/325744
merge_request: 60086
author: Amit Patel @amit.savani
type: performance
---
title: 'Merge Request edit: make breadcrumbs consistent'
merge_request: 62138
author: Santiago Gil @santigl
type: other
---
title: Optimize query for loading artifacts in pipeline
merge_request: 62249
author:
type: performance
---
title: Simplify error code handling for external pipeline validation
merge_request: 61190
author:
type: changed
---
title: Fix `pry` debugging location with `pry-byebug` and `pry-shell` by updating the `pry-shell` gem
merge_request: 62122
author:
type: fixed
This diff is collapsed.
......@@ -1014,7 +1014,7 @@ Check if new metrics need to be added to the Versions Application. See `usage_da
Add the `feature` label to the Merge Request for new Usage Ping metrics. These are user-facing changes and are part of expanding the Usage Ping feature.
### 8. Add a changelog file
### 8. Add a changelog
Ensure you comply with the [Changelog entries guide](../changelog.md).
......
# frozen_string_literal: true
require 'spec_helper'
load File.expand_path('../../bin/changelog', __dir__)
RSpec.describe 'bin/changelog' do
let(:options) { OpenStruct.new(title: 'Test title', type: 'fixed', dry_run: true) }
describe ChangelogEntry do
it 'truncates the file path' do
entry = described_class.new(options)
allow(entry).to receive(:ee?).and_return(false)
allow(entry).to receive(:branch_name).and_return('long-branch-' * 100)
file_path = entry.send(:file_path)
expect(file_path.length).to eq(99)
end
end
describe ChangelogOptionParser do
describe '.parse' do
it 'parses --amend' do
options = described_class.parse(%w[foo bar --amend])
expect(options.amend).to eq true
end
it 'parses --force and -f' do
%w[--force -f].each do |flag|
options = described_class.parse(%W[foo #{flag} bar])
expect(options.force).to eq true
end
end
it 'parses --merge-request and -m' do
%w[--merge-request -m].each do |flag|
options = described_class.parse(%W[foo #{flag} 1234 bar])
expect(options.merge_request).to eq 1234
end
end
it 'parses --dry-run and -n' do
%w[--dry-run -n].each do |flag|
options = described_class.parse(%W[foo #{flag} bar])
expect(options.dry_run).to eq true
end
end
it 'parses --git-username and -u' do
allow(described_class).to receive(:git_user_name).and_return('Jane Doe')
%w[--git-username -u].each do |flag|
options = described_class.parse(%W[foo #{flag} bar])
expect(options.author).to eq 'Jane Doe'
end
end
it 'parses --type and -t' do
%w[--type -t].each do |flag|
options = described_class.parse(%W[foo #{flag} security])
expect(options.type).to eq 'security'
end
end
it 'parses --ee and -e' do
%w[--ee -e].each do |flag|
options = described_class.parse(%W[foo #{flag} security])
expect(options.ee).to eq true
end
end
it 'parses -h' do
expect do
expect { described_class.parse(%w[foo -h bar]) }.to output.to_stdout
end.to raise_error(ChangelogHelpers::Done)
end
it 'assigns title' do
options = described_class.parse(%W[foo -m 1 bar\n baz\r\n --amend])
expect(options.title).to eq 'foo bar baz'
end
end
describe '.read_type' do
let(:type) { '1' }
it 'reads type from $stdin' do
expect($stdin).to receive(:getc).and_return(type)
expect do
expect(described_class.read_type).to eq('added')
end.to output.to_stdout
end
context 'invalid type given' do
let(:type) { '99' }
it 'shows error message and exits the program' do
allow($stdin).to receive(:getc).and_return(type)
expect do
expect { described_class.read_type }.to raise_error(
ChangelogHelpers::Abort,
'Invalid category index, please select an index between 1 and 8'
)
end.to output.to_stdout
end
end
end
end
end
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment