diff options
33 files changed, 419 insertions, 177 deletions
diff --git a/.rubocop_todo/lint/missing_cop_enable_directive.yml b/.rubocop_todo/lint/missing_cop_enable_directive.yml index 4c1c8430204..87ac47deaf5 100644 --- a/.rubocop_todo/lint/missing_cop_enable_directive.yml +++ b/.rubocop_todo/lint/missing_cop_enable_directive.yml @@ -1,8 +1,5 @@ --- Lint/MissingCopEnableDirective: - # Offense count: 199 - # Temporarily disabled due to too many offenses - Enabled: false Exclude: - 'app/controllers/admin/users_controller.rb' - 'app/controllers/projects/forks_controller.rb' @@ -20,14 +17,19 @@ Lint/MissingCopEnableDirective: - 'app/graphql/types/ci/build_need_type.rb' - 'app/graphql/types/ci/config/config_type.rb' - 'app/graphql/types/ci/config/group_type.rb' + - 'app/graphql/types/ci/config/include_type.rb' - 'app/graphql/types/ci/config/job_restriction_type.rb' - 'app/graphql/types/ci/config/job_type.rb' - 'app/graphql/types/ci/config/need_type.rb' - 'app/graphql/types/ci/config/stage_type.rb' - 'app/graphql/types/ci/group_type.rb' + - 'app/graphql/types/ci/group_variable_type.rb' + - 'app/graphql/types/ci/instance_variable_type.rb' - 'app/graphql/types/ci/job_artifact_type.rb' - 'app/graphql/types/ci/job_type.rb' + - 'app/graphql/types/ci/manual_variable_type.rb' - 'app/graphql/types/ci/pipeline_message_type.rb' + - 'app/graphql/types/ci/project_variable_type.rb' - 'app/graphql/types/ci/runner_architecture_type.rb' - 'app/graphql/types/ci/runner_platform_type.rb' - 'app/graphql/types/ci/runner_setup_type.rb' @@ -41,6 +43,7 @@ Lint/MissingCopEnableDirective: - 'app/graphql/types/countable_connection_type.rb' - 'app/graphql/types/design_management_type.rb' - 'app/graphql/types/issue_connection_type.rb' + - 'app/graphql/types/limited_countable_connection_type.rb' - 'app/graphql/types/merge_request_connection_type.rb' - 'app/graphql/types/packages/composer/json_type.rb' - 'app/graphql/types/packages/helm/dependency_type.rb' @@ -71,6 +74,7 @@ Lint/MissingCopEnableDirective: - 'db/migrate/20210818061156_remove_project_profile_compound_index_from_dast_profile_schedules.rb' - 'db/migrate/20210818115613_add_index_project_id_on_dast_profile_schedule.rb' - 'db/migrate/20211013014228_add_content_validation_endpoint_to_application_settings.rb' + - 'db/migrate/20220531024905_add_operations_access_levels_to_project_feature.rb' - 'db/post_migrate/20210825182303_remove_duplicate_dast_site_tokens_with_same_token.rb' - 'ee/app/controllers/ee/admin/dashboard_controller.rb' - 'ee/app/controllers/ee/admin/groups_controller.rb' @@ -90,6 +94,7 @@ Lint/MissingCopEnableDirective: - 'ee/app/graphql/types/ci/minutes/project_monthly_usage_type.rb' - 'ee/app/graphql/types/compliance_management/compliance_framework_type.rb' - 'ee/app/graphql/types/dast/profile_cadence_type.rb' + - 'ee/app/graphql/types/geo/ci_secure_file_registry_type.rb' - 'ee/app/graphql/types/geo/group_wiki_repository_registry_type.rb' - 'ee/app/graphql/types/geo/job_artifact_registry_type.rb' - 'ee/app/graphql/types/geo/lfs_object_registry_type.rb' @@ -107,6 +112,7 @@ Lint/MissingCopEnableDirective: - 'ee/app/graphql/types/security_report_summary_type.rb' - 'ee/app/graphql/types/security_scanners.rb' - 'ee/app/graphql/types/time_report_stats_type.rb' + - 'ee/app/graphql/types/timebox_error_type.rb' - 'ee/app/graphql/types/timebox_metrics_type.rb' - 'ee/app/graphql/types/timebox_report_type.rb' - 'ee/app/graphql/types/vulnerabilities_count_by_day_type.rb' @@ -135,20 +141,29 @@ Lint/MissingCopEnableDirective: - 'ee/app/graphql/types/vulnerable_dependency_type.rb' - 'ee/app/graphql/types/vulnerable_kubernetes_resource_type.rb' - 'ee/app/graphql/types/vulnerable_package_type.rb' + - 'ee/app/services/ee/ci/queue/build_queue_service.rb' + - 'ee/app/workers/ci/runners/stale_group_runners_prune_cron_worker.rb' - 'ee/app/workers/groups/export_memberships_worker.rb' - 'ee/app/workers/update_max_seats_used_for_gitlab_com_subscriptions_worker.rb' - 'ee/lib/api/ldap_group_links.rb' - 'ee/lib/api/scim.rb' + - 'ee/lib/ee/gitlab/background_migration/backfill_project_statistics_container_repository_size.rb' - 'ee/lib/ee/gitlab/background_migration/migrate_approver_to_approval_rules.rb' + - 'ee/lib/ee/gitlab/background_migration/purge_stale_security_scans.rb' - 'ee/lib/ee/gitlab/usage_data.rb' - - 'ee/lib/elastic/latest/git_class_proxy.rb' - 'ee/lib/gitlab/spdx/license.rb' + - 'ee/spec/controllers/projects/legacy_pipelines_controller_spec.rb' + - 'ee/spec/helpers/groups/security_features_helper_spec.rb' + - 'ee/spec/helpers/projects/security/discover_helper_spec.rb' + - 'ee/spec/lib/ee/gitlab/background_migration/delete_invalid_epic_issues_spec.rb' + - 'lib/gitlab/audit/null_author.rb' - 'lib/gitlab/auth/ldap/dn.rb' + - 'lib/gitlab/background_migration/backfill_imported_issue_search_data.rb' - 'lib/gitlab/background_migration/backfill_issue_search_data.rb' - 'lib/gitlab/background_migration/backfill_iteration_cadence_id_for_boards.rb' - 'lib/gitlab/background_migration/backfill_namespace_traversal_ids_children.rb' - 'lib/gitlab/background_migration/backfill_namespace_traversal_ids_roots.rb' - - 'lib/gitlab/background_migration/copy_ci_builds_columns_to_security_scans.rb' + - 'lib/gitlab/background_migration/delete_invalid_epic_issues.rb' - 'lib/gitlab/background_migration/drop_invalid_vulnerabilities.rb' - 'lib/gitlab/background_migration/fix_incorrect_max_seats_used.rb' - 'lib/gitlab/background_migration/mailers/unconfirm_mailer.rb' @@ -161,11 +176,13 @@ Lint/MissingCopEnableDirective: - 'lib/gitlab/background_migration/populate_resolved_on_default_branch_column.rb' - 'lib/gitlab/background_migration/populate_test_reports_issue_id.rb' - 'lib/gitlab/background_migration/populate_uuids_for_security_findings.rb' + - 'lib/gitlab/background_migration/purge_stale_security_scans.rb' - 'lib/gitlab/background_migration/recalculate_vulnerabilities_occurrences_uuid.rb' - 'lib/gitlab/background_migration/recalculate_vulnerability_finding_signatures_for_findings.rb' - 'lib/gitlab/background_migration/remove_duplicate_vulnerabilities_findings.rb' - 'lib/gitlab/background_migration/update_jira_tracker_data_deployment_type_based_on_url.rb' - 'lib/gitlab/background_migration/update_users_where_two_factor_auth_required_from_group.rb' + - 'lib/gitlab/buffered_io.rb' - 'lib/gitlab/ci/reports/test_suite_summary.rb' - 'lib/gitlab/data_builder/push.rb' - 'lib/gitlab/database/load_balancing/connection_proxy.rb' @@ -174,7 +191,6 @@ Lint/MissingCopEnableDirective: - 'lib/gitlab/github_import/client.rb' - 'lib/gitlab/github_import/importer/diff_note_importer.rb' - 'lib/gitlab/gon_helper.rb' - - 'lib/gitlab/graphql/pagination/keyset/generic_keyset_pagination.rb' - 'lib/gitlab/graphql/pagination/keyset/last_items.rb' - 'lib/gitlab/graphql/standard_graphql_error.rb' - 'lib/gitlab/metrics/methods.rb' @@ -184,10 +200,13 @@ Lint/MissingCopEnableDirective: - 'lib/gitlab/testing/request_blocker_middleware.rb' - 'lib/gitlab/testing/request_inspector_middleware.rb' - 'lib/gitlab/testing/robots_blocker_middleware.rb' + - 'lib/unnested_in_filters/dsl.rb' + - 'lib/unnested_in_filters/rewriter.rb' - 'qa/qa/scenario/test/integration/registry_with_cdn.rb' - 'spec/benchmarks/banzai_benchmark.rb' - 'spec/lib/gitlab/sidekiq_middleware/size_limiter/server_spec.rb' + - 'spec/lib/initializer_connections_spec.rb' - 'spec/support/capybara.rb' - 'spec/support/cycle_analytics_helpers/test_generation.rb' - 'spec/support/google_api/cloud_platform_helpers.rb' - - 'tooling/danger/product_intelligence.rb'
\ No newline at end of file + - 'tooling/danger/product_intelligence.rb' diff --git a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue index 7ed77426a5e..54b9953270b 100644 --- a/app/assets/javascripts/batch_comments/components/submit_dropdown.vue +++ b/app/assets/javascripts/batch_comments/components/submit_dropdown.vue @@ -84,7 +84,7 @@ export default { class="submit-review-dropdown" data-qa-selector="submit_review_dropdown" variant="info" - category="secondary" + category="primary" > <template #button-content> {{ __('Finish review') }} @@ -139,7 +139,7 @@ export default { </div> </div> </gl-form-group> - <div class="gl-display-flex gl-justify-content-end gl-mt-5"> + <div class="gl-display-flex gl-justify-content-start gl-mt-5"> <gl-button :loading="isSubmitting" variant="confirm" diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue index f5946797626..36e1b883400 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/details/package_title.vue @@ -65,9 +65,6 @@ export default { this.checkBreakpoints(); }, methods: { - dynamicSlotName(index) { - return `metadata-tag${index}`; - }, checkBreakpoints() { this.isDesktop = GlBreakpointInstance.isDesktop(); }, @@ -83,21 +80,38 @@ export default { data-qa-selector="package_title" > <template #sub-header> - <span data-testid="sub-header"> + <div data-testid="sub-header" class="gl-display-flex gl-gap-3"> <gl-sprintf :message="$options.i18n.packageInfo"> <template #version> {{ packageEntity.version }} </template> <template #timeAgo> - <time-ago-tooltip - v-if="packageEntity.createdAt" - class="gl-ml-2" - :time="packageEntity.createdAt" - /> + <time-ago-tooltip v-if="packageEntity.createdAt" :time="packageEntity.createdAt" /> </template> </gl-sprintf> - </span> + + <package-tags + v-if="isDesktop && hasTagsToDisplay" + :tag-display-limit="2" + :tags="packageEntity.tags.nodes" + hide-label + /> + + <!-- we need to duplicate the package tags on mobile to ensure proper styling inside the flex wrap --> + <template v-else-if="hasTagsToDisplay"> + <gl-badge + v-for="(tag, index) in packageEntity.tags.nodes" + :key="index" + class="gl-my-1" + data-testid="tag-badge" + variant="info" + size="sm" + > + {{ tag.name }} + </gl-badge> + </template> + </div> </template> <template v-if="packageTypeDisplay" #metadata-type> @@ -121,21 +135,6 @@ export default { <metadata-item data-testid="package-ref" icon="branch" :text="packagePipeline.ref" /> </template> - <template v-if="isDesktop && hasTagsToDisplay" #metadata-tags> - <package-tags :tag-display-limit="2" :tags="packageEntity.tags.nodes" hide-label /> - </template> - - <!-- we need to duplicate the package tags on mobile to ensure proper styling inside the flex wrap --> - <template - v-for="(tag, index) in packageEntity.tags.nodes" - v-else-if="hasTagsToDisplay" - #[dynamicSlotName(index)] - > - <gl-badge :key="index" class="gl-my-1" data-testid="tag-badge" variant="info" size="sm"> - {{ tag.name }} - </gl-badge> - </template> - <template #right-actions> <slot name="delete-button"></slot> </template> diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy.vue index 90a18d5cf5a..1c44d2bc38b 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/container_expiration_policy.vue @@ -11,7 +11,7 @@ import { UNAVAILABLE_ADMIN_FEATURE_TEXT, } from '~/packages_and_registries/settings/project/constants'; import expirationPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_expiration_policy.query.graphql'; -import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; +import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue'; import ContainerExpirationPolicyForm from './container_expiration_policy_form.vue'; diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue index 7682754fdcb..f06e3a41bd0 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/expiration_dropdown.vue @@ -35,22 +35,34 @@ export default { required: false, default: '', }, + dropdownClass: { + type: String, + required: false, + default: '', + }, }, }; </script> <template> <gl-form-group :id="`${name}-form-group`" :label-for="name" :label="label"> - <gl-form-select :id="name" :value="value" :disabled="disabled" @input="$emit('input', $event)"> - <option - v-for="option in formOptions" - :key="option.key" - :value="option.key" - data-testid="option" + <div :class="dropdownClass"> + <gl-form-select + :id="name" + :value="value" + :disabled="disabled" + @input="$emit('input', $event)" > - {{ option.label }} - </option> - </gl-form-select> + <option + v-for="option in formOptions" + :key="option.key" + :value="option.key" + data-testid="option" + > + {{ option.label }} + </option> + </gl-form-select> + </div> <template v-if="description" #description> <span data-testid="description" class="gl-text-gray-400"> {{ description }} diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy.vue index 1170407a349..2f4bc35e5f7 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy.vue @@ -6,7 +6,7 @@ import { PACKAGES_CLEANUP_POLICY_DESCRIPTION, } from '~/packages_and_registries/settings/project/constants'; import packagesCleanupPolicyQuery from '~/packages_and_registries/settings/project/graphql/queries/get_packages_cleanup_policy.query.graphql'; -import SettingsBlock from '~/vue_shared/components/settings/settings_block.vue'; +import SettingsBlock from '~/packages_and_registries/shared/components/settings_block.vue'; import PackagesCleanupPolicyForm from './packages_cleanup_policy_form.vue'; diff --git a/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue index b1751d5174a..f1f0b970b15 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue +++ b/app/assets/javascripts/packages_and_registries/settings/project/components/packages_cleanup_policy_form.vue @@ -3,10 +3,10 @@ import { GlButton } from '@gitlab/ui'; import { UPDATE_SETTINGS_ERROR_MESSAGE, UPDATE_SETTINGS_SUCCESS_MESSAGE, - SET_CLEANUP_POLICY_BUTTON, KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION, KEEP_N_DUPLICATED_PACKAGE_FILES_FIELDNAME, KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL, + SET_CLEANUP_POLICY_BUTTON, } from '~/packages_and_registries/settings/project/constants'; import updatePackagesCleanupPolicyMutation from '~/packages_and_registries/settings/project/graphql/mutations/update_packages_cleanup_policy.mutation.graphql'; import { formOptionsGenerator } from '~/packages_and_registries/settings/project/utils'; @@ -108,18 +108,17 @@ export default { <template> <form ref="form-element" @submit.prevent="submit"> - <div class="gl-md-max-w-50p"> - <expiration-dropdown - v-model="prefilledForm.keepNDuplicatedPackageFiles" - :disabled="isFieldDisabled" - :form-options="$options.formOptions.keepNDuplicatedPackageFiles" - :label="$options.i18n.KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL" - :description="$options.i18n.KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION" - name="keep-n-duplicated-package-files" - data-testid="keep-n-duplicated-package-files-dropdown" - @input="onModelChange($event, 'keepNDuplicatedPackageFiles')" - /> - </div> + <expiration-dropdown + :value="prefilledForm.keepNDuplicatedPackageFiles" + :disabled="isFieldDisabled" + :form-options="$options.formOptions.keepNDuplicatedPackageFiles" + :label="$options.i18n.KEEP_N_DUPLICATED_PACKAGE_FILES_LABEL" + :description="$options.i18n.KEEP_N_DUPLICATED_PACKAGE_FILES_DESCRIPTION" + dropdown-class="gl-md-max-w-50p gl-sm-pr-5" + name="keep-n-duplicated-package-files" + data-testid="keep-n-duplicated-package-files-dropdown" + @input="onModelChange($event, 'keepNDuplicatedPackageFiles')" + /> <div class="gl-mt-7 gl-display-flex gl-align-items-center"> <gl-button data-testid="save-button" diff --git a/app/assets/javascripts/packages_and_registries/settings/project/constants.js b/app/assets/javascripts/packages_and_registries/settings/project/constants.js index 948520151ce..fcb4a8ee297 100644 --- a/app/assets/javascripts/packages_and_registries/settings/project/constants.js +++ b/app/assets/javascripts/packages_and_registries/settings/project/constants.js @@ -4,7 +4,7 @@ export const CONTAINER_CLEANUP_POLICY_TITLE = s__(`ContainerRegistry|Clean up im export const CONTAINER_CLEANUP_POLICY_DESCRIPTION = s__( `ContainerRegistry|Save storage space by automatically deleting tags from the container registry and keeping the ones you want. %{linkStart}How does cleanup work?%{linkEnd}`, ); -export const SET_CLEANUP_POLICY_BUTTON = __('Save'); +export const SET_CLEANUP_POLICY_BUTTON = __('Save changes'); export const UNAVAILABLE_FEATURE_TITLE = s__( `ContainerRegistry|Cleanup policy for tags is disabled`, ); diff --git a/app/assets/javascripts/packages_and_registries/shared/components/settings_block.vue b/app/assets/javascripts/packages_and_registries/shared/components/settings_block.vue index 5caf95cd050..0458b914b58 100644 --- a/app/assets/javascripts/packages_and_registries/shared/components/settings_block.vue +++ b/app/assets/javascripts/packages_and_registries/shared/components/settings_block.vue @@ -1,7 +1,7 @@ <template> <section class="settings gl-py-7"> - <div class="gl-lg-display-flex"> - <div class="gl-lg-w-half gl-pr-10"> + <div class="gl-lg-display-flex gl-gap-6"> + <div class="gl-lg-w-40p gl-pr-10 gl-flex-shrink-0"> <h4> <slot name="title"></slot> </h4> @@ -9,7 +9,7 @@ <slot name="description"></slot> </p> </div> - <div class="gl-lg-w-half gl-pt-3"> + <div class="gl-pt-3 gl-flex-grow-1"> <slot></slot> </div> </div> diff --git a/app/graphql/mutations/ci/runners_registration_token/reset.rb b/app/graphql/mutations/ci/runners_registration_token/reset.rb index 8c49b682ab0..c9fe7ea47f0 100644 --- a/app/graphql/mutations/ci/runners_registration_token/reset.rb +++ b/app/graphql/mutations/ci/runners_registration_token/reset.rb @@ -49,7 +49,10 @@ module Mutations end def reset_token(scope) - ::Ci::Runners::ResetRegistrationTokenService.new(scope, current_user).execute if scope + return unless scope + + result = ::Ci::Runners::ResetRegistrationTokenService.new(scope, current_user).execute + result.payload[:new_registration_token] if result.success? end end end diff --git a/app/models/ci/runner.rb b/app/models/ci/runner.rb index 47d9cb9393e..6c3754d84d0 100644 --- a/app/models/ci/runner.rb +++ b/app/models/ci/runner.rb @@ -437,7 +437,12 @@ module Ci cache_attributes(values) # We save data without validation, it will always change due to `contacted_at` - self.update_columns(values) if persist_cached_data? + if persist_cached_data? + version_updated = values.include?(:version) && values[:version] != version + + update_columns(values) + schedule_runner_version_update if version_updated + end end end @@ -565,6 +570,12 @@ module Ci errors.add(:runner, 'needs to be assigned to exactly one group') end end + + def schedule_runner_version_update + return unless version + + Ci::Runners::ProcessRunnerVersionUpdateWorker.perform_async(version) + end end end diff --git a/app/services/ci/runners/process_runner_version_update_service.rb b/app/services/ci/runners/process_runner_version_update_service.rb new file mode 100644 index 00000000000..ed591a9ab3e --- /dev/null +++ b/app/services/ci/runners/process_runner_version_update_service.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +module Ci + module Runners + class ProcessRunnerVersionUpdateService + def initialize(version) + @version = version + end + + def execute + return ServiceResponse.error(message: 'version not present') unless @version + + _, status = upgrade_check_service.check_runner_upgrade_suggestion(@version) + return ServiceResponse.error(message: 'upgrade version check failed') if status == :error + + Ci::RunnerVersion.upsert({ version: @version, status: status }) + ServiceResponse.success(payload: { upgrade_status: status.to_s }) + end + + private + + def upgrade_check_service + Gitlab::Ci::RunnerUpgradeCheck.instance + end + end + end +end diff --git a/app/services/ci/runners/reset_registration_token_service.rb b/app/services/ci/runners/reset_registration_token_service.rb index 81a70a771cf..dddbfb78d44 100644 --- a/app/services/ci/runners/reset_registration_token_service.rb +++ b/app/services/ci/runners/reset_registration_token_service.rb @@ -11,15 +11,19 @@ module Ci end def execute - return unless @user.present? && @user.can?(:update_runners_registration_token, scope) + unless @user.present? && @user.can?(:update_runners_registration_token, scope) + return ServiceResponse.error(message: 'user not allowed to update runners registration token') + end if scope.respond_to?(:runners_registration_token) scope.reset_runners_registration_token! - scope.runners_registration_token + runners_token = scope.runners_registration_token else scope.reset_runners_token! - scope.runners_token + runners_token = scope.runners_token end + + ServiceResponse.success(payload: { new_registration_token: runners_token }) end private diff --git a/app/views/profiles/emails/index.html.haml b/app/views/profiles/emails/index.html.haml index 0ec32004a9a..ef9e7512b57 100644 --- a/app/views/profiles/emails/index.html.haml +++ b/app/views/profiles/emails/index.html.haml @@ -36,28 +36,31 @@ %ul.content-list %li = render partial: 'shared/email_with_badge', locals: { email: @primary_email, verified: current_user.confirmed? } - %span.float-right - = gl_badge_tag s_('Profiles|Primary email'), variant: :success + %ul + %li= s_('Profiles|Primary email') - if @primary_email === current_user.commit_email_or_default - = gl_badge_tag s_('Profiles|Commit email'), variant: :info + %li= s_('Profiles|Commit email') - if @primary_email === current_user.public_email - = gl_badge_tag s_('Profiles|Public email'), variant: :info + %li= s_('Profiles|Public email') - if @primary_email === current_user.notification_email_or_default - = gl_badge_tag s_('Profiles|Default notification email'), variant: :info + %li= s_('Profiles|Default notification email') - @emails.reject(&:user_primary_email?).each do |email| %li{ data: { qa_selector: 'email_row_content' } } - = render partial: 'shared/email_with_badge', locals: { email: email.email, verified: email.confirmed? } - %span.float-right + .gl-display-flex.gl-justify-content-space-between{ style: 'flex-flow: wrap-reverse; row-gap: 0.5rem' } + %div + = render partial: 'shared/email_with_badge', locals: { email: email.email, verified: email.confirmed? } + .gl-ml-n3 + - unless email.confirmed? + - confirm_title = "#{email.confirmation_sent_at ? _('Resend confirmation email') : _('Send confirmation email')}" + = link_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, class: 'gl-button btn btn-sm btn-default gl-ml-3' + + = link_to profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, class: 'gl-button btn btn-sm btn-danger gl-ml-3' do + %span.sr-only= _('Remove') + = sprite_icon('remove') + %ul - if email.email === current_user.commit_email_or_default - = gl_badge_tag s_('Profiles|Commit email'), variant: :info + %li= s_('Profiles|Commit email') - if email.email === current_user.public_email - = gl_badge_tag s_('Profiles|Public email'), variant: :info + %li= s_('Profiles|Public email') - if email.email === current_user.notification_email_or_default - = gl_badge_tag s_('Profiles|Notification email'), variant: :info - - unless email.confirmed? - - confirm_title = "#{email.confirmation_sent_at ? _('Resend confirmation email') : _('Send confirmation email')}" - = link_to confirm_title, resend_confirmation_instructions_profile_email_path(email), method: :put, class: 'gl-button btn btn-sm btn-default gl-ml-3' - - = link_to profile_email_path(email), data: { confirm: _('Are you sure?'), qa_selector: 'delete_email_link'}, method: :delete, class: 'gl-button btn btn-sm btn-danger gl-ml-3' do - %span.sr-only= _('Remove') - = sprite_icon('remove') + %li= s_('Profiles|Notification email') diff --git a/app/workers/all_queues.yml b/app/workers/all_queues.yml index 2fc1998568c..73a9eea3a7d 100644 --- a/app/workers/all_queues.yml +++ b/app/workers/all_queues.yml @@ -2136,6 +2136,15 @@ :weight: 1 :idempotent: true :tags: [] +- :name: ci_runners_process_runner_version_update + :worker_name: Ci::Runners::ProcessRunnerVersionUpdateWorker + :feature_category: :runner_fleet + :has_external_dependencies: false + :urgency: :low + :resource_boundary: :unknown + :weight: 1 + :idempotent: true + :tags: [] - :name: create_commit_signature :worker_name: CreateCommitSignatureWorker :feature_category: :source_code_management diff --git a/app/workers/ci/runners/process_runner_version_update_worker.rb b/app/workers/ci/runners/process_runner_version_update_worker.rb new file mode 100644 index 00000000000..f1ad0c8563e --- /dev/null +++ b/app/workers/ci/runners/process_runner_version_update_worker.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +module Ci + module Runners + class ProcessRunnerVersionUpdateWorker + include ApplicationWorker + + data_consistency :always + + feature_category :runner_fleet + urgency :low + + idempotent! + deduplicate :until_executing + + def perform(version) + result = ::Ci::Runners::ProcessRunnerVersionUpdateService.new(version).execute + + result.to_h.slice(:status, :message, :upgrade_status).each do |key, value| + log_extra_metadata_on_done(key, value) + end + end + end + end +end diff --git a/config/sidekiq_queues.yml b/config/sidekiq_queues.yml index b4e2071668e..d49c2f1b072 100644 --- a/config/sidekiq_queues.yml +++ b/config/sidekiq_queues.yml @@ -93,6 +93,8 @@ - 1 - - ci_job_artifacts_expire_project_build_artifacts - 1 +- - ci_runners_process_runner_version_update + - 1 - - ci_upstream_projects_subscriptions_cleanup - 1 - - cluster_agent diff --git a/doc/ci/variables/predefined_variables.md b/doc/ci/variables/predefined_variables.md index 024e47b2cea..87624d98bbb 100644 --- a/doc/ci/variables/predefined_variables.md +++ b/doc/ci/variables/predefined_variables.md @@ -93,7 +93,7 @@ as it can cause the pipeline to behave unexpectedly. | `CI_PROJECT_NAMESPACE` | 8.10 | 0.5 | The project namespace (username or group name) of the job. | | `CI_PROJECT_PATH_SLUG` | 9.3 | all | `$CI_PROJECT_PATH` in lowercase with characters that are not `a-z` or `0-9` replaced with `-` and shortened to 63 bytes. Use in URLs and domain names. | | `CI_PROJECT_PATH` | 8.10 | 0.5 | The project namespace with the project name included. | -| `CI_PROJECT_REPOSITORY_LANGUAGES` | 12.3 | all | A comma-separated, lowercase list of the languages used in the repository. For example `ruby,javascript,html,css`. | +| `CI_PROJECT_REPOSITORY_LANGUAGES` | 12.3 | all | A comma-separated, lowercase list of the languages used in the repository. For example `ruby,javascript,html,css`. The maximum number of languages is limited to 5. An issue [proposes to increase the limit](https://gitlab.com/gitlab-org/gitlab/-/issues/368925). | | `CI_PROJECT_ROOT_NAMESPACE` | 13.2 | 0.5 | The root project namespace (username or group name) of the job. For example, if `CI_PROJECT_NAMESPACE` is `root-group/child-group/grandchild-group`, `CI_PROJECT_ROOT_NAMESPACE` is `root-group`. | | `CI_PROJECT_TITLE` | 12.4 | all | The human-readable project name as displayed in the GitLab web interface. | | `CI_PROJECT_DESCRIPTION` | 15.1 | all | The project description as displayed in the GitLab web interface. | diff --git a/doc/user/project/pages/pages_access_control.md b/doc/user/project/pages/pages_access_control.md index eb897c176fa..e6446c34bf0 100644 --- a/doc/user/project/pages/pages_access_control.md +++ b/doc/user/project/pages/pages_access_control.md @@ -6,8 +6,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w # GitLab Pages access control **(FREE)** -> Available on GitLab.com in GitLab 12.4. - You can enable Pages access control on your project if your administrator has [enabled the access control feature](../../../administration/pages/index.md#access-control) on your GitLab instance. When enabled, only authenticated diff --git a/lib/gitlab/background_migration/migrate_shared_vulnerability_scanners.rb b/lib/gitlab/background_migration/migrate_shared_vulnerability_scanners.rb index 6b6fa1cc848..bea0120f093 100644 --- a/lib/gitlab/background_migration/migrate_shared_vulnerability_scanners.rb +++ b/lib/gitlab/background_migration/migrate_shared_vulnerability_scanners.rb @@ -7,8 +7,10 @@ module Gitlab def perform end end + # rubocop: enable Style/Documentation end end # rubocop: disable Layout/LineLength Gitlab::BackgroundMigration::MigrateSharedVulnerabilityScanners.prepend_mod_with("Gitlab::BackgroundMigration::MigrateSharedVulnerabilityScanners") +# rubocop: enable Layout/LineLength diff --git a/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml b/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml index 464b81965f2..dc55277318b 100644 --- a/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Getting-Started.gitlab-ci.yml @@ -42,6 +42,7 @@ lint-test-job: # This job also runs in the test stage. deploy-job: # This job runs in the deploy stage. stage: deploy # It only runs when *both* jobs in the test stage complete successfully. + environment: production script: - echo "Deploying application..." - echo "Application successfully deployed." diff --git a/lib/gitlab/tracking.rb b/lib/gitlab/tracking.rb index 04745bafe7c..3b46b4c5498 100644 --- a/lib/gitlab/tracking.rb +++ b/lib/gitlab/tracking.rb @@ -41,7 +41,7 @@ module Gitlab def snowplow_micro_enabled? Rails.env.development? && Gitlab.config.snowplow_micro.enabled rescue Settingslogic::MissingSetting - Gitlab::Utils.to_boolean(ENV['SNOWPLOW_MICRO_ENABLE']) + false end private diff --git a/lib/gitlab/tracking/destinations/snowplow_micro.rb b/lib/gitlab/tracking/destinations/snowplow_micro.rb index c7a95e88d0b..09480f26106 100644 --- a/lib/gitlab/tracking/destinations/snowplow_micro.rb +++ b/lib/gitlab/tracking/destinations/snowplow_micro.rb @@ -54,7 +54,7 @@ module Gitlab scheme = Gitlab.config.gitlab.https ? 'https' : 'http' "#{scheme}://#{url}" rescue Settingslogic::MissingSetting - ENV['SNOWPLOW_MICRO_URI'] || DEFAULT_URI + DEFAULT_URI end end end diff --git a/spec/controllers/projects/merge_requests_controller_spec.rb b/spec/controllers/projects/merge_requests_controller_spec.rb index 8ccbc0d3fe2..a943a5e0205 100644 --- a/spec/controllers/projects/merge_requests_controller_spec.rb +++ b/spec/controllers/projects/merge_requests_controller_spec.rb @@ -1894,15 +1894,12 @@ RSpec.describe Projects::MergeRequestsController do # First run to insert test data from lets, which does take up some 30 queries get_ci_environments_status - control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) { get_ci_environments_status }.count + control_count = ActiveRecord::QueryRecorder.new { get_ci_environments_status } environment2 = create(:environment, project: forked) create(:deployment, :succeed, environment: environment2, sha: sha, ref: 'master', deployable: build) - # TODO address the last 3 queries - # See https://gitlab.com/gitlab-org/gitlab-foss/issues/63952 (3 queries) - leeway = 3 - expect { get_ci_environments_status }.not_to exceed_all_query_limit(control_count + leeway) + expect { get_ci_environments_status }.not_to exceed_all_query_limit(control_count) end end diff --git a/spec/features/projects/settings/registry_settings_spec.rb b/spec/features/projects/settings/registry_settings_spec.rb index 9468540736f..1fb46c669e7 100644 --- a/spec/features/projects/settings/registry_settings_spec.rb +++ b/spec/features/projects/settings/registry_settings_spec.rb @@ -31,7 +31,6 @@ RSpec.describe 'Project > Settings > Packages & Registries > Container registry subject within '[data-testid="container-expiration-policy-project-settings"]' do - click_button('Expand') select('Every day', from: 'Run cleanup') select('50 tags per image name', from: 'Keep the most recent:') fill_in('Keep tags matching:', with: 'stable') @@ -50,7 +49,6 @@ RSpec.describe 'Project > Settings > Packages & Registries > Container registry subject within '[data-testid="container-expiration-policy-project-settings"]' do - click_button('Expand') fill_in('Remove tags matching:', with: '*-production') submit_button = find('[data-testid="save-button"') @@ -76,7 +74,6 @@ RSpec.describe 'Project > Settings > Packages & Registries > Container registry subject within '[data-testid="container-expiration-policy-project-settings"]' do - click_button('Expand') expect(find('[data-testid="enable-toggle"]')).to have_content('Disabled - Tags will not be automatically deleted.') end end @@ -91,7 +88,6 @@ RSpec.describe 'Project > Settings > Packages & Registries > Container registry subject within '[data-testid="container-expiration-policy-project-settings"]' do - click_button('Expand') expect(find('.gl-alert-title')).to have_content('Cleanup policy for tags is disabled') end end diff --git a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap index fdddc131412..61923233d2e 100644 --- a/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap +++ b/spec/frontend/packages_and_registries/package_registry/components/details/__snapshots__/package_title_spec.js.snap @@ -29,19 +29,25 @@ exports[`PackageTitle renders with tags 1`] = ` <div class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-3" > - <span + <div + class="gl-display-flex gl-gap-3" data-testid="sub-header" > v 1.0.0 published <time-ago-tooltip-stub - class="gl-ml-2" cssclass="" time="2020-08-17T14:23:32Z" tooltipplacement="top" /> - </span> + + <package-tags-stub + hidelabel="true" + tagdisplaylimit="2" + tags="[object Object],[object Object],[object Object]" + /> + </div> </div> </div> </div> @@ -73,15 +79,6 @@ exports[`PackageTitle renders with tags 1`] = ` texttooltip="" /> </div> - <div - class="gl-display-flex gl-align-items-center gl-mr-5" - > - <package-tags-stub - hidelabel="true" - tagdisplaylimit="2" - tags="[object Object],[object Object],[object Object]" - /> - </div> </div> </div> @@ -121,19 +118,21 @@ exports[`PackageTitle renders without tags 1`] = ` <div class="gl-display-flex gl-align-items-center gl-text-gray-500 gl-mt-3" > - <span + <div + class="gl-display-flex gl-gap-3" data-testid="sub-header" > v 1.0.0 published <time-ago-tooltip-stub - class="gl-ml-2" cssclass="" time="2020-08-17T14:23:32Z" tooltipplacement="top" /> - </span> + + <!----> + </div> </div> </div> </div> diff --git a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap index 108d9478788..5d08574234c 100644 --- a/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap +++ b/spec/frontend/packages_and_registries/settings/project/settings/components/__snapshots__/container_expiration_policy_form_spec.js.snap @@ -5,6 +5,7 @@ exports[`Container Expiration Policy Settings Form Cadence matches snapshot 1`] class="gl-mr-7 gl-mb-0!" data-testid="cadence-dropdown" description="" + dropdownclass="" formoptions="[object Object],[object Object],[object Object],[object Object],[object Object]" label="Run cleanup:" name="cadence" @@ -24,6 +25,7 @@ exports[`Container Expiration Policy Settings Form Keep N matches snapshot 1`] = <expiration-dropdown-stub data-testid="keep-n-dropdown" description="" + dropdownclass="" formoptions="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" label="Keep the most recent:" name="keep-n" @@ -47,6 +49,7 @@ exports[`Container Expiration Policy Settings Form OlderThan matches snapshot 1` <expiration-dropdown-stub data-testid="older-than-dropdown" description="" + dropdownclass="" formoptions="[object Object],[object Object],[object Object],[object Object],[object Object],[object Object]" label="Remove tags older than:" name="older-than" diff --git a/spec/lib/gitlab/tracking/destinations/snowplow_micro_spec.rb b/spec/lib/gitlab/tracking/destinations/snowplow_micro_spec.rb index 2554a15d97e..48092a33da3 100644 --- a/spec/lib/gitlab/tracking/destinations/snowplow_micro_spec.rb +++ b/spec/lib/gitlab/tracking/destinations/snowplow_micro_spec.rb @@ -48,40 +48,8 @@ RSpec.describe Gitlab::Tracking::Destinations::SnowplowMicro do allow(Gitlab.config).to receive(:snowplow_micro).and_raise(Settingslogic::MissingSetting) end - context 'when SNOWPLOW_MICRO_URI has scheme and port' do - before do - stub_env('SNOWPLOW_MICRO_URI', 'http://gdk.test:9091') - end - - it 'returns hostname URI part' do - expect(subject.hostname).to eq('gdk.test:9091') - end - end - - context 'when SNOWPLOW_MICRO_URI is without protocol' do - before do - stub_env('SNOWPLOW_MICRO_URI', 'gdk.test:9091') - end - - it 'returns hostname URI part' do - expect(subject.hostname).to eq('gdk.test:9091') - end - end - - context 'when SNOWPLOW_MICRO_URI is hostname only' do - before do - stub_env('SNOWPLOW_MICRO_URI', 'uriwithoutport') - end - - it 'returns hostname URI with default HTTP port' do - expect(subject.hostname).to eq('uriwithoutport:80') - end - end - - context 'when SNOWPLOW_MICRO_URI is not set' do - it 'returns localhost hostname' do - expect(subject.hostname).to eq('localhost:9090') - end + it 'returns localhost hostname' do + expect(subject.hostname).to eq('localhost:9090') end end end diff --git a/spec/lib/gitlab/tracking_spec.rb b/spec/lib/gitlab/tracking_spec.rb index 36ef1abcb50..028c985f3b3 100644 --- a/spec/lib/gitlab/tracking_spec.rb +++ b/spec/lib/gitlab/tracking_spec.rb @@ -90,15 +90,6 @@ RSpec.describe Gitlab::Tracking do it_behaves_like 'delegates to SnowplowMicro destination with proper options' end - - context "enabled with env variable" do - before do - allow(Gitlab.config).to receive(:snowplow_micro).and_raise(Settingslogic::MissingSetting) - stub_env('SNOWPLOW_MICRO_ENABLE', '1') - end - - it_behaves_like 'delegates to SnowplowMicro destination with proper options' - end end it 'when feature flag is disabled' do @@ -149,7 +140,6 @@ RSpec.describe Gitlab::Tracking do context 'when destination is Snowplow' do before do - stub_env('SNOWPLOW_MICRO_ENABLE', '0') allow(Rails.env).to receive(:development?).and_return(true) end @@ -158,7 +148,6 @@ RSpec.describe Gitlab::Tracking do context 'when destination is SnowplowMicro' do before do - stub_env('SNOWPLOW_MICRO_ENABLE', '1') allow(Rails.env).to receive(:development?).and_return(true) end @@ -212,4 +201,28 @@ RSpec.describe Gitlab::Tracking do project: project, user: user, namespace: namespace, extra_key_1: 'extra value 1') end end + + describe 'snowplow_micro_enabled?' do + before do + allow(Rails.env).to receive(:development?).and_return(true) + end + + it 'returns true when snowplow_micro is enabled' do + stub_config(snowplow_micro: { enabled: true }) + + expect(described_class).to be_snowplow_micro_enabled + end + + it 'returns false when snowplow_micro is disabled' do + stub_config(snowplow_micro: { enabled: false }) + + expect(described_class).not_to be_snowplow_micro_enabled + end + + it 'returns false when snowplow_micro is not configured' do + allow(Gitlab.config).to receive(:snowplow_micro).and_raise(Settingslogic::MissingSetting) + + expect(described_class).not_to be_snowplow_micro_enabled + end + end end diff --git a/spec/models/ci/runner_spec.rb b/spec/models/ci/runner_spec.rb index a822e613860..ae8748f8ae3 100644 --- a/spec/models/ci/runner_spec.rb +++ b/spec/models/ci/runner_spec.rb @@ -552,6 +552,10 @@ RSpec.describe Ci::Runner do allow_any_instance_of(described_class).to receive(:cached_attribute).and_call_original allow_any_instance_of(described_class).to receive(:cached_attribute) .with(:platform).and_return("darwin") + allow_any_instance_of(described_class).to receive(:cached_attribute) + .with(:version).and_return("14.0.0") + + allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).once end context 'table tests' do @@ -623,6 +627,10 @@ RSpec.describe Ci::Runner do allow_any_instance_of(described_class).to receive(:cached_attribute).and_call_original allow_any_instance_of(described_class).to receive(:cached_attribute) .with(:platform).and_return("darwin") + allow_any_instance_of(described_class).to receive(:cached_attribute) + .with(:version).and_return("14.0.0") + + allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async).once end context 'no cache value' do @@ -693,19 +701,6 @@ RSpec.describe Ci::Runner do it { is_expected.to eq([runner1]) } end - describe '#tick_runner_queue' do - it 'sticks the runner to the primary and calls the original method' do - runner = create(:ci_runner) - - expect(described_class.sticking).to receive(:stick) - .with(:runner, runner.id) - - expect(Gitlab::Workhorse).to receive(:set_key_and_notify) - - runner.tick_runner_queue - end - end - describe '#matches_build?' do using RSpec::Parameterized::TableSyntax @@ -989,6 +984,16 @@ RSpec.describe Ci::Runner do it 'returns a new last_update value' do expect(runner.tick_runner_queue).not_to be_empty end + + it 'sticks the runner to the primary and calls the original method' do + runner = create(:ci_runner) + + expect(described_class.sticking).to receive(:stick).with(:runner, runner.id) + + expect(Gitlab::Workhorse).to receive(:set_key_and_notify) + + runner.tick_runner_queue + end end describe '#ensure_runner_queue_value' do @@ -1055,14 +1060,19 @@ RSpec.describe Ci::Runner do it 'updates cache' do expect_redis_update + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to receive(:perform_async) heartbeat + + expect(runner.runner_version).to be_nil end end context 'when database was not updated recently' do before do runner.contacted_at = 2.hours.ago + + allow(Ci::Runners::ProcessRunnerVersionUpdateWorker).to receive(:perform_async) end context 'with invalid runner' do @@ -1075,12 +1085,25 @@ RSpec.describe Ci::Runner do expect_redis_update does_db_update + + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).once + end + end + + context 'with unchanged runner version' do + let(:runner) { create(:ci_runner, version: version) } + + it 'does not schedule ci_runner_versions update' do + heartbeat + + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).not_to have_received(:perform_async) end end it 'updates redis cache and database' do expect_redis_update does_db_update + expect(Ci::Runners::ProcessRunnerVersionUpdateWorker).to have_received(:perform_async).once end %w(custom shell docker docker-windows docker-ssh ssh parallels virtualbox docker+machine docker-ssh+machine kubernetes some-unknown-type).each do |executor| diff --git a/spec/services/ci/runners/process_runner_version_update_service_spec.rb b/spec/services/ci/runners/process_runner_version_update_service_spec.rb new file mode 100644 index 00000000000..b885138fc7a --- /dev/null +++ b/spec/services/ci/runners/process_runner_version_update_service_spec.rb @@ -0,0 +1,80 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::Runners::ProcessRunnerVersionUpdateService do + subject(:service) { described_class.new(version) } + + let(:version) { '1.0.0' } + let(:available_runner_releases) { %w[1.0.0 1.0.1] } + + describe '#execute' do + subject(:execute) { service.execute } + + context 'with upgrade check returning error' do + let(:service_double) { instance_double(Gitlab::Ci::RunnerUpgradeCheck) } + + before do + allow(service_double).to receive(:check_runner_upgrade_suggestion).with(version) + .and_return([version, :error]) + allow(service).to receive(:upgrade_check_service).and_return(service_double) + end + + it 'does not update ci_runner_versions records', :aggregate_failures do + expect do + expect(execute).to be_error + expect(execute.message).to eq 'upgrade version check failed' + end.not_to change(Ci::RunnerVersion, :count).from(0) + expect(service_double).to have_received(:check_runner_upgrade_suggestion).with(version).once + end + end + + context 'with successful result from upgrade check' do + before do + url = ::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url + + WebMock.stub_request(:get, url).to_return( + body: available_runner_releases.map { |v| { name: v } }.to_json, + status: 200, + headers: { 'Content-Type' => 'application/json' } + ) + end + + context 'with no existing ci_runner_version record' do + it 'creates ci_runner_versions record', :aggregate_failures do + expect do + expect(execute).to be_success + expect(execute.http_status).to eq :ok + expect(execute.payload).to eq({ upgrade_status: 'recommended' }) + end.to change(Ci::RunnerVersion, :all).to contain_exactly( + an_object_having_attributes(version: version, status: 'recommended') + ) + end + end + + context 'with existing ci_runner_version record' do + let!(:runner_version) { create(:ci_runner_version, version: '1.0.0', status: :not_available) } + + it 'updates ci_runner_versions record', :aggregate_failures do + expect do + expect(execute).to be_success + expect(execute.http_status).to eq :ok + expect(execute.payload).to eq({ upgrade_status: 'recommended' }) + end.to change { runner_version.reload.status }.from('not_available').to('recommended') + end + end + + context 'with up-to-date ci_runner_version record' do + let!(:runner_version) { create(:ci_runner_version, version: '1.0.0', status: :recommended) } + + it 'does not update ci_runner_versions record', :aggregate_failures do + expect do + expect(execute).to be_success + expect(execute.http_status).to eq :ok + expect(execute.payload).to eq({ upgrade_status: 'recommended' }) + end.not_to change { runner_version.reload.status } + end + end + end + end +end diff --git a/spec/services/ci/runners/reset_registration_token_service_spec.rb b/spec/services/ci/runners/reset_registration_token_service_spec.rb index c4bfff51cc8..f96838cea98 100644 --- a/spec/services/ci/runners/reset_registration_token_service_spec.rb +++ b/spec/services/ci/runners/reset_registration_token_service_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe ::Ci::Runners::ResetRegistrationTokenService, '#execute' do - subject { described_class.new(scope, current_user).execute } + subject(:execute) { described_class.new(scope, current_user).execute } let_it_be(:user) { build(:user) } let_it_be(:admin_user) { create(:user, :admin) } @@ -12,20 +12,20 @@ RSpec.describe ::Ci::Runners::ResetRegistrationTokenService, '#execute' do context 'without user' do let(:current_user) { nil } - it 'does not reset registration token and returns nil' do + it 'does not reset registration token and returns error response' do expect(scope).not_to receive(token_reset_method_name) - is_expected.to be_nil + is_expected.to be_error end end context 'with unauthorized user' do let(:current_user) { user } - it 'does not reset registration token and returns nil' do + it 'does not reset registration token and returns error response' do expect(scope).not_to receive(token_reset_method_name) - is_expected.to be_nil + is_expected.to be_error end end @@ -37,7 +37,8 @@ RSpec.describe ::Ci::Runners::ResetRegistrationTokenService, '#execute' do expect(scope).to receive(token_method_name).once.and_return("#{token_method_name} return value") end - is_expected.to eq("#{token_method_name} return value") + is_expected.to be_success + expect(execute.payload[:new_registration_token]).to eq("#{token_method_name} return value") end end end diff --git a/spec/workers/ci/runners/process_runner_version_update_worker_spec.rb b/spec/workers/ci/runners/process_runner_version_update_worker_spec.rb new file mode 100644 index 00000000000..ff67266c3e8 --- /dev/null +++ b/spec/workers/ci/runners/process_runner_version_update_worker_spec.rb @@ -0,0 +1,48 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Ci::Runners::ProcessRunnerVersionUpdateWorker do + subject(:worker) { described_class.new } + + describe '#perform' do + let(:version) { '1.0.0' } + let(:job_args) { version } + + include_examples 'an idempotent worker' do + subject(:perform_twice) { perform_multiple(job_args, worker: worker, exec_times: 2) } + + let(:service) { ::Ci::Runners::ProcessRunnerVersionUpdateService.new(version) } + let(:available_runner_releases) do + %w[1.0.0 1.0.1] + end + + before do + allow(Ci::Runners::ProcessRunnerVersionUpdateService).to receive(:new).and_return(service) + allow(service).to receive(:execute).and_call_original + + url = ::Gitlab::CurrentSettings.current_application_settings.public_runner_releases_url + + WebMock.stub_request(:get, url).to_return( + body: available_runner_releases.map { |v| { name: v } }.to_json, + status: 200, + headers: { 'Content-Type' => 'application/json' } + ) + end + + it 'logs the service result', :aggregate_failures do + perform_twice + + expect(Ci::Runners::ProcessRunnerVersionUpdateService).to have_received(:new).twice + expect(service).to have_received(:execute).twice + expect(worker.logging_extras).to eq( + { + 'extra.ci_runners_process_runner_version_update_worker.status' => :success, + 'extra.ci_runners_process_runner_version_update_worker.message' => nil, + 'extra.ci_runners_process_runner_version_update_worker.upgrade_status' => 'recommended' + } + ) + end + end + end +end |