gitlab-dangerfiles 2.0.0 → 2.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0d3407bad03ff3220a55329e625c1fd5a962b4ffe29b4ab1da68a7e998761024
4
- data.tar.gz: a9f31b18452500fa6e437a847b1d726cbbe2c47a1912c5e40fd18196ca3716fa
3
+ metadata.gz: 30a4d627f19b9baece5e677425892f5ede2b883db11c57ae4178956975dcdb69
4
+ data.tar.gz: dfb9f139593171a0ddf7b075993ebe9419c0b32a33a391c5b7dfa4814871f553
5
5
  SHA512:
6
- metadata.gz: 3390ab204b7572654e748198fb1d03b70056ab26b32a8ea29cc2c624e307e59c5cfab5306afb8900c71df62671b984ccdbb21e7c1e9adb16b2ab43a9299774c0
7
- data.tar.gz: '06879db4e54bff63e540793f8c94f3c9412d6481641144bfa80934bb36a82872c76e9693c86aa9b381d78528da06a27795f620ff9127829e4904938807958ede'
6
+ metadata.gz: 504abc1a266560c6277dd9cb329b35894e2cdc958703403bdd88e3b2a7ad883860ed56be1bb14bf48529d0207b61f69a896260e4ab87cd0e251b373bcb902b18
7
+ data.tar.gz: ba5ff6ef20d7571c70a6bc4b130b5b54a89881c3757bf2b4c6949be6e7c441ba9deca33b13753be8428f0877663d24410a05a9aa3e45bac8fc2f5ff9e5a6aeae
data/.gitignore CHANGED
@@ -9,6 +9,7 @@
9
9
  /pkg/
10
10
  /spec/reports/
11
11
  /tmp/
12
+ /doc/
12
13
 
13
14
  # rspec failure tracking
14
15
  .rspec_status
data/.gitlab-ci.yml CHANGED
@@ -11,7 +11,7 @@ workflow:
11
11
  # For tags, create a pipeline.
12
12
  - if: '$CI_COMMIT_TAG'
13
13
 
14
- default:
14
+ .default:
15
15
  image: ruby:2.7
16
16
  tags:
17
17
  - gitlab-org
@@ -29,15 +29,50 @@ default:
29
29
  policy: pull
30
30
 
31
31
  test:rspec:
32
+ extends: .default
32
33
  stage: test
33
34
  script:
34
35
  - bundle exec rspec
35
36
 
36
37
  test:rufo:
38
+ extends: .default
37
39
  stage: test
38
40
  script:
39
41
  - bundle exec rufo --check .
40
42
 
41
43
  include:
44
+ - template: Security/Dependency-Scanning.gitlab-ci.yml
45
+ - template: Security/License-Scanning.gitlab-ci.yml
46
+ - template: Security/SAST.gitlab-ci.yml
47
+ - template: Security/Secret-Detection.gitlab-ci.yml
42
48
  - project: 'gitlab-org/quality/pipeline-common'
43
49
  file: '/ci/gem-release.yml'
50
+
51
+ # run security jobs on MRs
52
+ # see: https://gitlab.com/gitlab-org/gitlab/-/issues/218444#note_478761991
53
+
54
+ brakeman-sast:
55
+ rules:
56
+ - if: '$CI_MERGE_REQUEST_IID'
57
+ - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
58
+
59
+ gemnasium-dependency_scanning:
60
+ rules:
61
+ - if: '$CI_MERGE_REQUEST_IID'
62
+ - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
63
+
64
+ bundler-audit-dependency_scanning:
65
+ rules:
66
+ - if: '$CI_MERGE_REQUEST_IID'
67
+ - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
68
+
69
+ license_scanning:
70
+ rules:
71
+ - if: '$CI_MERGE_REQUEST_IID'
72
+ - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
73
+
74
+ secret_detection:
75
+ rules:
76
+ - if: '$CI_MERGE_REQUEST_IID'
77
+ - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
78
+
data/README.md CHANGED
@@ -64,6 +64,17 @@ Danger rules are located under `lib/danger/rules`.
64
64
  `:high` is the lines changed threshold which triggers an error, and
