Skip to content
Commits on Source (15)
---
# Settings for generating changelogs using the GitLab API. See
# https://docs.gitlab.com/ee/api/repositories.html#generate-changelog-data for
# more information.
categories:
added: Added
fixed: Fixed
changed: Changed
deprecated: Deprecated
removed: Removed
security: Security
performance: Performance
other: Other
<!-- Replace `v4.5.0` with the previous release here, and `e18d76b309e42888759c1effe96767f13e34ae55`
with the latest commit from https://gitlab.com/gitlab-org/gitlab-dangerfiles/commits/master that will be included in the release. -->
- Diff: https://gitlab.com/gitlab-org/gitlab-dangerfiles/compare/v4.5.0...e18d76b309e42888759c1effe96767f13e34ae55
- Release notes:
<!-- Keep the sections order but remove the empty sections -->
```markdown
### New features and features updates
- !aaa <Title of the aaa MR>.
### Fixes
- !bbb <Title of the bbb MR>.
### Doc changes
- !ccc <Title of the ccc MR>.
### Other changes (tooling, technical debt)
- !ddd <Title of the ddd MR>.
```
<!-- Replace `<NEW_VERSION>` with the previous release here, and `<COMMIT_UPDATING_VERSION>`
with the latest commit from this merge request. -->
- Diff: https://gitlab.com/gitlab-org/ruby/gems/gitlab-dangerfiles/compare/v<NEW_VERSION>...<COMMIT_UPDATING_VERSION>
- Checklist before merging:
- [ ] Diff link is up-to-date.
- [ ] Based on the diff, `lib/gitlab/dangerfiles/version.rb` is updated, according to [SemVer](https://semver.org).
- [ ] Release notes are accurate.
- [ ] Based on the diff, `version.rb` is updated, according to [SemVer](https://semver.org).
- Checklist after merging:
- [ ] [Update the release notes for the newly created tag](docs/release_process.md#how-to).
- [ ] Check that automatic release notes (generated following the same process as https://docs.gitlab.com/ee/development/changelog.html) are correct.
/label ~"Engineering Productivity" ~"ep::workflow" ~"tooling::workflow" ~tooling ~"Danger bot"
/label ~"type::maintenance" ~"static code analysis"
## Developer Certificate of Origin and License
By contributing to GitLab B.V., you accept and agree to the following terms and
conditions for your present and future contributions submitted to GitLab B.V.
Except for the license granted herein to GitLab B.V. and recipients of software
distributed by GitLab B.V., you reserve all right, title, and interest in and to
your Contributions.
All contributions are subject to the Developer Certificate of Origin and license set out at [docs.gitlab.com/ce/legal/developer_certificate_of_origin](https://docs.gitlab.com/ce/legal/developer_certificate_of_origin).
_This notice should stay as the first item in the CONTRIBUTING.md file._
## Code of conduct
As contributors and maintainers of this project, we pledge to respect all people
who contribute through reporting issues, posting feature requests, updating
documentation, submitting pull requests or patches, and other activities.
We are committed to making participation in this project a harassment-free
experience for everyone, regardless of level of experience, gender, gender
identity and expression, sexual orientation, disability, personal appearance,
body size, race, ethnicity, age, or religion.
Examples of unacceptable behavior by participants include the use of sexual
language or imagery, derogatory comments or personal attacks, trolling, public
or private harassment, insults, or other unprofessional conduct.
Project maintainers have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct. Project maintainers who do not follow the
Code of Conduct may be removed from the project team.
This code of conduct applies both within project spaces and in public spaces
when an individual is representing the project or its community.
Instances of abusive, harassing, or otherwise unacceptable behavior can be
reported by emailing contact@gitlab.com.
This Code of Conduct is adapted from the [Contributor Covenant](https://contributor-covenant.org), version 1.1.0,
available at [https://contributor-covenant.org/version/1/1/0/](https://contributor-covenant.org/version/1/1/0/).
require_relative "lib/gitlab-dangerfiles"
# Get an instance of Gitlab::Dangerfiles
gitlab_dangerfiles = Gitlab::Dangerfiles::Engine.new(self)
# Import all plugins from the gem
gitlab_dangerfiles.import_plugins
# Import all rules from the gem
gitlab_dangerfiles.import_dangerfiles
Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
dangerfiles.import_defaults
end
......@@ -26,22 +26,45 @@ $ gem install gitlab-dangerfiles
### Importing plugins and rules
In your project's `Dangerfile`, add the following two line to import the plugins and rules from this gem:
In your project's `Dangerfile`, add the following to import the plugins and rules from this gem:
```ruby
require 'gitlab-dangerfiles'
# Get an instance of Gitlab::Dangerfiles
gitlab_dangerfiles = Gitlab::Dangerfiles::Engine.new(self)
Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
# Import all plugins from the gem
dangerfiles.import_plugins
# Import all plugins from the gem
gitlab_dangerfiles.import_plugins
# Import all rules from the gem
dangerfiles.import_dangerfiles
# Import all rules from the gem
gitlab_dangerfiles.import_dangerfiles
# Or import only a subset of rules
dangerfiles.import_dangerfiles(only: %w[changes_size])
# Or import a subset of rules from the gem
gitlab_dangerfiles.import_dangerfiles(rules: [:changes_size])
# Or import all rules except a subset of rules
dangerfiles.import_dangerfiles(except: %w[commit_messages])
# Or import only a subset of rules, except a subset of rules
dangerfiles.import_dangerfiles(only: %w[changes_size], except: %w[commit_messages])
end
```
For simple projects such as libraries, you can use the convenience method `import_defaults`:
```ruby
Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
# Imports all plugins, rules and the default reviewer roulette
dangerfiles.import_defaults
end
```
You may optionally pass a project name; by default, `ENV['CI_PROJECT_NAME']` will be used:
```ruby
Gitlab::Dangerfiles.for_project(self, 'my-project') do |dangerfiles|
# Imports all plugins, rules and the default reviewer roulette
dangerfiles.import_defaults
end
```
### Plugins
......@@ -53,6 +76,20 @@ Danger plugins are located under `lib/danger/plugins`.
For the full documentation about the plugins, please see https://www.rubydoc.info/gems/gitlab-dangerfiles.
### Configuration
Default configuration can be overriden in the form `helper.config.CONFIG_NAME = NEW_VALUE` (`CONFIG_NAME` being a value configuration key).
Alternatively, you can also get/set configuration on the engine directly via `Gitlab::Dangerfiles::Engine#config`.
#### Available general configurations
- `project_name`: The project name. Currently used by the Roulette plugin to fetch relevant
reviewers/maintainers based on the project name. Default to `ENV["CI_PROJECT_NAME"]`.
- `files_to_category`: A hash of the form `{ filename_regex => categories, [filename_regex, changes_regex] => categories }`.
`filename_regex` is the regex pattern to match file names. `changes_regex` is the regex pattern to
match changed lines in files that match `filename_regex`. Used in `helper.changes_by_category`, `helper.changes`, and `helper.categories_for_file`.
### Rules
Danger rules are located under `lib/danger/rules`.
......@@ -72,6 +109,21 @@ Danger rules are located under `lib/danger/rules`.
- `max_commits_count`: The maximum number of allowed non-squashed/non-fixup commits for a given MR.
A warning is triggered if the MR has more commits.
### Reviewer Roulette
The library includes a simplified default reviewer roulette that you can use in your
project. To use it in your project, perform the following steps:
1. If not yet done, create a `Dangerfile` at the top-level of your project. Refer to [Usage](#usage) to
see how to set it up.
1. When using the default roulette, use `import_defaults` or import it manually when setting
up the gitlab-dangerfiles instance:
```ruby
Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
dangerfiles.import_dangerfiles(only: %w[simple_roulette])
end
```
## Documentation
Latest documentation can be found at <https://www.rubydoc.info/gems/gitlab-dangerfiles>.
......
......@@ -175,7 +175,7 @@ module Danger
#
# @return [{Symbol => Array<String>}] a hash of the type +{ category1: ["file1", "file2"], category2: ["file3", "file4"] }+
# using filename regex (+filename_regex+) and specific change regex (+changes_regex+) from the given +categories+ hash.
def changes_by_category(categories)
def changes_by_category(categories = [])
all_changed_files.each_with_object(Hash.new { |h, k| h[k] = [] }) do |file, hash|
categories_for_file(file, categories).each { |category| hash[category] << file }
end
......@@ -187,7 +187,7 @@ module Danger
#
# @return [Gitlab::Dangerfiles::Changes] a +Gitlab::Dangerfiles::Changes+ object that represents the changes of an MR
# using filename regex (+filename_regex+) and specific change regex (+changes_regex+) from the given +categories+ hash.
def changes(categories)
def changes(categories = [])
Gitlab::Dangerfiles::Changes.new([]).tap do |changes|
added_files.each do |file|
categories_for_file(file, categories).each { |category| changes << Gitlab::Dangerfiles::Change.new(file, :added, category) }
......@@ -212,14 +212,17 @@ module Danger
end
# @param filename [String] A file name.
# @param categories [{Regexp => Array<Symbol>}, {Array<Regexp> => Array<Symbol>}] A hash of the form +{ filename_regex => categories, [filename_regex, changes_regex] => categories }+.
# +filename_regex+ is the regex pattern to match file names. +changes_regex+ is the regex pattern to
# match changed lines in files that match +filename_regex+
# @param files_to_category [{Regexp => Array<Symbol>}, {Array<Regexp> => Array<Symbol>}] A hash of the form +{ filename_regex => categories, [filename_regex, changes_regex] => categories }+.
# +filename_regex+ is the regex pattern to match file names. +changes_regex+ is the regex pattern to
# match changed lines in files that match +filename_regex+
#
# @return [Array<Symbol>] the categories a file is in, e.g., +[:frontend]+, +[:backend]+, or +%i[frontend tooling]+
# using filename regex (+filename_regex+) and specific change regex (+changes_regex+) from the given +categories+ hash.
def categories_for_file(filename, categories)
_, categories = categories.find do |key, _|
def categories_for_file(filename, files_to_category = [])
files_to_category = Array(files_to_category).compact
files_to_category = helper.config.files_to_category if files_to_category.empty?
_, categories = files_to_category.find do |key, _|
filename_regex, changes_regex = Array(key)
found = filename_regex.match?(filename)
......
......@@ -33,8 +33,8 @@ module Danger
# @param timezone_experiment [Boolean] Whether to select reviewers based in timezone or not.
#
# @return [Array<Spin>]
def spin(project, categories = [nil], timezone_experiment: false)
project = project.downcase
def spin(project = nil, categories = [nil], timezone_experiment: false)
project = (project || helper.config.project_name).downcase
categories = categories.map { |category| category&.downcase }
spins = categories.sort_by(&:to_s).map do |category|
......
# frozen_string_literal: true
PROJECT_NAME = helper.config.project_name
MESSAGE = <<MARKDOWN
## Reviewer roulette
Changes that require review have been detected! A merge request is normally
reviewed by both a reviewer and a maintainer in its primary category and by a
maintainer in all other categories.
MARKDOWN
TABLE_MARKDOWN = <<MARKDOWN
To spread load more evenly across eligible reviewers, Danger has picked a candidate for each
review slot. Feel free to
[override these selections](https://about.gitlab.com/handbook/engineering/projects/##{PROJECT_NAME})
if you think someone else would be better-suited.
To read more on how to use the reviewer roulette, please take a look at the
[Engineering workflow](https://about.gitlab.com/handbook/engineering/workflow/#basics)
and [code review guidelines](https://docs.gitlab.com/ee/development/code_review.html).
Once you've decided who will review this merge request, mention them as you
normally would! Danger does not automatically notify them for you.
| Reviewer | Maintainer |
| -------- | ---------- |
MARKDOWN
def note_for_spins_role(spins, role)
spins.each do |spin|
note = note_for_spin_role(spin, role)
return note if note
end
'No %{role} available' % { role: role }
end
def note_for_spin_role(spin, role)
spin.public_send(role)&.markdown_name(author: roulette.team_mr_author)
end
def markdown_row_for_spins(spins_array)
reviewer_note = note_for_spins_role(spins_array, :reviewer)
maintainer_note = note_for_spins_role(spins_array, :maintainer)
"#{reviewer_note} | #{maintainer_note} |"
end
if helper.changes.any?
random_roulette_spins = roulette.spin
rows = random_roulette_spins.map do |spin|
markdown_row_for_spins([spin])
end
markdown(MESSAGE)
markdown(TABLE_MARKDOWN + rows.join("\n")) unless rows.empty?
end
......@@ -13,8 +13,24 @@ module Gitlab
commit_messages
].freeze
CI_ONLY_RULES = %w[
simple_roulette
].freeze
# Utility method to construct a [Gitlab::Dangerfiles::Engine] instance,
# which is yielded to the given block.
#
# @param dangerfile [Danger::Dangerfile] A +Danger::Dangerfile+ object.
# @param project_name An option string to set the project name. Defaults to +ENV['CI_PROJECT_NAME']+.
#
# @return [Gitlab::Dangerfiles::Engine]
def self.for_project(dangerfile, project_name = nil)
Engine.new(dangerfile).tap do |engine|
engine.config.project_name = project_name if project_name
yield engine
end
end
# This class provides utility methods to import plugins and dangerfiles easily.
class Engine
# @param dangerfile [Danger::Dangerfile] A +Danger::Dangerfile+ object.
......@@ -32,35 +48,66 @@ module Gitlab
#
# @example
# # In your main Dangerfile:
# dangerfiles = Gitlab::Dangerfiles::Engine.new(self)
#
# # Import all plugins
# dangerfiles.import_plugins
# Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
# dangerfiles.import_plugins
# end
def import_plugins
danger_plugin.import_plugin(File.expand_path("../danger/plugins/*.rb", __dir__))
end
# Import available Dangerfiles.
#
# @deprecated
# @param rules [Symbol, Array<String>] Can be either +:all+ (default) to import all rules,
# or an array of rules.
# Available rules are: +changes_size+.
#
# @example
# # In your main Dangerfile:
# dangerfiles = Gitlab::Dangerfiles::Engine.new(self)
# @param only [Symbol, Array<String>] An array of rules to import (defaults to all rules).
# Available rules are: +changes_size+.
#
# # Import all rules
# dangerfiles.import_dangerfiles
# @param except [Symbol, Array<String>] An array of rules to not import (defaults to []).
# Available rules are: +changes_size+.
#
# # Or import only a subset of rules
# dangerfiles.import_dangerfiles(rules: %w[changes_size])
def import_dangerfiles(rules: :all)
filtered_rules(rules).each do |rule|
# @example
# # In your main Dangerfile:
# Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
# # Import all rules
# dangerfiles.import_dangerfiles
# # Or import only a subset of rules
# dangerfiles.import_dangerfiles(only: %w[changes_size])
# # Or import all rules except a subset of rules
# dangerfiles.import_dangerfiles(except: %w[commit_messages])
# # Or import only a subset of rules, except a subset of rules
# dangerfiles.import_dangerfiles(only: %w[changes_size], except: %w[commit_messages])
# end
def import_dangerfiles(rules: nil, only: nil, except: [])
puts "The `:rules` parameter is deprecated in favor of `:only`." unless rules.nil?
only ||= EXISTING_RULES if rules == :all
only ||= rules || EXISTING_RULES
filtered_rules(only, except).each do |rule|
danger_plugin.import_dangerfile(path: File.join(RULES_DIR, rule))
end
end
# Proxy method to +helper_plugin.config+.
def config
helper_plugin.config
end
# Imports all default plugins and rules.
#
# @example
# # In your main Dangerfile:
# Gitlab::Dangerfiles.for_project(self) do |dangerfiles|
# dangerfiles.import_defaults
# end
def import_defaults
import_plugins
import_dangerfiles
end
private
attr_reader :dangerfile
......@@ -71,10 +118,8 @@ module Gitlab
helper_plugin.ci? ? LOCAL_RULES | CI_ONLY_RULES : LOCAL_RULES
end
def filtered_rules(rules)
rules = EXISTING_RULES if rules == :all
Array(rules).map(&:to_s) & EXISTING_RULES & allowed_rules
def filtered_rules(only, except)
(Array(only).map(&:to_s) & EXISTING_RULES & allowed_rules) - except
end
def danger_plugin
......
......@@ -3,6 +3,16 @@
module Gitlab
module Dangerfiles
class Config
# @!attribute project_name
# @return [String] the project name. Currently used by the Roulette plugin to fetch relevant reviewers/maintainers based on the project name. Default to +ENV["CI_PROJECT_NAME"]+.
attr_accessor :project_name
# @!attribute files_to_category
# @return [{Regexp => Array<Symbol>}, {Array<Regexp> => Array<Symbol>}] A hash of the form +{ filename_regex => categories, [filename_regex, changes_regex] => categories }+.
# +filename_regex+ is the regex pattern to match file names. +changes_regex+ is the regex pattern to
# match changed lines in files that match +filename_regex+. Used in `helper.changes_by_category`, `helper.changes`, and `helper.categories_for_file`.
attr_accessor :files_to_category
# @!attribute code_size_thresholds
# @return [{ high: Integer, medium: Integer }] a hash of the form +{ high: 42, medium: 12 }+ where +:high+ is the lines changed threshold which triggers an error, and +:medium+ is the lines changed threshold which triggers a warning. Also, see +DEFAULT_CHANGES_SIZE_THRESHOLDS+ for the format of the hash.
attr_accessor :code_size_thresholds
......@@ -15,6 +25,8 @@ module Gitlab
DEFAULT_COMMIT_MESSAGES_MAX_COMMITS_COUNT = 10
def initialize
@files_to_category = []
@project_name = ENV["CI_PROJECT_NAME"]
@code_size_thresholds = DEFAULT_CHANGES_SIZE_THRESHOLDS
@max_commits_count = DEFAULT_COMMIT_MESSAGES_MAX_COMMITS_COUNT
end
......
......@@ -116,11 +116,10 @@ module Gitlab
area && labels.any?("devops::#{area.downcase}") if kind == :reviewer
when :tooling, :engineering_productivity # Deprecated as of 2.3.0 in favor of tooling
return false unless role[/Engineering Productivity/]
return true if kind == :reviewer
return true if capabilities(project).include?("#{kind} engineering_productivity")
return true if capabilities(project).include?("#{kind} #{category}")
return false if kind == :maintainer
capabilities(project).include?("#{kind} backend")
capabilities(project).include?("#{kind} backend") # fallback to backend reviewer
when :integrations_be
kind == :reviewer &&
role.match?(/Backend Engineer.+Ecosystem:Integrations/)
......
module Gitlab
module Dangerfiles
VERSION = "2.5.0"
VERSION = "2.6.0"
end
end
......@@ -285,9 +285,11 @@ RSpec.describe Danger::Helper do
end
describe "#changes_by_category" do
let(:files_to_category) { { /added/ => [:doc], /modified/ => [:changelog] } }
context "on CI" do
it "interprets a list of changes from the danger git plugin" do
expect(helper.changes_by_category(categories)).to eq(unknown: %w[added-from-api modified-from-api renamed_after-from-api])
expect(helper.changes_by_category(files_to_category)).to eq(doc: ["added-from-api"], changelog: ["modified-from-api"], unknown: ["renamed_after-from-api"])
end
end
......@@ -308,6 +310,34 @@ RSpec.describe Danger::Helper do
)
end
end
context "with [] categories mapping" do
it "returns files as :unknown category" do
expect(helper.changes_by_category([])).to eq(unknown: %w[added-from-api modified-from-api renamed_after-from-api])
end
end
context "with nil categories mapping" do
it "returns files as :unknown category" do
expect(helper.changes_by_category(nil)).to eq(unknown: %w[added-from-api modified-from-api renamed_after-from-api])
end
end
context "with no categories mapping" do
it "returns files as :unknown category" do
expect(helper.changes_by_category).to eq(unknown: %w[added-from-api modified-from-api renamed_after-from-api])
end
end
context "with helper.config.files_to_category set" do
before do
helper.config.files_to_category = files_to_category
end
it "categorizes changed files" do
expect(helper.changes_by_category).to eq(doc: ["added-from-api"], changelog: ["modified-from-api"], unknown: ["renamed_after-from-api"])
end
end
end
describe "#changes" do
......@@ -324,21 +354,59 @@ RSpec.describe Danger::Helper do
expect(changes.renamed_before.files).to eq(["renamed_before-from-api"])
expect(changes.renamed_after.files).to eq(["renamed_after-from-api"])
end
context "with [] categories mapping" do
it "raises no error" do
expect(helper.changes([])).to be_an(Gitlab::Dangerfiles::Changes)
end
end
context "with nil categories mapping" do
it "raises no error" do
expect(helper.changes(nil)).to be_an(Gitlab::Dangerfiles::Changes)
end
end
context "with no categories mapping" do
it "raises no error" do
expect(helper.changes).to be_an(Gitlab::Dangerfiles::Changes)
end
end
end
describe "#categories_for_file" do
using RSpec::Parameterized::TableSyntax
context "with categories mapping given" do
using RSpec::Parameterized::TableSyntax
where(:path, :expected_categories) do
"doc/foo" | [:docs]
"changelogs/foo" | [:none]
"foo" | [:unknown]
end
where(:path, :expected_categories) do
"doc/foo" | [:docs]
"changelogs/foo" | [:none]
"foo" | [:unknown]
with_them do
subject { helper.categories_for_file(path, categories) }
it { is_expected.to eq(expected_categories) }
end
end
with_them do
subject { helper.categories_for_file(path, categories) }
context "with [] categories mapping" do
it "raises no error" do
expect(helper.categories_for_file("doc/foo", [])).to eq([:unknown])
end
end
it { is_expected.to eq(expected_categories) }
context "with nil categories mapping" do
it "raises no error" do
expect(helper.categories_for_file("doc/foo", nil)).to eq([:unknown])
end
end
context "with no categories mapping" do
it "raises no error" do
expect(helper.categories_for_file("doc/foo")).to eq([:unknown])
end
end
end
......
......@@ -7,22 +7,62 @@ require "gitlab/dangerfiles/config"
RSpec.describe Gitlab::Dangerfiles::Config do
subject(:config) { described_class.new }
describe "#code_size_thresholds" do
context "with no failures" do
it { expect(config.code_size_thresholds).to eq(high: 2_000, medium: 500) }
describe "DEFAULT_CHANGES_SIZE_THRESHOLDS" do
it { expect(described_class::DEFAULT_CHANGES_SIZE_THRESHOLDS).to eq(high: 2_000, medium: 500) }
end
describe "DEFAULT_COMMIT_MESSAGES_MAX_COMMITS_COUNT" do
it { expect(described_class::DEFAULT_COMMIT_MESSAGES_MAX_COMMITS_COUNT).to eq(10) }
end
shared_examples "overridable config" do |config_name, default_value|
describe "default value" do
it { expect(config.public_send(config_name)).to eq(default_value) }
end
describe "overriding" do
it "is possible to override a config directly" do
config.public_send("#{config_name}=", new_config)
expect(config.public_send(config_name)).to eq(new_config)
end
end
end
describe "#project_name" do
before do
allow(ENV).to receive(:[]).with("CI_PROJECT_NAME").and_return("my-project")
end
it_behaves_like "overridable config", :project_name, "my-project" do
let(:new_config) { "my-other-project" }
end
end
describe "overriding of config" do
it "is possible to override a config directly" do
new_config = {
high: config.code_size_thresholds[:high] / 2,
medium: config.code_size_thresholds[:medium] / 2,
}
describe "#files_to_category" do
before do
allow(ENV).to receive(:[]).with("CI_PROJECT_NAME").and_return("my-project")
end
it_behaves_like "overridable config", :files_to_category, [] do
let(:new_config) { { /foo/ => %w[bar baz] } }
end
end
config.code_size_thresholds = new_config
describe "#code_size_thresholds" do
it_behaves_like "overridable config", :code_size_thresholds, described_class::DEFAULT_CHANGES_SIZE_THRESHOLDS do
let(:new_config) do
{
high: config.code_size_thresholds[:high] / 2,
medium: config.code_size_thresholds[:medium] / 2,
}
end
end
end
expect(config.code_size_thresholds).to eq(new_config)
describe "#max_commits_count" do
it_behaves_like "overridable config", :max_commits_count, described_class::DEFAULT_COMMIT_MESSAGES_MAX_COMMITS_COUNT do
let(:new_config) { 30 }
end
end
end
......@@ -104,8 +104,8 @@ RSpec.describe Gitlab::Dangerfiles::Teammate do
end
end
context "when role is Backend Engineer, Engineering Productivity" do
let(:role) { "Backend Engineer, Engineering Productivity" }
context "when capabilities include 'reviewer tooling'" do
let(:capabilities) { ["reviewer tooling"] }
it "#reviewer? returns true" do
expect(subject.reviewer?(project, :tooling, labels)).to be_truthy
......@@ -115,15 +115,31 @@ RSpec.describe Gitlab::Dangerfiles::Teammate do
expect(subject.maintainer?(project, :tooling, labels)).to be_falsey
end
context "when capabilities include maintainer backend" do
context "when capabilities include 'reviewer backend'" do
let(:capabilities) { ["reviewer backend"] }
it "#reviewer? returns true" do
expect(subject.reviewer?(project, :tooling, labels)).to be_truthy
end
it "#maintainer? returns false" do
expect(subject.maintainer?(project, :tooling, labels)).to be_falsey
end
end
context "when capabilities include 'maintainer backend'" do
let(:capabilities) { ["maintainer backend"] }
it "#maintainer? returns true" do
expect(subject.maintainer?(project, :tooling, labels)).to be_truthy
it "#reviewer? returns true" do
expect(subject.reviewer?(project, :tooling, labels)).to be_falsey
end
it "#maintainer? returns false" do
expect(subject.maintainer?(project, :tooling, labels)).to be_falsey
end
end
context "when capabilities include trainee_maintainer backend" do
context "when capabilities include 'trainee_maintainer backend'" do
let(:capabilities) { ["trainee_maintainer backend"] }
it "#traintainer? returns true" do
......
RSpec.describe Gitlab::Dangerfiles do
it "has a version number" do
expect(described_class::VERSION).not_to be nil
end
end
require_relative "../../lib/danger/plugins/helper"
RSpec.describe Gitlab::Dangerfiles do
it "has a version number" do
expect(described_class::VERSION).not_to be nil
include_context "with dangerfile"
let(:helper_plugin) { dangerfile.plugins[Danger::Helper] }
let(:danger_plugin) { dangerfile.plugins[Danger::DangerfileDangerPlugin] }
describe ".for_project" do
it "yields an Engine instance" do
expect { |b| described_class.for_project(dangerfile, &b) }.to(
yield_with_args(be_instance_of(described_class::Engine))
)
end
it "returns an Engine instance" do
expect(described_class.for_project(dangerfile) { nil }).to be_instance_of(described_class::Engine)
end
context "when passing a project_name" do
it "configures the helper with it" do
engine = described_class.for_project(dangerfile, "my-project") { nil }
expect(engine.config.project_name).to eq("my-project")
end
end
context "when not passing a project name" do
it "uses the helper config default" do
engine = described_class.for_project(dangerfile) { nil }
expect(engine.config.project_name).to eq(helper_plugin.config.project_name)
end
end
end
describe ".import_dangerfiles" do
it "imports all rules by default" do
described_class::EXISTING_RULES.each do |existing_rule|
expect(danger_plugin).to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, existing_rule))
end
described_class.for_project(dangerfile) { |e| e.import_dangerfiles }
end
context "with rules: :all" do
it "imports all rules" do
described_class::EXISTING_RULES.each do |existing_rule|
expect(danger_plugin).to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, existing_rule))
end
described_class.for_project(dangerfile) { |e| e.import_dangerfiles(rules: :all) }
end
end
context "with rules: %w[commit_messages]" do
it "imports the :rules rules" do
expect(danger_plugin).to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, "commit_messages"))
described_class.for_project(dangerfile) { |e| e.import_dangerfiles(rules: %w[commit_messages]) }
end
end
context "with only: %w[changes_size]" do
it "imports the :only rules" do
expect(danger_plugin).to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, "changes_size"))
described_class.for_project(dangerfile) { |e| e.import_dangerfiles(only: %w[changes_size]) }
end
end
context "with rules: %w[commit_messages] and only: %w[changes_size]" do
it "imports the :only rules" do
expect(danger_plugin).to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, "changes_size"))
described_class.for_project(dangerfile) { |e| e.import_dangerfiles(rules: %w[commit_messages], only: %w[changes_size]) }
end
end
context "with except: %w[commit_messages]" do
it "does not import the given rules" do
expect(danger_plugin).not_to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, "commit_messages"))
described_class.for_project(dangerfile) { |e| e.import_dangerfiles(except: %w[commit_messages]) }
end
end
context "with only: %w[changes_size] and except: %w[changes_size]" do
it "imports the :only rules but not the :except rules" do
expect(danger_plugin).to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, "changes_size"))
expect(danger_plugin).not_to receive(:import_dangerfile).with(path: File.join(described_class::RULES_DIR, "changes_size"))
described_class.for_project(dangerfile) { |e| e.import_dangerfiles(only: %w[changes_size], except: %w[commit_messages]) }
end
end
context "with only: %w[changes_size] and except: %w[changes_size]" do
it "imports no rules" do
expect(danger_plugin).not_to receive(:import_dangerfile)
described_class.for_project(dangerfile) { |e| e.import_dangerfiles(only: %w[changes_size], except: %w[changes_size]) }
end
end
end
describe described_class::Engine do
let(:engine) { described_class.new(dangerfile) }
describe "#config" do
it "proxies to helper_plugin.config" do
expect(engine.config).to eq(helper_plugin.config)
end
end
end
end