diff options
19 files changed, 215 insertions, 94 deletions
diff --git a/GITALY_SERVER_VERSION b/GITALY_SERVER_VERSION index 4b482c71175..625d40b74f9 100644 --- a/GITALY_SERVER_VERSION +++ b/GITALY_SERVER_VERSION @@ -1 +1 @@ -d19c6eab3ecc995ee5b947134657ebd92e35deb8 +b5f5b5a9a3ee4ba8f9fb6678a35e400e1087ba04 diff --git a/app/graphql/types/merge_request_type.rb b/app/graphql/types/merge_request_type.rb index c2ee04463d8..ea5eda204fb 100644 --- a/app/graphql/types/merge_request_type.rb +++ b/app/graphql/types/merge_request_type.rb @@ -249,10 +249,18 @@ module Types !!object.discussion_locked end + def default_merge_commit_message + object.default_merge_commit_message(include_description: false, user: current_user) + end + def default_merge_commit_message_with_description object.default_merge_commit_message(include_description: true) end + def default_squash_commit_message + object.default_squash_commit_message(user: current_user) + end + def available_auto_merge_strategies AutoMergeService.new(object.project, current_user).available_strategies(object) end diff --git a/app/models/external_pull_request.rb b/app/models/external_pull_request.rb index 3fc166203e7..4654f7e2341 100644 --- a/app/models/external_pull_request.rb +++ b/app/models/external_pull_request.rb @@ -11,7 +11,7 @@ # When the mirror is updated and changes are pushed to branches we check # if there are open pull requests for the source and target branch. # If so, we create pipelines for external pull requests. -class ExternalPullRequest < ApplicationRecord +class ExternalPullRequest < Ci::ApplicationRecord include Gitlab::Utils::StrongMemoize include ShaAttribute @@ -40,6 +40,9 @@ class ExternalPullRequest < ApplicationRecord scope :by_source_branch, ->(branch) { where(source_branch: branch) } scope :by_source_repository, -> (repository) { where(source_repository: repository) } + # Needed to override Ci::ApplicationRecord as this does not have ci_ table prefix + self.table_name = 'external_pull_requests' + def self.create_or_update_from_params(params) find_params = params.slice(:project_id, :source_branch, :target_branch) diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index f88aee38d67..a4da63d1af4 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -1315,9 +1315,9 @@ class MergeRequest < ApplicationRecord self.target_project.repository.branch_exists?(self.target_branch) end - def default_merge_commit_message(include_description: false) + def default_merge_commit_message(include_description: false, user: nil) if self.target_project.merge_commit_template.present? && !include_description - return ::Gitlab::MergeRequests::CommitMessageGenerator.new(merge_request: self).merge_message + return ::Gitlab::MergeRequests::CommitMessageGenerator.new(merge_request: self, current_user: user).merge_message end closes_issues_references = visible_closing_issues_for.map do |issue| @@ -1339,9 +1339,9 @@ class MergeRequest < ApplicationRecord message.join("\n\n") end - def default_squash_commit_message + def default_squash_commit_message(user: nil) if self.target_project.squash_commit_template.present? - return ::Gitlab::MergeRequests::CommitMessageGenerator.new(merge_request: self).squash_message + return ::Gitlab::MergeRequests::CommitMessageGenerator.new(merge_request: self, current_user: user).squash_message end title diff --git a/app/serializers/merge_request_poll_cached_widget_entity.rb b/app/serializers/merge_request_poll_cached_widget_entity.rb index 8b0f3c8eb74..5bf02c93c99 100644 --- a/app/serializers/merge_request_poll_cached_widget_entity.rb +++ b/app/serializers/merge_request_poll_cached_widget_entity.rb @@ -17,7 +17,6 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity expose :target_project_id expose :squash expose :rebase_in_progress?, as: :rebase_in_progress - expose :default_squash_commit_message expose :commits_count expose :merge_ongoing?, as: :merge_ongoing expose :work_in_progress?, as: :work_in_progress @@ -27,6 +26,10 @@ class MergeRequestPollCachedWidgetEntity < IssuableEntity expose :source_branch_exists?, as: :source_branch_exists expose :branch_missing?, as: :branch_missing + expose :default_squash_commit_message do |merge_request| + merge_request.default_squash_commit_message(user: request.current_user) + end + expose :commits_without_merge_commits, using: MergeRequestWidgetCommitEntity do |merge_request| merge_request.recent_commits.without_merge_commits end diff --git a/app/serializers/merge_request_poll_widget_entity.rb b/app/serializers/merge_request_poll_widget_entity.rb index 074bd2d18d7..f68477e82c9 100644 --- a/app/serializers/merge_request_poll_widget_entity.rb +++ b/app/serializers/merge_request_poll_widget_entity.rb @@ -19,7 +19,9 @@ class MergeRequestPollWidgetEntity < Grape::Entity # User entities expose :merge_user, using: UserEntity - expose :default_merge_commit_message + expose :default_merge_commit_message do |merge_request, options| + merge_request.default_merge_commit_message(include_description: false, user: current_user) + end expose :mergeable do |merge_request, options| next merge_request.mergeable? if Feature.disabled?(:check_mergeability_async_in_widget, merge_request.project, default_enabled: :yaml) diff --git a/app/services/merge_requests/merge_base_service.rb b/app/services/merge_requests/merge_base_service.rb index 3b9d3bccacf..3e630d40b3d 100644 --- a/app/services/merge_requests/merge_base_service.rb +++ b/app/services/merge_requests/merge_base_service.rb @@ -56,7 +56,7 @@ module MergeRequests def commit_message params[:commit_message] || - merge_request.default_merge_commit_message + merge_request.default_merge_commit_message(user: current_user) end def squash_sha! diff --git a/app/services/merge_requests/squash_service.rb b/app/services/merge_requests/squash_service.rb index 0600fd1d740..daed1ccfa5b 100644 --- a/app/services/merge_requests/squash_service.rb +++ b/app/services/merge_requests/squash_service.rb @@ -39,7 +39,7 @@ module MergeRequests end def message - params[:squash_commit_message].presence || merge_request.default_squash_commit_message + params[:squash_commit_message].presence || merge_request.default_squash_commit_message(user: current_user) end end end diff --git a/danger/datateam/Dangerfile b/danger/datateam/Dangerfile index 263fd4aa8e3..a4ccd65510d 100644 --- a/danger/datateam/Dangerfile +++ b/danger/datateam/Dangerfile @@ -6,14 +6,28 @@ DATA_WAREHOUSE_LABELS = [ "Data Warehouse::Not Impacted" ].freeze +FILE_PATH_REGEX = %r{((ee|jh)/)?config/metrics(/.+\.yml)}.freeze +PERFORMANCE_INDICATOR_REGEX = %r{gmau|smau|paid_gmau|umau}.freeze + CHANGED_SCHEMA_MESSAGE = <<~MSG -Notification to the Data Team about changes to the db/structure.sql file, add label `Data Warehouse::Impact Check`. +Notification to the Data Team about changes to files with possible impact on Data Warehouse, add label `Data Warehouse::Impact Check`. /label ~"Data Warehouse::Impact Check" +The following files require a review: + MSG db_schema_updated = !git.modified_files.grep(%r{\Adb/structure\.sql}).empty? + +metrics_definitions_files = git.modified_files.grep(FILE_PATH_REGEX) + +data_warehouse_impact_files = metrics_definitions_files.select do |file| + helper.changed_lines(file).grep(PERFORMANCE_INDICATOR_REGEX).any? +end.compact + +data_warehouse_impact_files << 'db/structure.sql' if db_schema_updated + no_data_warehouse_labels = (gitlab.mr_labels & DATA_WAREHOUSE_LABELS).empty? -markdown(CHANGED_SCHEMA_MESSAGE) if db_schema_updated && no_data_warehouse_labels +markdown(CHANGED_SCHEMA_MESSAGE + helper.markdown_list(data_warehouse_impact_files)) if data_warehouse_impact_files.any? && no_data_warehouse_labels diff --git a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md index ccfa93d9bc8..3b1103b8f89 100644 --- a/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md +++ b/doc/administration/troubleshooting/gitlab_rails_cheat_sheet.md @@ -909,6 +909,14 @@ end Gitlab::CurrentSettings.current_application_settings.runners_registration_token ``` +### Seed runners registration token + +```ruby +appSetting = Gitlab::CurrentSettings.current_application_settings +appSetting.set_runners_registration_token('<new-runners-registration-token>') +appSetting.save! +``` + ### Run pipeline schedules manually You can run pipeline schedules manually through the Rails console to reveal any errors that are usually not visible. diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index a168df4fd63..ec212ca3d61 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -73,7 +73,7 @@ Returns [`CiConfig`](#ciconfig). ### `Query.ciMinutesUsage` -Monthly CI minutes usage data for the current user. +CI/CD minutes usage data for a namespace. Returns [`CiMinutesNamespaceMonthlyUsageConnection`](#ciminutesnamespacemonthlyusageconnection). @@ -81,6 +81,12 @@ This field returns a [connection](#connections). It accepts the four standard [pagination arguments](#connection-pagination-arguments): `before: String`, `after: String`, `first: Int`, `last: Int`. +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="queryciminutesusagenamespaceid"></a>`namespaceId` | [`NamespaceID`](#namespaceid) | Global ID of the Namespace for the monthly CI/CD minutes usage. | + ### `Query.containerRepository` Find a container repository. diff --git a/doc/api/issues.md b/doc/api/issues.md index 204d75e9ee4..f17b9e0e726 100644 --- a/doc/api/issues.md +++ b/doc/api/issues.md @@ -54,9 +54,9 @@ GET /issues?state=opened | Attribute | Type | Required | Description | | ------------------- | ---------------- | ---------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | -| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5)_ | +| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. | | `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE, the `assignee_username` array should only contain a single value. Otherwise, an invalid parameter error is returned. | -| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5)_ | +| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. | | `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. | | `confidential` | boolean | no | Filter confidential or public issues. | | `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | @@ -70,11 +70,11 @@ GET /issues?state=opened | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | | `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. Using `None` or `Any` will be [deprecated in the future](https://gitlab.com/gitlab-org/gitlab/-/issues/336044). Please use `milestone_id` attribute instead. `milestone` and `milestone_id` are mutually exclusive. | | `milestone_id` | string | no | Returns issues assigned to milestones with a given timebox value (`None`, `Any`, `Upcoming`, and `Started`). `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. `Upcoming` lists all issues assigned to milestones due in the future. `Started` lists all issues assigned to open, started milestones. `milestone` and `milestone_id` are mutually exclusive. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/335939) in GitLab 14.3)_ | -| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_ | +| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. | | `non_archived` | boolean | no | Return issues only from non-archived projects. If `false`, the response returns issues from both archived and non-archived projects. Default is `true`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/197170) in GitLab 13.0)_ | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `assignee_id`, `assignee_username`, `author_id`, `author_username`, `iids`, `iteration_id`, `iteration_title`, `labels`, `milestone`, `milestone_id` and `weight`. | | `order_by` | string | no | Return issues ordered by `created_at`, `due_date`, `label_priority`, `milestone_due`, `popularity`, `priority`, `relative_position`, `title`, `updated_at`, or `weight` fields. Default is `created_at`. | -| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5. [Changed to snake_case](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18935) in GitLab 11.0)_ | +| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. Defaults to `created_by_me`. | | `search` | string | no | Search issues against their `title` and `description` | | `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | | `state` | string | no | Return `all` issues or just those that are `opened` or `closed` | @@ -228,11 +228,6 @@ WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. -This value is only present for issues closed after GitLab 10.6 and if the user account -that closed the issue still exists. - ## List group issues > The `weight` property moved to GitLab Premium in 13.9. @@ -261,9 +256,9 @@ GET /groups/:id/issues?state=opened | Attribute | Type | Required | Description | | ------------------- | ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | -| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5)_ | +| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. | | `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE, the `assignee_username` array should only contain a single value. Otherwise, an invalid parameter error is returned. | -| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5)_ | +| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. | | `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. | | `confidential` | boolean | no | Filter confidential or public issues. | | `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | @@ -276,11 +271,11 @@ GET /groups/:id/issues?state=opened | `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | | `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. | -| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_ | +| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. | | `non_archived` | boolean | no | Return issues from non archived projects. Default is true. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/23785) in GitLab 12.8)_ | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji`, `search`, `in` | | `order_by` | string | no | Return issues ordered by `created_at`, `updated_at`, `priority`, `due_date`, `relative_position`, `label_priority`, `milestone_due`, `popularity`, `weight` fields. Default is `created_at` | -| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the now deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5. [Changed to snake_case](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18935) in GitLab 11.0)_ | +| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. | | `search` | string | no | Search group issues against their `title` and `description` | | `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | | `state` | string | no | Return all issues or just those that are `opened` or `closed` | @@ -432,11 +427,6 @@ WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. -This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - ## List project issues > The `weight` property moved to GitLab Premium in 13.9. @@ -465,9 +455,9 @@ GET /projects/:id/issues?state=opened | Attribute | Type | Required | Description | | ------------------- | ---------------- | ---------- | ----------------------------------------------------------------------------------------------------------------------------- | -| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5)_ | +| `assignee_id` | integer | no | Return issues assigned to the given user `id`. Mutually exclusive with `assignee_username`. `None` returns unassigned issues. `Any` returns issues with an assignee. | | `assignee_username` | string array | no | Return issues assigned to the given `username`. Similar to `assignee_id` and mutually exclusive with `assignee_id`. In GitLab CE, the `assignee_username` array should only contain a single value. Otherwise, an invalid parameter error is returned. | -| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5)_ | +| `author_id` | integer | no | Return issues created by the given user `id`. Mutually exclusive with `author_username`. Combine with `scope=all` or `scope=assigned_to_me`. | | `author_username` | string | no | Return issues created by the given `username`. Similar to `author_id` and mutually exclusive with `author_id`. | | `confidential` | boolean | no | Filter confidential or public issues. | | `created_after` | datetime | no | Return issues created on or after the given time. Expected in ISO 8601 format (`2019-03-15T08:00:00Z`) | @@ -480,10 +470,10 @@ GET /projects/:id/issues?state=opened | `iteration_title` **(PREMIUM)** | string | no | Return issues assigned to the iteration with the given title. Similar to `iteration_id` and mutually exclusive with `iteration_id`. _([Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/118742) in GitLab 13.6)_ | | `labels` | string | no | Comma-separated list of label names, issues must have all labels to be returned. `None` lists all issues with no labels. `Any` lists all issues with at least one label. `No+Label` (Deprecated) lists all issues with no labels. Predefined names are case-insensitive. | | `milestone` | string | no | The milestone title. `None` lists all issues with no milestone. `Any` lists all issues that have an assigned milestone. | -| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/14016) in GitLab 10.0)_ | +| `my_reaction_emoji` | string | no | Return issues reacted by the authenticated user by the given `emoji`. `None` returns issues not given a reaction. `Any` returns issues given at least one reaction. | | `not` | Hash | no | Return issues that do not match the parameters supplied. Accepts: `labels`, `milestone`, `author_id`, `author_username`, `assignee_id`, `assignee_username`, `my_reaction_emoji`, `search`, `in` | | `order_by` | string | no | Return issues ordered by `created_at`, `updated_at`, `priority`, `due_date`, `relative_position`, `label_priority`, `milestone_due`, `popularity`, `weight` fields. Default is `created_at` | -| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`.<br> For versions before 11.0, use the deprecated `created-by-me` or `assigned-to-me` scopes instead.<br> _([Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/13004) in GitLab 9.5. [Changed to snake_case](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/18935) in GitLab 11.0)_ | +| `scope` | string | no | Return issues for the given scope: `created_by_me`, `assigned_to_me` or `all`. | | `search` | string | no | Search project issues against their `title` and `description` | | `sort` | string | no | Return issues sorted in `asc` or `desc` order. Default is `desc` | | `state` | string | no | Return all issues or just those that are `opened` or `closed` | @@ -642,10 +632,6 @@ WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - ## Single issue Only for administrators. Get a single issue. @@ -807,11 +793,6 @@ WARNING: The `epic_iid` attribute is deprecated, and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. -This value is only present for issues closed after GitLab 10.6 and if the user account -that closed the issue still exists. - ## Single project issue Get a single project issue. @@ -968,10 +949,6 @@ WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - ## New issue > The `weight` property moved to GitLab Premium in 13.9. @@ -1118,10 +1095,6 @@ WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - ## Rate limits To help avoid abuse, users can be limited to a specific number of `Create` requests per minute. @@ -1289,10 +1262,6 @@ Issues created by users on GitLab Ultimate include the `health_status` property: ] ``` -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. @@ -1483,10 +1452,6 @@ WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - ## Clone an issue Clone the issue to given project. If the user has insufficient permissions, @@ -1735,10 +1700,6 @@ WARNING: The `epic_iid` attribute is deprecated and [scheduled for removal](https://gitlab.com/gitlab-org/gitlab/-/issues/35157) in API version 5. Please use `iid` of the `epic` attribute instead. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - ## Unsubscribe from an issue Unsubscribes the authenticated user from the issue to not receive notifications @@ -1929,10 +1890,6 @@ Example response: WARNING: The `assignee` column is deprecated. We now show it as a single-sized array `assignees` to conform to the GitLab EE API. -NOTE: -The `closed_by` attribute was [introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17042) in GitLab 10.6. This value is only present for issues closed after GitLab 10.6 and if the user account that closed -the issue still exists. - ## Promote an issue to an epic **(PREMIUM)** Promotes an issue to an epic by adding a comment with the `/promote` diff --git a/doc/user/project/merge_requests/commit_templates.md b/doc/user/project/merge_requests/commit_templates.md index bffb66755e0..4272c23e9c8 100644 --- a/doc/user/project/merge_requests/commit_templates.md +++ b/doc/user/project/merge_requests/commit_templates.md @@ -67,6 +67,7 @@ GitLab creates a squash commit message with this template: > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/20263) in GitLab 14.5. > - [Added](https://gitlab.com/gitlab-org/gitlab/-/issues/346805) `first_commit` and `first_multiline_commit` variables in GitLab 14.6. +> - [Added](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/75639) `url`, `approved_by`, and `merged_by` variables in GitLab 14.6. Commit message templates support these variables: @@ -80,8 +81,11 @@ Commit message templates support these variables: | `%{reference}` | Reference to the merge request. | `group-name/project-name!72359` | | `%{first_commit}` | Full message of the first commit in merge request diff. | `Update README.md` | | `%{first_multiline_commit}` | Full message of the first commit that's not a merge commit and has more than one line in message body. Merge Request title if all commits aren't multiline. | `Update README.md`<br><br>`Improved project description in readme file.` | +| `%{url}` | Full URL to the merge request. | `https://gitlab.com/gitlab-org/gitlab/-/merge_requests/1` | +| `%{approved_by}` | Line-separated list of the merge request approvers. This value is not updated until the first page refresh after an approval. | `Approved-by: User A <user@example.com>` <br> `Approved-by: User B <user@gitlab.com>` | +| `%{merged_by}` | User who merged the merge request. | `Some User <user@example.com>` | -Empty variables that are the only word in a line are removed, along with all newline characters preceding it. +Empty variables that are the only word in a line are removed, along with all newline characters preceding it. ## Related topics diff --git a/lib/gitlab/database/gitlab_schemas.yml b/lib/gitlab/database/gitlab_schemas.yml index c9096de6b6e..025a59a14fd 100644 --- a/lib/gitlab/database/gitlab_schemas.yml +++ b/lib/gitlab/database/gitlab_schemas.yml @@ -200,7 +200,7 @@ experiment_subjects: :gitlab_main experiment_users: :gitlab_main external_approval_rules: :gitlab_main external_approval_rules_protected_branches: :gitlab_main -external_pull_requests: :gitlab_main +external_pull_requests: :gitlab_ci external_status_checks: :gitlab_main external_status_checks_protected_branches: :gitlab_main feature_gates: :gitlab_main diff --git a/lib/gitlab/merge_requests/commit_message_generator.rb b/lib/gitlab/merge_requests/commit_message_generator.rb index 0e9ec6f5cb3..39247a47bf5 100644 --- a/lib/gitlab/merge_requests/commit_message_generator.rb +++ b/lib/gitlab/merge_requests/commit_message_generator.rb @@ -2,8 +2,9 @@ module Gitlab module MergeRequests class CommitMessageGenerator - def initialize(merge_request:) + def initialize(merge_request:, current_user:) @merge_request = merge_request + @current_user = @merge_request.metrics&.merged_by || @merge_request.merge_user || current_user end def merge_message @@ -21,12 +22,13 @@ module Gitlab private attr_reader :merge_request + attr_reader :current_user PLACEHOLDERS = { - 'source_branch' => ->(merge_request) { merge_request.source_branch.to_s }, - 'target_branch' => ->(merge_request) { merge_request.target_branch.to_s }, - 'title' => ->(merge_request) { merge_request.title }, - 'issues' => ->(merge_request) do + 'source_branch' => ->(merge_request, _) { merge_request.source_branch.to_s }, + 'target_branch' => ->(merge_request, _) { merge_request.target_branch.to_s }, + 'title' => ->(merge_request, _) { merge_request.title }, + 'issues' => ->(merge_request, _) do return "" if merge_request.visible_closing_issues_for.blank? closes_issues_references = merge_request.visible_closing_issues_for.map do |issue| @@ -34,10 +36,13 @@ module Gitlab end "Closes #{closes_issues_references.to_sentence}" end, - 'description' => ->(merge_request) { merge_request.description.presence || '' }, - 'reference' => ->(merge_request) { merge_request.to_reference(full: true) }, - 'first_commit' => -> (merge_request) { merge_request.first_commit&.safe_message&.strip.presence || '' }, - 'first_multiline_commit' => -> (merge_request) { merge_request.first_multiline_commit&.safe_message&.strip.presence || merge_request.title } + 'description' => ->(merge_request, _) { merge_request.description.presence || '' }, + 'reference' => ->(merge_request, _) { merge_request.to_reference(full: true) }, + 'first_commit' => -> (merge_request, _) { merge_request.first_commit&.safe_message&.strip.presence || '' }, + 'first_multiline_commit' => -> (merge_request, _) { merge_request.first_multiline_commit&.safe_message&.strip.presence || merge_request.title }, + 'url' => ->(merge_request, _) { Gitlab::UrlBuilder.build(merge_request) }, + 'approved_by' => ->(merge_request, _) { merge_request.approved_by_users.map { |user| "Approved-by: #{user.name} <#{user.commit_email_or_default}>" }.join("\n") }, + 'merged_by' => ->(_, user) { "#{user&.name} <#{user&.commit_email_or_default}>" } }.freeze PLACEHOLDERS_REGEX = Regexp.union(PLACEHOLDERS.keys.map do |key| @@ -57,14 +62,14 @@ module Gitlab # This allows us to recreate previous default merge commit message behaviour - we skipped new line character # before empty description and before closed issues when none were present. PLACEHOLDERS.each do |key, value| - unless value.call(merge_request).present? + unless value.call(merge_request, current_user).present? message = message.gsub(BLANK_PLACEHOLDERS_REGEXES[key], '') end end Gitlab::StringPlaceholderReplacer .replace_string_placeholders(message, PLACEHOLDERS_REGEX) do |key| - PLACEHOLDERS[key].call(merge_request) + PLACEHOLDERS[key].call(merge_request, current_user) end end end diff --git a/spec/lib/gitlab/merge_requests/commit_message_generator_spec.rb b/spec/lib/gitlab/merge_requests/commit_message_generator_spec.rb index 65c76aac10c..28318de12c9 100644 --- a/spec/lib/gitlab/merge_requests/commit_message_generator_spec.rb +++ b/spec/lib/gitlab/merge_requests/commit_message_generator_spec.rb @@ -15,7 +15,9 @@ RSpec.describe Gitlab::MergeRequests::CommitMessageGenerator do ) end - let(:user) { project.creator } + let(:owner) { project.creator } + let(:developer) { create(:user, access_level: Gitlab::Access::DEVELOPER) } + let(:maintainer) { create(:user, access_level: Gitlab::Access::MAINTAINER) } let(:source_branch) { 'feature' } let(:merge_request_description) { "Merge Request Description\nNext line" } let(:merge_request_title) { 'Bugfix' } @@ -27,13 +29,13 @@ RSpec.describe Gitlab::MergeRequests::CommitMessageGenerator do target_project: project, target_branch: 'master', source_branch: source_branch, - author: user, + author: owner, description: merge_request_description, title: merge_request_title ) end - subject { described_class.new(merge_request: merge_request) } + subject { described_class.new(merge_request: merge_request, current_user: maintainer) } shared_examples_for 'commit message with template' do |message_template_name| it 'returns nil when template is not set in target project' do @@ -274,6 +276,111 @@ RSpec.describe Gitlab::MergeRequests::CommitMessageGenerator do end end end + + context 'when project has merge commit template with approvers' do + let(message_template_name) do + "Merge Request approved by:\n%{approved_by}" + end + + context "and mr has no approval" do + before do + merge_request.approved_by_users = [] + end + + it "returns empty string" do + expect(result_message).to eq <<~MSG.rstrip + Merge Request approved by: + MSG + end + end + + context "and mr has one approval" do + before do + merge_request.approved_by_users = [developer] + end + + it "returns user name and email" do + expect(result_message).to eq <<~MSG.rstrip + Merge Request approved by: + Approved-by: #{developer.name} <#{developer.email}> + MSG + end + end + + context "and mr has multiple approvals" do + before do + merge_request.approved_by_users = [developer, maintainer] + end + + it "returns users names and emails" do + expect(result_message).to eq <<~MSG.rstrip + Merge Request approved by: + Approved-by: #{developer.name} <#{developer.email}> + Approved-by: #{maintainer.name} <#{maintainer.email}> + MSG + end + end + end + + context 'when project has merge commit template with url' do + let(message_template_name) do + "Merge Request URL is '%{url}'" + end + + context "and merge request has url" do + it "returns mr url" do + expect(result_message).to eq <<~MSG.rstrip + Merge Request URL is '#{Gitlab::UrlBuilder.build(merge_request)}' + MSG + end + end + end + + context 'when project has merge commit template with merged_by' do + let(message_template_name) do + "Merge Request merged by '%{merged_by}'" + end + + context "and current_user is passed" do + it "returns user name and email" do + expect(result_message).to eq <<~MSG.rstrip + Merge Request merged by '#{maintainer.name} <#{maintainer.email}>' + MSG + end + end + end + + context 'user' do + subject { described_class.new(merge_request: merge_request, current_user: nil) } + + let(message_template_name) do + "Merge Request merged by '%{merged_by}'" + end + + context 'comes from metrics' do + before do + merge_request.metrics.merged_by = developer + end + + it "returns user name and email" do + expect(result_message).to eq <<~MSG.rstrip + Merge Request merged by '#{developer.name} <#{developer.email}>' + MSG + end + end + + context 'comes from merge_user' do + before do + merge_request.merge_user = maintainer + end + + it "returns user name and email" do + expect(result_message).to eq <<~MSG.rstrip + Merge Request merged by '#{maintainer.name} <#{maintainer.email}>' + MSG + end + end + end end describe '#merge_message' do diff --git a/spec/metrics_server/metrics_server_spec.rb b/spec/metrics_server/metrics_server_spec.rb index 4f0d5bc5bb2..1120fab2de3 100644 --- a/spec/metrics_server/metrics_server_spec.rb +++ b/spec/metrics_server/metrics_server_spec.rb @@ -8,14 +8,22 @@ require_relative '../support/helpers/next_instance_of' RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath include NextInstanceOf + let(:prometheus_config) { ::Prometheus::Client.configuration } let(:metrics_dir) { Dir.mktmpdir } + # Prometheus::Client is a singleton, i.e. shared global state, so + # we need to reset it after testing. + let!(:old_multiprocess_files_dir) { prometheus_config.multiprocess_files_dir } + before do # We do not want this to have knock-on effects on the test process. allow(Gitlab::ProcessManagement).to receive(:modify_signals) end after do + Gitlab::Metrics.reset_registry! + prometheus_config.multiprocess_files_dir = old_multiprocess_files_dir + FileUtils.rm_rf(metrics_dir, secure: true) end @@ -55,9 +63,7 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath describe '#start' do let(:exporter_class) { Class.new(Gitlab::Metrics::Exporter::BaseExporter) } let(:exporter_double) { double('fake_exporter', start: true) } - let(:prometheus_config) { ::Prometheus::Client.configuration } let(:settings) { { "fake_exporter" => { "enabled" => true } } } - let!(:old_metrics_dir) { prometheus_config.multiprocess_files_dir } let(:ruby_sampler_double) { double(Gitlab::Metrics::Samplers::RubySampler) } subject(:metrics_server) { described_class.new('fake', metrics_dir, true)} @@ -71,11 +77,6 @@ RSpec.describe MetricsServer do # rubocop:disable RSpec/FilePath allow(ruby_sampler_double).to receive(:start) end - after do - Gitlab::Metrics.reset_registry! - prometheus_config.multiprocess_files_dir = old_metrics_dir - end - it 'configures ::Prometheus::Client' do metrics_server.start diff --git a/spec/models/merge_request_spec.rb b/spec/models/merge_request_spec.rb index e1db1b3cf3e..79b8765b540 100644 --- a/spec/models/merge_request_spec.rb +++ b/spec/models/merge_request_spec.rb @@ -1647,13 +1647,13 @@ RSpec.describe MergeRequest, factory_default: :keep do end it 'uses template from target project' do - request = build(:merge_request, title: 'Fix everything') - request.compare_commits = [ + subject.title = 'Fix everything' + subject.compare_commits = [ double(safe_message: 'Commit message', gitaly_commit?: true, merge_commit?: false, description?: false) ] subject.target_project.merge_commit_template = '%{title}' - expect(request.default_merge_commit_message) + expect(subject.default_merge_commit_message) .to eq('Fix everything') end diff --git a/spec/views/projects/edit.html.haml_spec.rb b/spec/views/projects/edit.html.haml_spec.rb index 8c96f286c79..ee1bb0e9541 100644 --- a/spec/views/projects/edit.html.haml_spec.rb +++ b/spec/views/projects/edit.html.haml_spec.rb @@ -67,6 +67,9 @@ RSpec.describe 'projects/edit' do expect(rendered).to have_content('%{issues}') expect(rendered).to have_content('%{description}') expect(rendered).to have_content('%{reference}') + expect(rendered).to have_content('%{approved_by}') + expect(rendered).to have_content('%{url}') + expect(rendered).to have_content('%{merged_by}') end it 'displays a placeholder if none is set' do |