65
65
  `:medium` is the lines changed threshold which triggers a warning.
66
66
 
67
+ #### `commit_messages`
68
+
69
+ ##### Available configurations
70
+
71
+ - `max_commits_count`: The maximum number of allowed non-squashed/non-fixup commits for a given MR.
72
+ A warning is triggered if the MR has more commits.
73
+
74
+ ## Documentation
75
+
76
+ Latest documentation can be found at <https://www.rubydoc.info/gems/gitlab-dangerfiles>.
77
+
67
78
  ## Development
68
79
 
69
80
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -283,9 +283,18 @@ module Danger
283
283
  gitlab_helper.mr_json["target_branch"]
284
284
  end
285
285
 
286
+ # @return [Boolean] +true+ when not in the CI context, and whether the MR is set to be squashed otherwise.
287
+ def squash_mr?
288
+ return true unless ci?
289
+
290
+ gitlab.mr_json["squash"]
291
+ end
292
+
286
293
  # @return [Boolean] whether a MR is a Draft or not.
287
294
  def draft_mr?
288
- Gitlab::Dangerfiles::TitleLinting.has_draft_flag?(mr_title)
295
+ return false unless ci?
296
+
297
+ gitlab.mr_json["work_in_progress"]
289
298
  end
290
299
 
291
300
  # @return [Boolean] whether a MR is opened in the security mirror or not.
