Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
7e99f6b9fc
commit
3e0178f80c
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module WorkItems
|
||||
class WorkItemDeletedEvent < Gitlab::EventStore::Event
|
||||
def schema
|
||||
{
|
||||
'type' => 'object',
|
||||
'required' => %w[id namespace_id],
|
||||
'properties' => {
|
||||
'id' => { 'type' => 'integer' },
|
||||
'namespace_id' => { 'type' => 'integer' },
|
||||
'work_item_parent_id' => { 'type' => 'integer' }
|
||||
}
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -8,10 +8,23 @@ module WorkItems
|
|||
end
|
||||
|
||||
if super
|
||||
publish_event(work_item)
|
||||
::ServiceResponse.success
|
||||
else
|
||||
::ServiceResponse.error(message: work_item.errors.full_messages)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def publish_event(work_item)
|
||||
Gitlab::EventStore.publish(
|
||||
WorkItems::WorkItemDeletedEvent.new(data: {
|
||||
id: work_item.id,
|
||||
namespace_id: work_item.namespace_id,
|
||||
work_item_parent_id: work_item.work_item_parent&.id
|
||||
}.tap(&:compact_blank!))
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
migration_job_name: BackfillHasIssuesForExternalIssueLinks
|
||||
description: Backfill has_issues value in vulnerability_reads for Vulnerabilities which have an ExternalIssueLink record
|
||||
feature_category: vulnerability_management
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146643
|
||||
milestone: '16.10'
|
||||
queued_migration_version: 20240305120551
|
||||
finalize_after: '2024-04-15'
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueBackfillHasIssuesForExternalIssueLinks < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.10'
|
||||
|
||||
MIGRATION = "BackfillHasIssuesForExternalIssueLinks"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 10_000
|
||||
SUB_BATCH_SIZE = 200
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:vulnerability_reads,
|
||||
:vulnerability_id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :vulnerability_reads, :vulnerability_id, [])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
eca08fbea06ecb67ed56674a2c365e1e8a1fb5414845a916a2479165195a586b
|
||||
|
|
@ -388,6 +388,7 @@ Note the following:
|
|||
- `.pipeline-policy-pre`at the beginning of the pipeline, before the `.pre` stage.
|
||||
- `.pipeline-policy-test` after the `test` stage. If the `test` stage does not exist, it will be injected after the `build` stage. If the `build` stage does not exist, it will be injected at the beginning of the pipeline after the `.pre` stage.
|
||||
- `.pipeline-policy-post` at the very end of the pipeline, after the .post stage.
|
||||
- Jobs without a stage are assigned to the `.pipeline-policy-test` stage by default.
|
||||
|
||||
#### Example security policies project
|
||||
|
||||
|
|
|
|||
|
|
@ -288,6 +288,36 @@ To review the results of an import:
|
|||
1. To see the details of a failed import, select the **See failures** link on any import with a **Failed** or **Partially completed** status.
|
||||
1. If the import has a **Partially completed** or **Complete** status, to see which items were and were not imported, select **Details**.
|
||||
|
||||
## Cancel a running import
|
||||
|
||||
To cancel a running import:
|
||||
|
||||
1. Start a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session)
|
||||
on the destination GitLab instance.
|
||||
1. Find the last import by running the following command. Replace `USER_ID` with the user ID of the user that started the import:
|
||||
|
||||
```ruby
|
||||
bulk_import = BulkImport.where(user_id: USER_ID).last
|
||||
```
|
||||
|
||||
1. Cause the import and all items associated with it to fail by running the following command:
|
||||
|
||||
```ruby
|
||||
bulk_import.entities.each do |entity|
|
||||
entity.trackers.each do |tracker|
|
||||
tracker.batches.each(&:fail_op!)
|
||||
end
|
||||
entity.trackers.each(&:fail_op!)
|
||||
entity.fail_op!
|
||||
end
|
||||
bulk_import.fail_op!
|
||||
```
|
||||
|
||||
Cancelling a `bulk_import` doesn't stop workers that are exporting the project on the source instance, but:
|
||||
|
||||
- Prevents the destination from asking for more projects to be exported.
|
||||
- Prevents the target from making more API calls to the source.
|
||||
|
||||
## Migrated group items
|
||||
|
||||
The group items that are migrated depend on the version of GitLab you use on the destination. To determine if a
|
||||
|
|
@ -502,28 +532,6 @@ entities.where(status: [-1]).pluck(:destination_name, :destination_namespace, :s
|
|||
You can also see all migrated entities with any failures related to them using an
|
||||
[API endpoint](../../../api/bulk_imports.md#list-all-group-or-project-migrations-entities).
|
||||
|
||||
### Remove cancelled imports
|
||||
|
||||
Sometime you might have to cancel an import. Cancelled imports don't clean up after themselves so you must delete
|
||||
the imported items yourself. To delete the import by direct transfer that was most recently run:
|
||||
|
||||
1. Start a [Rails console session](../../../administration/operations/rails_console.md#starting-a-rails-console-session).
|
||||
1. Find the last import by running the following command. Replace `USER_ID` with the user ID of the user that ran the
|
||||
cancelled import:
|
||||
|
||||
```ruby
|
||||
bulk_import = BulkImport.find_by(user_id: USER_ID).last
|
||||
```
|
||||
|
||||
1. Delete the last import, including all items associated with it, by running the following command:
|
||||
|
||||
```ruby
|
||||
bulk_import.destroy!
|
||||
```
|
||||
|
||||
Any items associated with the import by direct transfer, including merge requests, projects, and issues, should be
|
||||
deleted.
|
||||
|
||||
### Stale imports
|
||||
|
||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/352985) in GitLab 14.10.
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ module Backup
|
|||
@remote_storage = Backup::RemoteStorage.new(progress: progress, options: options)
|
||||
end
|
||||
|
||||
# @return [Boolean] whether all tasks succeeded
|
||||
def create
|
||||
# Deprecation: Using backup_id (ENV['BACKUP']) to specify previous backup was deprecated in 15.0
|
||||
previous_backup = options.previous_backup || options.backup_id
|
||||
|
|
@ -27,28 +28,32 @@ module Backup
|
|||
"and are not included in this backup. You will need these files to restore a backup.\n" \
|
||||
"Please back them up manually.".color(:red)
|
||||
puts_time "Backup #{backup_id} is done."
|
||||
true
|
||||
end
|
||||
|
||||
# @param [Gitlab::Backup::Tasks::Task] task
|
||||
# @return [Boolean] whether the task succeeded
|
||||
def run_create_task(task)
|
||||
build_backup_information
|
||||
|
||||
unless task.enabled?
|
||||
puts_time "Dumping #{task.human_name} ... ".color(:blue) + "[DISABLED]".color(:cyan)
|
||||
return
|
||||
return true
|
||||
end
|
||||
|
||||
if options.skip_task?(task.id)
|
||||
puts_time "Dumping #{task.human_name} ... ".color(:blue) + "[SKIPPED]".color(:cyan)
|
||||
return
|
||||
return true
|
||||
end
|
||||
|
||||
puts_time "Dumping #{task.human_name} ... ".color(:blue)
|
||||
task.backup!(backup_path, backup_id)
|
||||
puts_time "Dumping #{task.human_name} ... ".color(:blue) + "done".color(:green)
|
||||
true
|
||||
|
||||
rescue Backup::DatabaseBackupError, Backup::FileBackupError => e
|
||||
puts_time "Dumping #{task.human_name} failed: #{e.message}".color(:red)
|
||||
false
|
||||
end
|
||||
|
||||
def restore
|
||||
|
|
|
|||
|
|
@ -0,0 +1,41 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
class BackfillHasIssuesForExternalIssueLinks < BatchedMigrationJob
|
||||
operation_name :backfill_has_issues_for_external_issue_links
|
||||
scope_to ->(relation) { relation.where(has_issues: false) }
|
||||
feature_category :vulnerability_management
|
||||
|
||||
UPDATE_SQL = <<~SQL
|
||||
UPDATE
|
||||
vulnerability_reads
|
||||
SET
|
||||
has_issues = true
|
||||
FROM
|
||||
(%<subquery>s) as sub_query
|
||||
WHERE
|
||||
vulnerability_reads.vulnerability_id = sub_query.vulnerability_id
|
||||
SQL
|
||||
|
||||
def perform
|
||||
each_sub_batch do |sub_batch|
|
||||
update_query = update_query_for(sub_batch)
|
||||
|
||||
connection.execute(update_query)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def update_query_for(sub_batch)
|
||||
subquery = sub_batch.joins("
|
||||
INNER JOIN vulnerability_external_issue_links ON
|
||||
vulnerability_reads.vulnerability_id =
|
||||
vulnerability_external_issue_links.vulnerability_id")
|
||||
|
||||
format(UPDATE_SQL, subquery: subquery.to_sql)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -9,8 +9,8 @@ module Tasks
|
|||
def self.create_backup
|
||||
lock_backup do
|
||||
::Gitlab::TaskHelpers.warn_user_is_not_gitlab
|
||||
|
||||
::Backup::Manager.new(backup_progress).create
|
||||
success = ::Backup::Manager.new(backup_progress).create
|
||||
exit 1 unless success
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -26,8 +26,8 @@ module Tasks
|
|||
lock_backup do
|
||||
backup_manager = ::Backup::Manager.new(backup_progress)
|
||||
task = backup_manager.find_task(task_id)
|
||||
|
||||
backup_manager.run_create_task(task)
|
||||
success = backup_manager.run_create_task(task)
|
||||
exit 1 unless success
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -27,44 +27,66 @@ RSpec.describe Backup::Manager, feature_category: :backup_restore do
|
|||
end
|
||||
|
||||
describe '#run_create_task' do
|
||||
let(:terraform_state) do
|
||||
Backup::Tasks::TerraformState.new(progress: progress, options: options)
|
||||
describe 'other task' do
|
||||
let(:terraform_state) do
|
||||
Backup::Tasks::TerraformState.new(progress: progress, options: options)
|
||||
.tap { |state| allow(state).to receive(:target).and_return(target) }
|
||||
end
|
||||
|
||||
let(:target) { instance_double(Backup::Targets::Target) }
|
||||
let(:backup_tasks) do
|
||||
{ 'terraform_state' => terraform_state }
|
||||
end
|
||||
|
||||
it 'runs the provided task' do
|
||||
expect(target).to receive(:dump)
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... ')
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... done')
|
||||
|
||||
subject.run_create_task(terraform_state)
|
||||
end
|
||||
|
||||
context 'when disabled' do
|
||||
it 'does not run the task and informs the user' do
|
||||
allow(terraform_state).to receive(:enabled).and_return(false)
|
||||
|
||||
expect(target).not_to receive(:dump)
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... [DISABLED]')
|
||||
|
||||
subject.run_create_task(terraform_state)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when skipped' do
|
||||
it 'does not run the task and informs the user' do
|
||||
stub_env('SKIP', 'terraform_state')
|
||||
|
||||
expect(target).not_to receive(:dump)
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... [SKIPPED]')
|
||||
|
||||
subject.run_create_task(terraform_state)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'database task' do
|
||||
let(:backup_state) do
|
||||
Backup::Tasks::Database.new(progress: progress, options: options)
|
||||
.tap { |state| allow(state).to receive(:target).and_return(target) }
|
||||
end
|
||||
|
||||
let(:target) { instance_double(Backup::Targets::Target) }
|
||||
let(:backup_tasks) do
|
||||
{ 'terraform_state' => terraform_state }
|
||||
backup_state
|
||||
end
|
||||
|
||||
it 'runs the provided task' do
|
||||
expect(target).to receive(:dump)
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... ')
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... done')
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping database ... ')
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping database ... done')
|
||||
|
||||
subject.run_create_task(terraform_state)
|
||||
end
|
||||
|
||||
context 'when disabled' do
|
||||
it 'does not run the task and informs the user' do
|
||||
allow(terraform_state).to receive(:enabled).and_return(false)
|
||||
|
||||
expect(target).not_to receive(:dump)
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... [DISABLED]')
|
||||
|
||||
subject.run_create_task(terraform_state)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when skipped' do
|
||||
it 'does not run the task and informs the user' do
|
||||
stub_env('SKIP', 'terraform_state')
|
||||
|
||||
expect(target).not_to receive(:dump)
|
||||
expect(Gitlab::BackupLogger).to receive(:info).with(message: 'Dumping terraform states ... [SKIPPED]')
|
||||
|
||||
subject.run_create_task(terraform_state)
|
||||
end
|
||||
subject.run_create_task(backup_tasks)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,170 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::BackgroundMigration::BackfillHasIssuesForExternalIssueLinks, feature_category: :vulnerability_management do
|
||||
let(:users) { table(:users) }
|
||||
let(:user) { create_user(email: "test1@example.com", username: "test1") }
|
||||
|
||||
let(:namespaces) { table(:namespaces) }
|
||||
let(:namespace) { namespaces.create!(name: 'test-1', path: 'test-1', owner_id: user.id) }
|
||||
|
||||
let(:projects) { table(:projects) }
|
||||
let(:project) { projects.create!(namespace_id: namespace.id, project_namespace_id: namespace.id) }
|
||||
|
||||
let(:members) { table(:members) }
|
||||
let!(:membership) do
|
||||
members.create!(access_level: 50, source_id: project.id, source_type: "Project", user_id: user.id, state: 0,
|
||||
notification_level: 3, type: "ProjectMember", member_namespace_id: namespace.id)
|
||||
end
|
||||
|
||||
let(:vulnerability_identifiers) { table(:vulnerability_identifiers) }
|
||||
|
||||
let(:vulnerability_scanners) { table(:vulnerability_scanners) }
|
||||
let(:scanner) { create_scanner(project_id: project.id) }
|
||||
|
||||
let(:vulnerability_findings) { table(:vulnerability_occurrences) }
|
||||
let(:vulnerabilities) { table(:vulnerabilities) }
|
||||
let(:vulnerability_reads) { table(:vulnerability_reads) }
|
||||
let(:vulnerability_external_issue_links) { table(:vulnerability_external_issue_links) }
|
||||
|
||||
let(:vulnerability) do
|
||||
create_full_vulnerability(project)
|
||||
end
|
||||
|
||||
let(:vulnerability_read) do
|
||||
vulnerability_reads.find_by(vulnerability_id: vulnerability.id)
|
||||
end
|
||||
|
||||
let!(:external_issue_link) do
|
||||
vulnerability_external_issue_links.create!(
|
||||
author_id: user.id,
|
||||
vulnerability_id: vulnerability.id,
|
||||
external_project_key: "TEST",
|
||||
external_issue_key: "123"
|
||||
)
|
||||
end
|
||||
|
||||
subject(:perform_migration) do
|
||||
described_class.new(
|
||||
start_id: vulnerability_reads.first.vulnerability_id,
|
||||
end_id: vulnerability_reads.last.vulnerability_id,
|
||||
batch_table: :vulnerability_reads,
|
||||
batch_column: :vulnerability_id,
|
||||
sub_batch_size: vulnerability_reads.count,
|
||||
pause_ms: 0,
|
||||
connection: ActiveRecord::Base.connection
|
||||
).perform
|
||||
end
|
||||
|
||||
it 'sets has_issues of an existing record' do
|
||||
expect { perform_migration }.to change { vulnerability_read.reload.has_issues }.from(false).to(true)
|
||||
end
|
||||
|
||||
context 'when there exists a record with has_issues' do
|
||||
let(:vulnerability_2) do
|
||||
create_full_vulnerability(project, read_overrides: { has_issues: true })
|
||||
end
|
||||
|
||||
let(:vulnerability_read_2) { vulnerability_reads.find_by(vulnerability_id: vulnerability_2.id) }
|
||||
|
||||
it 'does not modify existing records with has_issues' do
|
||||
expect { perform_migration }.not_to change { vulnerability_read_2.reload.has_merge_request }.from(false)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_full_vulnerability(project, finding_overrides: {}, vulnerability_overrides: {}, read_overrides: {})
|
||||
finding = create_finding(project, finding_overrides)
|
||||
vulnerability = create_vulnerability(vulnerability_overrides.merge(finding_id: finding.id))
|
||||
create_vulnerability_read(vulnerability, finding, read_overrides)
|
||||
|
||||
vulnerability
|
||||
end
|
||||
|
||||
def create_scanner(project, overrides = {})
|
||||
random_scanner_uuid = SecureRandom.uuid
|
||||
|
||||
attrs = {
|
||||
project_id: project.id,
|
||||
external_id: "test_vulnerability_scanner-#{random_scanner_uuid})",
|
||||
name: "Test Vulnerabilities::Scanner #{random_scanner_uuid}"
|
||||
}.merge(overrides)
|
||||
|
||||
vulnerability_scanners.create!(attrs)
|
||||
end
|
||||
|
||||
def create_identifier(project, overrides = {})
|
||||
attrs = {
|
||||
project_id: project.id,
|
||||
external_id: "CVE-2018-1234",
|
||||
external_type: "CVE",
|
||||
name: "CVE-2018-1234",
|
||||
fingerprint: SecureRandom.hex(20)
|
||||
}.merge(overrides)
|
||||
|
||||
vulnerability_identifiers.create!(attrs)
|
||||
end
|
||||
|
||||
def create_finding(project, overrides = {})
|
||||
attrs = {
|
||||
project_id: project.id,
|
||||
scanner_id: create_scanner(project).id,
|
||||
severity: 5, # medium
|
||||
confidence: 2, # unknown,
|
||||
report_type: 99, # generic
|
||||
primary_identifier_id: create_identifier(project).id,
|
||||
project_fingerprint: SecureRandom.hex(20),
|
||||
location_fingerprint: SecureRandom.hex(20),
|
||||
uuid: SecureRandom.uuid,
|
||||
name: "CVE-2018-1234",
|
||||
raw_metadata: "{}",
|
||||
metadata_version: "test:1.0"
|
||||
}.merge(overrides)
|
||||
|
||||
vulnerability_findings.create!(attrs)
|
||||
end
|
||||
|
||||
def create_vulnerability(overrides = {})
|
||||
attrs = {
|
||||
project_id: project.id,
|
||||
author_id: user.id,
|
||||
title: 'test',
|
||||
severity: 1,
|
||||
confidence: 1,
|
||||
report_type: 1,
|
||||
state: 1,
|
||||
detected_at: Time.zone.now
|
||||
}.merge(overrides)
|
||||
|
||||
vulnerabilities.create!(attrs)
|
||||
end
|
||||
|
||||
def create_vulnerability_read(vulnerability, finding, overrides = {})
|
||||
attrs = {
|
||||
project_id: vulnerability.project_id,
|
||||
vulnerability_id: vulnerability.id,
|
||||
scanner_id: finding.scanner_id,
|
||||
severity: vulnerability.severity,
|
||||
report_type: vulnerability.report_type,
|
||||
state: vulnerability.state,
|
||||
uuid: finding.uuid
|
||||
}.merge(overrides)
|
||||
|
||||
vulnerability_reads.create!(attrs)
|
||||
end
|
||||
|
||||
def create_user(overrides = {})
|
||||
attrs = {
|
||||
email: "test@example.com",
|
||||
notification_email: "test@example.com",
|
||||
name: "test",
|
||||
username: "test",
|
||||
state: "active",
|
||||
projects_limit: 10
|
||||
}.merge(overrides)
|
||||
|
||||
users.create!(attrs)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe QueueBackfillHasIssuesForExternalIssueLinks, feature_category: :vulnerability_management do
|
||||
let!(:batched_migration) { described_class::MIGRATION }
|
||||
|
||||
it 'schedules a new batched migration' do
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
expect(batched_migration).not_to have_scheduled_batched_migration
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
expect(batched_migration).to have_scheduled_batched_migration(
|
||||
table_name: :vulnerability_reads,
|
||||
column_name: :vulnerability_id,
|
||||
interval: described_class::DELAY_INTERVAL,
|
||||
batch_size: described_class::BATCH_SIZE,
|
||||
sub_batch_size: described_class::SUB_BATCH_SIZE
|
||||
)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -11,17 +11,29 @@ RSpec.describe WorkItems::DeleteService, feature_category: :team_planning do
|
|||
|
||||
let(:user) { guest }
|
||||
|
||||
let(:service) { described_class.new(container: project, current_user: user) }
|
||||
|
||||
before_all do
|
||||
# note necessary to test note removal as part of work item deletion
|
||||
create(:note, project: project, noteable: work_item)
|
||||
end
|
||||
|
||||
describe '#execute' do
|
||||
subject(:result) { described_class.new(container: project, current_user: user).execute(work_item) }
|
||||
subject(:result) { service.execute(work_item) }
|
||||
|
||||
context 'when user can delete the work item' do
|
||||
it { is_expected.to be_success }
|
||||
|
||||
it 'publish WorkItems::WorkItemDeletedEvent' do
|
||||
expect { service.execute(work_item) }
|
||||
.to publish_event(::WorkItems::WorkItemDeletedEvent)
|
||||
.with({
|
||||
id: work_item.id,
|
||||
namespace_id: work_item.namespace_id,
|
||||
work_item_parent_id: work_item.work_item_parent&.id
|
||||
}.tap(&:compact_blank!))
|
||||
end
|
||||
|
||||
context 'when work item exists at the group level' do
|
||||
let_it_be(:work_item) { create(:work_item, :group_level, namespace: group) }
|
||||
|
||||
|
|
@ -63,6 +75,11 @@ RSpec.describe WorkItems::DeleteService, feature_category: :team_planning do
|
|||
it 'returns error messages' do
|
||||
expect(result.errors).to contain_exactly('User not authorized to delete work item')
|
||||
end
|
||||
|
||||
it 'does not publish WorkItems::WorkItemDeletedEvent' do
|
||||
expect { service.execute(work_item) }
|
||||
.not_to publish_event(::WorkItems::WorkItemDeletedEvent)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -361,7 +361,9 @@ RSpec.describe 'gitlab:backup namespace rake tasks', :delete, feature_category:
|
|||
end
|
||||
|
||||
it "raises an error with message" do
|
||||
expect { run_rake_task(rake_task) }.to output(Regexp.new(error.message)).to_stdout_from_any_process
|
||||
expect do
|
||||
expect { run_rake_task(rake_task) }.to raise_error(SystemExit)
|
||||
end.to output(Regexp.new(error.message)).to_stdout_from_any_process
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ module gitlab.com/gitlab-org/gitlab/workhorse
|
|||
go 1.20
|
||||
|
||||
require (
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.0
|
||||
github.com/BurntSushi/toml v1.3.2
|
||||
github.com/alecthomas/chroma/v2 v2.12.0
|
||||
github.com/aws/aws-sdk-go v1.50.7
|
||||
|
|
@ -32,7 +32,7 @@ require (
|
|||
golang.org/x/tools v0.18.0
|
||||
google.golang.org/grpc v1.61.0
|
||||
google.golang.org/protobuf v1.32.0
|
||||
honnef.co/go/tools v0.4.6
|
||||
honnef.co/go/tools v0.4.7
|
||||
)
|
||||
|
||||
require (
|
||||
|
|
@ -45,12 +45,12 @@ require (
|
|||
cloud.google.com/go/storage v1.35.1 // indirect
|
||||
cloud.google.com/go/trace v1.10.4 // indirect
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.14 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible // indirect
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 // indirect
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 // indirect
|
||||
github.com/DataDog/datadog-go v4.4.0+incompatible // indirect
|
||||
github.com/DataDog/sketches-go v1.0.0 // indirect
|
||||
github.com/Microsoft/go-winio v0.6.1 // indirect
|
||||
|
|
@ -69,7 +69,7 @@ require (
|
|||
github.com/golang/protobuf v1.5.3 // indirect
|
||||
github.com/google/pprof v0.0.0-20230926050212-f7f687d19a98 // indirect
|
||||
github.com/google/s2a-go v0.1.7 // indirect
|
||||
github.com/google/uuid v1.4.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/google/wire v0.5.0 // indirect
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect
|
||||
github.com/googleapis/gax-go/v2 v2.12.0 // indirect
|
||||
|
|
@ -88,7 +88,7 @@ require (
|
|||
github.com/oklog/ulid/v2 v2.0.2 // indirect
|
||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||
github.com/philhofer/fwd v1.1.1 // indirect
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 // indirect
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||
github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect
|
||||
|
|
|
|||
|
|
@ -60,21 +60,21 @@ cloud.google.com/go/trace v1.10.4/go.mod h1:Nso99EDIK8Mj5/zmB+iGr9dosS/bzWCJ8wGm
|
|||
contrib.go.opencensus.io/exporter/stackdriver v0.13.14 h1:zBakwHardp9Jcb8sQHcHpXy/0+JIb1M8KjigCJzx7+4=
|
||||
contrib.go.opencensus.io/exporter/stackdriver v0.13.14/go.mod h1:5pSSGY0Bhuk7waTHuDf4aQ8D2DrhgETRo9fy6k3Xlzc=
|
||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1 h1:lGlwhPtrX6EVml1hO0ivjkUxsSyl4dsiw9qcA1k/3IQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.1/go.mod h1:RKUqNu35KJYcVG/fqTRqmuXJZYNhYkBrnC/hX7yGbTA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0 h1:BMAjVKJM0U/CYF27gA0ZMmXGkOcvfFtD0oHVZ1TIPRI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.4.0/go.mod h1:1fXstnBMas5kzG+S3q8UoJcmyU6nUeunJcMDHcRYHhs=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1 h1:6oNBlSdi1QqM1PNW7FPA6xOGA5UNsXnkaYZz9vdPGhA=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.1/go.mod h1:s4kgfzA0covAXNicZHDMN58jExvcng2mC/DepXiF1EI=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2 h1:c4k2FIYIh4xtwqrQwV0Ct1v5+ehlNXj5NI/MWVsiTkQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.9.2/go.mod h1:5FDJtLEO/GxwNgUxbwrY3LP0pEoThTQJtk2oysdXHxM=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2/go.mod h1:yInRyqWXAuaPrgI7p70+lDDgh3mlBohis29jGMISnmc=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/storage/armstorage v1.5.0 h1:AifHbc4mg0x9zW52WOpKbsHaDKuRhlI7TVl47thgQ70=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1 h1:AMf7YbZOZIW5b66cXNHMWWT/zkjhz5+a+k/3x40EO7E=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.2.1/go.mod h1:uwfk06ZBcvL/g4VHNjurPfVln9NMbsk2XIZxJ+hu81k=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.0 h1:IfFdxTUDiV58iZqPKgyWiz4X4fCxZeQ1pTQPImLYXpY=
|
||||
github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.3.0/go.mod h1:SUZc9YRRHfx2+FAQKNDGrssXehqLpxmwRv2mC/5ntj4=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible h1:V5VMDjClD3GiElqLWO7mz2MxNAK/vTfRHdAubSIPRgs=
|
||||
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0 h1:oXVqrxakqqV1UZdSazDOPOLvOIz+XA683u8EctwboHk=
|
||||
github.com/Azure/go-autorest/autorest/to v0.4.0/go.mod h1:fE8iZBn7LQR7zH/9XU2NcPR4o9jEImooCeWJcYV/zLE=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0 h1:hVeq+yCyUi+MsoO/CU95yqCIcdzra5ovzk8Q2BBpV2M=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.0/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1 h1:DzHpqpoJVaCgOUdVHxE8QB52S6NiVdDQvGlny1qvPqA=
|
||||
github.com/AzureAD/microsoft-authentication-library-for-go v1.2.1/go.mod h1:wP83P5OoQ5p6ip3ScPr0BAq0BvuPAvacpEuSzyouqAI=
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/BurntSushi/toml v1.3.2 h1:o7IhLm0Msx3BaB+n3Ag7L8EVlByGnpq14C4YWiu/gL8=
|
||||
github.com/BurntSushi/toml v1.3.2/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ=
|
||||
|
|
@ -269,8 +269,8 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
|||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
|
||||
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
|
||||
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.3.2 h1:Vie5ybvEvT75RniqhfFxPRy3Bf7vr3h0cechB90XaQs=
|
||||
|
|
@ -358,8 +358,8 @@ github.com/pborman/getopt v0.0.0-20170112200414-7148bc3a4c30/go.mod h1:85jBQOZwp
|
|||
github.com/pelletier/go-toml v1.0.1-0.20170904195809-1d6b12b7cb29/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/philhofer/fwd v1.1.1 h1:GdGcTjf5RNAxwS4QLsiMzJYj5KEvPJD3Abr261yRQXQ=
|
||||
github.com/philhofer/fwd v1.1.1/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8 h1:KoWmjvw+nsYOo29YJK9vDA65RGE3NrOnUtO7a+RF9HU=
|
||||
github.com/pkg/browser v0.0.0-20210911075715-681adbf594b8/go.mod h1:HKlIX3XHQyzLZPlr7++PzdhaXEj94dEiJgZDTsxEqUI=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=
|
||||
github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c/go.mod h1:7rwL4CYBLnjLxUqIJNnCWiEdr3bn6IUYi15bNlnbCCU=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
|
|
@ -645,7 +645,6 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc
|
|||
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616045830-e2b7044e8c71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
|
|
@ -928,8 +927,8 @@ honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWh
|
|||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
|
||||
honnef.co/go/tools v0.4.6 h1:oFEHCKeID7to/3autwsWfnuv69j3NsfcXbvJKuIcep8=
|
||||
honnef.co/go/tools v0.4.6/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
|
||||
honnef.co/go/tools v0.4.7 h1:9MDAWxMoSnB6QoSqiVr7P5mtkT9pOc1kSxchzPCnqJs=
|
||||
honnef.co/go/tools v0.4.7/go.mod h1:+rnGS1THNh8zMwnd2oVOTL9QF6vmfyG6ZXBULae2uc0=
|
||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
|
||||
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
|
||||
|
|
|
|||
Loading…
Reference in New Issue