Commit 33468656 authored by Lin Jen-Shin's avatar Lin Jen-Shin

Merge branch '293846-handle-wip-draft-in-commit-mr-linting' into 'master'

Handle WIP/DRAFT in commit/mr linting

See merge request gitlab-org/gitlab!50718
parents f07fee3a 1d23f0a6
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'title_linting'
module Gitlab module Gitlab
module Danger module Danger
class BaseLinter class BaseLinter
MIN_SUBJECT_WORDS_COUNT = 3 MIN_SUBJECT_WORDS_COUNT = 3
MAX_LINE_LENGTH = 72 MAX_LINE_LENGTH = 72
WIP_PREFIX = 'WIP: '
attr_reader :commit, :problems attr_reader :commit, :problems
...@@ -58,7 +59,7 @@ module Gitlab ...@@ -58,7 +59,7 @@ module Gitlab
private private
def subject def subject
message_parts[0].delete_prefix(WIP_PREFIX) TitleLinting.remove_draft_flag(message_parts[0])
end end
def subject_too_short? def subject_too_short?
......
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'title_linting'
module Gitlab module Gitlab
module Danger module Danger
module Changelog module Changelog
...@@ -75,7 +77,7 @@ module Gitlab ...@@ -75,7 +77,7 @@ module Gitlab
end end
def sanitized_mr_title def sanitized_mr_title
helper.sanitize_mr_title(gitlab.mr_json["title"]) TitleLinting.sanitize_mr_title(gitlab.mr_json["title"])
end end
def categories_need_changelog? def categories_need_changelog?
......
# frozen_string_literal: true # frozen_string_literal: true
require_relative 'teammate' require_relative 'teammate'
require_relative 'title_linting'
module Gitlab module Gitlab
module Danger module Danger
module Helper module Helper
RELEASE_TOOLS_BOT = 'gitlab-release-tools-bot' RELEASE_TOOLS_BOT = 'gitlab-release-tools-bot'
DRAFT_REGEX = /\A*#{Regexp.union(/(?i)(\[WIP\]\s*|WIP:\s*|WIP$)/, /(?i)(\[draft\]|\(draft\)|draft:|draft\s\-\s|draft$)/)}+\s*/i.freeze
# Returns a list of all files that have been added, modified or renamed. # Returns a list of all files that have been added, modified or renamed.
# `git.modified_files` might contain paths that already have been renamed, # `git.modified_files` might contain paths that already have been renamed,
...@@ -216,14 +216,10 @@ module Gitlab ...@@ -216,14 +216,10 @@ module Gitlab
usernames.map { |u| Gitlab::Danger::Teammate.new('username' => u) } usernames.map { |u| Gitlab::Danger::Teammate.new('username' => u) }
end end
def sanitize_mr_title(title)
title.gsub(DRAFT_REGEX, '').gsub(/`/, '\\\`')
end
def draft_mr? def draft_mr?
return false unless gitlab_helper return false unless gitlab_helper
DRAFT_REGEX.match?(gitlab_helper.mr_json['title']) TitleLinting.has_draft_flag?(gitlab_helper.mr_json['title'])
end end
def security_mr? def security_mr?
......
# frozen_string_literal: true
module Gitlab
module Danger
module TitleLinting
DRAFT_REGEX = /\A*#{Regexp.union(/(?i)(\[WIP\]\s*|WIP:\s*|WIP$)/, /(?i)(\[draft\]|\(draft\)|draft:|draft\s\-\s|draft$)/)}+\s*/i.freeze
module_function
def sanitize_mr_title(title)
remove_draft_flag(title).gsub(/`/, '\\\`')
end
def remove_draft_flag(title)
title.gsub(DRAFT_REGEX, '')
end
def has_draft_flag?(title)
DRAFT_REGEX.match?(title)
end
end
end
end
# frozen_string_literal: true # frozen_string_literal: true
require 'fast_spec_helper' require 'fast_spec_helper'
require 'rspec-parameterized'
require_relative 'danger_spec_helper' require_relative 'danger_spec_helper'
require 'gitlab/danger/base_linter' require 'gitlab/danger/base_linter'
...@@ -70,19 +71,57 @@ RSpec.describe Gitlab::Danger::BaseLinter do ...@@ -70,19 +71,57 @@ RSpec.describe Gitlab::Danger::BaseLinter do
end end
end end
context 'when subject is a WIP' do context 'when ignoring length issues for subject having not-ready wording' do
using RSpec::Parameterized::TableSyntax
let(:final_message) { 'A B C' } let(:final_message) { 'A B C' }
# commit message with prefix will be over max length. commit message without prefix will be of maximum size
let(:commit_message) { described_class::WIP_PREFIX + final_message + 'D' * (described_class::MAX_LINE_LENGTH - final_message.size) }
context 'when used as prefix' do
where(prefix: [
'WIP: ',
'WIP:',
'wIp:',
'[WIP] ',
'[WIP]',
'[draft]',
'[draft] ',
'(draft)',
'(draft) ',
'draft - ',
'draft: ',
'draft:',
'DRAFT:'
])
with_them do
it 'does not have any problems' do it 'does not have any problems' do
commit_linter.lint_subject commit_message = prefix + final_message + 'D' * (described_class::MAX_LINE_LENGTH - final_message.size)
commit = commit_class.new(commit_message, anything, anything)
expect(commit_linter.problems).to be_empty linter = described_class.new(commit).lint_subject
expect(linter.problems).to be_empty
end
end
end
context 'when used as suffix' do
where(suffix: %w[WIP draft])
with_them do
it 'does not have any problems' do
commit_message = final_message + 'D' * (described_class::MAX_LINE_LENGTH - final_message.size) + suffix
commit = commit_class.new(commit_message, anything, anything)
linter = described_class.new(commit).lint_subject
expect(linter.problems).to be_empty
end
end
end end
end end
context 'when subject is too short and too long' do context 'when subject does not have enough words and is too long' do
let(:commit_message) { 'A ' + 'B' * described_class::MAX_LINE_LENGTH } let(:commit_message) { 'A ' + 'B' * described_class::MAX_LINE_LENGTH }
it 'adds a problem' do it 'adds a problem' do
......
...@@ -150,41 +150,80 @@ RSpec.describe Gitlab::Danger::Changelog do ...@@ -150,41 +150,80 @@ RSpec.describe Gitlab::Danger::Changelog do
end end
describe '#modified_text' do describe '#modified_text' do
let(:sanitize_mr_title) { 'Fake Title' }
let(:mr_json) { { "iid" => 1234, "title" => sanitize_mr_title } } let(:mr_json) { { "iid" => 1234, "title" => sanitize_mr_title } }
subject { changelog.modified_text } subject { changelog.modified_text }
it do context "when title is not changed from sanitization", :aggregate_failures do
let(:sanitize_mr_title) { 'Fake Title' }
specify do
expect(subject).to include('CHANGELOG.md was edited') expect(subject).to include('CHANGELOG.md was edited')
expect(subject).to include('bin/changelog -m 1234 "Fake Title"') expect(subject).to include('bin/changelog -m 1234 "Fake Title"')
expect(subject).to include('bin/changelog --ee -m 1234 "Fake Title"') expect(subject).to include('bin/changelog --ee -m 1234 "Fake Title"')
end end
end end
context "when title needs sanitization", :aggregate_failures do
let(:sanitize_mr_title) { 'DRAFT: Fake Title' }
specify do
expect(subject).to include('CHANGELOG.md was edited')
expect(subject).to include('bin/changelog -m 1234 "Fake Title"')
expect(subject).to include('bin/changelog --ee -m 1234 "Fake Title"')
end
end
end
describe '#required_text' do describe '#required_text' do
let(:sanitize_mr_title) { 'Fake Title' }
let(:mr_json) { { "iid" => 1234, "title" => sanitize_mr_title } } let(:mr_json) { { "iid" => 1234, "title" => sanitize_mr_title } }
subject { changelog.required_text } subject { changelog.required_text }
it do context "when title is not changed from sanitization", :aggregate_failures do
let(:sanitize_mr_title) { 'Fake Title' }
specify do
expect(subject).to include('CHANGELOG missing') expect(subject).to include('CHANGELOG missing')
expect(subject).to include('bin/changelog -m 1234 "Fake Title"') expect(subject).to include('bin/changelog -m 1234 "Fake Title"')
expect(subject).not_to include('--ee') expect(subject).not_to include('--ee')
end end
end end
describe 'optional_text' do context "when title needs sanitization", :aggregate_failures do
let(:sanitize_mr_title) { 'Fake Title' } let(:sanitize_mr_title) { 'DRAFT: Fake Title' }
specify do
expect(subject).to include('CHANGELOG missing')
expect(subject).to include('bin/changelog -m 1234 "Fake Title"')
expect(subject).not_to include('--ee')
end
end
end
describe '#optional_text' do
let(:mr_json) { { "iid" => 1234, "title" => sanitize_mr_title } } let(:mr_json) { { "iid" => 1234, "title" => sanitize_mr_title } }
subject { changelog.optional_text } subject { changelog.optional_text }
it do context "when title is not changed from sanitization", :aggregate_failures do
let(:sanitize_mr_title) { 'Fake Title' }
specify do
expect(subject).to include('CHANGELOG missing') expect(subject).to include('CHANGELOG missing')
expect(subject).to include('bin/changelog -m 1234 "Fake Title"') expect(subject).to include('bin/changelog -m 1234 "Fake Title"')
expect(subject).to include('bin/changelog --ee -m 1234 "Fake Title"') expect(subject).to include('bin/changelog --ee -m 1234 "Fake Title"')
end end
end end
context "when title needs sanitization", :aggregate_failures do
let(:sanitize_mr_title) { 'DRAFT: Fake Title' }
specify do
expect(subject).to include('CHANGELOG missing')
expect(subject).to include('bin/changelog -m 1234 "Fake Title"')
expect(subject).to include('bin/changelog --ee -m 1234 "Fake Title"')
end
end
end
end end
...@@ -402,24 +402,6 @@ RSpec.describe Gitlab::Danger::Helper do ...@@ -402,24 +402,6 @@ RSpec.describe Gitlab::Danger::Helper do
end end
end end
describe '#sanitize_mr_title' do
where(:mr_title, :expected_mr_title) do
'My MR title' | 'My MR title'
'WIP: My MR title' | 'My MR title'
'Draft: My MR title' | 'My MR title'
'(Draft) My MR title' | 'My MR title'
'[Draft] My MR title' | 'My MR title'
'[DRAFT] My MR title' | 'My MR title'
'DRAFT: My MR title' | 'My MR title'
end
with_them do
subject { helper.sanitize_mr_title(mr_title) }
it { is_expected.to eq(expected_mr_title) }
end
end
describe '#security_mr?' do describe '#security_mr?' do
it 'returns false when `gitlab_helper` is unavailable' do it 'returns false when `gitlab_helper` is unavailable' do
expect(helper).to receive(:gitlab_helper).and_return(nil) expect(helper).to receive(:gitlab_helper).and_return(nil)
......
# frozen_string_literal: true
require 'fast_spec_helper'
require 'rspec-parameterized'
require 'gitlab/danger/title_linting'
RSpec.describe Gitlab::Danger::TitleLinting do
using RSpec::Parameterized::TableSyntax
describe '#sanitize_mr_title' do
where(:mr_title, :expected_mr_title) do
'`My MR title`' | "\\`My MR title\\`"
'WIP: My MR title' | 'My MR title'
'Draft: My MR title' | 'My MR title'
'(Draft) My MR title' | 'My MR title'
'[Draft] My MR title' | 'My MR title'
'[DRAFT] My MR title' | 'My MR title'
'DRAFT: My MR title' | 'My MR title'
'DRAFT: `My MR title`' | "\\`My MR title\\`"
end
with_them do
subject { described_class.sanitize_mr_title(mr_title) }
it { is_expected.to eq(expected_mr_title) }
end
end
describe '#remove_draft_flag' do
where(:mr_title, :expected_mr_title) do
'WIP: My MR title' | 'My MR title'
'Draft: My MR title' | 'My MR title'
'(Draft) My MR title' | 'My MR title'
'[Draft] My MR title' | 'My MR title'
'[DRAFT] My MR title' | 'My MR title'
'DRAFT: My MR title' | 'My MR title'
end
with_them do
subject { described_class.remove_draft_flag(mr_title) }
it { is_expected.to eq(expected_mr_title) }
end
end
describe '#has_draft_flag?' do
it 'returns true for a draft title' do
expect(described_class.has_draft_flag?('Draft: My MR title')).to be true
end
it 'returns false for non draft title' do
expect(described_class.has_draft_flag?('My MR title')).to be false
end
end
end
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