@@ -0,0 +1,139 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../../../gitlab/dangerfiles/commit_linter"
4
+ require_relative "../../../gitlab/dangerfiles/merge_request_linter"
5
+
6
+ COMMIT_MESSAGE_GUIDELINES = "https://docs.gitlab.com/ee/development/contributing/merge_request_workflow.html#commit-messages-guidelines"
7
+ MORE_INFO = "For more information, take a look at our [Commit message guidelines](#{COMMIT_MESSAGE_GUIDELINES})."
8
+ THE_DANGER_JOB_TEXT = "the `%<job_name>` job"
9
+ MAX_COMMITS_COUNT_EXCEEDED_MESSAGE = <<~MSG
10
+ This merge request includes more than %<max_commits_count>d commits. Each commit should meet the following criteria:
11
+
12
+ 1. Have a well-written commit message.
13
+ 1. Has all tests passing when used on its own (e.g. when using git checkout SHA).
14
+ 1. Can be reverted on its own without also requiring the revert of commit that came before it.
15
+ 1. Is small enough that it can be reviewed in isolation in under 30 minutes or so.
16
+
17
+ If this merge request contains commits that do not meet this criteria and/or contains intermediate work, please rebase these commits into a smaller number of commits or split this merge request into multiple smaller merge requests.
18
+ MSG
19
+
20
+ max_commits_count = helper.config.max_commits_count
21
+
22
+ def fail_commit(commit, message, more_info: true)
23
+ self.fail(build_message(commit, message, more_info: more_info))
24
+ end
25
+
26
+ def warn_commit(commit, message, more_info: true)
27
+ self.warn(build_message(commit, message, more_info: more_info))
28
+ end
29
+
30
+ def build_message(commit, message, more_info: true)
31
+ [message].tap do |full_message|
32
+ full_message << ". #{MORE_INFO}" if more_info
33
+ full_message.unshift("#{commit.sha}: ") if commit.sha
34
+ end.join
35
+ end
36
+
37
+ def danger_job_link
38
+ helper.ci? ? "[#{format(THE_DANGER_JOB_TEXT, job_name: ENV["CI_JOB_NAME"])}](#{ENV['CI_JOB_URL']})" : THE_DANGER_JOB_TEXT
39
+ end
40
+
41
+ # Perform various checks against commits. We're not using
42
+ # https://github.com/jonallured/danger-commit_lint because its output is not
43
+ # very helpful, and it doesn't offer the means of ignoring merge commits.
44
+ def lint_commit(commit)
45
+ linter = Gitlab::Dangerfiles::CommitLinter.new(commit)
46
+
47
+ # For now we'll ignore merge commits, as getting rid of those is a problem
48
+ # separate from enforcing good commit messages.
49
+ return linter if linter.merge?
50
+
51
+ # We ignore revert commits as they are well structured by Git already
52
+ return linter if linter.revert?
53
+
54
+ # If MR is set to squash, we ignore fixup commits
55
+ return linter if linter.fixup? && helper.squash_mr?
56
+
57
+ if linter.fixup?
58
+ msg = "Squash or fixup commits must be squashed before merge, or enable squash merge option and re-run #{danger_job_link}."
59
+ if helper.draft_mr? || helper.squash_mr?
60
+ warn_commit(commit, msg, more_info: false)
61
+ else
62
+ fail_commit(commit, msg, more_info: false)
63
+ end
64
+
65
+ # Makes no sense to process other rules for fixup commits, they trigger just more noise
66
+ return linter
67
+ end
68
+
69
+ # Fail if a suggestion commit is used and squash is not enabled
70
+ if linter.suggestion?
71
+ unless helper.squash_mr?
72
+ fail_commit(commit, "If you are applying suggestions, enable squash in the merge request and re-run #{danger_job_link}.", more_info: false)
73
+ end
74
+
75
+ return linter
76
+ end
77
+
78
+ linter.lint
79
+ end
80
+
81
+ def lint_mr_title(mr_title)
82
+ commit = Struct.new(:message, :sha).new(mr_title)
83
+
84
+ Gitlab::Dangerfiles::MergeRequestLinter.new(commit).lint
85
+ end
86
+
87
+ def count_non_fixup_commits(commit_linters)
88
+ commit_linters.count { |commit_linter| !commit_linter.fixup? }
89
+ end
90
+
91
+ def lint_commits(commits)
92
+ commit_linters = commits.map { |commit| lint_commit(commit) }
93
+
94
+ if helper.squash_mr?
95
+ multi_line_commit_linter = commit_linters.detect { |commit_linter| !commit_linter.merge? && commit_linter.multi_line? }
96
+
97
+ if multi_line_commit_linter && multi_line_commit_linter.failed?
98
+ warn_or_fail_commits(multi_line_commit_linter)
99
+ commit_linters.delete(multi_line_commit_linter) # Don't show an error (here) and a warning (below)
100
+ elsif helper.ci? # We don't have access to the MR title locally
101
+ title_linter = lint_mr_title(gitlab.mr_json['title'])
102
+ if title_linter.failed?
103
+ warn_or_fail_commits(title_linter)
104
+ end
105
+ end
106
+ else
107
+ if count_non_fixup_commits(commit_linters) > max_commits_count
108
+ self.warn(format(MAX_COMMITS_COUNT_EXCEEDED_MESSAGE, max_commits_count: max_commits_count))
109
+ end
110
+ end
111
+
112
+ failed_commit_linters = commit_linters.select { |commit_linter| commit_linter.failed? }
113
+ warn_or_fail_commits(failed_commit_linters, default_to_fail: !helper.squash_mr?)
114
+ end
115
+
116
+ def warn_or_fail_commits(failed_linters, default_to_fail: true)
117
+ level = default_to_fail ? :fail : :warn
118
+
119
+ Array(failed_linters).each do |linter|
120
+ linter.problems.each do |problem_key, problem_desc|
121
+ case problem_key
122
+ when :subject_too_short, :subject_above_warning, :details_too_many_changes, :details_line_too_long
123
+ warn_commit(linter.commit, problem_desc)
124
+ else
125
+ self.__send__("#{level}_commit", linter.commit, problem_desc) # rubocop:disable GitlabSecurity/PublicSend
126
+ end
127
+ end
128
+ end
129
+ end
130
+
131
+ # As part of https://gitlab.com/groups/gitlab-org/-/epics/4826 we are
132
+ # vendoring workhorse commits from the stand-alone gitlab-workhorse
133
+ # repo. There is no point in linting commits that we want to vendor as
134
+ # is.
135
+ def workhorse_changes?
136
+ git.diff.any? { |file| file.path.start_with?('workhorse/') }
137
+ end
138
+
139
+ lint_commits(git.commits) unless workhorse_changes?
@@ -8,7 +8,10 @@ module Gitlab
8
8
  class CommitLinter < BaseLinter
