Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2021-04-01 21:09:22 +00:00
parent 1769b59b9f
commit 1e0d9b7134
56 changed files with 387 additions and 213 deletions

View File

@ -232,8 +232,6 @@ Rails/SaveBang:
- 'spec/initializers/fog_google_https_private_urls_spec.rb'
- 'spec/lib/after_commit_queue_spec.rb'
- 'spec/lib/backup/manager_spec.rb'
- 'spec/lib/banzai/reference_parser/external_issue_parser_spec.rb'
- 'spec/lib/banzai/reference_redactor_spec.rb'
- 'spec/lib/gitlab/alerting/alert_spec.rb'
- 'spec/lib/gitlab/analytics/cycle_analytics/records_fetcher_spec.rb'
- 'spec/lib/gitlab/auth/ldap/user_spec.rb'

View File

@ -640,11 +640,6 @@ Rails/WhereEquals:
Rails/WhereExists:
Enabled: false
# Offense count: 21
# Cop supports --auto-correct.
Rails/WhereNot:
Enabled: false
# Offense count: 8
# Cop supports --auto-correct.
Security/YAMLLoad:

View File

@ -131,7 +131,7 @@ module Ci
def by_yaml_errors(items)
case Gitlab::Utils.to_boolean(params[:yaml_errors])
when true
items.where("yaml_errors IS NOT NULL")
items.where.not(yaml_errors: nil)
when false
items.where("yaml_errors IS NULL")
else

View File

@ -4,29 +4,29 @@ module ServicesHelper
def service_event_description(event)
case event
when "push", "push_events"
s_("ProjectService|Event will be triggered by a push to the repository")
s_("ProjectService|Event triggered when someone pushes to the repository.")
when "tag_push", "tag_push_events"
s_("ProjectService|Event will be triggered when a new tag is pushed to the repository")
s_("ProjectService|Event triggered when a new tag is pushed to the repository.")
when "note", "note_events"
s_("ProjectService|Event will be triggered when someone adds a comment")
s_("ProjectService|Event triggered when someone adds a comment.")
when "confidential_note", "confidential_note_events"
s_("ProjectService|Event will be triggered when someone adds a comment on a confidential issue")
s_("ProjectService|Event triggered when someone adds a comment on a confidential issue.")
when "issue", "issue_events"
s_("ProjectService|Event will be triggered when an issue is created/updated/closed")
s_("ProjectService|Event triggered when an issue is created, updated, or closed.")
when "confidential_issue", "confidential_issue_events"
s_("ProjectService|Event will be triggered when a confidential issue is created/updated/closed")
s_("ProjectService|Event triggered when a confidential issue is created, updated, or closed.")
when "merge_request", "merge_request_events"
s_("ProjectService|Event will be triggered when a merge request is created/updated/merged")
s_("ProjectService|Event triggered when a merge request is created, updated, or merged.")
when "pipeline", "pipeline_events"
s_("ProjectService|Event will be triggered when a pipeline status changes")
s_("ProjectService|Event triggered when a pipeline status changes.")
when "wiki_page", "wiki_page_events"
s_("ProjectService|Event will be triggered when a wiki page is created/updated")
s_("ProjectService|Event triggered when a wiki page is created or updated.")
when "commit", "commit_events"
s_("ProjectService|Event will be triggered when a commit is created/updated")
s_("ProjectService|Event triggered when a commit is created or updated.")
when "deployment"
s_("ProjectService|Event will be triggered when a deployment starts or finishes")
s_("ProjectService|Event triggered when a deployment starts or finishes.")
when "alert"
s_("ProjectService|Event will be triggered when a new, unique alert is recorded")
s_("ProjectService|Event triggered when a new, unique alert is recorded.")
end
end

View File

@ -93,8 +93,7 @@ module Ci
validates :ref, presence: true
scope :not_interruptible, -> do
joins(:metadata).where('ci_builds_metadata.id NOT IN (?)',
Ci::BuildMetadata.scoped_build.with_interruptible.select(:id))
joins(:metadata).where.not('ci_builds_metadata.id' => Ci::BuildMetadata.scoped_build.with_interruptible.select(:id))
end
scope :unstarted, -> { where(runner_id: nil) }

View File

@ -44,7 +44,7 @@ module Ci
next if position.present?
self.position = statuses.select(:stage_idx)
.where('stage_idx IS NOT NULL')
.where.not(stage_idx: nil)
.group(:stage_idx)
.order('COUNT(*) DESC')
.first&.stage_idx.to_i

View File

@ -16,7 +16,7 @@ module Clusters
model
.unscoped
.where('clusters.id IS NOT NULL')
.where.not('clusters.id' => nil)
.with
.recursive(cte.to_arel)
.from(cte_alias)

