diff options
39 files changed, 460 insertions, 244 deletions
diff --git a/.gitlab/ci/frontend.gitlab-ci.yml b/.gitlab/ci/frontend.gitlab-ci.yml index cb07384676d..5d4521b3f36 100644 --- a/.gitlab/ci/frontend.gitlab-ci.yml +++ b/.gitlab/ci/frontend.gitlab-ci.yml @@ -335,10 +335,13 @@ bundle-size-review: stage: test needs: ["compile-production-assets"] script: + - source scripts/utils.sh - mkdir -p bundle-size-review - cp webpack-report/index.html bundle-size-review/bundle-report.html - yarn global add https://gitlab.com/gitlab-org/frontend/playground/webpack-memory-metrics.git - - danger --dangerfile=danger/bundle_size/Dangerfile --fail-on-errors=true --verbose --danger_id=bundle-size-review + - | + danger_id=$(echo -n ${DANGER_GITLAB_API_TOKEN} | md5sum | awk '{print $1}' | cut -c5-10) + run_timed_command "danger --dangerfile=danger/Dangerfile-bundle_size --fail-on-errors=true --verbose --danger_id=bundle-size-review-${danger_id}" artifacts: when: always name: bundle-size-review diff --git a/Dangerfile b/Dangerfile index aaa1aae813b..280a73d432c 100644 --- a/Dangerfile +++ b/Dangerfile @@ -11,16 +11,8 @@ project_name = ee? ? 'gitlab' : 'gitlab-foss' Gitlab::Dangerfiles.for_project(self, project_name) do |gitlab_dangerfiles| gitlab_dangerfiles.import_plugins + gitlab_dangerfiles.config.ci_only_rules = ProjectHelper::CI_ONLY_RULES + gitlab_dangerfiles.config.files_to_category = ProjectHelper::CATEGORIES - unless helper.release_automation? - danger.import_plugin('danger/plugins/*.rb') - gitlab_dangerfiles.import_dangerfiles(except: %w[simple_roulette]) - gitlab_dangerfiles.config.files_to_category = ProjectHelper::CATEGORIES - end -end - -return if helper.release_automation? - -project_helper.rule_names.each do |rule| - danger.import_dangerfile(path: File.join('danger', rule)) + gitlab_dangerfiles.import_dangerfiles(except: %w[simple_roulette]) end @@ -403,7 +403,7 @@ group :development, :test do end group :development, :test, :danger do - gem 'gitlab-dangerfiles', '~> 2.11.0', require: false + gem 'gitlab-dangerfiles', '~> 3.0', require: false end group :development, :test, :coverage do diff --git a/Gemfile.lock b/Gemfile.lock index dbffdd3835c..6a981d37fe6 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -224,7 +224,7 @@ GEM css_parser (1.7.0) addressable daemons (1.3.1) - danger (8.4.5) + danger (8.5.0) claide (~> 1.0) claide-plugins (>= 0.9.2) colored2 (~> 3.1) @@ -463,9 +463,10 @@ GEM terminal-table (~> 1.5, >= 1.5.1) gitlab-chronic (0.10.5) numerizer (~> 0.2) - gitlab-dangerfiles (2.11.0) + gitlab-dangerfiles (3.0.0) danger (>= 8.4.5) danger-gitlab (>= 8.0.0) + rake gitlab-experiment (0.7.0) activesupport (>= 3.0) request_store (>= 1.0) @@ -1494,7 +1495,7 @@ DEPENDENCIES gitaly (~> 14.9.0.pre.rc4) github-markup (~> 1.7.0) gitlab-chronic (~> 0.10.5) - gitlab-dangerfiles (~> 2.11.0) + gitlab-dangerfiles (~> 3.0) gitlab-experiment (~> 0.7.0) gitlab-fog-azure-rm (~> 1.2.0) gitlab-labkit (~> 0.22.0) @@ -16,3 +16,6 @@ require File.expand_path('config/initializers/01_active_record_database_tasks_co Gitlab::Application.load_tasks Knapsack.load_tasks if defined?(Knapsack) + +require 'gitlab-dangerfiles' +Gitlab::Dangerfiles.load_tasks diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb index d1c409d071e..e13c240de25 100644 --- a/app/controllers/oauth/authorizations_controller.rb +++ b/app/controllers/oauth/authorizations_controller.rb @@ -37,9 +37,6 @@ class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController # limit scopes when signing in with GitLab def downgrade_scopes! - return unless Feature.enabled?(:omniauth_login_minimal_scopes, current_user, - default_enabled: :yaml) - auth_type = params.delete('gl_auth_type') return unless auth_type == 'login' diff --git a/app/helpers/webpack_helper.rb b/app/helpers/webpack_helper.rb index 64900714327..ba3c232bec4 100644 --- a/app/helpers/webpack_helper.rb +++ b/app/helpers/webpack_helper.rb @@ -83,16 +83,8 @@ module WebpackHelper end def webpack_public_host - # We do not proxy the webpack output in the 'test' environment, - # so we must reference the webpack dev server directly. - if Rails.env.test? && Gitlab.config.webpack.dev_server.enabled - host = Gitlab.config.webpack.dev_server.host - port = Gitlab.config.webpack.dev_server.port - protocol = Gitlab.config.webpack.dev_server.https ? 'https' : 'http' - "#{protocol}://#{host}:#{port}" - else - ActionController::Base.asset_host.try(:chomp, '/') - end + # We proxy webpack output in 'test' and 'dev' environment, so we can just use asset_host + ActionController::Base.asset_host.try(:chomp, '/') end def webpack_public_path diff --git a/app/models/suggestion.rb b/app/models/suggestion.rb index f1ca5c23997..ca2ad8bf88c 100644 --- a/app/models/suggestion.rb +++ b/app/models/suggestion.rb @@ -16,10 +16,14 @@ class Suggestion < ApplicationRecord note.latest_diff_file end - def project + def source_project noteable.source_project end + def target_project + noteable.target_project + end + def branch noteable.source_branch end diff --git a/app/policies/suggestion_policy.rb b/app/policies/suggestion_policy.rb index 4c84c8ba690..3c273dc6d39 100644 --- a/app/policies/suggestion_policy.rb +++ b/app/policies/suggestion_policy.rb @@ -1,10 +1,10 @@ # frozen_string_literal: true class SuggestionPolicy < BasePolicy - delegate { @subject.project } + delegate { @subject.source_project } condition(:can_push_to_branch) do - Gitlab::UserAccess.new(@user, container: @subject.project).can_push_to_branch?(@subject.branch) + Gitlab::UserAccess.new(@user, container: @subject.source_project).can_push_to_branch?(@subject.branch) end rule { can_push_to_branch }.enable :apply_suggestion diff --git a/app/services/suggestions/apply_service.rb b/app/services/suggestions/apply_service.rb index a0d26e08341..a20eb6b79c5 100644 --- a/app/services/suggestions/apply_service.rb +++ b/app/services/suggestions/apply_service.rb @@ -54,7 +54,7 @@ module Suggestions author_email: author&.email } - ::Files::MultiService.new(suggestion_set.project, current_user, params) + ::Files::MultiService.new(suggestion_set.source_project, current_user, params) end def commit_message diff --git a/config/feature_flags/development/omniauth_login_minimal_scopes.yml b/config/feature_flags/development/omniauth_login_minimal_scopes.yml deleted file mode 100644 index b2ca3484a98..00000000000 --- a/config/feature_flags/development/omniauth_login_minimal_scopes.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: omniauth_login_minimal_scopes -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/78556 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/351331 -milestone: '14.8' -type: development -group: 'group::authentication and authorization' -default_enabled: false diff --git a/config/initializers/static_files.rb b/config/initializers/static_files.rb index 2879d48387d..a26d78f102b 100644 --- a/config/initializers/static_files.rb +++ b/config/initializers/static_files.rb @@ -21,7 +21,7 @@ if app.config.public_file_server.enabled # If webpack-dev-server is configured, proxy webpack's public directory # instead of looking for static assets - if Gitlab.config.webpack.dev_server.enabled && Rails.env.development? + if Gitlab.config.webpack.dev_server.enabled && Gitlab.dev_or_test_env? app.config.middleware.insert_before( Gitlab::Middleware::Static, Gitlab::Webpack::DevServerMiddleware, diff --git a/danger/bundle_size/Dangerfile b/danger/Dangerfile-bundle_size index b824edb5dab..23ab726096e 100644 --- a/danger/bundle_size/Dangerfile +++ b/danger/Dangerfile-bundle_size @@ -1,4 +1,5 @@ # frozen_string_literal: true +# This file isn't named "Dangerfile" so that it's not imported by default since it's only meant to be run in the `bundle-size-review` job. analysis_result = "./bundle-size-review/analysis.json" markdown_result = "./bundle-size-review/comparison.md" diff --git a/danger/ci_templates/Dangerfile b/danger/ci_templates/Dangerfile index 3d57436ef94..ace9905e91d 100644 --- a/danger/ci_templates/Dangerfile +++ b/danger/ci_templates/Dangerfile @@ -19,7 +19,7 @@ return unless helper.ci? template_paths_to_review = helper.changes_by_category[:ci_template] -if gitlab.mr_labels.include?('ci::templates') || template_paths_to_review.any? +if helper.mr_labels.include?('ci::templates') || template_paths_to_review.any? message 'This merge request adds or changes files that require a ' \ 'review from the CI/CD Templates maintainers.' diff --git a/danger/database/Dangerfile b/danger/database/Dangerfile index 0128f0fa195..f94184263ad 100644 --- a/danger/database/Dangerfile +++ b/danger/database/Dangerfile @@ -49,11 +49,11 @@ if geo_migration_created && !geo_db_schema_updated end return unless helper.ci? -return if gitlab.mr_labels.include?(DATABASE_APPROVED_LABEL) +return if helper.mr_labels.include?(DATABASE_APPROVED_LABEL) db_paths_to_review = helper.changes_by_category[:database] -if gitlab.mr_labels.include?('database') || db_paths_to_review.any? +if helper.mr_labels.include?('database') || db_paths_to_review.any? message 'This merge request adds or changes files that require a ' \ 'review from the [Database team](https://gitlab.com/groups/gl-database/-/group_members).' diff --git a/danger/feature_flag/Dangerfile b/danger/feature_flag/Dangerfile index 5fe9d42a7a1..d5b907377aa 100644 --- a/danger/feature_flag/Dangerfile +++ b/danger/feature_flag/Dangerfile @@ -22,21 +22,21 @@ def check_feature_flag_yaml(feature_flag) end rescue Psych::Exception # YAML could not be parsed, fail the build. - fail "#{gitlab.html_link(feature_flag.path)} isn't valid YAML! #{SEE_DOC}" + fail "#{helper.html_link(feature_flag.path)} isn't valid YAML! #{SEE_DOC}" rescue StandardError => e warn "There was a problem trying to check the Feature Flag file. Exception: #{e.class.name} - #{e.message}" end def message_for_feature_flag_missing_group!(feature_flag:, mr_group_label:) if mr_group_label.nil? - warn "Consider setting `group` in #{gitlab.html_link(feature_flag.path)}. #{SEE_DOC}" + warn "Consider setting `group` in #{helper.html_link(feature_flag.path)}. #{SEE_DOC}" else mr_line = feature_flag.raw.lines.find_index("group:\n") if mr_line markdown(format(SUGGEST_MR_COMMENT, group: mr_group_label), file: feature_flag.path, line: mr_line.succ) else - warn %(Consider setting `group: "#{mr_group_label}"` in #{gitlab.html_link(feature_flag.path)}. #{SEE_DOC}) + warn %(Consider setting `group: "#{mr_group_label}"` in #{helper.html_link(feature_flag.path)}. #{SEE_DOC}) end end end @@ -60,7 +60,7 @@ def message_for_feature_flag_with_group!(feature_flag:, mr_group_label:) if mr_group_label.nil? helper.labels_to_add << feature_flag.group else - fail %(`group` is set to ~"#{feature_flag.group}" in #{gitlab.html_link(feature_flag.path)}, which does not match ~"#{mr_group_label}" set on the MR!) + fail %(`group` is set to ~"#{feature_flag.group}" in #{helper.html_link(feature_flag.path)}, which does not match ~"#{mr_group_label}" set on the MR!) end end diff --git a/danger/specialization_labels/Dangerfile b/danger/specialization_labels/Dangerfile index f161c470f36..615ceb8625d 100644 --- a/danger/specialization_labels/Dangerfile +++ b/danger/specialization_labels/Dangerfile @@ -16,11 +16,11 @@ SPECIALIZATIONS = { labels_to_add = helper.changes_by_category.each_with_object([]) do |(category, _changes), memo| label = SPECIALIZATIONS[category] next unless label - next if gitlab.mr_labels.include?(label) + next if helper.mr_labels.include?(label) # Don't override already-set scoped labels. label_scope = label.split('::')[0...-1].join('::') - next if !label_scope.empty? && gitlab.mr_labels.any? { |mr_label| mr_label.start_with?(label_scope) } + next if !label_scope.empty? && helper.has_scoped_label_with_scope?(label_scope) memo << label end diff --git a/danger/specs/Dangerfile b/danger/specs/Dangerfile index 8ef046f7bc1..dc9809b20b5 100644 --- a/danger/specs/Dangerfile +++ b/danger/specs/Dangerfile @@ -37,7 +37,7 @@ has_ee_app_changes = all_changed_files.grep(%r{\Aee/(app|lib|db/(geo/)?(post_)?m spec_changes = specs.changed_specs_files(ee: :exclude) has_spec_changes = spec_changes.any? has_ee_spec_changes = specs.changed_specs_files(ee: :only).any? -new_specs_needed = (gitlab.mr_labels & NO_SPECS_LABELS).empty? +new_specs_needed = (helper.mr_labels & NO_SPECS_LABELS).empty? if (has_app_changes || has_ee_app_changes) && !(has_spec_changes || has_ee_spec_changes) && new_specs_needed warn format(NO_NEW_SPEC_MESSAGE, labels: helper.labels_list(NO_SPECS_LABELS)), sticky: false diff --git a/danger/z_metadata/Dangerfile b/danger/z_metadata/Dangerfile index 546fdc8de5f..8aeb0c33a9c 100644 --- a/danger/z_metadata/Dangerfile +++ b/danger/z_metadata/Dangerfile @@ -14,12 +14,12 @@ end has_milestone = !gitlab.mr_json["milestone"].nil? -unless has_milestone || (helper.security_mr? && gitlab.branch_for_base == DEFAULT_BRANCH) +unless has_milestone || (helper.security_mr? && helper.mr_target_branch == DEFAULT_BRANCH) warn "This merge request does not refer to an existing milestone.", sticky: false end -has_pick_into_stable_label = gitlab.mr_labels.find { |label| label.start_with?('Pick into') } +has_pick_into_stable_label = helper.mr_labels.find { |label| label.start_with?('Pick into') } -if gitlab.branch_for_base != DEFAULT_BRANCH && !has_pick_into_stable_label && !helper.security_mr? +if helper.mr_target_branch != DEFAULT_BRANCH && !has_pick_into_stable_label && !helper.security_mr? warn "Most of the time, merge requests should target `#{DEFAULT_BRANCH}`. Otherwise, please set the relevant `Pick into X.Y` label." end diff --git a/db/post_migrate/20220315171027_add_tmp_index_to_support_leaky_regex_cleanup.rb b/db/post_migrate/20220315171027_add_tmp_index_to_support_leaky_regex_cleanup.rb new file mode 100644 index 00000000000..6f4bd29337e --- /dev/null +++ b/db/post_migrate/20220315171027_add_tmp_index_to_support_leaky_regex_cleanup.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class AddTmpIndexToSupportLeakyRegexCleanup < Gitlab::Database::Migration[1.0] + INDEX_NAME = "tmp_index_merge_requests_draft_and_status_leaky_regex" + LEAKY_REGEXP_STR = "^\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP" + CORRECTED_REGEXP_STR = "^(\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP)" + + disable_ddl_transaction! + + def up + add_concurrent_index :merge_requests, :id, + where: "draft = true AND state_id = 1 AND ((title)::text ~* '#{LEAKY_REGEXP_STR}'::text) AND ((title)::text !~* '#{CORRECTED_REGEXP_STR}'::text)", + name: INDEX_NAME + end + + def down + remove_concurrent_index_by_name :merge_requests, INDEX_NAME + end +end diff --git a/db/post_migrate/20220315171129_cleanup_draft_data_from_faulty_regex.rb b/db/post_migrate/20220315171129_cleanup_draft_data_from_faulty_regex.rb new file mode 100644 index 00000000000..be81bf85f62 --- /dev/null +++ b/db/post_migrate/20220315171129_cleanup_draft_data_from_faulty_regex.rb @@ -0,0 +1,42 @@ +# frozen_string_literal: true + +class CleanupDraftDataFromFaultyRegex < Gitlab::Database::Migration[1.0] + MIGRATION = 'CleanupDraftDataFromFaultyRegex' + DELAY_INTERVAL = 5.minutes + BATCH_SIZE = 20 + + disable_ddl_transaction! + + class MergeRequest < ActiveRecord::Base + LEAKY_REGEXP_STR = "^\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP" + CORRECTED_REGEXP_STR = "^(\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP)" + + self.table_name = 'merge_requests' + + include ::EachBatch + + def self.eligible + where(state_id: 1) + .where(draft: true) + .where("title ~* ?", LEAKY_REGEXP_STR) + .where("title !~* ?", CORRECTED_REGEXP_STR) + end + end + + def up + return unless Gitlab.com? + + queue_background_migration_jobs_by_range_at_intervals( + MergeRequest.eligible, + MIGRATION, + DELAY_INTERVAL, + batch_size: BATCH_SIZE, + track_jobs: true + ) + end + + def down + # noop + # + end +end diff --git a/db/schema_migrations/20220315171027 b/db/schema_migrations/20220315171027 new file mode 100644 index 00000000000..7a4c65f3b7f --- /dev/null +++ b/db/schema_migrations/20220315171027 @@ -0,0 +1 @@ +4c329622299c76ca753381f1ccc0686714d07eeee8acfc834e576d5a5addaafc
\ No newline at end of file diff --git a/db/schema_migrations/20220315171129 b/db/schema_migrations/20220315171129 new file mode 100644 index 00000000000..1f558096664 --- /dev/null +++ b/db/schema_migrations/20220315171129 @@ -0,0 +1 @@ +7ca832e710026c0721ecdcd50b477073aeaf7cb795c50acd604897f85707b163
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 1e169489c1e..2b7a8e5a5ba 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -29617,6 +29617,8 @@ CREATE INDEX tmp_index_issues_on_issue_type_and_id ON issues USING btree (issue_ CREATE INDEX tmp_index_members_on_state ON members USING btree (state) WHERE (state = 2); +CREATE INDEX tmp_index_merge_requests_draft_and_status_leaky_regex ON merge_requests USING btree (id) WHERE ((draft = true) AND (state_id = 1) AND ((title)::text ~* '^\[draft\]|\(draft\)|draft:|draft|\[WIP\]|WIP:|WIP'::text) AND ((title)::text !~* '^(\[draft\]|\(draft\)|draft:|draft|\[WIP\]|WIP:|WIP)'::text)); + CREATE INDEX tmp_index_namespaces_empty_traversal_ids_with_child_namespaces ON namespaces USING btree (id) WHERE ((parent_id IS NOT NULL) AND (traversal_ids = '{}'::integer[])); CREATE INDEX tmp_index_namespaces_empty_traversal_ids_with_root_namespaces ON namespaces USING btree (id) WHERE ((parent_id IS NULL) AND (traversal_ids = '{}'::integer[])); diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 8bc87d37a48..df68a27673e 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -3236,6 +3236,10 @@ Input type: `iterationCreateInput` ### `Mutation.iterationDelete` +WARNING: +**Deprecated** in 14.10. +Manual iteration management is deprecated. Only automatic iteration cadences will be supported in the future. + Input type: `IterationDeleteInput` #### Arguments diff --git a/doc/development/documentation/styleguide/word_list.md b/doc/development/documentation/styleguide/word_list.md index 9954a3cc3e4..dcb9a5f7362 100644 --- a/doc/development/documentation/styleguide/word_list.md +++ b/doc/development/documentation/styleguide/word_list.md @@ -261,11 +261,17 @@ Do not use **Developer permissions**. A user who is assigned the Developer role See [the Microsoft style guide](https://docs.microsoft.com/en-us/style-guide/a-z-word-list-term-collections/d/disable-disabled) for guidance on **disable**. Use **inactive** or **off** instead. ([Vale](../testing.md#vale) rule: [`InclusionAbleism.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/InclusionAbleism.yml)) - ## disallow Use **prevent** instead of **disallow**. ([Vale](../testing.md#vale) rule: [`Substitutions.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Substitutions.yml)) +## downgrade + +To be more upbeat and precise, do not use **downgrade**. Focus instead on the action the user is taking. + +- For changing to earlier GitLab versions, use [**roll back**](#roll-back). +- For changing to lower GitLab tiers, use **change the subscription tier**. + ## dropdown list Use **dropdown list** to refer to the UI element. Do not use **dropdown** without **list** after it. @@ -748,6 +754,12 @@ Do not use **roles** and [**permissions**](#permissions) interchangeably. Each u Roles are not the same as [**access levels**](#access-level). +## roll back + +Use **roll back** for changing a GitLab version to an earlier one. + +Do not use **roll back** for licensing or subscriptions. Use **change the subscription tier** instead. + ## runner, runners Use lowercase for **runners**. These are the agents that run CI/CD jobs. See also [GitLab Runner](#gitlab-runner) and [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/233529). @@ -934,6 +946,33 @@ Use [**2FA** and **two-factor authentication**](#2fa-two-factor-authentication) Do not use **type** if you can avoid it. Use **enter** instead. +## update + +Use **update** for installing a newer **patch** version of the software only. For example: + +- Update GitLab from 14.9 to 14.9.1. + +Do not use **update** for any other case. Instead, use **upgrade**. + +## upgrade + +Use **upgrade** for: + +- Choosing a higher subscription tier (Premium or Ultimate). +- Installing a newer **major** (13.0, 14.0) or **minor** (13.8, 14.5) version of GitLab. + +For example: + +- Upgrade to GitLab Ultimate. +- Upgrade GitLab from 14.0 to 14.1. +- Upgrade GitLab from 14.0 to 15.0. + +Use caution with the phrase **Upgrade GitLab** without any other text. +Ensure the surrounding text clarifies whether +you're talking about the product version or the subscription tier. + +See also [downgrade](#downgrade) and [roll back](#roll-back). + ## useful Do not use **useful**. If the user doesn't find the process to be useful, we lose their trust. ([Vale](../testing.md#vale) rule: [`Simplicity.yml`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/doc/.vale/gitlab/Simplicity.yml)) diff --git a/doc/integration/gitlab.md b/doc/integration/gitlab.md index 132006ab996..c79aeb8546d 100644 --- a/doc/integration/gitlab.md +++ b/doc/integration/gitlab.md @@ -117,10 +117,9 @@ signed in. ## Reduce access privileges on sign in -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337663) in GitLab 14.8 [with a flag](../administration/feature_flags.md) named `omniauth_login_minimal_scopes`. Disabled by default. - -FLAG: -On self-managed GitLab, by default this feature is not available. To make it available, ask an administrator to [enable the feature flag](../administration/feature_flags.md) named `omniauth_login_minimal_scopes`. On GitLab.com, this feature is not available. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/337663) in GitLab 14.8 [with a flag](../administration/feature_flags.md) named `omniauth_login_minimal_scopes`. Disabled by default. +> - [Enabled on GitLab.com](https://gitlab.com/gitlab-org/gitlab/-/issues/351331) in GitLab 14.9. +> - [Feature flag `omniauth_login_minimal_scopes`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/83453) removed in GitLab 14.10 If you use a GitLab instance for authentication, you can reduce access rights when an OAuth application is used for sign in. diff --git a/doc/user/project/merge_requests/reviews/suggestions.md b/doc/user/project/merge_requests/reviews/suggestions.md index 9868f2619ba..8e6794bcfa7 100644 --- a/doc/user/project/merge_requests/reviews/suggestions.md +++ b/doc/user/project/merge_requests/reviews/suggestions.md @@ -108,6 +108,8 @@ For example, to customize the commit message to output **Addresses user_1's review**, set the custom text to `Addresses %{username}'s review`. +For merge requests created from forks, GitLab uses the template defined in target project. + NOTE: Custom commit messages for each applied suggestion is introduced by [#25381](https://gitlab.com/gitlab-org/gitlab/-/issues/25381). diff --git a/lefthook.yml b/lefthook.yml index b21db70a385..086e70fcbb9 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -2,7 +2,7 @@ pre-push: parallel: true commands: danger: - run: CI_PROJECT_DIR=. bundle exec danger dry_run + run: bundle exec rake danger_local eslint: tags: frontend style files: git diff --name-only --diff-filter=d $(git merge-base origin/master HEAD)..HEAD diff --git a/lib/gitlab/background_migration/cleanup_draft_data_from_faulty_regex.rb b/lib/gitlab/background_migration/cleanup_draft_data_from_faulty_regex.rb new file mode 100644 index 00000000000..b703faf6a6c --- /dev/null +++ b/lib/gitlab/background_migration/cleanup_draft_data_from_faulty_regex.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +module Gitlab + module BackgroundMigration + # Cleanup draft column data inserted by a faulty regex + # + class CleanupDraftDataFromFaultyRegex + # Migration only version of MergeRequest table + ## + class MergeRequest < ActiveRecord::Base + LEAKY_REGEXP_STR = "^\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP" + CORRECTED_REGEXP_STR = "^(\\[draft\\]|\\(draft\\)|draft:|draft|\\[WIP\\]|WIP:|WIP)" + + include EachBatch + + self.table_name = 'merge_requests' + + def self.eligible + where(state_id: 1) + .where(draft: true) + .where("title ~* ?", LEAKY_REGEXP_STR) + .where("title !~* ?", CORRECTED_REGEXP_STR) + end + end + + def perform(start_id, end_id) + eligible_mrs = MergeRequest.eligible.where(id: start_id..end_id).pluck(:id) + + return if eligible_mrs.empty? + + eligible_mrs.each_slice(10) do |slice| + MergeRequest.where(id: slice).update_all(draft: false) + end + + mark_job_as_succeeded(start_id, end_id) + end + + private + + def mark_job_as_succeeded(*arguments) + Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded( + 'CleanupDraftDataFromFaultyRegex', + arguments + ) + end + end + end +end diff --git a/lib/gitlab/suggestions/commit_message.rb b/lib/gitlab/suggestions/commit_message.rb index 5bca3efe6e1..fcf30cd6df9 100644 --- a/lib/gitlab/suggestions/commit_message.rb +++ b/lib/gitlab/suggestions/commit_message.rb @@ -13,7 +13,7 @@ module Gitlab end def message - project = suggestion_set.project + project = suggestion_set.target_project user_defined_message = @custom_message.presence || project.suggestion_commit_message.presence message = user_defined_message || DEFAULT_SUGGESTION_COMMIT_MESSAGE @@ -37,8 +37,8 @@ module Gitlab 'branch_name' => ->(user, suggestion_set) { suggestion_set.branch }, 'files_count' => ->(user, suggestion_set) { suggestion_set.file_paths.length }, 'file_paths' => ->(user, suggestion_set) { format_paths(suggestion_set.file_paths) }, - 'project_name' => ->(user, suggestion_set) { suggestion_set.project.name }, - 'project_path' => ->(user, suggestion_set) { suggestion_set.project.path }, + 'project_name' => ->(user, suggestion_set) { suggestion_set.target_project.name }, + 'project_path' => ->(user, suggestion_set) { suggestion_set.target_project.path }, 'user_full_name' => ->(user, suggestion_set) { user.name }, 'username' => ->(user, suggestion_set) { user.username }, 'suggestions_count' => ->(user, suggestion_set) { suggestion_set.suggestions.size } diff --git a/lib/gitlab/suggestions/suggestion_set.rb b/lib/gitlab/suggestions/suggestion_set.rb index 53885cdbf19..21a5acf8afe 100644 --- a/lib/gitlab/suggestions/suggestion_set.rb +++ b/lib/gitlab/suggestions/suggestion_set.rb @@ -9,8 +9,12 @@ module Gitlab @suggestions = suggestions end - def project - first_suggestion.project + def source_project + first_suggestion.source_project + end + + def target_project + first_suggestion.target_project end def branch diff --git a/lib/tasks/gitlab_danger.rake b/lib/tasks/gitlab_danger.rake deleted file mode 100644 index ff9464a588a..00000000000 --- a/lib/tasks/gitlab_danger.rake +++ /dev/null @@ -1,19 +0,0 @@ -# frozen_string_literal: true - -desc 'Run local Danger rules' -task :danger_local do - require_relative '../../tooling/danger/project_helper' - require 'gitlab/popen' - - puts("#{Tooling::Danger::ProjectHelper.local_warning_message}\n") - - # _status will _always_ be 0, regardless of failure or success :( - output, _status = Gitlab::Popen.popen(%w{danger dry_run}) - - if output.empty? - puts(Tooling::Danger::ProjectHelper.success_message) - else - puts(output) - exit(1) - end -end diff --git a/spec/lib/gitlab/background_migration/cleanup_draft_data_from_faulty_regex_spec.rb b/spec/lib/gitlab/background_migration/cleanup_draft_data_from_faulty_regex_spec.rb new file mode 100644 index 00000000000..50489c26547 --- /dev/null +++ b/spec/lib/gitlab/background_migration/cleanup_draft_data_from_faulty_regex_spec.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::BackgroundMigration::CleanupDraftDataFromFaultyRegex do + let(:namespaces) { table(:namespaces) } + let(:projects) { table(:projects) } + let(:merge_requests) { table(:merge_requests) } + + let(:group) { namespaces.create!(name: 'gitlab', path: 'gitlab') } + let(:project) { projects.create!(namespace_id: group.id) } + + let(:draft_prefixes) { ["[Draft]", "(Draft)", "Draft:", "Draft", "[WIP]", "WIP:", "WIP"] } + + def create_merge_request(params) + common_params = { + target_project_id: project.id, + target_branch: 'feature1', + source_branch: 'master' + } + + merge_requests.create!(common_params.merge(params)) + end + + context "mr.draft == true, and title matches the leaky regex and not the corrected regex" do + let(:mr_ids) { merge_requests.all.collect(&:id) } + + before do + draft_prefixes.each do |prefix| + (1..4).each do |n| + create_merge_request( + title: "#{prefix} This is a title", + draft: true, + state_id: 1 + ) + end + end + + create_merge_request(title: "This has draft in the title", draft: true, state_id: 1) + end + + it "updates all open draft merge request's draft field to true" do + expect { subject.perform(mr_ids.first, mr_ids.last) } + .to change { MergeRequest.where(draft: true).count } + .by(-1) + end + + it "marks successful slices as completed" do + expect(subject).to receive(:mark_job_as_succeeded).with(mr_ids.first, mr_ids.last) + + subject.perform(mr_ids.first, mr_ids.last) + end + end +end diff --git a/spec/lib/gitlab/suggestions/commit_message_spec.rb b/spec/lib/gitlab/suggestions/commit_message_spec.rb index 965960f0c3e..dcadc206715 100644 --- a/spec/lib/gitlab/suggestions/commit_message_spec.rb +++ b/spec/lib/gitlab/suggestions/commit_message_spec.rb @@ -3,7 +3,10 @@ require 'spec_helper' RSpec.describe Gitlab::Suggestions::CommitMessage do - def create_suggestion(file_path, new_line, to_content) + include ProjectForksHelper + using RSpec::Parameterized::TableSyntax + + def create_suggestion(merge_request, file_path, new_line, to_content) position = Gitlab::Diff::Position.new(old_path: file_path, new_path: file_path, old_line: nil, @@ -29,69 +32,111 @@ RSpec.describe Gitlab::Suggestions::CommitMessage do create(:project, :repository, path: 'project-1', name: 'Project_1') end - let_it_be(:merge_request) do + let_it_be(:forked_project) { fork_project(project, nil, repository: true) } + + let_it_be(:merge_request_same_project) do create(:merge_request, source_project: project, target_project: project) end - let_it_be(:suggestion_set) do - suggestion1 = create_suggestion('files/ruby/popen.rb', 9, '*** SUGGESTION 1 ***') - suggestion2 = create_suggestion('files/ruby/popen.rb', 13, '*** SUGGESTION 2 ***') - suggestion3 = create_suggestion('files/ruby/regex.rb', 22, '*** SUGGESTION 3 ***') + let_it_be(:merge_request_from_fork) do + create(:merge_request, source_project: forked_project, target_project: project) + end + + let_it_be(:suggestion_set_same_project) do + suggestion1 = create_suggestion(merge_request_same_project, 'files/ruby/popen.rb', 9, '*** SUGGESTION 1 ***') + suggestion2 = create_suggestion(merge_request_same_project, 'files/ruby/popen.rb', 13, '*** SUGGESTION 2 ***') + suggestion3 = create_suggestion(merge_request_same_project, 'files/ruby/regex.rb', 22, '*** SUGGESTION 3 ***') + + Gitlab::Suggestions::SuggestionSet.new([suggestion1, suggestion2, suggestion3]) + end + + let_it_be(:suggestion_set_forked_project) do + suggestion1 = create_suggestion(merge_request_from_fork, 'files/ruby/popen.rb', 9, '*** SUGGESTION 1 ***') + suggestion2 = create_suggestion(merge_request_from_fork, 'files/ruby/popen.rb', 13, '*** SUGGESTION 2 ***') + suggestion3 = create_suggestion(merge_request_from_fork, 'files/ruby/regex.rb', 22, '*** SUGGESTION 3 ***') Gitlab::Suggestions::SuggestionSet.new([suggestion1, suggestion2, suggestion3]) end describe '#message' do - before do - # Updating the suggestion_commit_message on a project shared across specs - # avoids recreating the repository for each spec. - project.update!(suggestion_commit_message: message) - end + where(:suggestion_set) { [ref(:suggestion_set_same_project), ref(:suggestion_set_forked_project)] } + + with_them do + before do + # Updating the suggestion_commit_message on a project shared across specs + # avoids recreating the repository for each spec. + project.update!(suggestion_commit_message: message) + forked_project.update!(suggestion_commit_message: fork_message) + end + + let(:fork_message) { nil } - context 'when a custom commit message is not specified' do - let(:expected_message) { 'Apply 3 suggestion(s) to 2 file(s)' } + context 'when a custom commit message is not specified' do + let(:expected_message) { 'Apply 3 suggestion(s) to 2 file(s)' } - context 'and is nil' do - let(:message) { nil } + context 'and is nil' do + let(:message) { nil } - it 'uses the default commit message' do - expect(described_class - .new(user, suggestion_set) - .message).to eq(expected_message) + it 'uses the default commit message' do + expect(described_class + .new(user, suggestion_set) + .message).to eq(expected_message) + end end - end - context 'and is an empty string' do - let(:message) { '' } + context 'and is an empty string' do + let(:message) { '' } - it 'uses the default commit message' do - expect(described_class - .new(user, suggestion_set) - .message).to eq(expected_message) + it 'uses the default commit message' do + expect(described_class + .new(user, suggestion_set) + .message).to eq(expected_message) + end end - end - end - context 'when a custom commit message is specified' do - let(:message) { "i'm a project message. a user's custom message takes precedence over me :(" } - let(:custom_message) { "hello there! i'm a cool custom commit message." } + context 'when a custom commit message is specified for forked project' do + let(:message) { nil } + let(:fork_message) { "I'm a sad message that will not be used :(" } - it 'shows the custom commit message' do - expect(Gitlab::Suggestions::CommitMessage - .new(user, suggestion_set, custom_message) - .message).to eq(custom_message) + it 'uses the default commit message' do + expect(described_class + .new(user, suggestion_set) + .message).to eq(expected_message) + end + end end - end - context 'is specified and includes all placeholders' do - let(:message) do - '*** %{branch_name} %{files_count} %{file_paths} %{project_name} %{project_path} %{user_full_name} %{username} %{suggestions_count} ***' + context 'when a custom commit message is specified' do + let(:message) { "i'm a project message. a user's custom message takes precedence over me :(" } + let(:custom_message) { "hello there! i'm a cool custom commit message." } + + it 'shows the custom commit message' do + expect(Gitlab::Suggestions::CommitMessage + .new(user, suggestion_set, custom_message) + .message).to eq(custom_message) + end end - it 'generates a custom commit message' do - expect(Gitlab::Suggestions::CommitMessage - .new(user, suggestion_set) - .message).to eq('*** master 2 files/ruby/popen.rb, files/ruby/regex.rb Project_1 project-1 Test User test.user 3 ***') + context 'is specified and includes all placeholders' do + let(:message) do + '*** %{branch_name} %{files_count} %{file_paths} %{project_name} %{project_path} %{user_full_name} %{username} %{suggestions_count} ***' + end + + it 'generates a custom commit message' do + expect(Gitlab::Suggestions::CommitMessage + .new(user, suggestion_set) + .message).to eq('*** master 2 files/ruby/popen.rb, files/ruby/regex.rb Project_1 project-1 Test User test.user 3 ***') + end + + context 'when a custom commit message is specified for forked project' do + let(:fork_message) { "I'm a sad message that will not be used :(" } + + it 'uses the target project commit message' do + expect(Gitlab::Suggestions::CommitMessage + .new(user, suggestion_set) + .message).to eq('*** master 2 files/ruby/popen.rb, files/ruby/regex.rb Project_1 project-1 Test User test.user 3 ***') + end + end end end end diff --git a/spec/lib/gitlab/suggestions/suggestion_set_spec.rb b/spec/lib/gitlab/suggestions/suggestion_set_spec.rb index 54d79a9d4ba..469646986e1 100644 --- a/spec/lib/gitlab/suggestions/suggestion_set_spec.rb +++ b/spec/lib/gitlab/suggestions/suggestion_set_spec.rb @@ -3,6 +3,9 @@ require 'spec_helper' RSpec.describe Gitlab::Suggestions::SuggestionSet do + include ProjectForksHelper + using RSpec::Parameterized::TableSyntax + def create_suggestion(file_path, new_line, to_content) position = Gitlab::Diff::Position.new(old_path: file_path, new_path: file_path, @@ -24,86 +27,99 @@ RSpec.describe Gitlab::Suggestions::SuggestionSet do let_it_be(:user) { create(:user) } let_it_be(:project) { create(:project, :repository) } + let_it_be(:forked_project) { fork_project(project, nil, repository: true) } - let_it_be(:merge_request) do + let_it_be(:merge_request_same_project) do create(:merge_request, source_project: project, target_project: project) end - let_it_be(:suggestion) { create(:suggestion)} - - let_it_be(:suggestion2) do - create_suggestion('files/ruby/popen.rb', 13, "*** SUGGESTION 2 ***") - end - - let_it_be(:suggestion3) do - create_suggestion('files/ruby/regex.rb', 22, "*** SUGGESTION 3 ***") + let_it_be(:merge_request_from_fork) do + create(:merge_request, source_project: forked_project, target_project: project) end - let_it_be(:unappliable_suggestion) { create(:suggestion, :unappliable) } + where(:merge_request) { [ref(:merge_request_same_project), ref(:merge_request_from_fork)] } + with_them do + let(:note) { create(:diff_note_on_merge_request, project: project, noteable: merge_request) } + let(:suggestion) { create(:suggestion, note: note) } - let(:suggestion_set) { described_class.new([suggestion]) } - - describe '#project' do - it 'returns the project associated with the suggestions' do - expected_project = suggestion.project + let(:suggestion2) do + create_suggestion('files/ruby/popen.rb', 13, "*** SUGGESTION 2 ***") + end - expect(suggestion_set.project).to be(expected_project) + let(:suggestion3) do + create_suggestion('files/ruby/regex.rb', 22, "*** SUGGESTION 3 ***") end - end - describe '#branch' do - it 'returns the branch associated with the suggestions' do - expected_branch = suggestion.branch + let(:unappliable_suggestion) { create(:suggestion, :unappliable) } + + let(:suggestion_set) { described_class.new([suggestion]) } - expect(suggestion_set.branch).to be(expected_branch) + describe '#source_project' do + it 'returns the source project associated with the suggestions' do + expect(suggestion_set.source_project).to be(merge_request.source_project) + end end - end - describe '#valid?' do - it 'returns true if no errors are found' do - expect(suggestion_set.valid?).to be(true) + describe '#target_project' do + it 'returns the target project associated with the suggestions' do + expect(suggestion_set.target_project).to be(project) + end end - it 'returns false if an error is found' do - suggestion_set = described_class.new([unappliable_suggestion]) + describe '#branch' do + it 'returns the branch associated with the suggestions' do + expected_branch = suggestion.branch - expect(suggestion_set.valid?).to be(false) + expect(suggestion_set.branch).to be(expected_branch) + end end - end - describe '#error_message' do - it 'returns an error message if an error is found' do - suggestion_set = described_class.new([unappliable_suggestion]) + describe '#valid?' do + it 'returns true if no errors are found' do + expect(suggestion_set.valid?).to be(true) + end - expect(suggestion_set.error_message).to be_a(String) + it 'returns false if an error is found' do + suggestion_set = described_class.new([unappliable_suggestion]) + + expect(suggestion_set.valid?).to be(false) + end end - it 'returns nil if no errors are found' do - expect(suggestion_set.error_message).to be(nil) + describe '#error_message' do + it 'returns an error message if an error is found' do + suggestion_set = described_class.new([unappliable_suggestion]) + + expect(suggestion_set.error_message).to be_a(String) + end + + it 'returns nil if no errors are found' do + expect(suggestion_set.error_message).to be(nil) + end end - end - describe '#actions' do - it 'returns an array of hashes with proper key/value pairs' do - first_action = suggestion_set.actions.first + describe '#actions' do + it 'returns an array of hashes with proper key/value pairs' do + first_action = suggestion_set.actions.first - file_suggestion = suggestion_set.send(:suggestions_per_file).first + file_suggestion = suggestion_set.send(:suggestions_per_file).first - expect(first_action[:action]).to be('update') - expect(first_action[:file_path]).to eq(file_suggestion.file_path) - expect(first_action[:content]).to eq(file_suggestion.new_content) + expect(first_action[:action]).to be('update') + expect(first_action[:file_path]).to eq(file_suggestion.file_path) + expect(first_action[:content]).to eq(file_suggestion.new_content) + end end - end - describe '#file_paths' do - it 'returns an array of unique file paths associated with the suggestions' do - suggestion_set = described_class.new([suggestion, suggestion2, suggestion3]) + describe '#file_paths' do + it 'returns an array of unique file paths associated with the suggestions' do + suggestion_set = described_class.new([suggestion, suggestion2, suggestion3]) - expected_paths = %w(files/ruby/popen.rb files/ruby/regex.rb) + expected_paths = %w(files/ruby/popen.rb files/ruby/regex.rb) - actual_paths = suggestion_set.file_paths + actual_paths = suggestion_set.file_paths - expect(actual_paths.sort).to eq(expected_paths) + expect(actual_paths.sort).to eq(expected_paths) + end end end end diff --git a/spec/migrations/20220315171129_cleanup_draft_data_from_faulty_regex_spec.rb b/spec/migrations/20220315171129_cleanup_draft_data_from_faulty_regex_spec.rb new file mode 100644 index 00000000000..925f1e573be --- /dev/null +++ b/spec/migrations/20220315171129_cleanup_draft_data_from_faulty_regex_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' +require_migration! + +RSpec.describe CleanupDraftDataFromFaultyRegex do + let(:merge_requests) { table(:merge_requests) } + + let!(:namespace) { table(:namespaces).create!(name: 'namespace', path: 'namespace') } + let!(:project) { table(:projects).create!(namespace_id: namespace.id) } + + let(:default_mr_values) do + { + target_project_id: project.id, + draft: true, + source_branch: 'master', + target_branch: 'feature' + } + end + + let!(:known_good_1) { merge_requests.create!(default_mr_values.merge(title: "Draft: Test Title")) } + let!(:known_good_2) { merge_requests.create!(default_mr_values.merge(title: "WIP: Test Title")) } + let!(:known_bad_1) { merge_requests.create!(default_mr_values.merge(title: "Known bad title drafts")) } + let!(:known_bad_2) { merge_requests.create!(default_mr_values.merge(title: "Known bad title wip")) } + + describe '#up' do + it 'schedules CleanupDraftDataFromFaultyRegex background jobs filtering for eligble MRs' do + stub_const("#{described_class}::BATCH_SIZE", 2) + allow(Gitlab).to receive(:com?).and_return(true) + + freeze_time do + migrate! + + expect(described_class::MIGRATION).to be_scheduled_delayed_migration(5.minutes, known_bad_1.id, known_bad_2.id) + + expect(BackgroundMigrationWorker.jobs.size).to eq(1) + end + end + end +end diff --git a/spec/tooling/danger/project_helper_spec.rb b/spec/tooling/danger/project_helper_spec.rb index 902e01e2cbd..b3fb592c2e3 100644 --- a/spec/tooling/danger/project_helper_spec.rb +++ b/spec/tooling/danger/project_helper_spec.rb @@ -276,40 +276,6 @@ RSpec.describe Tooling::Danger::ProjectHelper do end end - describe '.local_warning_message' do - it 'returns an informational message with rules that can run' do - expect(described_class.local_warning_message).to eq('==> Only the following Danger rules can be run locally: ci_config, database, documentation, duplicate_yarn_dependencies, eslint, gitaly, pajamas, pipeline, prettier, product_intelligence, utility_css, vue_shared_documentation, datateam') - end - end - - describe '.success_message' do - it 'returns an informational success message' do - expect(described_class.success_message).to eq('==> No Danger rule violations!') - end - end - - describe '#rule_names' do - context 'when running locally' do - before do - expect(fake_helper).to receive(:ci?).and_return(false) - end - - it 'returns local only rules' do - expect(project_helper.rule_names).to match_array(described_class::LOCAL_RULES) - end - end - - context 'when running under CI' do - before do - expect(fake_helper).to receive(:ci?).and_return(true) - end - - it 'returns all rules' do - expect(project_helper.rule_names).to eq(described_class::LOCAL_RULES | described_class::CI_ONLY_RULES) - end - end - end - describe '#file_lines' do let(:filename) { 'spec/foo_spec.rb' } let(:file_spy) { spy } diff --git a/tooling/danger/project_helper.rb b/tooling/danger/project_helper.rb index 02002e1d1b2..fc87498f5d0 100644 --- a/tooling/danger/project_helper.rb +++ b/tooling/danger/project_helper.rb @@ -3,22 +3,6 @@ module Tooling module Danger module ProjectHelper - LOCAL_RULES ||= %w[ - ci_config - database - documentation - duplicate_yarn_dependencies - eslint - gitaly - pajamas - pipeline - prettier - product_intelligence - utility_css - vue_shared_documentation - datateam - ].freeze - CI_ONLY_RULES ||= %w[ ce_ee_vue_templates ci_templates @@ -31,8 +15,6 @@ module Tooling z_metadata ].freeze - MESSAGE_PREFIX = '==>' - # First-match win, so be sure to put more specific regex at the top... CATEGORIES = { [%r{usage_data\.rb}, %r{^(\+|-).*\s+(count|distinct_count|estimate_batch_distinct_count)\(.*\)(.*)$}] => [:database, :backend, :product_intelligence], @@ -181,20 +163,6 @@ module Tooling %r{\.js\z} => :frontend }.freeze - def local_warning_message - "#{MESSAGE_PREFIX} Only the following Danger rules can be run locally: #{LOCAL_RULES.join(', ')}" - end - module_function :local_warning_message # rubocop:disable Style/AccessModifierDeclarations - - def success_message - "#{MESSAGE_PREFIX} No Danger rule violations!" - end - module_function :success_message # rubocop:disable Style/AccessModifierDeclarations - - def rule_names - helper.ci? ? LOCAL_RULES | CI_ONLY_RULES : LOCAL_RULES - end - def file_lines(filename) read_file(filename).lines(chomp: true) end |