diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-24 18:12:40 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-11-24 18:12:40 +0300 |
commit | 92849dc177d5e0d11f89b4ca75f4e3e45ad6341b (patch) | |
tree | 6dd67ad9b1edc1ca2ded39077c041ffdd0ea38e0 | |
parent | 83ffdf48518e121c1ccab9d7913d3f7e79d7766c (diff) |
Add latest changes from gitlab-org/gitlab@master
87 files changed, 955 insertions, 198 deletions
diff --git a/.gitlab/ci/workhorse.gitlab-ci.yml b/.gitlab/ci/workhorse.gitlab-ci.yml index f10ef3ac41f..9aa0b349c16 100644 --- a/.gitlab/ci/workhorse.gitlab-ci.yml +++ b/.gitlab/ci/workhorse.gitlab-ci.yml @@ -47,7 +47,7 @@ workhorse:test fips: extends: .workhorse:test parallel: matrix: - - GO_VERSION: ["1.19", "1.20", "1.21"] + - GO_VERSION: ["1.20", "1.21"] REDIS_VERSION: ["7.0", "6.2"] image: ${REGISTRY_HOST}/${REGISTRY_GROUP}/gitlab-build-images/ubi-${UBI_VERSION}-ruby-${RUBY_VERSION}-golang-${GO_VERSION}-rust-${RUST_VERSION}:rubygems-${RUBYGEMS_VERSION}-git-2.36-exiftool-12.60 variables: diff --git a/.rubocop_todo/capybara/testid_finders.yml b/.rubocop_todo/capybara/testid_finders.yml index ddaf1e27beb..f78470479e9 100644 --- a/.rubocop_todo/capybara/testid_finders.yml +++ b/.rubocop_todo/capybara/testid_finders.yml @@ -15,18 +15,6 @@ Capybara/TestidFinders: - 'spec/features/groups/members/sort_members_spec.rb' - 'spec/features/groups/members/tabs_spec.rb' - 'spec/features/groups/merge_requests_spec.rb' - - 'spec/features/groups/milestone_spec.rb' - - 'spec/features/groups/packages_spec.rb' - - 'spec/features/groups/settings/ci_cd_spec.rb' - - 'spec/features/groups/settings/packages_and_registries_spec.rb' - - 'spec/features/groups/show_spec.rb' - - 'spec/features/groups_spec.rb' - - 'spec/features/incidents/incident_details_spec.rb' - - 'spec/features/incidents/incident_timeline_events_spec.rb' - - 'spec/features/issuables/shortcuts_issuable_spec.rb' - - 'spec/features/issues/form_spec.rb' - - 'spec/features/issues/incident_issue_spec.rb' - - 'spec/features/issues/issue_detail_spec.rb' - 'spec/features/issues/issue_sidebar_spec.rb' - 'spec/features/issues/issue_state_spec.rb' - 'spec/features/issues/user_creates_issue_spec.rb' diff --git a/.rubocop_todo/rspec/file_path.yml b/.rubocop_todo/rspec/file_path.yml index 06832184c04..cf457973e0e 100644 --- a/.rubocop_todo/rspec/file_path.yml +++ b/.rubocop_todo/rspec/file_path.yml @@ -31,6 +31,7 @@ RSpec/FilePath: - 'spec/requests/api/ci/runner/jobs_artifacts_spec.rb' - 'spec/requests/api/ci/runner/jobs_put_spec.rb' - 'spec/requests/api/ci/runner/jobs_request_post_spec.rb' + - 'spec/requests/api/ci/runner/jobs_request_yamls_spec.rb' - 'spec/requests/api/ci/runner/jobs_trace_spec.rb' - 'spec/requests/api/ci/runner/runners_delete_spec.rb' - 'spec/requests/api/ci/runner/runners_post_spec.rb' diff --git a/.rubocop_todo/rspec/named_subject.yml b/.rubocop_todo/rspec/named_subject.yml index 960b5bb5a05..230c2928343 100644 --- a/.rubocop_todo/rspec/named_subject.yml +++ b/.rubocop_todo/rspec/named_subject.yml @@ -830,7 +830,6 @@ RSpec/NamedSubject: - 'ee/spec/requests/groups/settings/merge_requests_controller_spec.rb' - 'ee/spec/requests/groups_controller_spec.rb' - 'ee/spec/requests/projects/analytics/cycle_analytics/stages_controller_spec.rb' - - 'ee/spec/requests/projects/metrics_controller_spec.rb' - 'ee/spec/requests/projects/pipelines_controller_spec.rb' - 'ee/spec/requests/projects/requirements_management/requirements_controller_spec.rb' - 'ee/spec/requests/projects/security/policies_controller_spec.rb' @@ -894,7 +893,6 @@ RSpec/NamedSubject: - 'ee/spec/serializers/vulnerability_entity_spec.rb' - 'ee/spec/serializers/vulnerability_note_entity_spec.rb' - 'ee/spec/services/admin/email_service_spec.rb' - - 'ee/spec/services/ai/service_access_tokens_storage_service_spec.rb' - 'ee/spec/services/analytics/cycle_analytics/stages/list_service_spec.rb' - 'ee/spec/services/analytics/cycle_analytics/value_streams/update_service_spec.rb' - 'ee/spec/services/analytics/devops_adoption/enabled_namespaces/find_or_create_service_spec.rb' @@ -1018,7 +1016,6 @@ RSpec/NamedSubject: - 'ee/spec/services/ee/projects/autocomplete_service_spec.rb' - 'ee/spec/services/ee/projects/deploy_tokens/create_service_spec.rb' - 'ee/spec/services/ee/projects/deploy_tokens/destroy_service_spec.rb' - - 'ee/spec/services/ee/projects/unlink_fork_service_spec.rb' - 'ee/spec/services/ee/resource_events/change_labels_service_spec.rb' - 'ee/spec/services/ee/system_notes/issuables_service_spec.rb' - 'ee/spec/services/ee/terraform/states/destroy_service_spec.rb' @@ -1096,7 +1093,6 @@ RSpec/NamedSubject: - 'ee/spec/services/llm/generate_test_file_service_spec.rb' - 'ee/spec/services/llm/git_command_service_spec.rb' - 'ee/spec/services/llm/resolve_vulnerability_service_spec.rb' - - 'ee/spec/services/member_roles/create_service_spec.rb' - 'ee/spec/services/merge_request_approval_settings/update_service_spec.rb' - 'ee/spec/services/merge_requests/merge_service_spec.rb' - 'ee/spec/services/merge_requests/mergeability/check_external_status_checks_passed_service_spec.rb' @@ -1778,6 +1774,7 @@ RSpec/NamedSubject: - 'spec/lib/bulk_imports/projects/graphql/get_project_query_spec.rb' - 'spec/lib/bulk_imports/projects/graphql/get_repository_query_spec.rb' - 'spec/lib/bulk_imports/projects/graphql/get_snippet_repository_query_spec.rb' + - 'spec/lib/bulk_imports/projects/pipelines/legacy_references_pipeline_spec.rb' - 'spec/lib/bulk_imports/projects/pipelines/references_pipeline_spec.rb' - 'spec/lib/bulk_imports/projects/stage_spec.rb' - 'spec/lib/bulk_imports/source_url_builder_spec.rb' @@ -2589,7 +2586,6 @@ RSpec/NamedSubject: - 'spec/mailers/emails/imports_spec.rb' - 'spec/mailers/emails/issues_spec.rb' - 'spec/mailers/emails/merge_requests_spec.rb' - - 'spec/mailers/emails/service_desk_spec.rb' - 'spec/mailers/notify_spec.rb' - 'spec/metrics_server/metrics_server_spec.rb' - 'spec/migrations/20221028022627_add_index_on_password_last_changed_at_to_user_details_spec.rb' @@ -2744,7 +2740,6 @@ RSpec/NamedSubject: - 'spec/models/integrations/bamboo_spec.rb' - 'spec/models/integrations/base_chat_notification_spec.rb' - 'spec/models/integrations/base_issue_tracker_spec.rb' - - 'spec/models/integrations/base_third_party_wiki_spec.rb' - 'spec/models/integrations/bugzilla_spec.rb' - 'spec/models/integrations/buildkite_spec.rb' - 'spec/models/integrations/campfire_spec.rb' @@ -2776,7 +2771,6 @@ RSpec/NamedSubject: - 'spec/models/integrations/pivotaltracker_spec.rb' - 'spec/models/integrations/pushover_spec.rb' - 'spec/models/integrations/redmine_spec.rb' - - 'spec/models/integrations/shimo_spec.rb' - 'spec/models/integrations/squash_tm_spec.rb' - 'spec/models/integrations/teamcity_spec.rb' - 'spec/models/integrations/telegram_spec.rb' @@ -2864,7 +2858,6 @@ RSpec/NamedSubject: - 'spec/models/terraform/state_version_spec.rb' - 'spec/models/timelog_spec.rb' - 'spec/models/todo_spec.rb' - - 'spec/models/tree_spec.rb' - 'spec/models/upload_spec.rb' - 'spec/models/uploads/fog_spec.rb' - 'spec/models/uploads/local_spec.rb' diff --git a/.rubocop_todo/style/inline_disable_annotation.yml b/.rubocop_todo/style/inline_disable_annotation.yml index 37c6c6b93b4..e49171b0362 100644 --- a/.rubocop_todo/style/inline_disable_annotation.yml +++ b/.rubocop_todo/style/inline_disable_annotation.yml @@ -327,7 +327,6 @@ Style/InlineDisableAnnotation: - 'app/graphql/types/user_preferences_type.rb' - 'app/graphql/types/user_status_type.rb' - 'app/graphql/types/work_item_id_type.rb' - - 'app/graphql/types/work_items/linked_item_type.rb' - 'app/graphql/types/work_items/widgets/assignees_type.rb' - 'app/graphql/types/work_items/widgets/award_emoji_type.rb' - 'app/graphql/types/work_items/widgets/current_user_todos_type.rb' @@ -688,10 +687,8 @@ Style/InlineDisableAnnotation: - 'app/services/packages/conan/single_package_search_service.rb' - 'app/services/packages/create_dependency_service.rb' - 'app/services/packages/create_package_service.rb' - - 'app/services/packages/debian/extract_metadata_service.rb' - 'app/services/packages/debian/generate_distribution_key_service.rb' - 'app/services/packages/debian/generate_distribution_service.rb' - - 'app/services/packages/helm/extract_file_metadata_service.rb' - 'app/services/packages/npm/create_package_service.rb' - 'app/services/packages/nuget/create_dependency_service.rb' - 'app/services/packages/nuget/extract_remote_metadata_file_service.rb' @@ -806,6 +803,7 @@ Style/InlineDisableAnnotation: - 'app/workers/bulk_imports/pipeline_worker.rb' - 'app/workers/bulk_imports/relation_batch_export_worker.rb' - 'app/workers/bulk_imports/stuck_import_worker.rb' + - 'app/workers/bulk_imports/transform_references_worker.rb' - 'app/workers/chaos/cpu_spin_worker.rb' - 'app/workers/chaos/db_spin_worker.rb' - 'app/workers/chaos/kill_worker.rb' @@ -1987,7 +1985,6 @@ Style/InlineDisableAnnotation: - 'ee/lib/gitlab/insights/executors/issuable_executor.rb' - 'ee/lib/gitlab/insights/finders/issuable_finder.rb' - 'ee/lib/gitlab/insights/reducers/count_per_period_reducer.rb' - - 'ee/lib/gitlab/llm/ai_message.rb' - 'ee/lib/gitlab/llm/chain/tools/identifier.rb' - 'ee/lib/gitlab/llm/chain/tools/json_reader/executor.rb' - 'ee/lib/gitlab/llm/chain/tools/summarize_comments/executor.rb' @@ -2011,7 +2008,6 @@ Style/InlineDisableAnnotation: - 'ee/lib/product_analytics/settings.rb' - 'ee/lib/quality/seeders/vulnerabilities.rb' - 'ee/lib/system_check/geo/authorized_keys_check.rb' - - 'ee/lib/system_check/geo/geo_database_configured_check.rb' - 'ee/lib/tasks/geo.rake' - 'ee/lib/tasks/gitlab/elastic.rake' - 'ee/locale/unfound_translations.rb' @@ -2284,7 +2280,6 @@ Style/InlineDisableAnnotation: - 'lib/bulk_imports/file_downloads/filename_fetch.rb' - 'lib/bulk_imports/groups/transformers/group_attributes_transformer.rb' - 'lib/bulk_imports/pipeline/runner.rb' - - 'lib/bulk_imports/projects/pipelines/references_pipeline.rb' - 'lib/bulk_imports/uniquify.rb' - 'lib/click_house/models/base_model.rb' - 'lib/click_house/query_builder.rb' @@ -2464,7 +2459,6 @@ Style/InlineDisableAnnotation: - 'lib/gitlab/console.rb' - 'lib/gitlab/container_repository/tags/cache.rb' - 'lib/gitlab/content_security_policy/config_loader.rb' - - 'lib/gitlab/contributions_calendar.rb' - 'lib/gitlab/current_settings.rb' - 'lib/gitlab/daemon.rb' - 'lib/gitlab/data_builder/pipeline.rb' @@ -2526,7 +2520,6 @@ Style/InlineDisableAnnotation: - 'lib/gitlab/encoding_helper.rb' - 'lib/gitlab/encrypted_command_base.rb' - 'lib/gitlab/encrypted_incoming_email_command.rb' - - 'lib/gitlab/encrypted_ldap_command.rb' - 'lib/gitlab/encrypted_redis_command.rb' - 'lib/gitlab/encrypted_service_desk_email_command.rb' - 'lib/gitlab/encrypted_smtp_command.rb' @@ -2561,7 +2554,6 @@ Style/InlineDisableAnnotation: - 'lib/gitlab/github_import/importer/labels_importer.rb' - 'lib/gitlab/github_import/importer/milestones_importer.rb' - 'lib/gitlab/github_import/importer/note_importer.rb' - - 'lib/gitlab/github_import/importer/pull_requests/review_importer.rb' - 'lib/gitlab/github_import/importer/pull_requests/review_requests_importer.rb' - 'lib/gitlab/github_import/importer/releases_importer.rb' - 'lib/gitlab/github_import/importer/repository_importer.rb' @@ -2767,8 +2759,6 @@ Style/InlineDisableAnnotation: - 'qa/qa/ee/page/main/banner.rb' - 'qa/qa/ee/page/project/monitor/on_call_schedule/index.rb' - 'qa/qa/ee/page/project/settings/merge_request.rb' - - 'qa/qa/ee/page/workspace/action.rb' - - 'qa/qa/ee/page/workspace/list.rb' - 'qa/qa/page/admin/applications.rb' - 'qa/qa/page/component/access_tokens.rb' - 'qa/qa/page/component/ci_icon.rb' @@ -2784,11 +2774,6 @@ Style/InlineDisableAnnotation: - 'qa/qa/page/project/settings/branch_rules_details.rb' - 'qa/qa/page/project/settings/integrations.rb' - 'qa/qa/page/project/settings/mirroring_repositories.rb' - - 'qa/qa/page/project/settings/runners.rb' - - 'qa/qa/page/project/settings/services/jenkins.rb' - - 'qa/qa/page/project/settings/services/jira.rb' - - 'qa/qa/page/project/settings/services/pipeline_status_emails.rb' - - 'qa/qa/page/search/results.rb' - 'qa/qa/page/sub_menus/super_sidebar/global_search_modal.rb' - 'qa/qa/resource/api_fabricator.rb' - 'qa/qa/resource/base.rb' @@ -2807,7 +2792,6 @@ Style/InlineDisableAnnotation: - 'qa/qa/scenario/test/integration/registry_with_cdn.rb' - 'qa/qa/service/docker_run/gitlab_runner.rb' - 'qa/qa/service/shellout.rb' - - 'qa/qa/specs/features/api/1_manage/import/import_large_github_repo_spec.rb' - 'qa/qa/specs/features/api/1_manage/migration/gitlab_migration_large_project_spec.rb' - 'qa/qa/specs/features/browser_ui/10_govern/user/user_access_termination_spec.rb' - 'qa/qa/specs/features/browser_ui/1_manage/integrations/jira/jira_basic_integration_spec.rb' diff --git a/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue b/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue index 504d3d38275..6e4ad5d60de 100644 --- a/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue +++ b/app/assets/javascripts/ci/catalog/components/list/ci_resources_list_item.vue @@ -1,6 +1,6 @@ <script> import { GlAvatar, GlBadge, GlIcon, GlLink, GlSprintf, GlTooltipDirective } from '@gitlab/ui'; -import { s__ } from '~/locale'; +import { s__, n__ } from '~/locale'; import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { formatDate, getTimeago } from '~/lib/utils/datetime_utility'; import { cleanLeadingSeparator } from '~/lib/utils/url_utility'; @@ -49,6 +49,9 @@ export default { starIcon() { return this.starCount > 0 ? 'star' : 'star-o'; }, + starCountText() { + return n__('Star', 'Stars', this.starCount); + }, hasReleasedVersion() { return Boolean(this.latestVersion?.releasedAt); }, @@ -115,7 +118,12 @@ export default { <div class="gl-display-flex gl-flex-grow-1 gl-md-justify-content-space-between"> <gl-badge size="sm" class="gl-h-5 gl-align-self-center">{{ tagName }}</gl-badge> <span class="gl-display-flex gl-align-items-center gl-ml-5"> - <span class="gl--flex-center" data-testid="stats-favorites"> + <span + v-gl-tooltip.top + :title="starCountText" + class="gl--flex-center" + data-testid="stats-favorites" + > <gl-icon :name="starIcon" :size="14" class="gl-mr-2" /> <span class="gl-mr-3">{{ starCount }}</span> </span> @@ -130,7 +138,7 @@ export default { <span v-if="hasReleasedVersion"> <gl-sprintf :message="$options.i18n.releasedMessage"> <template #timeAgo> - <span v-gl-tooltip.bottom :title="formattedDate"> + <span v-gl-tooltip.top :title="formattedDate"> {{ releasedAt }} </span> </template> diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json index 308a68544bc..b8d3606d23e 100644 --- a/app/assets/javascripts/editor/schema/ci.json +++ b/app/assets/javascripts/editor/schema/ci.json @@ -509,6 +509,18 @@ "description": "Command or script that should be executed as the container's entrypoint. It will be translated to Docker's --entrypoint option while creating the container. The syntax is similar to Dockerfile's ENTRYPOINT directive, where each shell token is a separate string in the array.", "minItems": 1 }, + "docker": { + "type": "object", + "markdownDescription": "Options to pass to Runners Docker Executor. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#imagedocker)", + "additionalProperties": false, + "properties": { + "platform": { + "type": "string", + "minLength": 1, + "description": "Image architecture to pull." + } + } + }, "pull_policy": { "markdownDescription": "Specifies how to pull the image in Runner. It can be one of `always`, `never` or `if-not-present`. The default value is `always`. [Learn more](https://docs.gitlab.com/ee/ci/yaml/#imagepull_policy).", "default": "always", @@ -540,13 +552,6 @@ "required": [ "name" ] - }, - { - "type": "array", - "minLength": 1, - "items": { - "type": "string" - } } ], "markdownDescription": "Specifies the docker image to use for the job or globally for all jobs. Job configuration takes precedence over global setting. Requires a certain kind of Gitlab runner executor. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#image)." @@ -579,8 +584,20 @@ "type": "string" } }, + "docker": { + "type": "object", + "markdownDescription": "Options to pass to Runners Docker Executor. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#servicesdocker)", + "additionalProperties": false, + "properties": { + "platform": { + "type": "string", + "minLength": 1, + "description": "Image architecture to pull." + } + } + }, "pull_policy": { - "markdownDescription": "Specifies how to pull the image in Runner. It can be one of `always`, `never` or `if-not-present`. The default value is `always`. [Learn more](https://docs.gitlab.com/ee/ci/yaml/#servicepull_policy).", + "markdownDescription": "Specifies how to pull the image in Runner. It can be one of `always`, `never` or `if-not-present`. The default value is `always`. [Learn more](https://docs.gitlab.com/ee/ci/yaml/#servicespull_policy).", "default": "always", "oneOf": [ { diff --git a/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js b/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js index 5b0266c95df..7a3d74e1e93 100644 --- a/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js +++ b/app/assets/javascripts/projects/settings_service_desk/custom_email_constants.js @@ -112,7 +112,7 @@ export const I18N_ERROR_SMTP_HOST_ISSUE_DESC = s__( ); export const I18N_ERROR_INVALID_CREDENTIALS_LABEL = s__('ServiceDesk|Invalid credentials'); export const I18N_ERROR_INVALID_CREDENTIALS_DESC = s__( - 'ServiceDesk|The given credentials (username and password) were rejected by the SMTP server.', + 'ServiceDesk|The given credentials (username and password) were rejected by the SMTP server, or you need to explicitly set an authentication method.', ); export const I18N_ERROR_MAIL_NOT_RECEIVED_IN_TIMEFRAME_LABEL = s__( 'ServiceDesk|Verification email not received within timeframe', diff --git a/app/validators/json_schema_validator.rb b/app/validators/json_schema_validator.rb index 2ef011df73e..f661392082f 100644 --- a/app/validators/json_schema_validator.rb +++ b/app/validators/json_schema_validator.rb @@ -1,4 +1,5 @@ # frozen_string_literal: true + # # JsonSchemaValidator # @@ -24,11 +25,19 @@ class JsonSchemaValidator < ActiveModel::EachValidator end def validate_each(record, attribute, value) - value = value.to_h.stringify_keys if options[:hash_conversion] == true + value = value.to_h.deep_stringify_keys if options[:hash_conversion] == true value = Gitlab::Json.parse(value.to_s) if options[:parse_json] == true && !value.nil? - unless valid_schema?(value) - record.errors.add(attribute, _("must be a valid json schema")) + if options[:detail_errors] + validator.validate(value).each do |error| + message = format( + _("'%{data_pointer}' must be a valid '%{type}'"), + data_pointer: error['data_pointer'], type: error['type'] + ) + record.errors.add(attribute, message) + end + else + record.errors.add(attribute, _("must be a valid json schema")) unless valid_schema?(value) end end diff --git a/app/views/notify/service_desk_verification_result_email.html.haml b/app/views/notify/service_desk_verification_result_email.html.haml index faf8ae2e28c..651f94533ec 100644 --- a/app/views/notify/service_desk_verification_result_email.html.haml +++ b/app/views/notify/service_desk_verification_result_email.html.haml @@ -35,7 +35,7 @@ %p %b = s_('Notify|Invalid credentials:') - = s_('Notify|The given credentials (username and password) were rejected by the SMTP server.') + = s_('Notify|The given credentials (username and password) were rejected by the SMTP server, or you need to explicitly set an authentication method.') - if @verification.mail_not_received_within_timeframe? %p %b diff --git a/app/views/notify/service_desk_verification_result_email.text.erb b/app/views/notify/service_desk_verification_result_email.text.erb index fd2e4446d0b..134b6592197 100644 --- a/app/views/notify/service_desk_verification_result_email.text.erb +++ b/app/views/notify/service_desk_verification_result_email.text.erb @@ -18,7 +18,7 @@ <%= s_('Notify|We were not able to make a connection to the specified host or there was an SSL issue.') %> <% elsif @verification.invalid_credentials? %> <%= s_('Notify|Invalid credentials:') %> - <%= s_('Notify|The given credentials (username and password) were rejected by the SMTP server.') %> + <%= s_('Notify|The given credentials (username and password) were rejected by the SMTP server, or you need to explicitly set an authentication method.') %> <% elsif @verification.mail_not_received_within_timeframe? %> <%= s_('Notify|Verification email not received within timeframe:') %> <%= s_('Notify|We did not receive the verification email we sent out to %{strong_open}%{email_address}%{strong_close} in time.') % { email_address: verify_email_address, strong_open: '', strong_close: '' } %> diff --git a/app/workers/bulk_imports/entity_worker.rb b/app/workers/bulk_imports/entity_worker.rb index caee292a504..6ff2d15d6e8 100644 --- a/app/workers/bulk_imports/entity_worker.rb +++ b/app/workers/bulk_imports/entity_worker.rb @@ -3,9 +3,10 @@ module BulkImports class EntityWorker include ApplicationWorker + include ExclusiveLeaseGuard idempotent! - deduplicate :until_executed, if_deduplicated: :reschedule_once + deduplicate :until_executing data_consistency :always feature_category :importers sidekiq_options retry: 3, dead: false @@ -27,7 +28,10 @@ module BulkImports if running_tracker.present? log_info(message: 'Stage running', entity_stage: running_tracker.stage) else - start_next_stage + # Use lease guard to prevent duplicated workers from starting multiple stages + try_obtain_lease do + start_next_stage + end end re_enqueue @@ -78,6 +82,18 @@ module BulkImports end end + def lease_timeout + PERFORM_DELAY + end + + def lease_key + "gitlab:bulk_imports:entity_worker:#{entity.id}" + end + + def log_lease_taken + log_info(message: lease_taken_message) + end + def source_version entity.bulk_import.source_version_info.to_s end diff --git a/app/workers/packages/npm/create_metadata_cache_worker.rb b/app/workers/packages/npm/create_metadata_cache_worker.rb index 0b6e34b13eb..cff7871dab7 100644 --- a/app/workers/packages/npm/create_metadata_cache_worker.rb +++ b/app/workers/packages/npm/create_metadata_cache_worker.rb @@ -16,7 +16,7 @@ module Packages def perform(project_id, package_name) project = Project.find_by_id(project_id) - return unless project && Feature.enabled?(:npm_metadata_cache, project) + return unless project ::Packages::Npm::CreateMetadataCacheService .new(project, package_name) diff --git a/config/feature_flags/development/npm_metadata_cache.yml b/config/feature_flags/development/npm_metadata_cache.yml deleted file mode 100644 index ddd1afa37e6..00000000000 --- a/config/feature_flags/development/npm_metadata_cache.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: npm_metadata_cache -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121714 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393745 -milestone: '16.1' -type: development -group: group::package registry -default_enabled: false diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 3572c30cdd3..c5640ce260b 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -26,7 +26,7 @@ Doorkeeper.configure do user = User.find_by_login(params[:username]) next unless user - next if user.password_automatically_set? + next if user.password_automatically_set? && !user.password_based_omniauth_user? next if user.two_factor_enabled? || Gitlab::Auth::TwoFactorAuthVerifier.new(user).two_factor_authentication_enforced? Gitlab::Auth.find_with_user_password(params[:username], params[:password], increment_failed_attempts: true) diff --git a/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml b/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml index d91b965765d..cfbcdf9c3ed 100644 --- a/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml +++ b/config/metrics/counts_28d/20210216175546_ci_internal_pipelines.yml @@ -16,6 +16,7 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "12.9" introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26441" diff --git a/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml b/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml index 341cc40bba4..dc72934d8ea 100644 --- a/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml +++ b/config/metrics/counts_28d/20210216175550_ci_pipeline_config_repository.yml @@ -16,6 +16,7 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "12.9" introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26441" diff --git a/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml b/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml index ed88363f2e4..1aca43b481c 100644 --- a/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml +++ b/config/metrics/counts_28d/20210216175552_ci_pipeline_schedules.yml @@ -16,6 +16,7 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "12.9" introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26441" diff --git a/config/metrics/counts_28d/20210216175554_ci_pipelines.yml b/config/metrics/counts_28d/20210216175554_ci_pipelines.yml index 4cbd7791013..85574876681 100644 --- a/config/metrics/counts_28d/20210216175554_ci_pipelines.yml +++ b/config/metrics/counts_28d/20210216175554_ci_pipelines.yml @@ -21,5 +21,6 @@ performance_indicator_type: - smau - gmau - paid_gmau +- customer_health_score milestone: "12.9" introduced_by_url: "https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26441" diff --git a/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml b/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml index 6953cbc2ce3..618d65d14f8 100644 --- a/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml +++ b/config/metrics/counts_28d/20210216180327_action_monthly_active_users_ide_edit.yml @@ -28,4 +28,5 @@ tier: performance_indicator_type: - gmau - paid_gmau +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216180814_events.yml b/config/metrics/counts_28d/20210216180814_events.yml index e30babe377d..d32c6b21000 100644 --- a/config/metrics/counts_28d/20210216180814_events.yml +++ b/config/metrics/counts_28d/20210216180814_events.yml @@ -18,4 +18,5 @@ tier: - ultimate performance_indicator_type: - umau +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216181057_projects_with_packages.yml b/config/metrics/counts_28d/20210216181057_projects_with_packages.yml index a1e10881251..2ae56078fb3 100644 --- a/config/metrics/counts_28d/20210216181057_projects_with_packages.yml +++ b/config/metrics/counts_28d/20210216181057_projects_with_packages.yml @@ -16,5 +16,6 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216181139_issues.yml b/config/metrics/counts_28d/20210216181139_issues.yml index ffb7a16e611..931a6d2cfc0 100644 --- a/config/metrics/counts_28d/20210216181139_issues.yml +++ b/config/metrics/counts_28d/20210216181139_issues.yml @@ -17,5 +17,6 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216181158_epics.yml b/config/metrics/counts_28d/20210216181158_epics.yml index d3f6b0805f5..51eca7b3009 100644 --- a/config/metrics/counts_28d/20210216181158_epics.yml +++ b/config/metrics/counts_28d/20210216181158_epics.yml @@ -14,5 +14,6 @@ distribution: tier: - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml b/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml index 105c05cf675..fa4b3d5ec13 100644 --- a/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml +++ b/config/metrics/counts_28d/20210216181337_g_project_management_issue_milestone_changed_monthly.yml @@ -23,5 +23,6 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216181935_deployments.yml b/config/metrics/counts_28d/20210216181935_deployments.yml index 3c2160e9640..ecf3840bd1d 100644 --- a/config/metrics/counts_28d/20210216181935_deployments.yml +++ b/config/metrics/counts_28d/20210216181935_deployments.yml @@ -18,4 +18,5 @@ tier: performance_indicator_type: - gmau - paid_gmau +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216181939_releases.yml b/config/metrics/counts_28d/20210216181939_releases.yml index 6818cd31fe8..390c3e913d8 100644 --- a/config/metrics/counts_28d/20210216181939_releases.yml +++ b/config/metrics/counts_28d/20210216181939_releases.yml @@ -16,5 +16,6 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml b/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml index 308b55d9a90..80913319bd6 100644 --- a/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml +++ b/config/metrics/counts_28d/20210216182040_action_monthly_active_users_project_repo.yml @@ -24,4 +24,5 @@ performance_indicator_type: - smau - gmau - paid_gmau +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216182051_protected_branches.yml b/config/metrics/counts_28d/20210216182051_protected_branches.yml index 8f6589b5c37..36c67780088 100644 --- a/config/metrics/counts_28d/20210216182051_protected_branches.yml +++ b/config/metrics/counts_28d/20210216182051_protected_branches.yml @@ -17,5 +17,6 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml b/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml index d01b08ea827..fef381fb775 100644 --- a/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml +++ b/config/metrics/counts_28d/20210216184303_o_pipeline_authoring_unique_users_committing_ciconfigfile_monthly.yml @@ -21,5 +21,6 @@ tier: - free - premium - ultimate -performance_indicator_type: [] +performance_indicator_type: +- customer_health_score milestone: "<13.9" diff --git a/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml b/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml index 06b1cbcc3cc..ac3aede50b2 100644 --- a/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml +++ b/config/metrics/counts_28d/20220621085114_unique_active_users_monthly.yml @@ -22,3 +22,5 @@ tier: - free - premium - ultimate +performance_indicator_type: +- customer_health_score diff --git a/config/metrics/counts_all/20210216175525_ci_builds.yml b/config/metrics/counts_all/20210216175525_ci_builds.yml index c44a35960c4..8b060470454 100644 --- a/config/metrics/counts_all/20210216175525_ci_builds.yml +++ b/config/metrics/counts_all/20210216175525_ci_builds.yml @@ -17,3 +17,5 @@ tier: - premium - ultimate milestone: "<13.9" +performance_indicator_type: +- customer_health_score diff --git a/config/metrics/counts_all/20210514141520_project_imports_total.yml b/config/metrics/counts_all/20210514141520_project_imports_total.yml index d3462f48afb..1eb380e9716 100644 --- a/config/metrics/counts_all/20210514141520_project_imports_total.yml +++ b/config/metrics/counts_all/20210514141520_project_imports_total.yml @@ -19,3 +19,5 @@ tier: - free - premium - ultimate +performance_indicator_type: +- customer_health_score diff --git a/db/post_migrate/20231122125550_drop_index_bulk_import_export_batches_on_export_id.rb b/db/post_migrate/20231122125550_drop_index_bulk_import_export_batches_on_export_id.rb new file mode 100644 index 00000000000..295eae13c06 --- /dev/null +++ b/db/post_migrate/20231122125550_drop_index_bulk_import_export_batches_on_export_id.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +class DropIndexBulkImportExportBatchesOnExportId < Gitlab::Database::Migration[2.2] + disable_ddl_transaction! + + milestone '16.7' + + INDEX_NAME = :index_bulk_import_export_batches_on_export_id + TABLE_NAME = :bulk_import_export_batches + + def up + remove_concurrent_index_by_name TABLE_NAME, INDEX_NAME + end + + def down + add_concurrent_index TABLE_NAME, :export_id, name: INDEX_NAME + end +end diff --git a/db/schema_migrations/20231122125550 b/db/schema_migrations/20231122125550 new file mode 100644 index 00000000000..8f8364313f8 --- /dev/null +++ b/db/schema_migrations/20231122125550 @@ -0,0 +1 @@ +50b84382c713219deda4f271ebffcfb786aa89d137d5693597d98183478da687
\ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 31d19255a15..b915344d7cb 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -31856,8 +31856,6 @@ CREATE INDEX index_bulk_import_entities_on_parent_id ON bulk_import_entities USI CREATE INDEX index_bulk_import_entities_on_project_id ON bulk_import_entities USING btree (project_id); -CREATE INDEX index_bulk_import_export_batches_on_export_id ON bulk_import_export_batches USING btree (export_id); - CREATE INDEX index_bulk_import_export_uploads_on_export_id ON bulk_import_export_uploads USING btree (export_id); CREATE INDEX index_bulk_import_failures_on_bulk_import_entity_id ON bulk_import_failures USING btree (bulk_import_entity_id); diff --git a/doc/architecture/blueprints/cells/index.md b/doc/architecture/blueprints/cells/index.md index e77ee750b92..6274a440810 100644 --- a/doc/architecture/blueprints/cells/index.md +++ b/doc/architecture/blueprints/cells/index.md @@ -96,6 +96,10 @@ The first 2-3 quarters are required to define a general split of data, and build The purpose is to make `users` cluster-wide. +1. **User can create Organization.** + + The purpose is to create Organizations that are isolated from each other. + 1. **User can create Group.** ✓ ([demo](https://www.youtube.com/watch?v=LUyV0ncfdRs)) The purpose is to perform a targeted decomposition of `users` and `namespaces`, because `namespaces` will be stored locally in the Cell. @@ -104,9 +108,9 @@ The first 2-3 quarters are required to define a general split of data, and build The purpose is to perform a targeted decomposition of `users` and `projects`, because `projects` will be stored locally in the Cell. -1. **User can create Organization on Cell 2.** +1. **User can create files in repository** - The purpose is to create Organizations that are isolated from each other. + The purpose is to allow `users` to create files in a repository. 1. **User can change profile avatar that is shared in cluster.** @@ -159,7 +163,7 @@ flowchart TD A --> L[Manage members] B --> L C --> L - L --> E[Create file in project] + L --> E[Create file in repository] ``` ### 3. Additional workflows @@ -316,6 +320,7 @@ It is expected that initial iterations will be rather slow, because they require - Data access layer: Data access layer. - Routing: User can use single domain to interact with many Cells. - Cell deployment: Extend GitLab Dedicated to support GCP. +- Essential workflows: User can create files in repository. - Essential workflows: User can push to Git repository. - Essential workflows: User can run CI pipeline. - Essential workflows: Instance-wide settings are shared across cluster. diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index 799b05df1b1..aa736884529 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -2441,6 +2441,37 @@ image: - [Override the entrypoint of an image](../docker/using_docker_images.md#override-the-entrypoint-of-an-image). +#### `image:docker` + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27919) in GitLab 16.7. Requires GitLab Runner 16.7 or later. + +Use `image:docker` to pass options to the Docker executor of a GitLab Runner. + +**Keyword type**: Job keyword. You can use it only as part of a job or in the +[`default` section](#default). + +**Possible inputs**: + +A hash of options for the Docker executor, which can include: + +- `platform`: Selects the architecture of the image to pull. When not specified, + the default is the same platform as the host runner. + +**Example of `image:docker`**: + +```yaml +arm-sql-job: + script: echo "Run sql tests" + image: + name: super/sql:experimental + docker: + platform: arm64/v8 +``` + +**Additional details**: + +- `image:docker:platform` maps to the [`docker pull --platform` option](https://docs.docker.com/engine/reference/commandline/pull/#options). + #### `image:pull_policy` > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21619) in GitLab 15.1 [with a flag](../../administration/feature_flags.md) named `ci_docker_image_pull_policy`. Disabled by default. @@ -4257,7 +4288,39 @@ In this example, GitLab launches two containers for the job: - [Run your CI/CD jobs in Docker containers](../docker/using_docker_images.md). - [Use Docker to build Docker images](../docker/using_docker_build.md). -#### `service:pull_policy` +#### `services:docker` + +> [Introduced](https://gitlab.com/gitlab-org/gitlab-runner/-/issues/27919) in GitLab 16.7. Requires GitLab Runner 16.7 or later. + +Use `services:docker` to pass options to the Docker executor of a GitLab Runner. + +**Keyword type**: Job keyword. You can use it only as part of a job or in the +[`default` section](#default). + +**Possible inputs**: + +A hash of options for the Docker executor, which can include: + +- `platform`: Selects the architecture of the image to pull. When not specified, + the default is the same platform as the host runner. + +**Example of `services:docker`**: + +```yaml +arm-sql-job: + script: echo "Run sql tests in service container" + image: ruby:2.6 + services: + - name: super/sql:experimental + docker: + platform: arm64/v8 +``` + +**Additional details**: + +- `services:docker:platform` maps to the [`docker pull --platform` option](https://docs.docker.com/engine/reference/commandline/pull/#options). + +#### `services:pull_policy` > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/21619) in GitLab 15.1 [with a flag](../../administration/feature_flags.md) named `ci_docker_image_pull_policy`. Disabled by default. > - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/363186) in GitLab 15.2. @@ -4273,7 +4336,7 @@ The pull policy that the runner uses to fetch the Docker image. - A single pull policy, or multiple pull policies in an array. Can be `always`, `if-not-present`, or `never`. -**Examples of `service:pull_policy`**: +**Examples of `services:pull_policy`**: ```yaml job1: diff --git a/doc/user/project/service_desk/configure.md b/doc/user/project/service_desk/configure.md index 06f0854953d..8a9e28a6d0d 100644 --- a/doc/user/project/service_desk/configure.md +++ b/doc/user/project/service_desk/configure.md @@ -159,6 +159,7 @@ To edit the custom email display name: > - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/329990) in GitLab 16.3 [with a flag](../../../administration/feature_flags.md) named `service_desk_custom_email`. Disabled by default. > - [Enabled on GitLab.com and self-managed](https://gitlab.com/gitlab-org/gitlab/-/issues/387003) in GitLab 16.4. +> - Ability to select the SMTP authentication method [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/429680) in GitLab 16.6. FLAG: On self-managed GitLab, by default this feature is available. To hide the feature per project or for @@ -237,6 +238,36 @@ If the verification failed, the email also contains details of the reason. If the verification was successful, the custom email address is ready to be used. You can now enable sending Service Desk emails via the custom email address. +#### Troubleshooting your configuration + +When configuring a custom email you might encounter the following issues. + +##### Invalid credentials + +You might get an error that states that invalid credentials were used. + +This occurs when the SMTP server returns that the authentication wasn't successful. + +To troubleshoot this: + +1. Check your SMTP credentials, especially the username and password. +1. Sometimes GitLab cannot automatically select an authentication method that the SMTP server supports. Either: + - Try the available authentication methods (**Plain**, **Login** and **CRAM-MD5**). + - Check which authentication methods your SMTP server supports, using the + [`swaks` command line tool](https://www.jetmore.org/john/code/swaks/): + 1. Run the following command with your credentials and look for a line that starts with `250-AUTH`: + + ```shell + swaks --to user@example.com \ + --from support@example.com \ + --auth-user support@example.com \ + --server smtp@example.com:587 \ + -tls-optional \ + --auth-password your-app-password + ``` + + 1. Select one of the supported authentication methods in the custom email setup form. + ### Enable or disable the custom email address After the custom email address has been verified, administrators can enable or disable sending Service Desk emails via the custom email address. @@ -353,6 +384,7 @@ In GitLab: - **SMTP port**: `587`. - **SMTP username**: Prefilled with the custom email address. - **SMTP password**: The app password you previously created for the custom email account. + - **SMTP authentication method**: Let GitLab select a server-supported method (recommended) 1. Select **Save and test connection** 1. After the [verification process](#verification) you should be able to [enable the custom email address](#enable-or-disable-the-custom-email-address). diff --git a/lib/api/concerns/packages/npm_endpoints.rb b/lib/api/concerns/packages/npm_endpoints.rb index 19d63a39242..69d23c408ab 100644 --- a/lib/api/concerns/packages/npm_endpoints.rb +++ b/lib/api/concerns/packages/npm_endpoints.rb @@ -238,7 +238,7 @@ module API not_found!('Packages') if available_packages.empty? - if endpoint_scope == :project && Feature.enabled?(:npm_metadata_cache, project) + if endpoint_scope == :project if metadata_cache&.file&.exists? metadata_cache.touch_last_downloaded_at present_carrierwave_file!(metadata_cache.file) diff --git a/lib/api/entities/ci/job_request/image.rb b/lib/api/entities/ci/job_request/image.rb index 92d68269265..08b0075a657 100644 --- a/lib/api/entities/ci/job_request/image.rb +++ b/lib/api/entities/ci/job_request/image.rb @@ -8,6 +8,7 @@ module API expose :name, :entrypoint expose :ports, using: Entities::Ci::JobRequest::Port + expose :executor_opts expose :pull_policy end end diff --git a/lib/api/entities/ci/job_request/service.rb b/lib/api/entities/ci/job_request/service.rb index 128591058fe..ae726a6b888 100644 --- a/lib/api/entities/ci/job_request/service.rb +++ b/lib/api/entities/ci/job_request/service.rb @@ -8,6 +8,7 @@ module API expose :name, :entrypoint expose :ports, using: Entities::Ci::JobRequest::Port + expose :executor_opts expose :pull_policy expose :alias, :command expose :variables diff --git a/lib/api/helpers/packages/npm.rb b/lib/api/helpers/packages/npm.rb index c91eef0c4b0..0ab3b64a2c6 100644 --- a/lib/api/helpers/packages/npm.rb +++ b/lib/api/helpers/packages/npm.rb @@ -86,8 +86,6 @@ module API strong_memoize_attr :project_id_or_nil def enqueue_sync_metadata_cache_worker(project, package_name) - return unless Feature.enabled?(:npm_metadata_cache, project) - ::Packages::Npm::CreateMetadataCacheWorker.perform_async(project.id, package_name) end diff --git a/lib/gitlab/ci/build/image.rb b/lib/gitlab/ci/build/image.rb index 84f8eae8deb..660d7701a8f 100644 --- a/lib/gitlab/ci/build/image.rb +++ b/lib/gitlab/ci/build/image.rb @@ -4,7 +4,7 @@ module Gitlab module Ci module Build class Image - attr_reader :alias, :command, :entrypoint, :name, :ports, :variables, :pull_policy + attr_reader :alias, :command, :entrypoint, :name, :ports, :variables, :executor_opts, :pull_policy class << self def from_image(job) @@ -28,6 +28,7 @@ module Gitlab when String @name = image @ports = [] + @executor_opts = {} when Hash @alias = image[:alias] @command = image[:command] @@ -35,6 +36,7 @@ module Gitlab @name = image[:name] @ports = build_ports(image).select(&:valid?) @variables = build_variables(image) + @executor_opts = image.fetch(:executor_opts, {}) @pull_policy = image[:pull_policy] end end diff --git a/lib/gitlab/ci/config/entry/image.rb b/lib/gitlab/ci/config/entry/image.rb index 84e31ca1fc6..58ab488d833 100644 --- a/lib/gitlab/ci/config/entry/image.rb +++ b/lib/gitlab/ci/config/entry/image.rb @@ -13,21 +13,6 @@ module Gitlab validations do validates :config, allowed_keys: IMAGEABLE_ALLOWED_KEYS end - - def value - if string? - { name: @config } - elsif hash? - { - name: @config[:name], - entrypoint: @config[:entrypoint], - ports: (ports_value if ports_defined?), - pull_policy: pull_policy_value - }.compact - else - {} - end - end end end end diff --git a/lib/gitlab/ci/config/entry/imageable.rb b/lib/gitlab/ci/config/entry/imageable.rb index 1aecfee9ab9..53b810b3037 100644 --- a/lib/gitlab/ci/config/entry/imageable.rb +++ b/lib/gitlab/ci/config/entry/imageable.rb @@ -12,7 +12,9 @@ module Gitlab include ::Gitlab::Config::Entry::Attributable include ::Gitlab::Config::Entry::Configurable - IMAGEABLE_ALLOWED_KEYS = %i[name entrypoint ports pull_policy].freeze + EXECUTOR_OPTS_KEYS = %i[docker].freeze + + IMAGEABLE_ALLOWED_KEYS = EXECUTOR_OPTS_KEYS + %i[name entrypoint ports pull_policy].freeze included do include ::Gitlab::Config::Entry::Validatable @@ -23,9 +25,15 @@ module Gitlab validates :name, type: String, presence: true validates :entrypoint, array_of_strings: true, allow_nil: true + validates :executor_opts, json_schema: { + base_directory: "lib/gitlab/ci/config/entry/schemas/imageable", + detail_errors: true, + filename: "executor_opts", + hash_conversion: true + }, allow_nil: true end - attributes :ports, :pull_policy + attributes :docker, :ports, :pull_policy entry :ports, Entry::Ports, description: 'Ports used to expose the image/service' @@ -49,6 +57,28 @@ module Gitlab def skip_config_hash_validation? true end + + def executor_opts + return unless config.is_a?(Hash) + + config.slice(*EXECUTOR_OPTS_KEYS).compact.presence + end + + def value + if string? + { name: config } + elsif hash? + { + name: config[:name], + entrypoint: config[:entrypoint], + executor_opts: executor_opts, + ports: (ports_value if ports_defined?), + pull_policy: pull_policy_value + }.compact + else + {} + end + end end end end diff --git a/lib/gitlab/ci/config/entry/schemas/imageable/executor_opts.json b/lib/gitlab/ci/config/entry/schemas/imageable/executor_opts.json new file mode 100644 index 00000000000..a31374650e6 --- /dev/null +++ b/lib/gitlab/ci/config/entry/schemas/imageable/executor_opts.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "description": "Describe `image:` and `service:` options like `docker:`", + "type": "object", + "properties": { + "docker": { + "type": "object", + "properties": { + "platform": { + "type": "string", + "minLength": 1, + "maxLength": 64 + } + }, + "additionalProperties": false + } + }, + "additionalProperties": false +} diff --git a/lib/gitlab/ci/config/entry/service.rb b/lib/gitlab/ci/config/entry/service.rb index 4b3a9990df4..94fd28badb7 100644 --- a/lib/gitlab/ci/config/entry/service.rb +++ b/lib/gitlab/ci/config/entry/service.rb @@ -34,14 +34,14 @@ module Gitlab end def value - if string? - { name: @config } - elsif hash? - @config.merge( - pull_policy: pull_policy_value + if hash? + super.merge( + command: @config[:command], + alias: @config[:alias], + variables: (variables_value if variables_defined?) ).compact else - {} + super end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 06db6608955..36c271bec7c 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -1363,6 +1363,9 @@ msgstr "" msgid "%{wildcards_link_start}Wildcards%{wildcards_link_end} such as %{code_tag_start}v*%{code_tag_end} or %{code_tag_start}*-release%{code_tag_end} are supported." msgstr "" +msgid "'%{data_pointer}' must be a valid '%{type}'" +msgstr "" + msgid "'%{level}' is not a valid visibility level" msgstr "" @@ -30283,6 +30286,9 @@ msgstr "" msgid "MetricImages|There was an issue uploading your image." msgstr "" +msgid "Metrics" +msgstr "" + msgid "Metrics - Grafana" msgstr "" @@ -32705,7 +32711,7 @@ msgstr "" msgid "Notify|The errors we encountered were:" msgstr "" -msgid "Notify|The given credentials (username and password) were rejected by the SMTP server." +msgid "Notify|The given credentials (username and password) were rejected by the SMTP server, or you need to explicitly set an authentication method." msgstr "" msgid "Notify|The project is now located under %{project_full_name_link_start}%{project_full_name}%{link_end}." @@ -32873,6 +32879,9 @@ msgstr "" msgid "ObservabilityMetrics|Error: Failed to load metrics details. Try reloading the page." msgstr "" +msgid "ObservabilityMetrics|Metric Details" +msgstr "" + msgid "ObservabilityMetrics|Metrics" msgstr "" @@ -44719,7 +44728,7 @@ msgstr "" msgid "ServiceDesk|The SMTP server did not respond in time." msgstr "" -msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server." +msgid "ServiceDesk|The given credentials (username and password) were rejected by the SMTP server, or you need to explicitly set an authentication method." msgstr "" msgid "ServiceDesk|The received email didn't contain the verification token that was sent to your email address." @@ -46418,6 +46427,11 @@ msgstr "" msgid "Standard" msgstr "" +msgid "Star" +msgid_plural "Stars" +msgstr[0] "" +msgstr[1] "" + msgid "Star labels to start sorting by priority." msgstr "" diff --git a/spec/features/groups/milestone_spec.rb b/spec/features/groups/milestone_spec.rb index bb7cc3db452..1374aa96578 100644 --- a/spec/features/groups/milestone_spec.rb +++ b/spec/features/groups/milestone_spec.rb @@ -98,7 +98,7 @@ RSpec.describe 'Group milestones', feature_category: :groups_and_projects do end it 'counts milestones correctly' do - page.within '[data-testid="milestones-filter"]' do + within_testid 'milestones-filter' do expect(page).to have_content('Open 3') expect(page).to have_content('Closed 3') expect(page).to have_content('All 6') diff --git a/spec/features/groups/packages_spec.rb b/spec/features/groups/packages_spec.rb index 7819b1f0ab6..6b2a15daf72 100644 --- a/spec/features/groups/packages_spec.rb +++ b/spec/features/groups/packages_spec.rb @@ -52,7 +52,7 @@ RSpec.describe 'Group Packages', feature_category: :package_registry do it_behaves_like 'package details link' it 'allows you to navigate to the project page' do - find('[data-testid="root-link"]', text: project.name).click + find_by_testid('root-link', text: project.name).click expect(page).to have_current_path(project_path(project)) expect(page).to have_content(project.name) diff --git a/spec/features/groups/settings/ci_cd_spec.rb b/spec/features/groups/settings/ci_cd_spec.rb index a1acb73178b..bf056f535f2 100644 --- a/spec/features/groups/settings/ci_cd_spec.rb +++ b/spec/features/groups/settings/ci_cd_spec.rb @@ -17,7 +17,7 @@ RSpec.describe 'Group CI/CD settings', feature_category: :continuous_integration end describe 'Runners section' do - let(:shared_runners_toggle) { page.find('[data-testid="shared-runners-toggle"]') } + let(:shared_runners_toggle) { find_by_testid('shared-runners-toggle') } before do visit group_settings_ci_cd_path(group) diff --git a/spec/features/groups/settings/packages_and_registries_spec.rb b/spec/features/groups/settings/packages_and_registries_spec.rb index cbd26441e2b..934234aa171 100644 --- a/spec/features/groups/settings/packages_and_registries_spec.rb +++ b/spec/features/groups/settings/packages_and_registries_spec.rb @@ -65,8 +65,10 @@ RSpec.describe 'Group Package and registry settings', feature_category: :package wait_for_requests + # rubocop:disable Capybara/TestidFinders -- Helper within_testid doesn't cover use case expect(page).to be_axe_clean.within('[data-testid="packages-and-registries-group-settings"]') .skipping :'link-in-text-block', :'heading-order' + # rubocop:enable Capybara/TestidFinders end it 'has a Duplicate packages section', :js do @@ -81,7 +83,7 @@ RSpec.describe 'Group Package and registry settings', feature_category: :package visit_settings_page wait_for_requests - within '[data-testid="maven-settings"]' do + within_testid 'maven-settings' do expect(page).to have_field _('Exceptions'), disabled: true click_button class: 'gl-toggle' @@ -98,7 +100,7 @@ RSpec.describe 'Group Package and registry settings', feature_category: :package visit_settings_page wait_for_requests - within '[data-testid="maven-settings"]' do + within_testid 'maven-settings' do click_button class: 'gl-toggle' fill_in _('Exceptions'), with: ')' @@ -115,7 +117,7 @@ RSpec.describe 'Group Package and registry settings', feature_category: :package visit_sub_group_settings_page wait_for_requests - within '[data-testid="maven-settings"]' do + within_testid 'maven-settings' do expect(page).to have_content('Allow duplicates') expect(page).to have_field _('Exceptions'), disabled: true diff --git a/spec/features/groups/show_spec.rb b/spec/features/groups/show_spec.rb index cf18f3cb4e5..c2ab5edf79c 100644 --- a/spec/features/groups/show_spec.rb +++ b/spec/features/groups/show_spec.rb @@ -38,7 +38,7 @@ RSpec.describe 'Group show page', feature_category: :groups_and_projects do expect(page).to have_content('Collaborate with your team') - page.within(find('[data-testid="invite-members-banner"]')) do + within_testid('invite-members-banner') do click_button('Invite your colleagues') end @@ -48,8 +48,8 @@ RSpec.describe 'Group show page', feature_category: :groups_and_projects do click_button('Cancel') end - page.within(find('[data-testid="invite-members-banner"]')) do - find('[data-testid="close-icon"]').click + within_testid('invite-members-banner') do + find_by_testid('close-icon').click end expect(page).not_to have_content('Collaborate with your team') @@ -119,7 +119,7 @@ RSpec.describe 'Group show page', feature_category: :groups_and_projects do wait_for_requests - page.within("[data-testid=\"group-overview-item-#{public_project.id}\"]") do + within_testid("group-overview-item-#{public_project.id}") do click_button _('Less restrictive visibility') end diff --git a/spec/features/groups_spec.rb b/spec/features/groups_spec.rb index 578f39181d1..c0aaa7f818a 100644 --- a/spec/features/groups_spec.rb +++ b/spec/features/groups_spec.rb @@ -485,7 +485,7 @@ RSpec.describe 'Group', feature_category: :groups_and_projects do it 'only displays "New subgroup" button' do visit group_path(group) - page.within '[data-testid="group-buttons"]' do + within_testid 'group-buttons' do expect(page).to have_link('New subgroup') expect(page).not_to have_link('New project') end @@ -502,7 +502,7 @@ RSpec.describe 'Group', feature_category: :groups_and_projects do sign_in(user) visit group_path(group) - page.within '[data-testid="group-buttons"]' do + within_testid 'group-buttons' do expect(page).to have_link('New project') expect(page).not_to have_link('New subgroup') end @@ -515,7 +515,7 @@ RSpec.describe 'Group', feature_category: :groups_and_projects do visit group_path(group) - page.within '[data-testid="group-buttons"]' do + within_testid 'group-buttons' do expect(page).to have_link('New subgroup') expect(page).to have_link('New project') end @@ -542,7 +542,7 @@ RSpec.describe 'Group', feature_category: :groups_and_projects do it 'does not display the "New project" button' do visit group_path(group) - page.within '[data-testid="group-buttons"]' do + within_testid 'group-buttons' do expect(page).not_to have_link('New project') end end diff --git a/spec/features/incidents/incident_details_spec.rb b/spec/features/incidents/incident_details_spec.rb index 693f2599de5..bc0674c4886 100644 --- a/spec/features/incidents/incident_details_spec.rb +++ b/spec/features/incidents/incident_details_spec.rb @@ -46,7 +46,7 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d # shows the incident tabs page.within('.issuable-details') do - incident_tabs = find('[data-testid="incident-tabs"]') + incident_tabs = find_by_testid('incident-tabs') expect(find('h1')).to have_content(incident.title) expect(incident_tabs).to have_content('Summary') @@ -66,14 +66,21 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d describe 'escalation status' do let(:sidebar) { page.find('.right-sidebar') } - let(:widget) { sidebar.find('[data-testid="escalation_status_container"]') } + let(:widget) do + within sidebar do + find_by_testid('escalation_status_container') + end + end + let(:expected_dropdown_options) { escalation_status.class::STATUSES.keys.take(3).map { |key| key.to_s.titleize } } it 'has an interactable escalation status widget', :aggregate_failures do expect(current_status).to have_text(escalation_status.status_name.to_s.titleize) # list the available statuses - widget.find('[data-testid="edit-button"]').click + within widget do + find_by_testid('edit-button').click + end expect(dropdown_options.map(&:text)).to eq(expected_dropdown_options) expect(widget).not_to have_selector('#escalation-status-help') @@ -95,7 +102,9 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d end def current_status - widget.find('[data-testid="collapsed-content"]') + within widget do + find_by_testid('collapsed-content') + end end end end @@ -108,9 +117,9 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d click_button 'Edit title and description' wait_for_requests - page.within('[data-testid="issuable-form"]') do + within_testid('issuable-form') do click_button 'Issue' - find('[data-testid="issue-type-list-item"]', text: 'Incident').click + find_by_testid('issue-type-list-item', text: 'Incident').click click_button 'Save changes' end @@ -130,9 +139,9 @@ RSpec.describe 'Incident details', :js, feature_category: :incident_management d click_button 'Edit title and description' wait_for_requests - page.within('[data-testid="issuable-form"]') do + within_testid('issuable-form') do click_button 'Incident' - find('[data-testid="issue-type-list-item"]', text: 'Issue').click + find_by_testid('issue-type-list-item', text: 'Issue').click click_button 'Save changes' end diff --git a/spec/features/incidents/incident_timeline_events_spec.rb b/spec/features/incidents/incident_timeline_events_spec.rb index bd3658ab60f..4ceae0f8780 100644 --- a/spec/features/incidents/incident_timeline_events_spec.rb +++ b/spec/features/incidents/incident_timeline_events_spec.rb @@ -86,8 +86,8 @@ RSpec.describe 'Incident timeline events', :js, feature_category: :incident_mana def trigger_dropdown_action(text) click_button _('More actions') - page.within '[data-testid="disclosure-content"]' do - page.find('[data-testid="disclosure-dropdown-item"]', text: text).click + within_testid 'disclosure-content' do + find_by_testid('disclosure-dropdown-item', text: text).click end end end diff --git a/spec/features/issuables/shortcuts_issuable_spec.rb b/spec/features/issuables/shortcuts_issuable_spec.rb index 6bb453c34e6..13bec61e4da 100644 --- a/spec/features/issuables/shortcuts_issuable_spec.rb +++ b/spec/features/issuables/shortcuts_issuable_spec.rb @@ -86,7 +86,7 @@ RSpec.describe 'Blob shortcuts', :js, feature_category: :team_planning do it "opens milestones dropdown for editing" do find('body').native.send_key('m') - expect(find('[data-testid="milestone-edit"]')).to have_selector('.gl-dropdown-inner') + expect(find_by_testid('milestone-edit')).to have_selector('.gl-dropdown-inner') end end diff --git a/spec/features/issues/form_spec.rb b/spec/features/issues/form_spec.rb index 2fb30469691..896d86e4004 100644 --- a/spec/features/issues/form_spec.rb +++ b/spec/features/issues/form_spec.rb @@ -148,12 +148,12 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do click_button _('Select label') wait_for_all_requests - page.within '[data-testid="sidebar-labels"]' do + within_testid('sidebar-labels') do click_button label.title click_button label2.title click_button _('Close') wait_for_requests - page.within('[data-testid="embedded-labels-list"]') do + within_testid('embedded-labels-list') do expect(page).to have_content(label.title) expect(page).to have_content(label2.title) end @@ -188,13 +188,13 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do wait_for_all_requests - page.within '[data-testid="sidebar-labels"]' do + within_testid 'sidebar-labels' do click_button label.title click_button _('Close') wait_for_requests - page.within('[data-testid="embedded-labels-list"]') do + within_testid('embedded-labels-list') do expect(page).to have_content(label.title) end @@ -205,7 +205,7 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do wait_for_all_requests - page.within '[data-testid="sidebar-labels"]' do + within_testid 'sidebar-labels' do click_button label.title, class: 'dropdown-item' click_button _('Close') @@ -221,7 +221,7 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do wait_for_all_requests - page.within '[data-testid="sidebar-labels"]' do + within_testid 'sidebar-labels' do search_field = find('input[type="search"]') search_field.native.send_keys(label.title) @@ -238,7 +238,7 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do it 'displays an error message when submitting an invalid form' do click_button 'Create issue' - page.within('[data-testid="issue-title-input-field"]') do + within_testid('issue-title-input-field') do expect(page).to have_text(_('This field is required.')) end end @@ -463,14 +463,14 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do wait_for_all_requests - page.within '[data-testid="sidebar-labels"]' do + within_testid 'sidebar-labels' do click_button label.title click_button label2.title click_button _('Close') wait_for_requests - page.within('[data-testid="embedded-labels-list"]') do + within_testid('embedded-labels-list') do expect(page).to have_content(label.title) expect(page).to have_content(label2.title) end @@ -580,14 +580,14 @@ RSpec.describe 'New/edit issue', :js, feature_category: :team_planning do wait_for_all_requests - page.within '[data-testid="sidebar-labels"]' do + within_testid 'sidebar-labels' do click_button _('Create project label') wait_for_requests end page.within '.js-labels-create' do - find('[data-testid="label-title-input"]').fill_in with: 'test label' + find_by_testid('label-title-input').fill_in with: 'test label' first('.suggest-colors-dropdown a').click click_button 'Create' diff --git a/spec/features/issues/incident_issue_spec.rb b/spec/features/issues/incident_issue_spec.rb index 5197f5d1e33..9225ba03003 100644 --- a/spec/features/issues/incident_issue_spec.rb +++ b/spec/features/issues/incident_issue_spec.rb @@ -35,7 +35,7 @@ RSpec.describe 'Incident Detail', :js, feature_category: :team_planning do it 'shows incident and alert data' do page.within('.issuable-details') do - incident_tabs = find('[data-testid="incident-tabs"]') + incident_tabs = find_by_testid('incident-tabs') aggregate_failures 'shows title and Summary tab' do expect(find('h1')).to have_content(incident.title) diff --git a/spec/features/issues/issue_detail_spec.rb b/spec/features/issues/issue_detail_spec.rb index c8802a9cc71..15cb1678c55 100644 --- a/spec/features/issues/issue_detail_spec.rb +++ b/spec/features/issues/issue_detail_spec.rb @@ -138,7 +138,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do it 'cannot see Incident option' do open_issue_edit_form - page.within('[data-testid="issuable-form"]') do + within_testid('issuable-form') do expect(page).to have_content('Issue') expect(page).not_to have_content('Incident') end @@ -151,7 +151,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do it 'routes the user to the incident details page when the `issue_type` is set to incident' do open_issue_edit_form - page.within('[data-testid="issuable-form"]') do + within_testid('issuable-form') do update_type_select('Issue', 'Incident') expect(page).to have_current_path(incident_project_issues_path(project, issue)) @@ -181,7 +181,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do it 'routes the user to the issue details page when the `issue_type` is set to issue' do open_issue_edit_form - page.within('[data-testid="issuable-form"]') do + within_testid('issuable-form') do update_type_select('Incident', 'Issue') expect(page).to have_current_path(project_issue_path(project, incident)) @@ -193,7 +193,7 @@ RSpec.describe 'Issue Detail', :js, feature_category: :team_planning do def update_type_select(from, to) click_button from - find('[data-testid="issue-type-list-item"]', text: to).click + find_by_testid('issue-type-list-item', text: to).click click_button 'Save changes' wait_for_requests diff --git a/spec/frontend/editor/schema/ci/ci_schema_spec.js b/spec/frontend/editor/schema/ci/ci_schema_spec.js index 0f380f13679..8e7f6e8e00a 100644 --- a/spec/frontend/editor/schema/ci/ci_schema_spec.js +++ b/spec/frontend/editor/schema/ci/ci_schema_spec.js @@ -23,6 +23,7 @@ import RetryUnknownWhenJson from './json_tests/negative_tests/retry_unknown_when // YAML POSITIVE TEST import ArtifactsYaml from './yaml_tests/positive_tests/artifacts.yml'; +import ImageYaml from './yaml_tests/positive_tests/image.yml'; import CacheYaml from './yaml_tests/positive_tests/cache.yml'; import FilterYaml from './yaml_tests/positive_tests/filter.yml'; import IncludeYaml from './yaml_tests/positive_tests/include.yml'; @@ -40,6 +41,7 @@ import ScriptYaml from './yaml_tests/positive_tests/script.yml'; // YAML NEGATIVE TEST import ArtifactsNegativeYaml from './yaml_tests/negative_tests/artifacts.yml'; +import ImageNegativeYaml from './yaml_tests/negative_tests/image.yml'; import CacheKeyNeative from './yaml_tests/negative_tests/cache.yml'; import IncludeNegativeYaml from './yaml_tests/negative_tests/include.yml'; import JobWhenNegativeYaml from './yaml_tests/negative_tests/job_when.yml'; @@ -90,6 +92,7 @@ describe('positive tests', () => { // YAML ArtifactsYaml, + ImageYaml, CacheYaml, FilterYaml, IncludeYaml, @@ -126,6 +129,7 @@ describe('negative tests', () => { // YAML ArtifactsNegativeYaml, + ImageNegativeYaml, CacheKeyNeative, HooksNegative, IdTokensNegativeYaml, diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/image.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/image.yml new file mode 100644 index 00000000000..ad37cd6c3ba --- /dev/null +++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/image.yml @@ -0,0 +1,38 @@ +empty_image: + image: + +multi_image_array: + image: + - alpine:latest + - ubuntu:latest + +image_without_name: + image: + entrypoint: ["/bin/sh", "-c"] + +image_with_invalid_entrypoint: + image: + name: my-postgres:11.7 + entrypoint: "/usr/local/bin/db-postgres" # must be array + +image_with_empty_pull_policy: + image: + name: postgres:11.6 + pull_policy: [] + +invalid_image_platform: + image: + name: alpine:latest + docker: + platform: ["arm64"] # The expected value is a string, not an array + +invalid_image_executor_opts: + image: + name: alpine:latest + docker: + unknown_key: test + +image_with_empty_executor_opts: + image: + name: alpine:latest + docker: diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml index 6761a603a0a..e14ac9ca86e 100644 --- a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml +++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/services.yml @@ -36,3 +36,17 @@ empty_pull_policy: services: - name: postgres:11.6 pull_policy: [] + +invalid_service_executor_opts: + script: echo "Specifying platform." + services: + - name: mysql:5.7 + docker: + unknown_key: test + +invalid_service_platform: + script: echo "Specifying platform." + services: + - name: mysql:5.7 + docker: + platform: ["arm64"] # The expected value is a string, not an array diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/image.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/image.yml new file mode 100644 index 00000000000..4c2559d0800 --- /dev/null +++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/image.yml @@ -0,0 +1,41 @@ +valid_image: + image: alpine:latest + +valid_image_basic: + image: + name: alpine:latest + +valid_image_with_entrypoint: + image: + name: alpine:latest + entrypoint: + - /bin/sh + - -c + +valid_image_with_pull_policy: + image: + name: alpine:latest + pull_policy: always + +valid_image_with_pull_policies: + image: + name: alpine:latest + pull_policy: + - always + - if-not-present + +valid_image_with_docker: + image: + name: alpine:latest + docker: + platform: linux/amd64 + +valid_image_full: + image: + name: alpine:latest + entrypoint: + - /bin/sh + - -c + docker: + platform: linux/amd64 + pull_policy: if-not-present diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml index 8a0f59d1dfd..1d19ee52cc3 100644 --- a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml +++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/services.yml @@ -29,3 +29,10 @@ pull_policy_array: services: - name: postgres:11.6 pull_policy: [always, if-not-present] + +services_platform_string: + script: echo "Specifying platform." + services: + - name: mysql:5.7 + docker: + platform: arm64 diff --git a/spec/lib/api/entities/ci/job_request/image_spec.rb b/spec/lib/api/entities/ci/job_request/image_spec.rb index 14d4a074fce..666ec31d3d9 100644 --- a/spec/lib/api/entities/ci/job_request/image_spec.rb +++ b/spec/lib/api/entities/ci/job_request/image_spec.rb @@ -4,7 +4,10 @@ require 'spec_helper' RSpec.describe API::Entities::Ci::JobRequest::Image do let(:ports) { [{ number: 80, protocol: 'http', name: 'name' }] } - let(:image) { double(name: 'image_name', entrypoint: ['foo'], ports: ports, pull_policy: ['if-not-present']) } + let(:image) do + double(name: 'image_name', entrypoint: ['foo'], executor_opts: {}, ports: ports, pull_policy: ['if-not-present']) + end + let(:entity) { described_class.new(image) } subject { entity.as_json } @@ -29,6 +32,10 @@ RSpec.describe API::Entities::Ci::JobRequest::Image do end end + it 'returns the executor_opts options' do + expect(subject[:executor_opts]).to eq({}) + end + it 'returns the pull policy' do expect(subject[:pull_policy]).to eq(['if-not-present']) end diff --git a/spec/lib/api/entities/ci/job_request/service_spec.rb b/spec/lib/api/entities/ci/job_request/service_spec.rb index 11350f7c41b..c2331799314 100644 --- a/spec/lib/api/entities/ci/job_request/service_spec.rb +++ b/spec/lib/api/entities/ci/job_request/service_spec.rb @@ -9,6 +9,7 @@ RSpec.describe API::Entities::Ci::JobRequest::Service do ::Gitlab::Ci::Build::Image, name: 'image_name', entrypoint: ['foo'], + executor_opts: {}, ports: ports, pull_policy: ['if-not-present'], alias: 'alias', @@ -25,6 +26,7 @@ RSpec.describe API::Entities::Ci::JobRequest::Service do expect(result).to eq( name: 'image_name', entrypoint: ['foo'], + executor_opts: {}, ports: ports, pull_policy: ['if-not-present'], alias: 'alias', diff --git a/spec/lib/gitlab/ci/build/image_spec.rb b/spec/lib/gitlab/ci/build/image_spec.rb index 4895077a731..f8c0d69be2e 100644 --- a/spec/lib/gitlab/ci/build/image_spec.rb +++ b/spec/lib/gitlab/ci/build/image_spec.rb @@ -10,7 +10,7 @@ RSpec.describe Gitlab::Ci::Build::Image do context 'when image is defined in job' do let(:image_name) { 'image:1.0' } - let(:job) { create(:ci_build, options: { image: image_name } ) } + let(:job) { create(:ci_build, options: { image: image_name }) } context 'when image is defined as string' do it 'fabricates an object of the proper class' do @@ -29,12 +29,14 @@ RSpec.describe Gitlab::Ci::Build::Image do context 'when image is defined as hash' do let(:entrypoint) { '/bin/sh' } let(:pull_policy) { %w[always if-not-present] } + let(:executor_opts) { { docker: { platform: 'arm64' } } } let(:job) do create(:ci_build, options: { image: { name: image_name, entrypoint: entrypoint, ports: [80], - pull_policy: pull_policy } } ) + executor_opts: executor_opts, + pull_policy: pull_policy } }) end it 'fabricates an object of the proper class' do @@ -44,6 +46,7 @@ RSpec.describe Gitlab::Ci::Build::Image do it 'populates fabricated object with the proper attributes' do expect(subject.name).to eq(image_name) expect(subject.entrypoint).to eq(entrypoint) + expect(subject.executor_opts).to eq(executor_opts) expect(subject.pull_policy).to eq(pull_policy) end @@ -98,11 +101,12 @@ RSpec.describe Gitlab::Ci::Build::Image do let(:service_entrypoint) { '/bin/sh' } let(:service_alias) { 'db' } let(:service_command) { 'sleep 30' } + let(:executor_opts) { { docker: { platform: 'amd64' } } } let(:pull_policy) { %w[always if-not-present] } let(:job) do create(:ci_build, options: { services: [{ name: service_image_name, entrypoint: service_entrypoint, alias: service_alias, command: service_command, ports: [80], - pull_policy: pull_policy }] }) + executor_opts: executor_opts, pull_policy: pull_policy }] }) end it 'fabricates an non-empty array of objects' do @@ -116,6 +120,7 @@ RSpec.describe Gitlab::Ci::Build::Image do expect(subject.first.entrypoint).to eq(service_entrypoint) expect(subject.first.alias).to eq(service_alias) expect(subject.first.command).to eq(service_command) + expect(subject.first.executor_opts).to eq(executor_opts) expect(subject.first.pull_policy).to eq(pull_policy) port = subject.first.ports.first diff --git a/spec/lib/gitlab/ci/config/entry/image_spec.rb b/spec/lib/gitlab/ci/config/entry/image_spec.rb index 17c45ec4c2c..99a6e25b313 100644 --- a/spec/lib/gitlab/ci/config/entry/image_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/image_spec.rb @@ -42,6 +42,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do end end + describe '#executor_opts' do + it "returns nil" do + expect(entry.executor_opts).to be_nil + end + end + describe '#ports' do it "returns image's ports" do expect(entry.ports).to be_nil @@ -88,6 +94,54 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do end end + context 'when configuration specifies docker' do + let(:config) { { name: 'image:1.0', docker: {} } } + + it 'is valid' do + expect(entry).to be_valid + end + + describe '#value' do + it "returns value" do + expect(entry.value).to eq( + name: 'image:1.0', + executor_opts: { + docker: {} + } + ) + end + end + + context "when docker specifies an option" do + let(:config) { { name: 'image:1.0', docker: { platform: 'amd64' } } } + + it 'is valid' do + expect(entry).to be_valid + end + + describe '#value' do + it "returns value" do + expect(entry.value).to eq( + name: 'image:1.0', + executor_opts: { + docker: { platform: 'amd64' } + } + ) + end + end + end + + context "when docker specifies an invalid option" do + let(:config) { { name: 'image:1.0', docker: { platform: 1 } } } + + it 'is not valid' do + expect(entry).not_to be_valid + expect(entry.errors.first) + .to match %r{image executor opts '/docker/platform' must be a valid 'string'} + end + end + end + context 'when configuration has ports' do let(:ports) { [{ number: 80, protocol: 'http', name: 'foobar' }] } let(:config) { { name: 'image:1.0', entrypoint: %w[/bin/sh run], ports: ports } } @@ -146,7 +200,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do describe '#errors' do it 'saves errors' do expect(entry.errors.first) - .to match /config should be a hash or a string/ + .to match(/config should be a hash or a string/) end end @@ -163,7 +217,7 @@ RSpec.describe Gitlab::Ci::Config::Entry::Image do describe '#errors' do it 'saves errors' do expect(entry.errors.first) - .to match /config contains unknown keys: non_existing/ + .to match(/config contains unknown keys: non_existing/) end end diff --git a/spec/lib/gitlab/ci/config/entry/service_spec.rb b/spec/lib/gitlab/ci/config/entry/service_spec.rb index bfe45645192..82747e7b521 100644 --- a/spec/lib/gitlab/ci/config/entry/service_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/service_spec.rb @@ -47,6 +47,12 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do expect(entry.ports).to be_nil end end + + describe '#executor_opts' do + it "returns service's executor_opts configuration" do + expect(entry.executor_opts).to be_nil + end + end end context 'when configuration is a hash' do @@ -147,6 +153,51 @@ RSpec.describe Gitlab::Ci::Config::Entry::Service do end end + context 'when configuration has docker options' do + let(:config) { { name: 'postgresql:9.5', docker: { platform: 'amd64' } } } + + describe '#valid?' do + it 'is valid' do + expect(entry).to be_valid + end + end + + describe '#value' do + it "returns value" do + expect(entry.value).to eq( + name: 'postgresql:9.5', + executor_opts: { + docker: { platform: 'amd64' } + } + ) + end + end + end + + context 'when docker options have an invalid property' do + let(:config) { { name: 'postgresql:9.5', docker: { invalid: 'option' } } } + + describe '#valid?' do + it 'is not valid' do + expect(entry).not_to be_valid + expect(entry.errors.first) + .to match %r{service executor opts '/docker/invalid' must be a valid 'schema'} + end + end + end + + context 'when docker options platform is not string' do + let(:config) { { name: 'postgresql:9.5', docker: { platform: 123 } } } + + describe '#valid?' do + it 'is not valid' do + expect(entry).not_to be_valid + expect(entry.errors.first) + .to match %r{service executor opts '/docker/platform' must be a valid 'string'} + end + end + end + context 'when configuration has pull_policy' do let(:config) { { name: 'postgresql:9.5', pull_policy: 'if-not-present' } } diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index f01c1c7d053..e44e01b2ffa 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -1313,6 +1313,46 @@ module Gitlab }) end end + + context 'when image and service have docker options' do + let(:config) do + <<~YAML + test: + script: exit 0 + image: + name: ruby:2.7 + docker: + platform: linux/amd64 + services: + - name: postgres:11.9 + docker: + platform: linux/amd64 + YAML + end + + it { is_expected.to be_valid } + + it "returns with image" do + expect(processor.builds).to contain_exactly({ + stage: "test", + stage_idx: 2, + name: "test", + only: { refs: %w[branches tags] }, + options: { + script: ["exit 0"], + image: { name: "ruby:2.7", + executor_opts: { docker: { platform: 'linux/amd64' } } }, + services: [{ name: "postgres:11.9", + executor_opts: { docker: { platform: 'linux/amd64' } } }] + }, + allow_failure: false, + when: "on_success", + job_variables: [], + root_variables_inheritance: true, + scheduling_type: :stage + }) + end + end end describe 'Variables' do diff --git a/spec/requests/api/ci/runner/jobs_request_post_spec.rb b/spec/requests/api/ci/runner/jobs_request_post_spec.rb index 2a870a25ea6..3d6d86335eb 100644 --- a/spec/requests/api/ci/runner/jobs_request_post_spec.rb +++ b/spec/requests/api/ci/runner/jobs_request_post_spec.rb @@ -272,16 +272,19 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego expect(json_response['job_info']).to include(expected_job_info) expect(json_response['git_info']).to eq(expected_git_info) expect(json_response['image']).to eq( - { 'name' => 'image:1.0', 'entrypoint' => '/bin/sh', 'ports' => [], 'pull_policy' => nil } + { 'name' => 'image:1.0', 'entrypoint' => '/bin/sh', 'ports' => [], 'executor_opts' => {}, + 'pull_policy' => nil } ) expect(json_response['services']).to eq( [ { 'name' => 'postgres', 'entrypoint' => nil, 'alias' => nil, 'command' => nil, 'ports' => [], - 'variables' => nil, 'pull_policy' => nil }, - { 'name' => 'docker:stable-dind', 'entrypoint' => '/bin/sh', 'alias' => 'docker', 'command' => 'sleep 30', - 'ports' => [], 'variables' => [], 'pull_policy' => nil }, + 'variables' => nil, 'executor_opts' => {}, 'pull_policy' => nil }, + { 'name' => 'docker:stable-dind', 'entrypoint' => '/bin/sh', 'alias' => 'docker', + 'command' => 'sleep 30', 'ports' => [], 'variables' => [], 'executor_opts' => {}, + 'pull_policy' => nil }, { 'name' => 'mysql:latest', 'entrypoint' => nil, 'alias' => nil, 'command' => nil, 'ports' => [], - 'variables' => [{ 'key' => 'MYSQL_ROOT_PASSWORD', 'value' => 'root123.' }], 'pull_policy' => nil } + 'variables' => [{ 'key' => 'MYSQL_ROOT_PASSWORD', 'value' => 'root123.' }], 'executor_opts' => {}, + 'pull_policy' => nil } ]) expect(json_response['steps']).to eq(expected_steps) expect(json_response['hooks']).to eq(expected_hooks) @@ -920,6 +923,41 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego end end + context 'when image has docker options' do + let(:job) { create(:ci_build, :pending, :queued, pipeline: pipeline, options: options) } + + let(:options) do + { + image: { + name: 'ruby', + executor_opts: { + docker: { + platform: 'amd64' + } + } + } + } + end + + it 'returns the image with docker options' do + request_job + + expect(response).to have_gitlab_http_status(:created) + expect(json_response).to include( + 'id' => job.id, + 'image' => { 'name' => 'ruby', + 'executor_opts' => { + 'docker' => { + 'platform' => 'amd64' + } + }, + 'pull_policy' => nil, + 'entrypoint' => nil, + 'ports' => [] } + ) + end + end + context 'when image has pull_policy' do let(:job) { create(:ci_build, :pending, :queued, pipeline: pipeline, options: options) } @@ -938,7 +976,11 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego expect(response).to have_gitlab_http_status(:created) expect(json_response).to include( 'id' => job.id, - 'image' => { 'name' => 'ruby', 'pull_policy' => ['if-not-present'], 'entrypoint' => nil, 'ports' => [] } + 'image' => { 'name' => 'ruby', + 'executor_opts' => {}, + 'pull_policy' => ['if-not-present'], + 'entrypoint' => nil, + 'ports' => [] } ) end end @@ -962,7 +1004,8 @@ RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_catego expect(json_response).to include( 'id' => job.id, 'services' => [{ 'alias' => nil, 'command' => nil, 'entrypoint' => nil, 'name' => 'postgres:11.9', - 'ports' => [], 'pull_policy' => ['if-not-present'], 'variables' => [] }] + 'ports' => [], 'executor_opts' => {}, 'pull_policy' => ['if-not-present'], + 'variables' => [] }] ) end end diff --git a/spec/requests/api/ci/runner/jobs_request_yamls_spec.rb b/spec/requests/api/ci/runner/jobs_request_yamls_spec.rb new file mode 100644 index 00000000000..f399c3e310e --- /dev/null +++ b/spec/requests/api/ci/runner/jobs_request_yamls_spec.rb @@ -0,0 +1,64 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::Ci::Runner, :clean_gitlab_redis_shared_state, feature_category: :continuous_integration do + include StubGitlabCalls + + let_it_be(:user) { create(:user) } + let_it_be(:project) { create(:project, :repository, shared_runners_enabled: false) } + let_it_be(:runner) { create(:ci_runner, :project, projects: [project]) } + + let(:user_agent) { 'gitlab-runner 9.0.0 (9-0-stable; go1.7.4; linux/amd64)' } + + before_all do + project.add_maintainer(user) + end + + Dir[Rails.root.join("spec/requests/api/ci/runner/yamls/*.yml")].each do |yml_file| + context "for #{File.basename(yml_file)}" do + let(:yaml_content) { YAML.load_file(yml_file) } + let(:gitlab_ci_yml) { yaml_content.fetch("gitlab_ci") } + let(:request_response) { yaml_content.fetch("request_response") } + + it 'runs a job' do + stub_ci_pipeline_yaml_file(YAML.dump(gitlab_ci_yml)) + + pipeline_response = create_pipeline! + expect(pipeline_response).to be_success, pipeline_response.message + expect(pipeline_response.payload).to be_created_successfully + expect(pipeline_response.payload.builds).to be_one + + build = pipeline_response.payload.builds.first + + process_pipeline!(pipeline_response.payload) + expect(build.reload).to be_pending + + request_job(runner.token) + expect(response).to have_gitlab_http_status(:created) + expect(response.headers['Content-Type']).to eq('application/json') + expect(json_response).to include('id' => build.id, 'token' => build.token) + expect(json_response).to include(request_response) + end + end + end + + def create_pipeline! + params = { ref: 'master', + before: '00000000', + after: project.commit.id, + commits: [{ message: 'some commit' }] } + + Ci::CreatePipelineService.new(project, user, params).execute(:push) + end + + def process_pipeline!(pipeline) + PipelineProcessWorker.new.perform(pipeline.id) + end + + def request_job(token, **params) + new_params = params.merge(token: token) + post api('/jobs/request'), params: new_params.to_json, + headers: { 'User-Agent' => user_agent, 'Content-Type': 'application/json' } + end +end diff --git a/spec/requests/api/ci/runner/yamls/README.md b/spec/requests/api/ci/runner/yamls/README.md new file mode 100644 index 00000000000..db8ef51ff9c --- /dev/null +++ b/spec/requests/api/ci/runner/yamls/README.md @@ -0,0 +1,15 @@ +# .gitlab-ci.yml end-to-end tests + +The purpose of this folder is to provide a single job `.gitlab-ci.yml` +that will be validated against end-to-end response that is send to runner. + +This allows to easily test end-to-end all CI job transformation that +and impact on how such job is rendered to be executed by the GitLab Runner. + +```yaml +gitlab_ci: + # .gitlab-ci.yml to stub + +request_response: + # exact payload that is checked as returned by `/api/v4/jobs/request` +``` diff --git a/spec/requests/api/ci/runner/yamls/image-basic.yml b/spec/requests/api/ci/runner/yamls/image-basic.yml new file mode 100644 index 00000000000..0c01dbc6e8b --- /dev/null +++ b/spec/requests/api/ci/runner/yamls/image-basic.yml @@ -0,0 +1,19 @@ +gitlab_ci: + rspec: + image: alpine:latest + script: echo Hello World + +request_response: + image: + name: alpine:latest + entrypoint: null + executor_opts: {} + ports: [] + pull_policy: null + steps: + - name: script + script: ["echo Hello World"] + timeout: 3600 + when: on_success + allow_failure: false + services: [] diff --git a/spec/requests/api/ci/runner/yamls/image-executor_opts-platform.yml b/spec/requests/api/ci/runner/yamls/image-executor_opts-platform.yml new file mode 100644 index 00000000000..62e301f2e9a --- /dev/null +++ b/spec/requests/api/ci/runner/yamls/image-executor_opts-platform.yml @@ -0,0 +1,25 @@ +gitlab_ci: + rspec: + image: + name: alpine:latest + docker: + platform: amd64 + script: echo Hello World + +request_response: + image: + name: alpine:latest + entrypoint: null + executor_opts: + docker: + platform: amd64 + ports: [] + pull_policy: null + steps: + - name: script + script: ["echo Hello World"] + timeout: 3600 + when: on_success + allow_failure: false + services: [] + diff --git a/spec/requests/api/ci/runner/yamls/service-basic.yml b/spec/requests/api/ci/runner/yamls/service-basic.yml new file mode 100644 index 00000000000..5438837c496 --- /dev/null +++ b/spec/requests/api/ci/runner/yamls/service-basic.yml @@ -0,0 +1,23 @@ +gitlab_ci: + rspec: + services: + - docker:dind + script: echo Hello World + +request_response: + image: null + steps: + - name: script + script: ["echo Hello World"] + timeout: 3600 + when: on_success + allow_failure: false + services: + - name: docker:dind + alias: null + command: null + entrypoint: null + executor_opts: {} + ports: [] + pull_policy: null + variables: [] diff --git a/spec/requests/api/ci/runner/yamls/service-executor_opts-platform.yml b/spec/requests/api/ci/runner/yamls/service-executor_opts-platform.yml new file mode 100644 index 00000000000..6483d749c45 --- /dev/null +++ b/spec/requests/api/ci/runner/yamls/service-executor_opts-platform.yml @@ -0,0 +1,27 @@ +gitlab_ci: + rspec: + services: + - name: docker:dind + docker: + platform: amd64 + script: echo Hello World + +request_response: + image: null + steps: + - name: script + script: ["echo Hello World"] + timeout: 3600 + when: on_success + allow_failure: false + services: + - name: docker:dind + alias: null + command: null + entrypoint: null + executor_opts: + docker: + platform: amd64 + ports: [] + pull_policy: null + variables: [] diff --git a/spec/requests/api/ci/runner/yamls/service-variables.yml b/spec/requests/api/ci/runner/yamls/service-variables.yml new file mode 100644 index 00000000000..c8e4dde674b --- /dev/null +++ b/spec/requests/api/ci/runner/yamls/service-variables.yml @@ -0,0 +1,30 @@ +gitlab_ci: + rspec: + services: + - name: docker:dind + variables: + DOCKER_HOST: tcp://docker:2375 + DOCKER_DRIVER: overlay2 + script: echo Hello World + +request_response: + image: null + steps: + - name: script + script: ["echo Hello World"] + timeout: 3600 + when: on_success + allow_failure: false + services: + - name: docker:dind + alias: null + command: null + entrypoint: null + executor_opts: {} + ports: [] + pull_policy: null + variables: + - key: DOCKER_HOST + value: tcp://docker:2375 + - key: DOCKER_DRIVER + value: overlay2 diff --git a/spec/requests/api/npm_project_packages_spec.rb b/spec/requests/api/npm_project_packages_spec.rb index b5f38698857..17cb5cf893e 100644 --- a/spec/requests/api/npm_project_packages_spec.rb +++ b/spec/requests/api/npm_project_packages_spec.rb @@ -54,14 +54,6 @@ RSpec.describe API::NpmProjectPackages, feature_category: :package_registry do it_behaves_like 'does not enqueue a worker to sync a metadata cache' - context 'when npm_metadata_cache disabled' do - before do - stub_feature_flags(npm_metadata_cache: false) - end - - it_behaves_like 'generates metadata response "on-the-fly"' - end - context 'when metadata cache file does not exist' do before do FileUtils.rm_rf(npm_metadata_cache.file.path) diff --git a/spec/requests/oauth/tokens_controller_spec.rb b/spec/requests/oauth/tokens_controller_spec.rb index aaacfce0ce8..b7755a30a78 100644 --- a/spec/requests/oauth/tokens_controller_spec.rb +++ b/spec/requests/oauth/tokens_controller_spec.rb @@ -55,6 +55,33 @@ RSpec.describe Oauth::TokensController, feature_category: :system_access do expect(response).to have_gitlab_http_status(:bad_request) expect(user.reload.failed_attempts).to eq(0) end + + context 'when the user has an identity matching a provider that is not password-based' do + before do + create(:identity, provider: 'google_oauth2', user: user) + end + + it 'fails to authenticate and does not call GitLab::Auth' do + expect(::Gitlab::Auth).not_to receive(:find_with_user_password) + + authenticate(password) + + expect(response).to have_gitlab_http_status(:bad_request) + expect(user.reload.failed_attempts).to eq(0) + end + end + + context 'when the user is a password-based omniauth user' do + before do + create(:identity, provider: 'ldapmain', user: user) + end + + it 'forwards the request to Gitlab::Auth' do + expect(::Gitlab::Auth).to receive(:find_with_user_password) + + authenticate(password) + end + end end end end diff --git a/spec/support/helpers/database/duplicate_indexes.yml b/spec/support/helpers/database/duplicate_indexes.yml index 0a01cb13e84..37aa4374608 100644 --- a/spec/support/helpers/database/duplicate_indexes.yml +++ b/spec/support/helpers/database/duplicate_indexes.yml @@ -27,9 +27,6 @@ boards_epic_board_recent_visits: boards_epic_user_preferences: index_boards_epic_user_preferences_on_board_user_epic_unique: - index_boards_epic_user_preferences_on_board_id -bulk_import_export_batches: - i_bulk_import_export_batches_id_batch_number: - - index_bulk_import_export_batches_on_export_id ci_job_artifacts: index_ci_job_artifacts_on_id_project_id_and_created_at: - index_ci_job_artifacts_on_project_id diff --git a/spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb b/spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb index de2dc4c3725..39870c41e1c 100644 --- a/spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb +++ b/spec/support/shared_examples/npm_sync_metadata_cache_worker_shared_examples.rb @@ -19,12 +19,4 @@ RSpec.shared_examples 'enqueue a worker to sync a metadata cache' do subject end - - context 'with npm_metadata_cache disabled' do - before do - stub_feature_flags(npm_metadata_cache: false) - end - - it_behaves_like 'does not enqueue a worker to sync a metadata cache' - end end diff --git a/spec/validators/json_schema_validator_spec.rb b/spec/validators/json_schema_validator_spec.rb index 01caf4ab0bd..f3a22892407 100644 --- a/spec/validators/json_schema_validator_spec.rb +++ b/spec/validators/json_schema_validator_spec.rb @@ -58,5 +58,30 @@ RSpec.describe JsonSchemaValidator do end end end + + context 'when detail_errors is true' do + let(:validator) { described_class.new(attributes: [:data], detail_errors: true, filename: "build_report_result_data") } + + context 'when data is valid' do + it 'returns no errors' do + subject + + expect(build_report_result.errors).to be_empty + end + end + + context 'when data is invalid' do + it 'returns json schema is invalid' do + build_report_result.data = { invalid: 'data' } + + subject + + expect(build_report_result.errors.size).to eq(1) + expect(build_report_result.errors.full_messages).to match_array( + ["Data '/invalid' must be a valid 'schema'"] + ) + end + end + end end end diff --git a/spec/workers/bulk_imports/entity_worker_spec.rb b/spec/workers/bulk_imports/entity_worker_spec.rb index 690555aa08f..4988a368598 100644 --- a/spec/workers/bulk_imports/entity_worker_spec.rb +++ b/spec/workers/bulk_imports/entity_worker_spec.rb @@ -49,10 +49,6 @@ RSpec.describe BulkImports::EntityWorker, feature_category: :importers do end end - it 'has the option to reschedule once if deduplicated' do - expect(described_class.get_deduplication_options).to include({ if_deduplicated: :reschedule_once }) - end - context 'when pipeline workers from a stage are running' do before do pipeline_tracker.enqueue! @@ -92,6 +88,26 @@ RSpec.describe BulkImports::EntityWorker, feature_category: :importers do worker.perform(entity.id) end + + context 'when exclusive lease cannot be obtained' do + it 'does not start next stage and re-enqueue worker' do + expect_next_instance_of(Gitlab::ExclusiveLease) do |lease| + expect(lease).to receive(:try_obtain).and_return(false) + end + + expect_next_instance_of(BulkImports::Logger) do |logger| + expect(logger).to receive(:info).with( + hash_including( + 'message' => 'Cannot obtain an exclusive lease. There must be another instance already in execution.' + ) + ) + end + + expect(described_class).to receive(:perform_in) + + worker.perform(entity.id) + end + end end context 'when there are no next stage to run' do diff --git a/spec/workers/packages/npm/create_metadata_cache_worker_spec.rb b/spec/workers/packages/npm/create_metadata_cache_worker_spec.rb index 360cc4223b4..a061d97ddf5 100644 --- a/spec/workers/packages/npm/create_metadata_cache_worker_spec.rb +++ b/spec/workers/packages/npm/create_metadata_cache_worker_spec.rb @@ -58,13 +58,5 @@ RSpec.describe Packages::Npm::CreateMetadataCacheWorker, type: :worker, feature_ it_behaves_like 'does not trigger service to create npm metadata cache' end - - context 'when npm_metadata_cache flag is disabled' do - before do - stub_feature_flags(npm_metadata_cache: false) - end - - it_behaves_like 'does not trigger service to create npm metadata cache' - end end end |