View File

@ -56,6 +56,7 @@ class CommitStatus < ApplicationRecord
scope :by_name, -> (name) { where(name: name) }
scope :in_pipelines, ->(pipelines) { where(pipeline: pipelines) }
scope :eager_load_pipeline, -> { eager_load(:pipeline, project: { namespace: :route }) }
scope :with_pipeline, -> { joins(:pipeline) }
scope :for_project_paths, -> (paths) do
where(project: Project.where_full_path_in(Array(paths)))
@ -180,6 +181,7 @@ class CommitStatus < ApplicationRecord
end
after_transition any => :failed do |commit_status|
next if Feature.enabled?(:async_add_build_failure_todo, commit_status.project, default_enabled: :yaml)
next unless commit_status.project
# rubocop: disable CodeReuse/ServiceClass

View File

@ -86,7 +86,7 @@ class Environment < ApplicationRecord
end
scope :for_project, -> (project) { where(project_id: project) }
scope :for_tier, -> (tier) { where(tier: tier).where('tier IS NOT NULL') }
scope :for_tier, -> (tier) { where(tier: tier).where.not(tier: nil) }
scope :with_deployment, -> (sha) { where('EXISTS (?)', Deployment.select(1).where('deployments.environment_id = environments.id').where(sha: sha)) }
scope :unfoldered, -> { where(environment_type: nil) }
scope :with_rank, -> do

View File

@ -519,7 +519,7 @@ class Project < ApplicationRecord
scope :with_packages, -> { joins(:packages) }
scope :in_namespace, ->(namespace_ids) { where(namespace_id: namespace_ids) }
scope :personal, ->(user) { where(namespace_id: user.namespace_id) }
scope :joined, ->(user) { where('namespace_id != ?', user.namespace_id) }
scope :joined, ->(user) { where.not(namespace_id: user.namespace_id) }
scope :starred_by, ->(user) { joins(:users_star_projects).where('users_star_projects.user_id': user.id) }
scope :visible_to_user, ->(user) { where(id: user.authorized_projects.select(:id).reorder(nil)) }
scope :visible_to_user_and_access_level, ->(user, access_level) { where(id: user.authorized_projects.where('project_authorizations.access_level >= ?', access_level).select(:id).reorder(nil)) }

View File

@ -2,7 +2,7 @@
class MicrosoftTeamsService < ChatNotificationService
def title
'Microsoft Teams Notification'
'Microsoft Teams notifications'
end
def description
@ -14,13 +14,7 @@ class MicrosoftTeamsService < ChatNotificationService
end
def help
'This service sends notifications about projects events to Microsoft Teams channels.<br />
To set up this service:
<ol>
<li><a href="https://docs.microsoft.com/en-us/microsoftteams/platform/concepts/connectors/connectors-using#setting-up-a-custom-incoming-webhook">Setup a custom Incoming Webhook using Office 365 Connectors For Microsoft Teams</a>.</li>
<li>Paste the <strong>Webhook URL</strong> into the field below.</li>
<li>Select events below to enable notifications.</li>
</ol>'
'<p>Use this service to send notifications about events in GitLab projects to your Microsoft Teams channels. <a href="https://docs.gitlab.com/ee/user/project/integrations/microsoft_teams.html">How do I configure this integration?</a></p>'
end
def webhook_placeholder
@ -40,8 +34,8 @@ class MicrosoftTeamsService < ChatNotificationService
def default_fields
[
{ type: 'text', name: 'webhook', placeholder: "e.g. #{webhook_placeholder}" },
{ type: 'checkbox', name: 'notify_only_broken_pipelines' },
{ type: 'text', name: 'webhook', placeholder: "#{webhook_placeholder}" },
{ type: 'checkbox', name: 'notify_only_broken_pipelines', help: 'If selected, successful pipelines do not trigger a notification event.' },
{ type: 'select', name: 'branches_to_be_notified', choices: branch_choices }
]
end

View File

@ -353,12 +353,7 @@ class User < ApplicationRecord
# this state transition object in order to do a rollback.
# For this reason the tradeoff is to disable this cop.
after_transition any => :blocked do |user|
if Feature.enabled?(:abort_user_pipelines_on_block, user)
Ci::AbortPipelinesService.new.execute(user.pipelines)
else
Ci::CancelUserPipelinesService.new.execute(user)
end
Ci::AbortPipelinesService.new.execute(user.pipelines)
Ci::DisableUserPipelineSchedulesService.new.execute(user)
end
# rubocop: enable CodeReuse/ServiceClass
@ -1041,7 +1036,7 @@ class User < ApplicationRecord
[
Project.where(namespace: namespace),
Project.joins(:project_authorizations)
.where("projects.namespace_id <> ?", namespace.id)
.where.not('projects.namespace_id' => namespace.id)
.where(project_authorizations: { user_id: id, access_level: Gitlab::Access::OWNER })
],
remove_duplicates: false