9
9
  MAX_CHANGED_FILES_IN_COMMIT = 3
10
10
  MAX_CHANGED_LINES_IN_COMMIT = 30
11
- SHORT_REFERENCE_REGEX = %r{([\w\-\/]+)?(?<!`)(#|!|&|%)\d+(?<!`)}.freeze
11
+ # Issue, MR, Epic
12
+ SHORT_REFERENCE_REGEX = %r{([\w\-\/]+)?(?<!`)(#|!|&)\d+(?<!`)}.freeze
13
+ # Milestone
14
+ MS_SHORT_REFERENCE_REGEX = %r{([\w\-\/]+)?(?<!`)%"?\d{1,3}\.\d{1,3}"?(?<!`)}.freeze
12
15
 
13
16
  def self.problems_mapping
14
17
  super.merge(
@@ -139,7 +142,8 @@ module Gitlab
139
142
  end
140
143
 
141
144
  def message_contains_short_reference?
142
- commit.message.match?(SHORT_REFERENCE_REGEX)
145
+ commit.message.match?(SHORT_REFERENCE_REGEX) ||
146
+ commit.message.match?(MS_SHORT_REFERENCE_REGEX)
143
147
  end
144
148
 
145
149
  def emoji_checker
@@ -7,10 +7,16 @@ module Gitlab
7
7
  # @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.
8
8
  attr_accessor :code_size_thresholds
9
9
 
10
+ # @!attribute max_commits_count
11
+ # @return [Integer] the maximum number of allowed non-squashed/non-fixup commits for a given MR. A warning is triggered if the MR has more commits.
12
+ attr_accessor :max_commits_count
13
+
10
14
  DEFAULT_CHANGES_SIZE_THRESHOLDS = { high: 2_000, medium: 500 }.freeze
15
+ DEFAULT_COMMIT_MESSAGES_MAX_COMMITS_COUNT = 10
11
16
 
12
17
  def initialize
13
18
  @code_size_thresholds = DEFAULT_CHANGES_SIZE_THRESHOLDS
19
+ @max_commits_count = DEFAULT_COMMIT_MESSAGES_MAX_COMMITS_COUNT
14
20
  end
15
21
  end
16
22
  end
@@ -19,6 +19,8 @@ module Gitlab
19
19
  end
20
20
 
21
21
  def has_draft_flag?(title)
22
+ puts "This method is deprecated in favor of `helper.draft_mr?`."
23
+
22
24
  DRAFT_REGEX.match?(title)
23
25
  end
24
26
 
@@ -1,5 +1,5 @@
1
1
  module Gitlab
2
2
  module Dangerfiles
3
- VERSION = "2.0.0"
3
+ VERSION = "2.1.0"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gitlab-dangerfiles
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - GitLab
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-04-27 00:00:00.000000000 Z
11
+ date: 2021-06-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: danger-gitlab
@@ -134,6 +134,7 @@ files:
134
134
  - lib/danger/plugins/helper.rb
135
135
  - lib/danger/plugins/roulette.rb
136
136
  - lib/danger/rules/changes_size/Dangerfile
137
+ - lib/danger/rules/commit_messages/Dangerfile
137
138
  - lib/gitlab-dangerfiles.rb
138
139
  - lib/gitlab/Dangerfile
139
140
  - lib/gitlab/dangerfiles.rb