Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
fa10e47f6e
commit
849e6f56ae
|
|
@ -1763,23 +1763,6 @@ Layout/ArgumentAlignment:
|
|||
- 'ee/spec/views/admin/identities/index.html.haml_spec.rb'
|
||||
- 'ee/spec/views/groups/edit.html.haml_spec.rb'
|
||||
- 'ee/spec/views/projects/edit.html.haml_spec.rb'
|
||||
- 'ee/spec/workers/adjourned_group_deletion_worker_spec.rb'
|
||||
- 'ee/spec/workers/analytics/cycle_analytics/consistency_worker_spec.rb'
|
||||
- 'ee/spec/workers/analytics/devops_adoption/create_snapshot_worker_spec.rb'
|
||||
- 'ee/spec/workers/audit_events/audit_event_streaming_worker_spec.rb'
|
||||
- 'ee/spec/workers/concerns/update_orchestration_policy_configuration_spec.rb'
|
||||
- 'ee/spec/workers/create_github_webhook_worker_spec.rb'
|
||||
- 'ee/spec/workers/ee/projects/inactive_projects_deletion_cron_worker_spec.rb'
|
||||
- 'ee/spec/workers/ee/repository_check/batch_worker_spec.rb'
|
||||
- 'ee/spec/workers/elastic_index_bulk_cron_worker_spec.rb'
|
||||
- 'ee/spec/workers/elastic_index_initial_bulk_cron_worker_spec.rb'
|
||||
- 'ee/spec/workers/epics/update_cached_metadata_worker_spec.rb'
|
||||
- 'ee/spec/workers/namespaces/sync_namespace_name_worker_spec.rb'
|
||||
- 'ee/spec/workers/pull_mirrors/reenable_configuration_worker_spec.rb'
|
||||
- 'ee/spec/workers/repository_update_mirror_worker_spec.rb'
|
||||
- 'ee/spec/workers/security/orchestration_policy_rule_schedule_namespace_worker_spec.rb'
|
||||
- 'ee/spec/workers/security/orchestration_policy_rule_schedule_worker_spec.rb'
|
||||
- 'ee/spec/workers/security/process_scan_result_policy_worker_spec.rb'
|
||||
- 'lib/api/access_requests.rb'
|
||||
- 'lib/api/admin/plan_limits.rb'
|
||||
- 'lib/api/alert_management_alerts.rb'
|
||||
|
|
@ -3073,37 +3056,4 @@ Layout/ArgumentAlignment:
|
|||
- 'spec/views/projects/tags/index.html.haml_spec.rb'
|
||||
- 'spec/views/shared/milestones/_issuables.html.haml_spec.rb'
|
||||
- 'spec/views/shared/runners/_runner_details.html.haml_spec.rb'
|
||||
- 'spec/workers/authorized_project_update/user_refresh_over_user_range_worker_spec.rb'
|
||||
- 'spec/workers/build_hooks_worker_spec.rb'
|
||||
- 'spec/workers/build_queue_worker_spec.rb'
|
||||
- 'spec/workers/ci/job_artifacts/track_artifact_report_worker_spec.rb'
|
||||
- 'spec/workers/concerns/worker_context_spec.rb'
|
||||
- 'spec/workers/deployments/hooks_worker_spec.rb'
|
||||
- 'spec/workers/design_management/new_version_worker_spec.rb'
|
||||
- 'spec/workers/every_sidekiq_worker_spec.rb'
|
||||
- 'spec/workers/integrations/irker_worker_spec.rb'
|
||||
- 'spec/workers/jira_connect/sync_branch_worker_spec.rb'
|
||||
- 'spec/workers/jira_connect/sync_builds_worker_spec.rb'
|
||||
- 'spec/workers/jira_connect/sync_deployments_worker_spec.rb'
|
||||
- 'spec/workers/jira_connect/sync_feature_flags_worker_spec.rb'
|
||||
- 'spec/workers/jira_connect/sync_merge_request_worker_spec.rb'
|
||||
- 'spec/workers/jira_connect/sync_project_worker_spec.rb'
|
||||
- 'spec/workers/merge_requests/delete_source_branch_worker_spec.rb'
|
||||
- 'spec/workers/merge_requests/update_head_pipeline_worker_spec.rb'
|
||||
- 'spec/workers/namespaces/root_statistics_worker_spec.rb'
|
||||
- 'spec/workers/object_pool/destroy_worker_spec.rb'
|
||||
- 'spec/workers/pipeline_hooks_worker_spec.rb'
|
||||
- 'spec/workers/pipeline_metrics_worker_spec.rb'
|
||||
- 'spec/workers/process_commit_worker_spec.rb'
|
||||
- 'spec/workers/projects/inactive_projects_deletion_cron_worker_spec.rb'
|
||||
- 'spec/workers/projects/inactive_projects_deletion_notification_worker_spec.rb'
|
||||
- 'spec/workers/rebase_worker_spec.rb'
|
||||
- 'spec/workers/remote_mirror_notification_worker_spec.rb'
|
||||
- 'spec/workers/remove_expired_members_worker_spec.rb'
|
||||
- 'spec/workers/remove_unaccepted_member_invites_worker_spec.rb'
|
||||
- 'spec/workers/remove_unreferenced_lfs_objects_worker_spec.rb'
|
||||
- 'spec/workers/repository_update_remote_mirror_worker_spec.rb'
|
||||
- 'spec/workers/run_pipeline_schedule_worker_spec.rb'
|
||||
- 'spec/workers/update_head_pipeline_for_merge_request_worker_spec.rb'
|
||||
- 'spec/workers/web_hook_worker_spec.rb'
|
||||
- 'tooling/danger/suggestor.rb'
|
||||
|
|
|
|||
|
|
@ -3164,7 +3164,6 @@ RSpec/ContextWording:
|
|||
- 'spec/support_specs/helpers/stub_method_calls_spec.rb'
|
||||
- 'spec/tasks/cache/clear/redis_spec.rb'
|
||||
- 'spec/tasks/dev_rake_spec.rb'
|
||||
- 'spec/tasks/gettext_rake_spec.rb'
|
||||
- 'spec/tasks/gitlab/cleanup_rake_spec.rb'
|
||||
- 'spec/tasks/gitlab/db/validate_config_rake_spec.rb'
|
||||
- 'spec/tasks/gitlab/db_rake_spec.rb'
|
||||
|
|
|
|||
|
|
@ -6079,7 +6079,6 @@ RSpec/MissingFeatureCategory:
|
|||
- 'spec/tasks/admin_mode_spec.rb'
|
||||
- 'spec/tasks/config_lint_spec.rb'
|
||||
- 'spec/tasks/dev_rake_spec.rb'
|
||||
- 'spec/tasks/gettext_rake_spec.rb'
|
||||
- 'spec/tasks/gitlab/artifacts/check_rake_spec.rb'
|
||||
- 'spec/tasks/gitlab/artifacts/migrate_rake_spec.rb'
|
||||
- 'spec/tasks/gitlab/background_migrations_rake_spec.rb'
|
||||
|
|
|
|||
|
|
@ -77,7 +77,6 @@ Style/RedundantRegexpEscape:
|
|||
- 'lib/gitlab/utils/sanitize_node_link.rb'
|
||||
- 'lib/gitlab/word_diff/segments/diff_hunk.rb'
|
||||
- 'lib/product_analytics/tracker.rb'
|
||||
- 'lib/tasks/gettext.rake'
|
||||
- 'lib/tasks/gitlab/info.rake'
|
||||
- 'qa/spec/runtime/key/ecdsa_spec.rb'
|
||||
- 'qa/spec/runtime/key/ed25519_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
534e1a1c783059ab7a24ede2c63a53867ba393a2
|
||||
1017fbf2f98b23dd93d86173015159fd31df64d0
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -102,7 +102,7 @@ gem 'acme-client', '~> 2.0'
|
|||
gem 'browser', '~> 5.3.1'
|
||||
|
||||
# OS detection for usage ping
|
||||
gem 'ohai', '~> 16.10'
|
||||
gem 'ohai', '~> 17.9'
|
||||
|
||||
# GPG
|
||||
gem 'gpgme', '~> 2.0.22'
|
||||
|
|
|
|||
|
|
@ -396,7 +396,7 @@
|
|||
{"name":"oauth","version":"0.5.6","platform":"ruby","checksum":"4085fe28e0c5e2434135e00a6555294fd2a4ff96a98d1bdecdcd619fc6368dff"},
|
||||
{"name":"oauth2","version":"2.0.9","platform":"ruby","checksum":"b21f9defcf52dc1610e0dfab4c868342173dcd707fd15c777d9f4f04e153f7fb"},
|
||||
{"name":"octokit","version":"4.25.1","platform":"ruby","checksum":"c02092ee82dcdfe84db0e0ea630a70d32becc54245a4f0bacfd21c010df09b96"},
|
||||
{"name":"ohai","version":"16.10.6","platform":"ruby","checksum":"b835806e585faea4ac8346b68c722fb5fc29a29f73fd7e3a022f9073132dec22"},
|
||||
{"name":"ohai","version":"17.9.0","platform":"ruby","checksum":"c59cf16124c0a6481fb85013ec7ec5b398651b6abed782d3e06ab058ce9a5406"},
|
||||
{"name":"oj","version":"3.13.23","platform":"ruby","checksum":"206dfdc4020ad9974705037f269cfba211d61b7662a58c717cce771829ccef51"},
|
||||
{"name":"oj-introspect","version":"0.7.2","platform":"ruby","checksum":"c415a44567ed2870d8e963a69421d9322128e194fab7867e37e54d5a25d5333d"},
|
||||
{"name":"omniauth","version":"2.1.0","platform":"ruby","checksum":"bff7234f5ec9323622b217c7f26d52f850de0b0e2b8c807c3358fc79fe572300"},
|
||||
|
|
|
|||
10
Gemfile.lock
10
Gemfile.lock
|
|
@ -1000,16 +1000,16 @@ GEM
|
|||
octokit (4.25.1)
|
||||
faraday (>= 1, < 3)
|
||||
sawyer (~> 0.9)
|
||||
ohai (16.10.6)
|
||||
chef-config (>= 12.8, < 17)
|
||||
chef-utils (>= 16.0, < 17)
|
||||
ohai (17.9.0)
|
||||
chef-config (>= 14.12, < 18)
|
||||
chef-utils (>= 16.0, < 18)
|
||||
ffi (~> 1.9)
|
||||
ffi-yajl (~> 2.2)
|
||||
ipaddress
|
||||
mixlib-cli (>= 1.7.0)
|
||||
mixlib-config (>= 2.0, < 4.0)
|
||||
mixlib-log (>= 2.0.1, < 4.0)
|
||||
mixlib-shellout (>= 2.0, < 4.0)
|
||||
mixlib-shellout (~> 3.2, >= 3.2.5)
|
||||
plist (~> 3.1)
|
||||
train-core
|
||||
wmi-lite (~> 1.0)
|
||||
|
|
@ -1801,7 +1801,7 @@ DEPENDENCIES
|
|||
nokogiri (~> 1.14.2)
|
||||
oauth2 (~> 2.0)
|
||||
octokit (~> 4.15)
|
||||
ohai (~> 16.10)
|
||||
ohai (~> 17.9)
|
||||
oj (~> 3.13.21)
|
||||
oj-introspect (~> 0.7)
|
||||
omniauth (~> 2.1.0)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Mutations
|
||||
module Achievements
|
||||
class Delete < BaseMutation
|
||||
graphql_name 'AchievementsDelete'
|
||||
|
||||
include Gitlab::Graphql::Authorize::AuthorizeResource
|
||||
|
||||
field :achievement,
|
||||
::Types::Achievements::AchievementType,
|
||||
null: true,
|
||||
description: 'Achievement.'
|
||||
|
||||
argument :achievement_id, ::Types::GlobalIDType[::Achievements::Achievement],
|
||||
required: true,
|
||||
description: 'Global ID of the achievement being deleted.'
|
||||
|
||||
authorize :admin_achievement
|
||||
|
||||
def resolve(args)
|
||||
achievement = authorized_find!(id: args[:achievement_id])
|
||||
|
||||
result = ::Achievements::DestroyService.new(current_user, achievement).execute
|
||||
{ achievement: result.payload, errors: result.errors }
|
||||
end
|
||||
|
||||
def find_object(id:)
|
||||
GitlabSchema.object_from_id(id, expected_type: ::Achievements::Achievement)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -8,6 +8,7 @@ module Types
|
|||
|
||||
mount_mutation Mutations::Achievements::Award, alpha: { milestone: '15.10' }
|
||||
mount_mutation Mutations::Achievements::Create, alpha: { milestone: '15.8' }
|
||||
mount_mutation Mutations::Achievements::Delete, alpha: { milestone: '15.11' }
|
||||
mount_mutation Mutations::Achievements::Revoke, alpha: { milestone: '15.10' }
|
||||
mount_mutation Mutations::Admin::SidekiqQueues::DeleteJobs
|
||||
mount_mutation Mutations::AlertManagement::CreateAlertIssue
|
||||
|
|
|
|||
|
|
@ -17,3 +17,5 @@ module ProtectedBranchesHelper
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
ProtectedBranchesHelper.prepend_mod
|
||||
|
|
|
|||
|
|
@ -58,12 +58,23 @@ module UsersHelper
|
|||
end
|
||||
|
||||
# Used to preload when you are rendering many projects and checking access
|
||||
#
|
||||
# rubocop: disable CodeReuse/ActiveRecord: `projects` can be array which also responds to pluck
|
||||
def load_max_project_member_accesses(projects)
|
||||
current_user&.max_member_access_for_project_ids(projects.pluck(:id))
|
||||
# There are two different request store paradigms for max member access and
|
||||
# we need to preload both of them. One is keyed User the other is keyed by
|
||||
# Project. See https://gitlab.com/gitlab-org/gitlab/-/issues/396822
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord: `projects` can be array which also responds to pluck
|
||||
project_ids = projects.pluck(:id)
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
if Feature.enabled?(:fix_users_helper_load_max_project_member_accesses)
|
||||
Preloaders::UserMaxAccessLevelInProjectsPreloader
|
||||
.new(project_ids, current_user)
|
||||
.execute
|
||||
end
|
||||
|
||||
current_user&.max_member_access_for_project_ids(project_ids)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def max_project_member_access(project)
|
||||
current_user&.max_member_access_for_project(project.id) || Gitlab::Access::NO_ACCESS
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ module VisibilityLevelHelper
|
|||
when Project
|
||||
project_visibility_level_description(level)
|
||||
when Group
|
||||
group_visibility_level_description(level)
|
||||
group_visibility_level_description(level, form_model)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -125,22 +125,39 @@ module VisibilityLevelHelper
|
|||
def project_visibility_level_description(level)
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
_("Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group.")
|
||||
s_("VisibilityLevel|Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group.")
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
_("The project can be accessed by any logged in user except external users.")
|
||||
s_("VisibilityLevel|The project can be accessed by any logged in user except external users.")
|
||||
when Gitlab::VisibilityLevel::PUBLIC
|
||||
_("The project can be accessed without any authentication.")
|
||||
s_("VisibilityLevel|The project can be accessed without any authentication.")
|
||||
end
|
||||
end
|
||||
|
||||
def group_visibility_level_description(level)
|
||||
def show_updated_public_description_for_setting(group)
|
||||
group && !group.new_record? && Gitlab::CurrentSettings.current_application_settings.try(:should_check_namespace_plan?)
|
||||
end
|
||||
|
||||
def group_visibility_level_description(level, group = nil)
|
||||
case level
|
||||
when Gitlab::VisibilityLevel::PRIVATE
|
||||
_("The group and its projects can only be viewed by members.")
|
||||
s_("VisibilityLevel|The group and its projects can only be viewed by members.")
|
||||
when Gitlab::VisibilityLevel::INTERNAL
|
||||
_("The group and any internal projects can be viewed by any logged in user except external users.")
|
||||
s_("VisibilityLevel|The group and any internal projects can be viewed by any logged in user except external users.")
|
||||
when Gitlab::VisibilityLevel::PUBLIC
|
||||
_("The group and any public projects can be viewed without any authentication.")
|
||||
unless show_updated_public_description_for_setting(group)
|
||||
return s_('VisibilityLevel|The group and any public projects can be viewed without any authentication.')
|
||||
end
|
||||
|
||||
Kernel.format(
|
||||
s_(
|
||||
'VisibilityLevel|The group, any public projects, and any of their members, issues, and merge requests can be viewed without authentication. ' \
|
||||
'Public groups and projects will be indexed by search engines. ' \
|
||||
'Read more about %{free_user_limit_doc_link_start}free user limits%{link_end}, ' \
|
||||
'or %{group_billings_link_start}upgrade to a paid tier%{link_end}.'),
|
||||
free_user_limit_doc_link_start: "<a href='#{help_page_path('user/free_user_limit')}' target='_blank' rel='noopener noreferrer'>".html_safe,
|
||||
group_billings_link_start: "<a href='#{group_billings_path(group)}' target='_blank' rel='noopener noreferrer'>".html_safe,
|
||||
link_end: "</a>".html_safe
|
||||
).html_safe
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ class Project < ApplicationRecord
|
|||
alias_method :parent, :namespace
|
||||
alias_attribute :parent_id, :namespace_id
|
||||
|
||||
has_one :catalog_resource, class_name: 'Ci::Catalog::Resource', inverse_of: :project
|
||||
has_one :last_event, -> { order 'events.created_at DESC' }, class_name: 'Event'
|
||||
has_many :boards
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,33 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Achievements
|
||||
class DestroyService
|
||||
attr_reader :current_user, :achievement
|
||||
|
||||
def initialize(current_user, achievement)
|
||||
@current_user = current_user
|
||||
@achievement = achievement
|
||||
end
|
||||
|
||||
def execute
|
||||
return error_no_permissions unless allowed?
|
||||
|
||||
achievement.delete
|
||||
ServiceResponse.success(payload: achievement)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def allowed?
|
||||
current_user&.can?(:admin_achievement, achievement)
|
||||
end
|
||||
|
||||
def error_no_permissions
|
||||
error('You have insufficient permissions to delete this achievement')
|
||||
end
|
||||
|
||||
def error(message)
|
||||
ServiceResponse.error(message: Array(message))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -18,6 +18,12 @@ module Releases
|
|||
|
||||
return tag unless tag.is_a?(Gitlab::Git::Tag)
|
||||
|
||||
if project.catalog_resource
|
||||
response = Ci::Catalog::ValidateResourceService.new(project, ref).execute
|
||||
|
||||
return error(response.message) if response.error?
|
||||
end
|
||||
|
||||
create_release(tag, evidence_pipeline)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ module ObjectStorage
|
|||
expiration = (Time.current + expiry).utc.to_i
|
||||
|
||||
uri = Addressable::URI.parse(cdn_url)
|
||||
uri.path = path
|
||||
uri.path = Addressable::URI.encode_component(path, Addressable::URI::CharacterClasses::PATH)
|
||||
# Use an Array to preserve order: Google CDN needs to have
|
||||
# Expires, KeyName, and Signature in that order or it will return a 403 error:
|
||||
# https://cloud.google.com/cdn/docs/troubleshooting-steps#signing
|
||||
|
|
|
|||
|
|
@ -34,7 +34,6 @@
|
|||
= dispensable_render_if_exists "shared/namespace_user_cap_reached_alert"
|
||||
= dispensable_render_if_exists "shared/new_user_signups_cap_reached_alert"
|
||||
= yield :page_level_alert
|
||||
= yield :free_user_cap_alert
|
||||
= yield :group_invite_members_banner
|
||||
- unless @hide_breadcrumbs
|
||||
= render "layouts/nav/breadcrumbs"
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
---
|
||||
name: disable_update_max_seats_worker
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114127
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/382725
|
||||
name: arkose_labs_trial_signup_challenge
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/113985
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/395754
|
||||
milestone: '15.10'
|
||||
type: development
|
||||
group: group::utilization
|
||||
group: group::anti-abuse
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
name: fix_users_helper_load_max_project_member_accesses
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/114665
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/396647
|
||||
milestone: '15.11'
|
||||
type: development
|
||||
group: 'group::pipeline execution'
|
||||
default_enabled: false
|
||||
|
|
@ -761,9 +761,6 @@ Gitlab.ee do
|
|||
Settings.cron_jobs['ldap_sync_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['ldap_sync_worker']['cron'] ||= '30 1 * * *'
|
||||
Settings.cron_jobs['ldap_sync_worker']['job_class'] = 'LdapSyncWorker'
|
||||
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['cron'] ||= '0 12 * * *'
|
||||
Settings.cron_jobs['update_max_seats_used_for_gitlab_com_subscriptions_worker']['job_class'] = 'UpdateMaxSeatsUsedForGitlabComSubscriptionsWorker'
|
||||
Settings.cron_jobs['elastic_index_bulk_cron_worker'] ||= Settingslogic.new({})
|
||||
Settings.cron_jobs['elastic_index_bulk_cron_worker']['cron'] ||= '*/1 * * * *'
|
||||
Settings.cron_jobs['elastic_index_bulk_cron_worker']['job_class'] ||= 'ElasticIndexBulkCronWorker'
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
available_in: [Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/user/permissions.html#custom-roles
|
||||
image_url: https://img.youtube.com/vi/46cp_-Rtxps/hqdefault.jpg
|
||||
published_at: 2023-02-02 # YYYY-MM-DD
|
||||
published_at: 2023-02-22 # YYYY-MM-DD
|
||||
release: 15.9
|
||||
- name: Manage license approval policies
|
||||
description: | # Do not modify this line, instead modify the lines below.
|
||||
|
|
@ -26,7 +26,7 @@
|
|||
available_in: [Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/user/compliance/license_approval_policies.html
|
||||
image_url: https://img.youtube.com/vi/34qBQ9t8qO8/hqdefault.jpg
|
||||
published_at: 2023-02-02 # YYYY-MM-DD
|
||||
published_at: 2023-02-22 # YYYY-MM-DD
|
||||
release: 15.9
|
||||
- name: New License Compliance scanner
|
||||
description: | # Do not modify this line, instead modify the lines below.
|
||||
|
|
@ -41,7 +41,7 @@
|
|||
available_in: [Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/user/compliance/license_scanning_of_cyclonedx_files/
|
||||
image_url: https://about.gitlab.com/images/15_9/new_license_scanner.png
|
||||
published_at: 2023-02-02 # YYYY-MM-DD
|
||||
published_at: 2023-02-22 # YYYY-MM-DD
|
||||
release: 15.9
|
||||
- name: Notifications now available in the GitLab for Slack app
|
||||
description: | # Do not modify this line, instead modify the lines below.
|
||||
|
|
@ -56,7 +56,7 @@
|
|||
available_in: [Free, Premium, Ultimate]
|
||||
documentation_link: https://docs.gitlab.com/ee/user/project/integrations/gitlab_slack_application.html#slack-notifications
|
||||
image_url: https://about.gitlab.com/images/15_9/slack_notifications_jan_31-optimized.png
|
||||
published_at: 2023-02-02 # YYYY-MM-DD
|
||||
published_at: 2023-02-22 # YYYY-MM-DD
|
||||
release: 15.9
|
||||
- name: Code Suggestions available in closed beta
|
||||
description: | # Do not modify this line, instead modify the lines below.
|
||||
|
|
@ -71,5 +71,5 @@
|
|||
available_in: [Ultimate]
|
||||
documentation_link: https://about.gitlab.com/releases/2023/02/22/gitlab-15-9-released/#code-suggestions-available-in-closed-beta
|
||||
image_url: https://about.gitlab.com/images/15_9/DemoFastApi.gif
|
||||
published_at: 2023-02-02 # YYYY-MM-DD
|
||||
published_at: 2023-02-22 # YYYY-MM-DD
|
||||
release: 15.9
|
||||
|
|
|
|||
|
|
@ -795,6 +795,29 @@ Input type: `AchievementsCreateInput`
|
|||
| <a id="mutationachievementscreateclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationachievementscreateerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
|
||||
### `Mutation.achievementsDelete`
|
||||
|
||||
WARNING:
|
||||
**Introduced** in 15.11.
|
||||
This feature is in Alpha. It can be changed or removed at any time.
|
||||
|
||||
Input type: `AchievementsDeleteInput`
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationachievementsdeleteachievementid"></a>`achievementId` | [`AchievementsAchievementID!`](#achievementsachievementid) | Global ID of the achievement being deleted. |
|
||||
| <a id="mutationachievementsdeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
|
||||
#### Fields
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="mutationachievementsdeleteachievement"></a>`achievement` | [`Achievement`](#achievement) | Achievement. |
|
||||
| <a id="mutationachievementsdeleteclientmutationid"></a>`clientMutationId` | [`String`](#string) | A unique identifier for the client performing the mutation. |
|
||||
| <a id="mutationachievementsdeleteerrors"></a>`errors` | [`[String!]!`](#string) | Errors encountered during execution of the mutation. |
|
||||
|
||||
### `Mutation.achievementsRevoke`
|
||||
|
||||
WARNING:
|
||||
|
|
|
|||
|
|
@ -140,7 +140,7 @@ The DORA metrics are displayed on the following charts:
|
|||
|
||||
The table below provides an overview of the DORA metrics' data aggregation in different charts.
|
||||
|
||||
| Metric name | Measured values | Data aggregation in the [Value Streams Dashboard](value_streams_dashboard.md) | Data aggregation in CI/CD analytics charts | Data aggregation in Value stream analytics | Data aggregation in Custom insights reporting |
|
||||
| Metric name | Measured values | Data aggregation in the [Value Streams Dashboard](value_streams_dashboard.md) | Data aggregation in [CI/CD analytics charts](ci_cd_analytics.md) | Data aggregation in Value stream analytics | Data aggregation in [Custom insights reporting](../../user/project/insights/index.md#dora-query-parameters) |
|
||||
|---------------------------|-------------------|-----------------------------------------------------|------------------------|-----------------------|----------|
|
||||
| Deployment frequency | Number of successful deployments | daily average per month | daily average | daily average | `day` (default) or `month` |
|
||||
| Lead time for changes | Number of seconds to successfully deliver a commit into production | daily median per month | median time | median time | `day` (default) or `month` |
|
||||
|
|
|
|||
|
|
@ -11,45 +11,23 @@ namespace :gettext do
|
|||
end
|
||||
|
||||
desc 'Regenerate gitlab.pot file'
|
||||
task :regenerate do
|
||||
task regenerate: ['gettext:setup'] do
|
||||
ensure_locale_folder_presence!
|
||||
|
||||
# Clean up folders that do not contain a gitlab.po file
|
||||
Pathname.new(locale_path).children.each do |child|
|
||||
next unless child.directory?
|
||||
|
||||
folder_path = child.to_path
|
||||
|
||||
if File.exist?("#{folder_path}/gitlab.po")
|
||||
# remove all translated files to speed up finding
|
||||
FileUtils.rm Dir["#{folder_path}/gitlab.*"]
|
||||
else
|
||||
# remove empty translation folders so we don't generate un-needed .po files
|
||||
puts "Deleting #{folder_path} as it does not contain a 'gitlab.po' file."
|
||||
|
||||
FileUtils.rm_r folder_path
|
||||
end
|
||||
end
|
||||
|
||||
# remove the `pot` file to ensure it's completely regenerated
|
||||
FileUtils.rm_f(pot_file_path)
|
||||
|
||||
Rake::Task['gettext:find'].invoke
|
||||
|
||||
# leave only the required changes.
|
||||
unless system(*%w(git -c core.hooksPath=/dev/null checkout -- locale/*/gitlab.po))
|
||||
raise 'failed to cleanup generated locale/*/gitlab.po files'
|
||||
end
|
||||
Rake::Task['gettext:pot:create'].invoke
|
||||
|
||||
raise 'gitlab.pot file not generated' unless File.exist?(pot_file_path)
|
||||
|
||||
# Remove timestamps from the pot file
|
||||
pot_content = File.read pot_file_path
|
||||
pot_content.gsub!(/^"POT?\-(?:Creation|Revision)\-Date\:.*\n/, '')
|
||||
pot_content.gsub!(/^"POT?-(?:Creation|Revision)-Date:.*\n/, '')
|
||||
File.write pot_file_path, pot_content
|
||||
|
||||
puts <<~MSG
|
||||
All done. Please commit the changes to `locale/gitlab.pot`.
|
||||
All done. Please commit the changes to `locale/gitlab.pot`.
|
||||
|
||||
MSG
|
||||
end
|
||||
|
|
@ -86,19 +64,7 @@ namespace :gettext do
|
|||
end
|
||||
end
|
||||
|
||||
task :updated_check do
|
||||
# Removing all pre-translated files speeds up `gettext:find` as the
|
||||
# files don't need to be merged.
|
||||
# Having `LC_MESSAGES/gitlab.mo files present also confuses the output.
|
||||
FileUtils.rm Dir['locale/**/gitlab.*']
|
||||
FileUtils.rm_f pot_file_path
|
||||
|
||||
# `gettext:find` writes touches to temp files to `stderr` which would cause
|
||||
# `static-analysis` to report failures. We can ignore these.
|
||||
silence_stderr do
|
||||
Rake::Task['gettext:find'].invoke
|
||||
end
|
||||
|
||||
task updated_check: [:regenerate] do
|
||||
pot_diff = `git diff -- #{pot_file_path} | grep -E '^(\\+|-)msgid'`.strip
|
||||
|
||||
# reset the locale folder for potential next tasks
|
||||
|
|
@ -159,7 +125,7 @@ namespace :gettext do
|
|||
def ensure_locale_folder_presence!
|
||||
unless Dir.exist?(locale_path)
|
||||
raise <<~MSG
|
||||
Cannot find '#{locale_path}' folder. Please ensure you're running this task from the gitlab repo.
|
||||
Cannot find '#{locale_path}' folder. Please ensure you're running this task from the gitlab repo.
|
||||
|
||||
MSG
|
||||
end
|
||||
|
|
|
|||
|
|
@ -33673,9 +33673,6 @@ msgstr ""
|
|||
msgid "Project URL"
|
||||
msgstr ""
|
||||
|
||||
msgid "Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group."
|
||||
msgstr ""
|
||||
|
||||
msgid "Project access token creation is disabled in this group. You can still use and manage existing tokens. %{link_start}Learn more.%{link_end}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -43627,15 +43624,6 @@ msgstr ""
|
|||
msgid "The global settings require you to enable Two-Factor Authentication for your account."
|
||||
msgstr ""
|
||||
|
||||
msgid "The group and any internal projects can be viewed by any logged in user except external users."
|
||||
msgstr ""
|
||||
|
||||
msgid "The group and any public projects can be viewed without any authentication."
|
||||
msgstr ""
|
||||
|
||||
msgid "The group and its projects can only be viewed by members."
|
||||
msgstr ""
|
||||
|
||||
msgid "The group export can be downloaded from:"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -43795,12 +43783,6 @@ msgstr ""
|
|||
msgid "The pipelines schedule runs pipelines in the future, repeatedly, for specific branches or tags. Those scheduled pipelines will inherit limited project access based on their associated user."
|
||||
msgstr ""
|
||||
|
||||
msgid "The project can be accessed by any logged in user except external users."
|
||||
msgstr ""
|
||||
|
||||
msgid "The project can be accessed without any authentication."
|
||||
msgstr ""
|
||||
|
||||
msgid "The project has already been added to your dashboard."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -48058,9 +48040,30 @@ msgstr ""
|
|||
msgid "VisibilityLevel|Private"
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|Project access must be granted explicitly to each user. If this project is part of a group, access is granted to members of the group."
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|Public"
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|The group and any internal projects can be viewed by any logged in user except external users."
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|The group and any public projects can be viewed without any authentication."
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|The group and its projects can only be viewed by members."
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|The group, any public projects, and any of their members, issues, and merge requests can be viewed without authentication. Public groups and projects will be indexed by search engines. Read more about %{free_user_limit_doc_link_start}free user limits%{link_end}, or %{group_billings_link_start}upgrade to a paid tier%{link_end}."
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|The project can be accessed by any logged in user except external users."
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|The project can be accessed without any authentication."
|
||||
msgstr ""
|
||||
|
||||
msgid "VisibilityLevel|Unknown"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,56 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Achievements::Delete, feature_category: :user_profile do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:maintainer) { create(:user) }
|
||||
let_it_be(:recipient) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
let(:achievement) { create(:achievement, namespace: group) }
|
||||
|
||||
describe '#resolve' do
|
||||
subject(:resolve_mutation) do
|
||||
described_class.new(object: nil, context: { current_user: current_user }, field: nil).resolve(
|
||||
achievement_id: achievement&.to_global_id
|
||||
)
|
||||
end
|
||||
|
||||
before_all do
|
||||
group.add_developer(developer)
|
||||
group.add_maintainer(maintainer)
|
||||
end
|
||||
|
||||
context 'when the user does not have permission' do
|
||||
let(:current_user) { developer }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { resolve_mutation }.to raise_error(Gitlab::Graphql::Errors::ResourceNotAvailable)
|
||||
.with_message(Gitlab::Graphql::Authorize::AuthorizeResource::RESOURCE_ACCESS_ERROR)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user has permission' do
|
||||
let(:current_user) { maintainer }
|
||||
|
||||
context 'when the params are invalid' do
|
||||
let(:achievement) { nil }
|
||||
|
||||
it 'returns the validation error' do
|
||||
expect { resolve_mutation }.to raise_error { Gitlab::Graphql::Errors::ArgumentError }
|
||||
end
|
||||
end
|
||||
|
||||
it 'deletes the achievement' do
|
||||
resolve_mutation
|
||||
|
||||
expect(Achievements::Achievement.find_by(id: achievement.id)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
specify { expect(described_class).to require_graphql_authorizations(:admin_achievement) }
|
||||
end
|
||||
|
|
@ -524,4 +524,54 @@ RSpec.describe UsersHelper do
|
|||
})
|
||||
end
|
||||
end
|
||||
|
||||
describe '#load_max_project_member_accesses' do
|
||||
let_it_be(:projects) { create_list(:project, 3) }
|
||||
|
||||
before(:all) do
|
||||
projects.first.add_developer(user)
|
||||
end
|
||||
|
||||
context 'without current_user' do
|
||||
before do
|
||||
allow(helper).to receive(:current_user).and_return(nil)
|
||||
end
|
||||
|
||||
it 'executes no queries' do
|
||||
sample = ActiveRecord::QueryRecorder.new do
|
||||
helper.load_max_project_member_accesses(projects)
|
||||
end
|
||||
|
||||
expect(sample).not_to exceed_query_limit(0)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when current_user is present', :request_store do
|
||||
before do
|
||||
allow(helper).to receive(:current_user).and_return(user)
|
||||
end
|
||||
|
||||
it 'preloads ProjectPolicy#lookup_access_level! and UsersHelper#max_member_project_member_access for current_user in two queries', :aggregate_failures do
|
||||
preload_queries = ActiveRecord::QueryRecorder.new do
|
||||
helper.load_max_project_member_accesses(projects)
|
||||
end
|
||||
|
||||
helper_queries = ActiveRecord::QueryRecorder.new do
|
||||
projects.each do |project|
|
||||
helper.max_project_member_access(project)
|
||||
end
|
||||
end
|
||||
|
||||
access_queries = ActiveRecord::QueryRecorder.new do
|
||||
projects.each do |project|
|
||||
user.can?(:read_code, project)
|
||||
end
|
||||
end
|
||||
|
||||
expect(preload_queries).not_to exceed_query_limit(2)
|
||||
expect(helper_queries).not_to exceed_query_limit(0)
|
||||
expect(access_queries).not_to exceed_query_limit(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe VisibilityLevelHelper do
|
||||
RSpec.describe VisibilityLevelHelper, feature_category: :system_access do
|
||||
include ProjectForksHelper
|
||||
|
||||
let(:project) { build(:project) }
|
||||
|
|
@ -78,6 +78,23 @@ RSpec.describe VisibilityLevelHelper do
|
|||
expect(descriptions.uniq.size).to eq(descriptions.size)
|
||||
expect(descriptions).to all match /group/i
|
||||
end
|
||||
|
||||
it 'returns default description for public group' do
|
||||
expect(descriptions[2]).to eq('The group and any public projects can be viewed without any authentication.')
|
||||
end
|
||||
|
||||
context 'when application setting `should_check_namespace_plan` is true', if: Gitlab.ee? do
|
||||
let(:group) { create(:group) }
|
||||
let(:public_option_description) { visibility_level_description(Gitlab::VisibilityLevel::PUBLIC, group) }
|
||||
|
||||
before do
|
||||
allow(Gitlab::CurrentSettings.current_application_settings).to receive(:should_check_namespace_plan?) { true }
|
||||
end
|
||||
|
||||
it 'returns updated description for public visibility option in group general settings' do
|
||||
expect(public_option_description).to match /^The group, any public projects, and any of their members, issues, and merge requests can be viewed without authentication./
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -493,6 +493,7 @@ container_repositories:
|
|||
- project
|
||||
- name
|
||||
project:
|
||||
- catalog_resource
|
||||
- external_status_checks
|
||||
- base_tags
|
||||
- project_topics
|
||||
|
|
@ -998,3 +999,5 @@ resource_iteration_events:
|
|||
iterations_cadence:
|
||||
- group
|
||||
- iterations
|
||||
catalog_resource:
|
||||
- project
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ RSpec.describe Project, factory_default: :keep, feature_category: :projects do
|
|||
it { is_expected.to have_many(:exported_protected_branches) }
|
||||
it { is_expected.to have_one(:wiki_repository).class_name('Projects::WikiRepository').inverse_of(:project) }
|
||||
it { is_expected.to have_one(:slack_integration) }
|
||||
it { is_expected.to have_one(:catalog_resource) }
|
||||
it { is_expected.to have_one(:microsoft_teams_integration) }
|
||||
it { is_expected.to have_one(:mattermost_integration) }
|
||||
it { is_expected.to have_one(:hangouts_chat_integration) }
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Mutations::Achievements::Delete, feature_category: :user_profile do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:maintainer) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
let!(:achievement) { create(:achievement, namespace: group) }
|
||||
let(:mutation) { graphql_mutation(:achievements_delete, params) }
|
||||
let(:achievement_id) { achievement&.to_global_id }
|
||||
let(:params) { { achievement_id: achievement_id } }
|
||||
|
||||
subject { post_graphql_mutation(mutation, current_user: current_user) }
|
||||
|
||||
def mutation_response
|
||||
graphql_mutation_response(:achievements_delete)
|
||||
end
|
||||
|
||||
before_all do
|
||||
group.add_developer(developer)
|
||||
group.add_maintainer(maintainer)
|
||||
end
|
||||
|
||||
context 'when the user does not have permission' do
|
||||
let(:current_user) { developer }
|
||||
|
||||
it_behaves_like 'a mutation that returns a top-level access error'
|
||||
|
||||
it 'does not revoke any achievements' do
|
||||
expect { subject }.not_to change { Achievements::Achievement.count }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the user has permission' do
|
||||
let(:current_user) { maintainer }
|
||||
|
||||
context 'when the params are invalid' do
|
||||
let(:achievement) { nil }
|
||||
|
||||
it 'returns the validation error' do
|
||||
subject
|
||||
|
||||
expect(graphql_errors.to_s).to include('invalid value for achievementId (Expected value to not be null)')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the achievement_id is invalid' do
|
||||
let(:achievement_id) { "gid://gitlab/Achievements::Achievement/#{non_existing_record_id}" }
|
||||
|
||||
it 'returns the validation error' do
|
||||
subject
|
||||
|
||||
expect(graphql_errors.to_s)
|
||||
.to include("The resource that you are attempting to access does not exist or you don't have permission")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(achievements: false)
|
||||
end
|
||||
|
||||
it 'returns the relevant error' do
|
||||
subject
|
||||
|
||||
expect(graphql_errors.to_s)
|
||||
.to include("The resource that you are attempting to access does not exist or you don't have permission")
|
||||
end
|
||||
end
|
||||
|
||||
it 'deletes the achievement' do
|
||||
expect { subject }.to change { Achievements::Achievement.count }.by(-1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Achievements::DestroyService, feature_category: :user_profile do
|
||||
describe '#execute' do
|
||||
let_it_be(:developer) { create(:user) }
|
||||
let_it_be(:maintainer) { create(:user) }
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
||||
let(:achievement) { create(:achievement, namespace: group) }
|
||||
|
||||
subject(:response) { described_class.new(current_user, achievement).execute }
|
||||
|
||||
before_all do
|
||||
group.add_developer(developer)
|
||||
group.add_maintainer(maintainer)
|
||||
end
|
||||
|
||||
context 'when user does not have permission' do
|
||||
let(:current_user) { developer }
|
||||
|
||||
it 'returns an error' do
|
||||
expect(response).to be_error
|
||||
expect(response.message).to match_array(
|
||||
['You have insufficient permissions to delete this achievement'])
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has permission' do
|
||||
let(:current_user) { maintainer }
|
||||
|
||||
it 'deletes the achievement' do
|
||||
expect(response).to be_success
|
||||
expect(Achievements::Achievement.find_by(id: achievement.id)).to be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -55,6 +55,26 @@ RSpec.describe Releases::CreateService, feature_category: :continuous_integratio
|
|||
end
|
||||
end
|
||||
|
||||
context 'when project is a catalog resource' do
|
||||
let(:ref) { 'master' }
|
||||
let!(:catalog_resource) { create(:catalog_resource, project: project) }
|
||||
|
||||
context 'and it is valid' do
|
||||
let_it_be(:project) { create(:project, :repository, description: 'our components') }
|
||||
|
||||
it_behaves_like 'a successful release creation'
|
||||
end
|
||||
|
||||
context 'and it is invalid' do
|
||||
it 'raises an error and does not update the release' do
|
||||
result = service.execute
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('Project must have a description')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when ref is provided' do
|
||||
let(:ref) { 'master' }
|
||||
let(:tag_name) { 'foobar' }
|
||||
|
|
|
|||
|
|
@ -3310,7 +3310,6 @@
|
|||
- './ee/spec/workers/sync_seat_link_worker_spec.rb'
|
||||
- './ee/spec/workers/todos_destroyer/confidential_epic_worker_spec.rb'
|
||||
- './ee/spec/workers/update_all_mirrors_worker_spec.rb'
|
||||
- './ee/spec/workers/update_max_seats_used_for_gitlab_com_subscriptions_worker_spec.rb'
|
||||
- './ee/spec/workers/vulnerabilities/historical_statistics/deletion_worker_spec.rb'
|
||||
- './ee/spec/workers/vulnerabilities/statistics/adjustment_worker_spec.rb'
|
||||
- './ee/spec/workers/vulnerabilities/statistics/schedule_worker_spec.rb'
|
||||
|
|
@ -10049,7 +10048,6 @@
|
|||
- './spec/tasks/cache/clear/redis_spec.rb'
|
||||
- './spec/tasks/config_lint_spec.rb'
|
||||
- './spec/tasks/dev_rake_spec.rb'
|
||||
- './spec/tasks/gettext_rake_spec.rb'
|
||||
- './spec/tasks/gitlab/artifacts/check_rake_spec.rb'
|
||||
- './spec/tasks/gitlab/artifacts/migrate_rake_spec.rb'
|
||||
- './spec/tasks/gitlab/background_migrations_rake_spec.rb'
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'rake_helper'
|
||||
|
||||
RSpec.describe 'gettext', :silence_stdout do
|
||||
RSpec.describe 'gettext', :silence_stdout, feature_category: :internationalization do
|
||||
let(:locale_path) { Rails.root.join('tmp/gettext_spec') }
|
||||
let(:pot_file_path) { File.join(locale_path, 'gitlab.pot') }
|
||||
|
||||
|
|
@ -35,9 +35,16 @@ RSpec.describe 'gettext', :silence_stdout do
|
|||
end
|
||||
|
||||
describe ':regenerate' do
|
||||
let(:locale_nz_path) { File.join(locale_path, 'en_NZ') }
|
||||
let(:po_file_path) { File.join(locale_nz_path, 'gitlab.po') }
|
||||
|
||||
before do
|
||||
FileUtils.mkdir(locale_nz_path)
|
||||
File.write(po_file_path, fixture_file('valid.po'))
|
||||
|
||||
Rake::Task['gettext:setup'].invoke
|
||||
# this task takes a *really* long time to complete, so stub it for the spec
|
||||
allow(Rake::Task['gettext:find']).to receive(:invoke) { invoke_find.call }
|
||||
allow(Rake::Task['gettext:pot:create']).to receive(:invoke) { invoke_find.call }
|
||||
end
|
||||
|
||||
context 'when the locale folder is not found' do
|
||||
|
|
@ -53,39 +60,6 @@ RSpec.describe 'gettext', :silence_stdout do
|
|||
end
|
||||
end
|
||||
|
||||
context 'where there are existing /**/gitlab.po files' do
|
||||
let(:locale_nz_path) { File.join(locale_path, 'en_NZ') }
|
||||
let(:po_file_path) { File.join(locale_nz_path, 'gitlab.po') }
|
||||
|
||||
let(:invoke_find) { -> { File.write pot_file_path, 'pot file test updates' } }
|
||||
|
||||
before do
|
||||
FileUtils.mkdir(locale_nz_path)
|
||||
File.write(po_file_path, fixture_file('valid.po'))
|
||||
end
|
||||
|
||||
it 'does not remove that locale' do
|
||||
expect { run_rake_task('gettext:regenerate') }
|
||||
.not_to change { Dir.exist?(locale_nz_path) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are locale folders without a gitlab.po file' do
|
||||
let(:empty_locale_path) { File.join(locale_path, 'en_NZ') }
|
||||
|
||||
let(:invoke_find) { -> { File.write pot_file_path, 'pot file test updates' } }
|
||||
|
||||
before do
|
||||
FileUtils.mkdir(empty_locale_path)
|
||||
end
|
||||
|
||||
it 'removes those folders' do
|
||||
expect { run_rake_task('gettext:regenerate') }
|
||||
.to change { Dir.exist?(empty_locale_path) }
|
||||
.to eq false
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the gitlab.pot file cannot be generated' do
|
||||
let(:invoke_find) { -> { true } }
|
||||
|
||||
|
|
@ -95,7 +69,7 @@ RSpec.describe 'gettext', :silence_stdout do
|
|||
end
|
||||
end
|
||||
|
||||
context 'when gettext:find changes the revision dates' do
|
||||
context 'when gettext:pot:create changes the revision dates' do
|
||||
let(:invoke_find) { -> { File.write pot_file_path, fixture_file('valid.po') } }
|
||||
|
||||
before do
|
||||
|
|
|
|||
|
|
@ -99,9 +99,10 @@ RSpec.describe ObjectStorage::CDN::GoogleCDN,
|
|||
let(:path) { '/path/to/file.txt' }
|
||||
let(:expiration) { (Time.current + 10.minutes).utc.to_i }
|
||||
let(:cdn_query_params) { "Expires=#{expiration}&KeyName=#{key_name}" }
|
||||
let(:encoded_path) { Addressable::URI.encode_component(path, Addressable::URI::CharacterClasses::PATH) }
|
||||
|
||||
def verify_signature(url, unsigned_url)
|
||||
expect(url).to start_with("#{options[:url]}#{path}")
|
||||
expect(url).to start_with("#{options[:url]}#{encoded_path}")
|
||||
|
||||
uri = Addressable::URI.parse(url)
|
||||
query = uri.query_values
|
||||
|
|
@ -116,6 +117,16 @@ RSpec.describe ObjectStorage::CDN::GoogleCDN,
|
|||
end
|
||||
end
|
||||
|
||||
context 'with UTF-8 characters in path' do
|
||||
let(:path) { "/path/to/©️job🧪" }
|
||||
let(:url) { subject.signed_url(path) }
|
||||
let(:unsigned_url) { "#{options[:url]}#{encoded_path}?#{cdn_query_params}" }
|
||||
|
||||
it 'returns a valid signed URL' do
|
||||
verify_signature(url, unsigned_url)
|
||||
end
|
||||
end
|
||||
|
||||
context 'with default query parameters' do
|
||||
let(:url) { subject.signed_url(path) }
|
||||
let(:unsigned_url) { "#{options[:url]}#{path}?#{cdn_query_params}" }
|
||||
|
|
|
|||
|
|
@ -10,9 +10,7 @@ RSpec.describe AuthorizedProjectUpdate::UserRefreshOverUserRangeWorker, feature_
|
|||
let(:end_user_id) { start_user_id }
|
||||
let(:execute_worker) { subject.perform(start_user_id, end_user_id) }
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
|
||||
describe '#perform' do
|
||||
context 'checks if project authorization update is required' do
|
||||
|
|
|
|||
|
|
@ -42,7 +42,5 @@ RSpec.describe BuildHooksWorker, feature_category: :continuous_integration do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,7 +24,5 @@ RSpec.describe BuildQueueWorker, feature_category: :continuous_integration do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :sticky
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :sticky
|
||||
end
|
||||
|
|
|
|||
|
|
@ -9,8 +9,7 @@ RSpec.describe Ci::JobArtifacts::TrackArtifactReportWorker, feature_category: :c
|
|||
let_it_be(:user) { create(:user) }
|
||||
|
||||
let_it_be(:pipeline) do
|
||||
create(:ci_pipeline, :with_test_reports, :with_coverage_reports,
|
||||
project: project, user: user)
|
||||
create(:ci_pipeline, :with_test_reports, :with_coverage_reports, project: project, user: user)
|
||||
end
|
||||
|
||||
subject(:perform) { described_class.new.perform(pipeline_id) }
|
||||
|
|
|
|||
|
|
@ -73,9 +73,11 @@ RSpec.describe WorkerContext, feature_category: :shared do
|
|||
|
||||
describe '.bulk_perform_async_with_contexts' do
|
||||
subject do
|
||||
worker.bulk_perform_async_with_contexts(%w(hello world),
|
||||
context_proc: -> (_) { { user: build_stubbed(:user) } },
|
||||
arguments_proc: -> (word) { word })
|
||||
worker.bulk_perform_async_with_contexts(
|
||||
%w(hello world),
|
||||
context_proc: -> (_) { { user: build_stubbed(:user) } },
|
||||
arguments_proc: -> (word) { word }
|
||||
)
|
||||
end
|
||||
|
||||
it 'calls bulk_perform_async with the arguments' do
|
||||
|
|
@ -89,10 +91,12 @@ RSpec.describe WorkerContext, feature_category: :shared do
|
|||
|
||||
describe '.bulk_perform_in_with_contexts' do
|
||||
subject do
|
||||
worker.bulk_perform_in_with_contexts(10.minutes,
|
||||
%w(hello world),
|
||||
context_proc: -> (_) { { user: build_stubbed(:user) } },
|
||||
arguments_proc: -> (word) { word })
|
||||
worker.bulk_perform_in_with_contexts(
|
||||
10.minutes,
|
||||
%w(hello world),
|
||||
context_proc: -> (_) { { user: build_stubbed(:user) } },
|
||||
arguments_proc: -> (word) { word }
|
||||
)
|
||||
end
|
||||
|
||||
it 'calls bulk_perform_in with the arguments and delay' do
|
||||
|
|
|
|||
|
|
@ -60,8 +60,6 @@ RSpec.describe Deployments::HooksWorker, feature_category: :continuous_delivery
|
|||
worker.perform(deployment_id: deployment.id, status_changed_at: status_changed_at)
|
||||
end
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -57,9 +57,11 @@ RSpec.describe DesignManagement::NewVersionWorker, feature_category: :design_man
|
|||
|
||||
context 'the version includes multiple types of action' do
|
||||
let_it_be(:version) do
|
||||
create(:design_version, :with_lfs_file,
|
||||
created_designs: create_list(:design, 1, :with_lfs_file),
|
||||
modified_designs: create_list(:design, 1))
|
||||
create(
|
||||
:design_version, :with_lfs_file,
|
||||
created_designs: create_list(:design, 1, :with_lfs_file),
|
||||
modified_designs: create_list(:design, 1)
|
||||
)
|
||||
end
|
||||
|
||||
it 'creates two system notes' do
|
||||
|
|
|
|||
|
|
@ -493,7 +493,7 @@ RSpec.describe 'Every Sidekiq worker', feature_category: :shared do
|
|||
it 'uses specified numbers of retries for workers with exceptions encoded here', :aggregate_failures do
|
||||
retry_exception_workers.each do |worker|
|
||||
expect(worker.retries).to eq(retry_exceptions[worker.klass.to_s]),
|
||||
"#{worker.klass} has #{worker.retries} retries, expected #{retry_exceptions[worker.klass]}"
|
||||
"#{worker.klass} has #{worker.retries} retries, expected #{retry_exceptions[worker.klass]}"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -88,10 +88,11 @@ RSpec.describe Integrations::IrkerWorker, '#perform', feature_category: :integra
|
|||
|
||||
context 'with new commits to existing branch' do
|
||||
it 'sends a correct message with a compare url' do
|
||||
compare_url = Gitlab::Routing.url_helpers
|
||||
.project_compare_url(project,
|
||||
from: Commit.truncate_sha(push_data[:before]),
|
||||
to: Commit.truncate_sha(push_data[:after]))
|
||||
compare_url = Gitlab::Routing.url_helpers.project_compare_url(
|
||||
project,
|
||||
from: Commit.truncate_sha(push_data[:before]),
|
||||
to: Commit.truncate_sha(push_data[:after])
|
||||
)
|
||||
|
||||
message = "pushed #{push_data['total_commits_count']} " \
|
||||
"new commits to master: #{compare_url}"
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe JiraConnect::SyncBranchWorker, feature_category: :integrations do
|
||||
include AfterNextHelpers
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
|
||||
describe '#perform' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe ::JiraConnect::SyncBuildsWorker, feature_category: :integrations do
|
||||
include AfterNextHelpers
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
|
||||
describe '#perform' do
|
||||
let_it_be(:pipeline) { create(:ci_pipeline) }
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe ::JiraConnect::SyncDeploymentsWorker, feature_category: :integrations do
|
||||
include AfterNextHelpers
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
|
||||
describe '#perform' do
|
||||
let_it_be(:deployment) { create(:deployment) }
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe ::JiraConnect::SyncFeatureFlagsWorker, feature_category: :integrations do
|
||||
include AfterNextHelpers
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
|
||||
describe '#perform' do
|
||||
let_it_be(:feature_flag) { create(:operations_feature_flag) }
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe JiraConnect::SyncMergeRequestWorker, feature_category: :integrations do
|
||||
include AfterNextHelpers
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
|
||||
describe '#perform' do
|
||||
let_it_be(:group) { create(:group) }
|
||||
|
|
|
|||
|
|
@ -5,9 +5,7 @@ require 'spec_helper'
|
|||
RSpec.describe JiraConnect::SyncProjectWorker, factory_default: :keep, feature_category: :integrations do
|
||||
include AfterNextHelpers
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
|
||||
describe '#perform' do
|
||||
let_it_be(:project) { create_default(:project).freeze }
|
||||
|
|
|
|||
|
|
@ -12,8 +12,11 @@ RSpec.describe MergeRequests::DeleteSourceBranchWorker, feature_category: :sourc
|
|||
describe '#perform' do
|
||||
before do
|
||||
allow_next_instance_of(::Projects::DeleteBranchWorker) do |instance|
|
||||
allow(instance).to receive(:perform).with(merge_request.source_project.id, user.id,
|
||||
merge_request.source_branch)
|
||||
allow(instance).to receive(:perform).with(
|
||||
merge_request.source_project.id,
|
||||
user.id,
|
||||
merge_request.source_branch
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -36,8 +39,11 @@ RSpec.describe MergeRequests::DeleteSourceBranchWorker, feature_category: :sourc
|
|||
context 'with existing user and merge request' do
|
||||
it 'calls delete branch worker' do
|
||||
expect_next_instance_of(::Projects::DeleteBranchWorker) do |instance|
|
||||
expect(instance).to receive(:perform).with(merge_request.source_project.id, user.id,
|
||||
merge_request.source_branch)
|
||||
expect(instance).to receive(:perform).with(
|
||||
merge_request.source_project.id,
|
||||
user.id,
|
||||
merge_request.source_branch
|
||||
)
|
||||
end
|
||||
|
||||
worker.perform(merge_request.id, sha, user.id)
|
||||
|
|
|
|||
|
|
@ -74,9 +74,12 @@ RSpec.describe MergeRequests::UpdateHeadPipelineWorker, feature_category: :code_
|
|||
|
||||
context 'when there is no pipeline for source branch' do
|
||||
it "does not update merge request head pipeline" do
|
||||
merge_request = create(:merge_request, source_branch: 'feature',
|
||||
target_branch: "branch_1",
|
||||
source_project: project)
|
||||
merge_request = create(
|
||||
:merge_request,
|
||||
source_branch: 'feature',
|
||||
target_branch: "branch_1",
|
||||
source_project: project
|
||||
)
|
||||
|
||||
subject
|
||||
|
||||
|
|
@ -96,10 +99,13 @@ RSpec.describe MergeRequests::UpdateHeadPipelineWorker, feature_category: :code_
|
|||
end
|
||||
|
||||
it 'updates head pipeline for merge request' do
|
||||
merge_request = create(:merge_request, source_branch: 'feature',
|
||||
target_branch: "master",
|
||||
source_project: project,
|
||||
target_project: target_project)
|
||||
merge_request = create(
|
||||
:merge_request,
|
||||
source_branch: 'feature',
|
||||
target_branch: "master",
|
||||
source_project: project,
|
||||
target_project: target_project
|
||||
)
|
||||
|
||||
subject
|
||||
|
||||
|
|
@ -109,9 +115,12 @@ RSpec.describe MergeRequests::UpdateHeadPipelineWorker, feature_category: :code_
|
|||
|
||||
context 'when the pipeline is not the latest for the branch' do
|
||||
it 'does not update merge request head pipeline' do
|
||||
merge_request = create(:merge_request, source_branch: 'master',
|
||||
target_branch: "branch_1",
|
||||
source_project: project)
|
||||
merge_request = create(
|
||||
:merge_request,
|
||||
source_branch: 'master',
|
||||
target_branch: "branch_1",
|
||||
source_project: project
|
||||
)
|
||||
|
||||
create(:ci_pipeline, project: pipeline.project, ref: pipeline.ref)
|
||||
|
||||
|
|
@ -127,9 +136,12 @@ RSpec.describe MergeRequests::UpdateHeadPipelineWorker, feature_category: :code_
|
|||
end
|
||||
|
||||
it 'updates merge request head pipeline reference' do
|
||||
merge_request = create(:merge_request, source_branch: 'master',
|
||||
target_branch: 'feature',
|
||||
source_project: project)
|
||||
merge_request = create(
|
||||
:merge_request,
|
||||
source_branch: 'master',
|
||||
target_branch: 'feature',
|
||||
source_project: project
|
||||
)
|
||||
|
||||
subject
|
||||
|
||||
|
|
|
|||
|
|
@ -90,9 +90,7 @@ RSpec.describe Namespaces::RootStatisticsWorker, '#perform', feature_category: :
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :sticky
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :sticky
|
||||
|
||||
it 'has the `until_executed` deduplicate strategy' do
|
||||
expect(described_class.get_deduplicate_strategy).to eq(:until_executed)
|
||||
|
|
|
|||
|
|
@ -16,9 +16,13 @@ RSpec.describe ObjectPool::DestroyWorker, feature_category: :shared do
|
|||
subject { described_class.new }
|
||||
|
||||
it 'requests Gitaly to remove the object pool' do
|
||||
expect(Gitlab::GitalyClient).to receive(:call)
|
||||
.with(pool.shard_name, :object_pool_service, :delete_object_pool,
|
||||
Object, timeout: Gitlab::GitalyClient.long_timeout)
|
||||
expect(Gitlab::GitalyClient).to receive(:call).with(
|
||||
pool.shard_name,
|
||||
:object_pool_service,
|
||||
:delete_object_pool,
|
||||
Object,
|
||||
timeout: Gitlab::GitalyClient.long_timeout
|
||||
)
|
||||
|
||||
subject.perform(pool.id)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -37,7 +37,5 @@ RSpec.describe PipelineHooksWorker, feature_category: :continuous_integration do
|
|||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
end
|
||||
|
|
|
|||
|
|
@ -6,19 +6,19 @@ RSpec.describe PipelineMetricsWorker, feature_category: :continuous_integration
|
|||
let(:project) { create(:project, :repository) }
|
||||
|
||||
let!(:merge_request) do
|
||||
create(:merge_request, source_project: project,
|
||||
source_branch: pipeline.ref,
|
||||
head_pipeline: pipeline)
|
||||
create(:merge_request, source_project: project, source_branch: pipeline.ref, head_pipeline: pipeline)
|
||||
end
|
||||
|
||||
let(:pipeline) do
|
||||
create(:ci_empty_pipeline,
|
||||
status: status,
|
||||
project: project,
|
||||
ref: 'master',
|
||||
sha: project.repository.commit('master').id,
|
||||
started_at: 1.hour.ago,
|
||||
finished_at: Time.current)
|
||||
create(
|
||||
:ci_empty_pipeline,
|
||||
status: status,
|
||||
project: project,
|
||||
ref: 'master',
|
||||
sha: project.repository.commit('master').id,
|
||||
started_at: 1.hour.ago,
|
||||
finished_at: Time.current
|
||||
)
|
||||
end
|
||||
|
||||
let(:status) { 'pending' }
|
||||
|
|
|
|||
|
|
@ -82,11 +82,13 @@ RSpec.describe ProcessCommitWorker, feature_category: :source_code_management do
|
|||
|
||||
context 'when commit is a merge request merge commit to the default branch' do
|
||||
let(:merge_request) do
|
||||
create(:merge_request,
|
||||
description: "Closes #{issue.to_reference}",
|
||||
source_branch: 'feature-merged',
|
||||
target_branch: 'master',
|
||||
source_project: project)
|
||||
create(
|
||||
:merge_request,
|
||||
description: "Closes #{issue.to_reference}",
|
||||
source_branch: 'feature-merged',
|
||||
target_branch: 'master',
|
||||
source_project: project
|
||||
)
|
||||
end
|
||||
|
||||
let(:commit) do
|
||||
|
|
|
|||
|
|
@ -92,8 +92,11 @@ RSpec.describe Projects::InactiveProjectsDeletionCronWorker, feature_category: :
|
|||
|
||||
it 'invokes Projects::InactiveProjectsDeletionNotificationWorker for inactive projects' do
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
expect(redis).to receive(:hset).with('inactive_projects_deletion_warning_email_notified',
|
||||
"project:#{inactive_large_project.id}", Date.current)
|
||||
expect(redis).to receive(:hset).with(
|
||||
'inactive_projects_deletion_warning_email_notified',
|
||||
"project:#{inactive_large_project.id}",
|
||||
Date.current
|
||||
)
|
||||
end
|
||||
expect(::Projects::InactiveProjectsDeletionNotificationWorker).to receive(:perform_async).with(
|
||||
inactive_large_project.id, deletion_date).and_call_original
|
||||
|
|
@ -104,8 +107,11 @@ RSpec.describe Projects::InactiveProjectsDeletionCronWorker, feature_category: :
|
|||
|
||||
it 'does not invoke InactiveProjectsDeletionNotificationWorker for already notified inactive projects' do
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
redis.hset('inactive_projects_deletion_warning_email_notified', "project:#{inactive_large_project.id}",
|
||||
Date.current.to_s)
|
||||
redis.hset(
|
||||
'inactive_projects_deletion_warning_email_notified',
|
||||
"project:#{inactive_large_project.id}",
|
||||
Date.current.to_s
|
||||
)
|
||||
end
|
||||
|
||||
expect(::Projects::InactiveProjectsDeletionNotificationWorker).not_to receive(:perform_async)
|
||||
|
|
@ -116,8 +122,11 @@ RSpec.describe Projects::InactiveProjectsDeletionCronWorker, feature_category: :
|
|||
|
||||
it 'invokes Projects::DestroyService for projects that are inactive even after being notified' do
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
redis.hset('inactive_projects_deletion_warning_email_notified', "project:#{inactive_large_project.id}",
|
||||
15.months.ago.to_date.to_s)
|
||||
redis.hset(
|
||||
'inactive_projects_deletion_warning_email_notified',
|
||||
"project:#{inactive_large_project.id}",
|
||||
15.months.ago.to_date.to_s
|
||||
)
|
||||
end
|
||||
|
||||
expect(::Projects::InactiveProjectsDeletionNotificationWorker).not_to receive(:perform_async)
|
||||
|
|
@ -129,8 +138,9 @@ RSpec.describe Projects::InactiveProjectsDeletionCronWorker, feature_category: :
|
|||
expect(inactive_large_project.reload.pending_delete).to eq(true)
|
||||
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
expect(redis.hget('inactive_projects_deletion_warning_email_notified',
|
||||
"project:#{inactive_large_project.id}")).to be_nil
|
||||
expect(
|
||||
redis.hget('inactive_projects_deletion_warning_email_notified', "project:#{inactive_large_project.id}")
|
||||
).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -22,14 +22,15 @@ RSpec.describe Projects::InactiveProjectsDeletionNotificationWorker, feature_cat
|
|||
worker.perform(project.id, deletion_date)
|
||||
|
||||
Gitlab::Redis::SharedState.with do |redis|
|
||||
expect(redis.hget('inactive_projects_deletion_warning_email_notified',
|
||||
"project:#{project.id}")).to eq(Date.current.to_s)
|
||||
expect(
|
||||
redis.hget('inactive_projects_deletion_warning_email_notified', "project:#{project.id}")
|
||||
).to eq(Date.current.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
it 'rescues and logs the exception if project does not exist' do
|
||||
expect(Gitlab::ErrorTracking).to receive(:log_exception).with(instance_of(ActiveRecord::RecordNotFound),
|
||||
{ project_id: non_existing_project_id })
|
||||
expect(Gitlab::ErrorTracking).to receive(:log_exception)
|
||||
.with(instance_of(ActiveRecord::RecordNotFound), { project_id: non_existing_project_id })
|
||||
|
||||
worker.perform(non_existing_project_id, deletion_date)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,11 +10,13 @@ RSpec.describe RebaseWorker, '#perform', feature_category: :source_code_manageme
|
|||
let(:forked_project) { fork_project(upstream_project, nil, repository: true) }
|
||||
|
||||
let(:merge_request) do
|
||||
create(:merge_request,
|
||||
source_project: forked_project,
|
||||
source_branch: 'feature_conflict',
|
||||
target_project: upstream_project,
|
||||
target_branch: 'master')
|
||||
create(
|
||||
:merge_request,
|
||||
source_project: forked_project,
|
||||
source_branch: 'feature_conflict',
|
||||
target_project: upstream_project,
|
||||
target_branch: 'master'
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the correct project for running hooks' do
|
||||
|
|
|
|||
|
|
@ -30,8 +30,10 @@ RSpec.describe RemoteMirrorNotificationWorker, :mailer, feature_category: :sourc
|
|||
end
|
||||
|
||||
it 'does nothing when a notification has already been sent' do
|
||||
mirror.update_columns(last_error: "There was a problem fetching",
|
||||
error_notification_sent: true)
|
||||
mirror.update_columns(
|
||||
last_error: "There was a problem fetching",
|
||||
error_notification_sent: true
|
||||
)
|
||||
|
||||
expect(NotificationService).not_to receive(:new)
|
||||
|
||||
|
|
|
|||
|
|
@ -35,8 +35,10 @@ RSpec.describe RemoveExpiredMembersWorker, feature_category: :system_access do
|
|||
|
||||
new_job = Sidekiq::Worker.jobs.last
|
||||
|
||||
expect(new_job).to include('meta.project' => expired_project_member.project.full_path,
|
||||
'meta.user' => expired_project_member.user.username)
|
||||
expect(new_job).to include(
|
||||
'meta.project' => expired_project_member.project.full_path,
|
||||
'meta.user' => expired_project_member.user.username
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -60,8 +62,7 @@ RSpec.describe RemoveExpiredMembersWorker, feature_category: :system_access do
|
|||
worker.perform
|
||||
|
||||
expect(
|
||||
Users::GhostUserMigration.where(user: expired_project_bot,
|
||||
initiator_user: nil)
|
||||
Users::GhostUserMigration.where(user: expired_project_bot, initiator_user: nil)
|
||||
).to be_exists
|
||||
end
|
||||
end
|
||||
|
|
@ -116,8 +117,10 @@ RSpec.describe RemoveExpiredMembersWorker, feature_category: :system_access do
|
|||
|
||||
new_job = Sidekiq::Worker.jobs.last
|
||||
|
||||
expect(new_job).to include('meta.root_namespace' => expired_group_member.group.full_path,
|
||||
'meta.user' => expired_group_member.user.username)
|
||||
expect(new_job).to include(
|
||||
'meta.root_namespace' => expired_group_member.group.full_path,
|
||||
'meta.user' => expired_group_member.user.username
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -13,15 +13,19 @@ RSpec.describe RemoveUnacceptedMemberInvitesWorker, feature_category: :system_ac
|
|||
|
||||
it 'removes unaccepted members', :aggregate_failures do
|
||||
unaccepted_group_invitee = create(
|
||||
:group_member, invite_token: 't0ken',
|
||||
invite_email: 'group_invitee@example.com',
|
||||
user: nil,
|
||||
created_at: Time.current - 5.days)
|
||||
:group_member,
|
||||
invite_token: 't0ken',
|
||||
invite_email: 'group_invitee@example.com',
|
||||
user: nil,
|
||||
created_at: Time.current - 5.days
|
||||
)
|
||||
unaccepted_project_invitee = create(
|
||||
:project_member, invite_token: 't0ken',
|
||||
invite_email: 'project_invitee@example.com',
|
||||
user: nil,
|
||||
created_at: Time.current - 5.days)
|
||||
:project_member,
|
||||
invite_token: 't0ken',
|
||||
invite_email: 'project_invitee@example.com',
|
||||
user: nil,
|
||||
created_at: Time.current - 5.days
|
||||
)
|
||||
|
||||
expect { worker.perform }.to change { Member.count }.by(-2)
|
||||
|
||||
|
|
@ -33,13 +37,17 @@ RSpec.describe RemoveUnacceptedMemberInvitesWorker, feature_category: :system_ac
|
|||
context 'invited members still within expiration threshold' do
|
||||
it 'leaves invited members', :aggregate_failures do
|
||||
group_invitee = create(
|
||||
:group_member, invite_token: 't0ken',
|
||||
invite_email: 'group_invitee@example.com',
|
||||
user: nil)
|
||||
:group_member,
|
||||
invite_token: 't0ken',
|
||||
invite_email: 'group_invitee@example.com',
|
||||
user: nil
|
||||
)
|
||||
project_invitee = create(
|
||||
:project_member, invite_token: 't0ken',
|
||||
invite_email: 'project_invitee@example.com',
|
||||
user: nil)
|
||||
:project_member,
|
||||
invite_token: 't0ken',
|
||||
invite_email: 'project_invitee@example.com',
|
||||
user: nil
|
||||
)
|
||||
|
||||
expect { worker.perform }.not_to change { Member.count }
|
||||
|
||||
|
|
@ -56,15 +64,19 @@ RSpec.describe RemoveUnacceptedMemberInvitesWorker, feature_category: :system_ac
|
|||
it 'leaves accepted members', :aggregate_failures do
|
||||
user = create(:user)
|
||||
accepted_group_invitee = create(
|
||||
:group_member, invite_token: 't0ken',
|
||||
invite_email: 'group_invitee@example.com',
|
||||
user: user,
|
||||
created_at: Time.current - 5.days)
|
||||
:group_member,
|
||||
invite_token: 't0ken',
|
||||
invite_email: 'group_invitee@example.com',
|
||||
user: user,
|
||||
created_at: Time.current - 5.days
|
||||
)
|
||||
accepted_project_invitee = create(
|
||||
:project_member, invite_token: nil,
|
||||
invite_email: 'project_invitee@example.com',
|
||||
user: user,
|
||||
created_at: Time.current - 5.days)
|
||||
:project_member,
|
||||
invite_token: nil,
|
||||
invite_email: 'project_invitee@example.com',
|
||||
user: user,
|
||||
created_at: Time.current - 5.days
|
||||
)
|
||||
|
||||
expect { worker.perform }.not_to change { Member.count }
|
||||
|
||||
|
|
|
|||
|
|
@ -13,24 +13,16 @@ RSpec.describe RemoveUnreferencedLfsObjectsWorker, feature_category: :source_cod
|
|||
let!(:referenced_lfs_object1) { create(:lfs_object, oid: '3' * 64) }
|
||||
let!(:referenced_lfs_object2) { create(:lfs_object, oid: '4' * 64) }
|
||||
let!(:lfs_objects_project1_1) do
|
||||
create(:lfs_objects_project,
|
||||
project: project1,
|
||||
lfs_object: referenced_lfs_object1
|
||||
create(:lfs_objects_project, project: project1, lfs_object: referenced_lfs_object1
|
||||
)
|
||||
end
|
||||
|
||||
let!(:lfs_objects_project2_1) do
|
||||
create(:lfs_objects_project,
|
||||
project: project2,
|
||||
lfs_object: referenced_lfs_object1
|
||||
)
|
||||
create(:lfs_objects_project, project: project2, lfs_object: referenced_lfs_object1)
|
||||
end
|
||||
|
||||
let!(:lfs_objects_project1_2) do
|
||||
create(:lfs_objects_project,
|
||||
project: project1,
|
||||
lfs_object: referenced_lfs_object2
|
||||
)
|
||||
create(:lfs_objects_project, project: project1, lfs_object: referenced_lfs_object2)
|
||||
end
|
||||
|
||||
it 'removes unreferenced lfs objects' do
|
||||
|
|
|
|||
|
|
@ -57,14 +57,16 @@ RSpec.describe RepositoryUpdateRemoteMirrorWorker, :clean_gitlab_redis_shared_st
|
|||
end
|
||||
|
||||
it 'retries 3 times for the worker to finish before rescheduling' do
|
||||
expect(subject).to receive(:in_lock)
|
||||
.with("#{described_class.name}:#{remote_mirror.id}",
|
||||
retries: 3,
|
||||
ttl: remote_mirror.max_runtime,
|
||||
sleep_sec: described_class::LOCK_WAIT_TIME)
|
||||
.and_raise(Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError)
|
||||
expect(described_class).to receive(:perform_in)
|
||||
.with(remote_mirror.backoff_delay, remote_mirror.id, scheduled_time, 0)
|
||||
expect(subject).to receive(:in_lock).with(
|
||||
"#{described_class.name}:#{remote_mirror.id}",
|
||||
retries: 3,
|
||||
ttl: remote_mirror.max_runtime,
|
||||
sleep_sec: described_class::LOCK_WAIT_TIME
|
||||
).and_raise(Gitlab::ExclusiveLeaseHelpers::FailedToObtainLockError)
|
||||
|
||||
expect(described_class)
|
||||
.to receive(:perform_in)
|
||||
.with(remote_mirror.backoff_delay, remote_mirror.id, scheduled_time, 0)
|
||||
|
||||
subject.perform(remote_mirror.id, scheduled_time)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -137,9 +137,11 @@ RSpec.describe RunPipelineScheduleWorker, feature_category: :continuous_integrat
|
|||
|
||||
expect(Gitlab::ErrorTracking)
|
||||
.to receive(:track_and_raise_for_dev_exception)
|
||||
.with(ActiveRecord::StatementInvalid,
|
||||
issue_url: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/41231',
|
||||
schedule_id: pipeline_schedule.id).once
|
||||
.with(
|
||||
ActiveRecord::StatementInvalid,
|
||||
issue_url: 'https://gitlab.com/gitlab-org/gitlab-foss/issues/41231',
|
||||
schedule_id: pipeline_schedule.id
|
||||
).once
|
||||
end
|
||||
|
||||
it 'increments Prometheus counter' do
|
||||
|
|
|
|||
|
|
@ -66,11 +66,13 @@ RSpec.describe UpdateHeadPipelineForMergeRequestWorker, feature_category: :conti
|
|||
|
||||
context 'when a merge request pipeline exists' do
|
||||
let_it_be(:merge_request_pipeline) do
|
||||
create(:ci_pipeline,
|
||||
project: project,
|
||||
source: :merge_request_event,
|
||||
sha: latest_sha,
|
||||
merge_request: merge_request)
|
||||
create(
|
||||
:ci_pipeline,
|
||||
project: project,
|
||||
source: :merge_request_event,
|
||||
sha: latest_sha,
|
||||
merge_request: merge_request
|
||||
)
|
||||
end
|
||||
|
||||
it 'sets the merge request pipeline as the head pipeline' do
|
||||
|
|
|
|||
|
|
@ -28,8 +28,6 @@ RSpec.describe WebHookWorker, feature_category: :integrations do
|
|||
.to change { Gitlab::WebHooks::RecursionDetection::UUID.instance.request_uuid }.to(uuid)
|
||||
end
|
||||
|
||||
it_behaves_like 'worker with data consistency',
|
||||
described_class,
|
||||
data_consistency: :delayed
|
||||
it_behaves_like 'worker with data consistency', described_class, data_consistency: :delayed
|
||||
end
|
||||
end
|
||||
|
|
|
|||
Loading…
Reference in New Issue