View File

@ -1,18 +0,0 @@
# frozen_string_literal: true
module Ci
class CancelUserPipelinesService
# rubocop: disable CodeReuse/ActiveRecord
# This is a bug with CodeReuse/ActiveRecord cop
# https://gitlab.com/gitlab-org/gitlab/issues/32332
def execute(user)
# TODO: fix N+1 queries https://gitlab.com/gitlab-org/gitlab/-/issues/300685
user.pipelines.cancelable.find_each(&:cancel_running)
ServiceResponse.success(message: 'Pipeline canceled')
rescue ActiveRecord::StaleObjectError
ServiceResponse.error(message: 'Error canceling pipeline')
end
# rubocop: enable CodeReuse/ActiveRecord
end
end

View File

@ -21,7 +21,7 @@ module Ci
Gitlab::OptimisticLocking.retry_lock(new_build, name: 'retry_build', &:enqueue)
MergeRequests::AddTodoWhenBuildFailsService
::MergeRequests::AddTodoWhenBuildFailsService
.new(project, current_user)
.close(new_build)
end

View File

@ -28,7 +28,7 @@ module Ci
pipeline.reset_ancestor_bridges!
MergeRequests::AddTodoWhenBuildFailsService
::MergeRequests::AddTodoWhenBuildFailsService
.new(project, current_user)
.close_all(pipeline)

View File

@ -164,7 +164,7 @@ module MergeRequests
def pipeline_merge_requests(pipeline)
pipeline.all_merge_requests.opened.each do |merge_request|
next unless pipeline == merge_request.head_pipeline
next unless pipeline.id == merge_request.head_pipeline_id
yield merge_request
end

View File

@ -27,7 +27,7 @@ module Namespaces
end
def execute
raise NotImplementedError, "Track #{track} not defined" unless TRACKS.key?(track)
raise ArgumentError, "Track #{track} not defined" unless TRACKS.key?(track)
groups_for_track.each_batch do |groups|
groups.each do |group|

View File

@ -13,7 +13,7 @@ module Todos
# rubocop: disable CodeReuse/ActiveRecord
def without_authorized(items)
items.where('todos.user_id NOT IN (?)', authorized_users)
items.where.not('todos.user_id' => authorized_users)
end
# rubocop: enable CodeReuse/ActiveRecord

View File

@ -36,7 +36,7 @@ module Todos
items = Todo.where(project_id: project_id)
items = items.where(user_id: user_id) if user_id
items.where('user_id NOT IN (?)', authorized_users)
items.where.not(user_id: authorized_users)
.where(target_type: target_types)
.delete_all
end

View File

@ -1235,6 +1235,14 @@
:weight: 3
:idempotent:
:tags: []
- :name: pipeline_default:ci_merge_requests_add_todo_when_build_fails
:feature_category: :continuous_integration
:has_external_dependencies:
:urgency: :low
:resource_boundary: :unknown
:weight: 3
:idempotent: true
:tags: []
- :name: pipeline_default:ci_pipeline_bridge_status
:feature_category: :continuous_integration
:has_external_dependencies:

View File

@ -37,6 +37,10 @@ class BuildFinishedWorker # rubocop:disable Scalability/IdempotentWorker
ExpirePipelineCacheWorker.perform_async(build.pipeline_id)
ChatNotificationWorker.perform_async(build.id) if build.pipeline.chat?
if build.failed? && Feature.enabled?(:async_add_build_failure_todo, build.project, default_enabled: :yaml)
::Ci::MergeRequests::AddTodoWhenBuildFailsWorker.perform_async(build.id)
end
##
# We want to delay sending a build trace to object storage operation to
# validate that this fixes a race condition between this and flushing live

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
module Ci
module MergeRequests
class AddTodoWhenBuildFailsWorker
include ApplicationWorker
include PipelineQueue
urgency :low
idempotent!
def perform(job_id)
job = ::CommitStatus.with_pipeline.find_by_id(job_id)
project = job&.project
return unless job && project
::MergeRequests::AddTodoWhenBuildFailsService.new(job.project, nil).execute(job)
end
end
end
end

View File

@ -0,0 +1,5 @@
---
title: Bulk-abort user pipelines on block
merge_request: 57801
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Backfill traversal_ids for gitlab-org .com
merge_request: 57075
author:
type: performance

View File

@ -0,0 +1,5 @@
---
title: Fix Rails/SaveBang Rubocop offenses for banzai modules
merge_request: 58108
author: Huzaifa Iftikhar @huzaifaiftikhar
type: fixed

View File

@ -0,0 +1,5 @@
---
title: Resolves rubocop offenses Rails/WhereNot
merge_request: 58062
author: Shubham Kumar (@imskr)
type: fixed

View File

@ -1,8 +1,8 @@
---
name: abort_user_pipelines_on_block
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56126
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/324045
milestone: '13.10'
name: async_add_build_failure_todo
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57490/diffs
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/326726
milestone: '13.11'
type: development
group: group::memory
group: group::continuous integration
default_enabled: false

View File

@ -5,6 +5,10 @@
"key_path": {
"type": "string"
},
"name": {
"type": ["string", "null"],
"pattern": "^([a-z]+_)*[a-z]+$"
},
"description": {
"type": "string"
},

View File

@ -17,7 +17,7 @@ class BackfillDeploymentClustersFromDeployments < ActiveRecord::Migration[6.0]
class Deployment < ActiveRecord::Base
include EachBatch
default_scope { where('cluster_id IS NOT NULL') } # rubocop:disable Cop/DefaultScope
default_scope { where.not(cluster_id: nil) } # rubocop:disable Cop/DefaultScope
self.table_name = 'deployments'
end

View File

@ -18,11 +18,11 @@ class CreateMissingVulnerabilitiesIssueLinks < ActiveRecord::Migration[6.0]
disable_ddl_transaction!
def up
VulnerabilitiesFeedback.where('issue_id IS NOT NULL').each_batch do |relation|
VulnerabilitiesFeedback.where.not(issue_id: nil).each_batch do |relation|
timestamp = Time.now
issue_links = relation
.joins("JOIN vulnerability_occurrences vo ON vo.project_id = vulnerability_feedback.project_id AND vo.report_type = vulnerability_feedback.category AND encode(vo.project_fingerprint, 'hex') = vulnerability_feedback.project_fingerprint")
.where('vo.vulnerability_id IS NOT NULL')
.where.not('vo.vulnerability_id' => nil)
.pluck(:vulnerability_id, :issue_id)
.map do |v_id, i_id|
{

View File

@ -0,0 +1,88 @@
# frozen_string_literal: true
class SetTraversalIdsForGitlabOrgGroupCom < ActiveRecord::Migration[6.0]
include Gitlab::Database::MigrationHelpers
DOWNTIME = false
def up
return unless Gitlab.com?
# namespace ID 9970 is gitlab-org on .com
with_lock_retries do
execute(<<~SQL)
UPDATE
namespaces
SET
traversal_ids = cte.traversal_ids
FROM
(
WITH RECURSIVE cte(id, traversal_ids, cycle) AS (
VALUES
(9970, ARRAY[9970], false)
UNION ALL
SELECT
n.id,
cte.traversal_ids || n.id,
n.id = ANY(cte.traversal_ids)
FROM
namespaces n,
cte
WHERE
n.parent_id = cte.id
AND NOT cycle
)
SELECT
id,
traversal_ids
FROM
cte FOR
UPDATE
) as cte
WHERE
namespaces.id = cte.id
AND namespaces.traversal_ids <> cte.traversal_ids
SQL
end
end
def down
return unless Gitlab.com?
# namespace ID 9970 is gitlab-org on .com
with_lock_retries do
execute(<<~SQL)
UPDATE
namespaces
SET
traversal_ids = '{}'
FROM
(
WITH RECURSIVE cte(id, traversal_ids, cycle) AS (
VALUES
(9970, ARRAY[9970], false)
UNION ALL
SELECT
n.id,
cte.traversal_ids || n.id,
n.id = ANY(cte.traversal_ids)
FROM
namespaces n,
cte
WHERE
n.parent_id = cte.id
AND NOT cycle
)
SELECT
id,
traversal_ids
FROM
cte FOR
UPDATE
) as cte
WHERE
namespaces.id = cte.id
SQL
end
end
end

View File

@ -0,0 +1 @@
2387c8a5516aaf8bcf44c9bad45bfc9844d68d2c03330f67773ce046b21a7a6c

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

View File

@ -6,49 +6,55 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Microsoft Teams service **(FREE)**
## On Microsoft Teams
You can integrate Microsoft Teams with GitLab, and display notifications about GitLab projects
in Microsoft Teams. To integrate the services, you must:
To enable Microsoft Teams integration you must create an incoming webhook integration on Microsoft
Teams by following the steps below:
1. [Configure Microsoft Teams](#configure-microsoft-teams) to enable a webhook
to listen for changes.
1. [Configure your GitLab project](#configure-your-gitlab-project) to push notifications
to the Microsoft Teams webhook.
1. Search for "incoming webhook" on the search bar in Microsoft Teams and select the
**Incoming Webhook** item.
## Configure Microsoft Teams
To configure Microsoft Teams to listen for notifications from GitLab:
1. In Microsoft Teams, search for "incoming webhook" in the search bar, and select the
**Incoming Webhook** item:
![Select Incoming Webhook](img/microsoft_teams_select_incoming_webhook.png)
1. Click the **Add to a team** button.
1. Select **Add to a team**.
1. Select the team and channel you want to add the integration to.
1. Add a name for the webhook. The name is displayed next to every message that
comes in through the webhook.
1. Copy the webhook URL for the next steps.
1. Copy the webhook URL, as you need it to configure GitLab.
Learn more about
[setting up an incoming webhook on Microsoft Teams](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using#setting-up-a-custom-incoming-webhook).
## Configure your GitLab project
## On GitLab
After you configure Microsoft Teams to receive notifications, you must configure
GitLab to send the notifications:
After you set up Microsoft Teams, it's time to set up GitLab.
1. Sign in to GitLab as a user with [Administrator](../../permissions.md) and go
to your project's page.
1. Go to **Settings > Integrations** and select **Microsoft Teams Notification**.
1. Select **Active** to enable the integration.
1. Select the check box next to each **Trigger** to enable:
- Push
- Issue
- Confidential issue
- Merge request
- Note
- Confidential note
- Tag push
- Pipeline - If you enable this trigger, you can also select **Notify only broken pipelines** to be notified only about failed pipelines.
- Wiki page
1. In **Webhook**, paste the URL you copied when you
[configured Microsoft Teams](#configure-microsoft-teams).
1. (Optional) If you enabled the pipeline trigger, you can select the
**Notify only broken pipelines** check box to push notifications only when pipelines break.
1. Select the branches you want to send notifications for.
1. Click **Save changes**.
Navigate to the [Integrations page](overview.md#accessing-integrations)
and select the **Microsoft Teams Notification** service to configure it.
There, you see a checkbox with the following events that can be triggered:
## Resources
- Push
- Issue
- Confidential issue
- Merge request
- Note
- Tag push
- Pipeline
- Wiki page
At the end fill in your Microsoft Teams details:
| Field | Description |
| ----- | ----------- |
| **Webhook** | The incoming webhook URL which you have to set up on Microsoft Teams. |
| **Notify only broken pipelines** | If you choose to enable the **Pipeline** event and you want to be only notified about failed pipelines. |
After you are all done, click **Save changes** for the changes to take effect.
![Microsoft Teams configuration](img/microsoft_teams_configuration.png)
- [Setting up an incoming webhook on Microsoft Teams](https://docs.microsoft.com/en-us/microsoftteams/platform/webhooks-and-connectors/how-to/connectors-using#setting-up-a-custom-incoming-webhook).

View File

@ -11,7 +11,7 @@ module Gitlab
MergeRequest
.where(merge_request_assignees_not_exists_clause)
.where(id: from_id..to_id)
.where('assignee_id IS NOT NULL')
.where.not(assignee_id: nil)
.select(:id, :assignee_id)
.to_sql

View File

@ -27,7 +27,7 @@ module Gitlab
joins(:user)
.merge(UserModel.active)
.where(id: (start_id..stop_id))
.where('emails.confirmed_at IS NOT NULL')
.where.not('emails.confirmed_at' => nil)
.where('emails.confirmed_at = users.confirmed_at')
.where('emails.email <> users.email')
.where('NOT EXISTS (SELECT 1 FROM user_synced_attributes_metadata WHERE user_id=users.id AND email_synced IS true)')

View File

@ -76,7 +76,7 @@ module Gitlab
def project_uploads_except_avatar(avatar_path)
return @project.uploads unless avatar_path
@project.uploads.where("path != ?", avatar_path)
@project.uploads.where.not(path: avatar_path)
end
def download_and_copy(upload)

View File

@ -24110,40 +24110,40 @@ msgstr ""
msgid "ProjectService|Enter new password"
msgstr ""
msgid "ProjectService|Event will be triggered by a push to the repository"
msgid "ProjectService|Event triggered when a commit is created or updated."
msgstr ""
msgid "ProjectService|Event will be triggered when a commit is created/updated"
msgid "ProjectService|Event triggered when a confidential issue is created, updated, or closed."
msgstr ""
msgid "ProjectService|Event will be triggered when a confidential issue is created/updated/closed"
msgid "ProjectService|Event triggered when a deployment starts or finishes."
msgstr ""
msgid "ProjectService|Event will be triggered when a deployment starts or finishes"
msgid "ProjectService|Event triggered when a merge request is created, updated, or merged."
msgstr ""
msgid "ProjectService|Event will be triggered when a merge request is created/updated/merged"
msgid "ProjectService|Event triggered when a new tag is pushed to the repository."
msgstr ""
msgid "ProjectService|Event will be triggered when a new tag is pushed to the repository"
msgid "ProjectService|Event triggered when a new, unique alert is recorded."
msgstr ""
msgid "ProjectService|Event will be triggered when a new, unique alert is recorded"
msgid "ProjectService|Event triggered when a pipeline status changes."
msgstr ""
msgid "ProjectService|Event will be triggered when a pipeline status changes"
msgid "ProjectService|Event triggered when a wiki page is created or updated."
msgstr ""
msgid "ProjectService|Event will be triggered when a wiki page is created/updated"
msgid "ProjectService|Event triggered when an issue is created, updated, or closed."
msgstr ""
msgid "ProjectService|Event will be triggered when an issue is created/updated/closed"
msgid "ProjectService|Event triggered when someone adds a comment on a confidential issue."
msgstr ""
msgid "ProjectService|Event will be triggered when someone adds a comment"
msgid "ProjectService|Event triggered when someone adds a comment."
msgstr ""
msgid "ProjectService|Event will be triggered when someone adds a comment on a confidential issue"
msgid "ProjectService|Event triggered when someone pushes to the repository."
msgstr ""
msgid "ProjectService|Issue URL"

View File

@ -21,7 +21,7 @@ RSpec.describe Banzai::ReferenceParser::ExternalIssueParser do
levels.each do |level|
it "creates reference when the feature is #{level}" do
project.project_feature.update(issues_access_level: level)
project.project_feature.update!(issues_access_level: level)
visible_nodes = subject.nodes_visible_to_user(user, [link])

View File

@ -64,7 +64,7 @@ RSpec.describe Banzai::ReferenceRedactor do
let(:redactor) { described_class.new(Banzai::RenderContext.new(project, user)) }
before do
project.update(pending_delete: true)
project.update!(pending_delete: true)
end
it 'redacts an issue attached' do

View File

@ -15,7 +15,7 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::StageEvents::CodeStageStart do
other_merge_request = create(:merge_request, source_project: project, source_branch: 'a', target_branch: 'master')
records = subject.apply_query_customization(MergeRequest.all).where('merge_requests_closing_issues.issue_id IS NOT NULL')
records = subject.apply_query_customization(MergeRequest.all).where.not('merge_requests_closing_issues.issue_id' => nil)
expect(records).to eq([merge_request])
expect(records).not_to include(other_merge_request)
end

View File

@ -16,7 +16,8 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
time_frame: 'none',
data_source: 'database',
distribution: %w(ee ce),
tier: %w(free starter premium ultimate bronze silver gold)
tier: %w(free starter premium ultimate bronze silver gold),
name: 'count_boards'
}
end
@ -53,6 +54,7 @@ RSpec.describe Gitlab::Usage::MetricDefinition do
:distribution | nil
:distribution | 'test'
:tier | %w(test ee)
:name | 'count_<adjective_describing>_boards'
end
with_them do

View File

@ -25,7 +25,7 @@ RSpec.describe CleanUpNoteableIdForNotesOnCommits do
end
def dirty_notes_on_commits
notes.where(noteable_type: 'Commit').where('noteable_id IS NOT NULL')
notes.where(noteable_type: 'Commit').where.not(noteable_id: nil)
end
def other_notes

View File

@ -15,6 +15,6 @@ RSpec.describe MigrateBotTypeToUserType, :migration do
migrate!
expect(users.where('user_type IS NOT NULL').map(&:user_type)).to match_array([1, 2, 3])
expect(users.where.not(user_type: nil).map(&:user_type)).to match_array([1, 2, 3])
end
end

View File

@ -3582,10 +3582,10 @@ RSpec.describe Ci::Build do
end
describe 'state transition when build fails' do
let(:service) { MergeRequests::AddTodoWhenBuildFailsService.new(project, user) }
let(:service) { ::MergeRequests::AddTodoWhenBuildFailsService.new(project, user) }
before do
allow(MergeRequests::AddTodoWhenBuildFailsService).to receive(:new).and_return(service)
allow(::MergeRequests::AddTodoWhenBuildFailsService).to receive(:new).and_return(service)
allow(service).to receive(:close)
end
@ -3670,15 +3670,42 @@ RSpec.describe Ci::Build do
subject.drop!
end
it 'creates a todo' do
project.add_developer(user)
context 'when async_add_build_failure_todo flag enabled' do
it 'creates a todo async', :sidekiq_inline do
project.add_developer(user)
expect_next_instance_of(TodoService) do |todo_service|
expect(todo_service)
.to receive(:merge_request_build_failed).with(merge_request)
expect_next_instance_of(TodoService) do |todo_service|
expect(todo_service)
.to receive(:merge_request_build_failed).with(merge_request)
end
subject.drop!
end
subject.drop!
it 'does not create a sync todo' do
project.add_developer(user)
expect(TodoService).not_to receive(:new)
subject.drop!
end
end
context 'when async_add_build_failure_todo flag disabled' do
before do
stub_feature_flags(async_add_build_failure_todo: false)
end
it 'creates a todo sync' do
project.add_developer(user)
expect_next_instance_of(TodoService) do |todo_service|
expect(todo_service)
.to receive(:merge_request_build_failed).with(merge_request)
end
subject.drop!
end
end
end

View File

@ -1790,28 +1790,14 @@ RSpec.describe User do
context 'when user has running CI pipelines' do
let(:service) { double }
let(:pipelines) { build_list(:ci_pipeline, 3, :running) }
context 'with abort_user_pipelines_on_block feature enabled' do
let(:pipelines) { build_list(:ci_pipeline, 3, :running) }
it 'aborts all running pipelines and related jobs' do
expect(user).to receive(:pipelines).and_return(pipelines)
expect(Ci::AbortPipelinesService).to receive(:new).and_return(service)
expect(service).to receive(:execute).with(pipelines)
it 'aborts all running pipelines and related jobs' do
stub_feature_flags(abort_user_pipelines_on_block: true)
expect(user).to receive(:pipelines).and_return(pipelines)
expect(Ci::AbortPipelinesService).to receive(:new).and_return(service)
expect(service).to receive(:execute).with(pipelines)
user.block
end
end
context 'with abort_user_pipelines_on_block feature disabled' do
it 'cancels all running pipelines and related jobs' do
stub_feature_flags(abort_user_pipelines_on_block: false)
expect(Ci::CancelUserPipelinesService).to receive(:new).and_return(service)
expect(service).to receive(:execute).with(user)
user.block
end
user.block
end
end

View File

@ -17,7 +17,7 @@ RSpec.describe ServiceEventEntity do
let(:event) { 'push' }
it 'exposes correct attributes' do
expect(subject[:description]).to eq('Event will be triggered by a push to the repository')
expect(subject[:description]).to eq('Event triggered when someone pushes to the repository.')
expect(subject[:name]).to eq('push_events')
expect(subject[:title]).to eq('push')
expect(subject[:value]).to be(true)
@ -29,7 +29,7 @@ RSpec.describe ServiceEventEntity do
let(:event) { 'note' }
it 'exposes correct attributes' do
expect(subject[:description]).to eq('Event will be triggered when someone adds a comment')
expect(subject[:description]).to eq('Event triggered when someone adds a comment.')
expect(subject[:name]).to eq('note_events')
expect(subject[:title]).to eq('note')
expect(subject[:value]).to eq(false)

View File

@ -1,35 +0,0 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::CancelUserPipelinesService do
describe '#execute' do
let(:user) { create(:user) }
subject { described_class.new.execute(user) }
context 'when user has running CI pipelines' do
let(:pipeline) { create(:ci_pipeline, :running, user: user) }
let!(:build) { create(:ci_build, :running, pipeline: pipeline) }
it 'cancels all running pipelines and related jobs', :sidekiq_might_not_need_inline do
subject
expect(pipeline.reload).to be_canceled
expect(build.reload).to be_canceled
end
end
context 'when an error ocurrs' do
it 'raises a service level error' do
service = double(execute: ServiceResponse.error(message: 'Error canceling pipeline'))
allow(::Ci::CancelUserPipelinesService).to receive(:new).and_return(service)
result = subject
expect(result).to be_a(ServiceResponse)
expect(result).to be_error
end
end
end
end

View File

@ -181,7 +181,7 @@ RSpec.describe Ci::RetryBuildService do
end
it 'resolves todos for old build that failed' do
expect(MergeRequests::AddTodoWhenBuildFailsService)
expect(::MergeRequests::AddTodoWhenBuildFailsService)
.to receive_message_chain(:new, :close)
service.execute(build)

View File

@ -272,7 +272,7 @@ RSpec.describe Ci::RetryPipelineService, '#execute' do
end
it 'closes all todos about failed jobs for pipeline' do
expect(MergeRequests::AddTodoWhenBuildFailsService)
expect(::MergeRequests::AddTodoWhenBuildFailsService)
.to receive_message_chain(:new, :close_all)
service.execute(pipeline)

View File

@ -2,7 +2,7 @@
require 'spec_helper'
RSpec.describe MergeRequests::AddTodoWhenBuildFailsService do
RSpec.describe ::MergeRequests::AddTodoWhenBuildFailsService do
let(:user) { create(:user) }
let(:project) { create(:project, :repository) }
let(:sha) { '1234567890abcdef1234567890abcdef12345678' }
@ -24,8 +24,8 @@ RSpec.describe MergeRequests::AddTodoWhenBuildFailsService do
before do
allow_any_instance_of(MergeRequest)
.to receive(:head_pipeline)
.and_return(pipeline)
.to receive(:head_pipeline_id)
.and_return(pipeline.id)
allow(service).to receive(:todo_service).and_return(todo_service)
end

View File

@ -218,7 +218,7 @@ RSpec.describe Namespaces::InProductMarketingEmailsService, '#execute' do
stub_const("#{described_class}::TRACKS", { bar: :git_write })
end
it { expect { subject }.to raise_error(NotImplementedError, 'Track foo not defined') }
it { expect { subject }.to raise_error(ArgumentError, 'Track foo not defined') }
end
context 'when group is a sub-group' do

View File

@ -6,10 +6,8 @@ RSpec.describe BuildFinishedWorker do
subject { described_class.new.perform(build.id) }
describe '#perform' do
let(:build) { create(:ci_build, :success, pipeline: create(:ci_pipeline)) }
context 'when build exists' do
let!(:build) { create(:ci_build) }
let_it_be(:build) { create(:ci_build, :success, pipeline: create(:ci_pipeline)) }
before do
expect(Ci::Build).to receive(:find_by).with(id: build.id).and_return(build)
@ -30,6 +28,42 @@ RSpec.describe BuildFinishedWorker do
subject
end
context 'when build is failed' do
before do
build.update!(status: :failed)
end
it 'adds a todo' do
expect(::Ci::MergeRequests::AddTodoWhenBuildFailsWorker).to receive(:perform_async)
subject
end
context 'when async_add_build_failure_todo disabled' do
before do
stub_feature_flags(async_add_build_failure_todo: false)
end
it 'does not add a todo' do
expect(::Ci::MergeRequests::AddTodoWhenBuildFailsWorker).not_to receive(:perform_async)
subject
end
end
end
context 'when build has a chat' do
before do
build.pipeline.update!(source: :chat)
end
it 'schedules a ChatNotification job' do
expect(ChatNotificationWorker).to receive(:perform_async).with(build.id)
subject
end
end
end
context 'when build does not exist' do
@ -38,15 +72,5 @@ RSpec.describe BuildFinishedWorker do
.not_to raise_error
end
end
context 'when build has a chat' do
let(:build) { create(:ci_build, :success, pipeline: create(:ci_pipeline, source: :chat)) }
it 'schedules a ChatNotification job' do
expect(ChatNotificationWorker).to receive(:perform_async).with(build.id)
subject
end
end
end
end

View File

@ -0,0 +1,53 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Ci::MergeRequests::AddTodoWhenBuildFailsWorker do
describe '#perform' do
let_it_be(:project) { create(:project) }
let_it_be(:pipeline) { create(:ci_pipeline, :detached_merge_request_pipeline) }
let_it_be(:job) { create(:ci_build, project: project, pipeline: pipeline, status: :failed) }
let(:job_args) { job.id }
subject(:perform_twice) { perform_multiple(job_args, exec_times: 2) }
include_examples 'an idempotent worker' do
it 'executes todo service' do
service = double
expect(::MergeRequests::AddTodoWhenBuildFailsService).to receive(:new).with(project, nil).and_return(service).twice
expect(service).to receive(:execute).with(job).twice
perform_twice
end
end
context 'when job does not exist' do
let(:job_args) { 0 }
it 'returns nil' do
expect(described_class.new.perform(job_args)).to eq(nil)
end
end
context 'when project does not exist' do
before do
job.update!(project_id: nil)
end
it 'returns nil' do
expect(described_class.new.perform(job_args)).to eq(nil)
end
end
context 'when pipeline does not exist' do
before do
job.update_attribute('pipeline_id', nil)
end
it 'returns nil' do
expect(described_class.new.perform(job_args)).to eq(nil)
end
end
end
end

0
vendor/gitignore/C++.gitignore vendored Normal file → Executable file
View File

0
vendor/gitignore/Java.gitignore vendored Normal file → Executable file
View File