diff options
65 files changed, 664 insertions, 520 deletions
diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index b25977cf5d2..56f91732c91 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -151,7 +151,7 @@ Dangerfile @gl-quality/eng-prod /lib/gitlab/ci/templates/ @gitlab-org/maintainers/cicd-templates /lib/gitlab/ci/templates/Auto-DevOps.gitlab-ci.yml @DylanGriffith @mayra-cabrera @tkuah /lib/gitlab/ci/templates/Security/ @gonzoyumo @twoodham @sethgitlab @thiagocsf -/lib/gitlab/ci/templates/Security/Container-Scanning.*.yml @gitlab-org/protect/container-security-backend +/lib/gitlab/ci/templates/Security/Container-Scanning.*.yml @gitlab-org/govern/security-policies-backend ^[Project Alias] /ee/app/models/project_alias.rb @patrickbajao @@ -183,23 +183,23 @@ Dangerfile @gl-quality/eng-prod /ee/app/services/app_sec/dast/ @gitlab-org/secure/dynamic-analysis-be ^[Container Security] -/ee/app/views/projects/threat_monitoring/** @gitlab-org/protect/container-security-frontend -/ee/app/views/projects/security/policies/** @gitlab-org/protect/container-security-frontend -/ee/spec/views/projects/security/policies/** @gitlab-org/protect/container-security-frontend -/ee/app/assets/javascripts/pages/projects/threat_monitoring/** @gitlab-org/protect/container-security-frontend -/ee/app/assets/javascripts/threat_monitoring/** @gitlab-org/protect/container-security-frontend -/ee/spec/frontend/threat_monitoring/** @gitlab-org/protect/container-security-frontend +/ee/app/views/projects/threat_monitoring/** @gitlab-org/govern/security-policies-frontend +/ee/app/views/projects/security/policies/** @gitlab-org/govern/security-policies-frontend +/ee/spec/views/projects/security/policies/** @gitlab-org/govern/security-policies-frontend +/ee/app/assets/javascripts/pages/projects/threat_monitoring/** @gitlab-org/govern/security-policies-frontend +/ee/app/assets/javascripts/threat_monitoring/** @gitlab-org/govern/security-policies-frontend +/ee/spec/frontend/threat_monitoring/** @gitlab-org/govern/security-policies-frontend -/ee/app/controllers/projects/threat_monitoring_controller.rb @gitlab-org/protect/container-security-backend -/ee/spec/controllers/projects/threat_monitoring_controller_spec.rb @gitlab-org/protect/container-security-backend -/ee/app/controllers/projects/security/policies_controller.rb @gitlab-org/protect/container-security-backend -/ee/spec/requests/projects/security/policies_controller_spec.rb @gitlab-org/protect/container-security-backend -/ee/app/models/security/orchestration_policy_configuration.rb @gitlab-org/protect/container-security-backend -/ee/spec/models/security/orchestration_policy_configuration_spec.rb @gitlab-org/protect/container-security-backend -/app/models/clusters/applications/cilium.rb @gitlab-org/protect/container-security-backend -/spec/models/clusters/applications/cilium_spec.rb @gitlab-org/protect/container-security-backend -/ee/app/services/security/orchestration/** @gitlab-org/protect/container-security-backend -/ee/spec/services/security/orchestration/** @gitlab-org/protect/container-security-backend +/ee/app/controllers/projects/threat_monitoring_controller.rb @gitlab-org/govern/security-policies-backend +/ee/spec/controllers/projects/threat_monitoring_controller_spec.rb @gitlab-org/govern/container-security-backend +/ee/app/controllers/projects/security/policies_controller.rb @gitlab-org/govern/security-policies-backend +/ee/spec/requests/projects/security/policies_controller_spec.rb @gitlab-org/govern/security-policies-backend +/ee/app/models/security/orchestration_policy_configuration.rb @gitlab-org/govern/security-policies-backend +/ee/spec/models/security/orchestration_policy_configuration_spec.rb @gitlab-org/govern/security-policies-backend +/app/models/clusters/applications/cilium.rb @gitlab-org/govern/security-policies-backend +/spec/models/clusters/applications/cilium_spec.rb @gitlab-org/govern/security-policies-backend +/ee/app/services/security/orchestration/** @gitlab-org/govern/security-policies-backend +/ee/spec/services/security/orchestration/** @gitlab-org/govern/security-policies-backend ^[Code Owners] /ee/lib/gitlab/code_owners.rb @reprazent @kerrizor @garyh diff --git a/.rubocop_todo/cop/user_admin.yml b/.rubocop_todo/cop/user_admin.yml index c9eed57e74d..653865e3d43 100644 --- a/.rubocop_todo/cop/user_admin.yml +++ b/.rubocop_todo/cop/user_admin.yml @@ -52,7 +52,6 @@ Cop/UserAdmin: - lib/api/entities/ci/runner_details.rb - lib/api/groups.rb - lib/api/helpers.rb - - lib/api/personal_access_tokens.rb - lib/api/users.rb - lib/api/v3/github.rb - lib/constraints/admin_constrainer.rb diff --git a/.rubocop_todo/layout/hash_alignment.yml b/.rubocop_todo/layout/hash_alignment.yml index 04beadbf905..f15ea0d2506 100644 --- a/.rubocop_todo/layout/hash_alignment.yml +++ b/.rubocop_todo/layout/hash_alignment.yml @@ -4,26 +4,6 @@ Layout/HashAlignment: Exclude: - 'ee/spec/lib/ee/gitlab/usage_data_spec.rb' - 'spec/controllers/projects/merge_requests_controller_spec.rb' - - 'spec/lib/gitlab/ci/config/external/mapper_spec.rb' - - 'spec/lib/gitlab/ci/lint_spec.rb' - - 'spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb' - - 'spec/lib/gitlab/ci/variables/builder_spec.rb' - - 'spec/lib/gitlab/ci/yaml_processor_spec.rb' - - 'spec/lib/gitlab/data_builder/issuable_spec.rb' - - 'spec/lib/gitlab/data_builder/note_spec.rb' - - 'spec/lib/gitlab/database/migration_helpers_spec.rb' - - 'spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb' - - 'spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb' - - 'spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb' - - 'spec/lib/gitlab/diff/highlight_cache_spec.rb' - - 'spec/lib/gitlab/diff/lines_unfolder_spec.rb' - - 'spec/lib/gitlab/diff/position_spec.rb' - - 'spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb' - - 'spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb' - - 'spec/lib/gitlab/etag_caching/middleware_spec.rb' - - 'spec/lib/gitlab/etag_caching/router/graphql_spec.rb' - - 'spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb' - - 'spec/lib/gitlab/import_export/attributes_finder_spec.rb' - 'spec/lib/gitlab/import_export/group/object_builder_spec.rb' - 'spec/lib/gitlab/import_export/group/relation_tree_restorer_spec.rb' - 'spec/lib/gitlab/import_export/project/relation_tree_restorer_spec.rb' diff --git a/app/assets/javascripts/graphql_shared/possible_types.json b/app/assets/javascripts/graphql_shared/possible_types.json index eac325f184f..72dbf9e7b7b 100644 --- a/app/assets/javascripts/graphql_shared/possible_types.json +++ b/app/assets/javascripts/graphql_shared/possible_types.json @@ -140,6 +140,7 @@ "WorkItemWidgetAssignees", "WorkItemWidgetDescription", "WorkItemWidgetHierarchy", + "WorkItemWidgetIteration", "WorkItemWidgetLabels", "WorkItemWidgetStartAndDueDate", "WorkItemWidgetVerificationStatus", diff --git a/app/assets/javascripts/notes/components/note_form.vue b/app/assets/javascripts/notes/components/note_form.vue index 66a28c0a2c8..b6ede10d02b 100644 --- a/app/assets/javascripts/notes/components/note_form.vue +++ b/app/assets/javascripts/notes/components/note_form.vue @@ -423,7 +423,7 @@ export default { category="primary" variant="confirm" data-qa-selector="reply_comment_button" - class="gl-mr-3 js-vue-issue-save js-comment-button" + class="gl-sm-mr-3 gl-xs-mb-3 js-vue-issue-save js-comment-button" @click="handleUpdate()" > {{ saveButtonTitle }} @@ -432,7 +432,7 @@ export default { v-if="discussion.resolvable" category="secondary" variant="default" - class="gl-mr-3 js-comment-resolve-button" + class="gl-sm-mr-3 gl-xs-mb-3 js-comment-resolve-button" @click.prevent="handleUpdate(true)" > {{ resolveButtonTitle }} diff --git a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue index 777a332333d..f5620876783 100644 --- a/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue +++ b/app/assets/javascripts/runner/admin_runners/admin_runners_app.vue @@ -15,6 +15,7 @@ import allRunnersQuery from 'ee_else_ce/runner/graphql/list/all_runners.query.gr import allRunnersCountQuery from 'ee_else_ce/runner/graphql/list/all_runners_count.query.graphql'; import RegistrationDropdown from '../components/registration/registration_dropdown.vue'; +import RunnerStackedLayoutBanner from '../components/runner_stacked_layout_banner.vue'; import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue'; import RunnerBulkDelete from '../components/runner_bulk_delete.vue'; import RunnerBulkDeleteCheckbox from '../components/runner_bulk_delete_checkbox.vue'; @@ -37,6 +38,7 @@ export default { components: { GlLink, RegistrationDropdown, + RunnerStackedLayoutBanner, RunnerFilteredSearchBar, RunnerBulkDelete, RunnerBulkDeleteCheckbox, @@ -169,6 +171,8 @@ export default { </script> <template> <div> + <runner-stacked-layout-banner /> + <div class="gl-display-flex gl-align-items-center gl-flex-direction-column-reverse gl-md-flex-direction-row gl-mt-3 gl-md-mt-0" > diff --git a/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue b/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue new file mode 100644 index 00000000000..c36efa73e0e --- /dev/null +++ b/app/assets/javascripts/runner/components/runner_stacked_layout_banner.vue @@ -0,0 +1,71 @@ +<script> +import allChangesCommittedSvg from '@gitlab/svgs/dist/illustrations/multi-editor_all_changes_committed_empty.svg'; +import { GlBanner } from '@gitlab/ui'; + +import { s__ } from '~/locale'; +import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; +import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; + +const I18N_TITLE = s__("Runners|We've made some changes and want your feedback"); +const I18N_DESCRIPTION = s__( + "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!", +); +const I18N_LINK = s__('Runners|Add your feedback in the issue'); + +// use a data url instead getting it from via HTML data-* attributes to simplify removal of this feature flag +const ILLUSTRATION_URL = `data:image/svg+xml;utf8,${encodeURIComponent(allChangesCommittedSvg)}`; +const ISSUE_URL = 'https://gitlab.com/gitlab-org/gitlab/-/issues/371621'; +const STORAGE_KEY = 'runner_list_stacked_layout_feedback_dismissed'; + +export default { + components: { + GlBanner, + LocalStorageSync, + }, + mixins: [glFeatureFlagMixin()], + data() { + return { + isDismissed: false, + }; + }, + computed: { + stackedLayoutEnabled() { + // Two feature flags can be used: runner_list_stacked_layout_admin or runner_list_stacked_layout + // Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/371031 + const { runnerListStackedLayoutAdmin, runnerListStackedLayout } = this.glFeatures || {}; + return runnerListStackedLayoutAdmin || runnerListStackedLayout; + }, + showBanner() { + return this.stackedLayoutEnabled && !this.isDismissed; + }, + }, + methods: { + onClose() { + this.isDismissed = true; + }, + }, + I18N_TITLE, + I18N_DESCRIPTION, + I18N_LINK, + ILLUSTRATION_URL, + ISSUE_URL, + STORAGE_KEY, +}; +</script> + +<template> + <div> + <local-storage-sync v-model="isDismissed" :storage-key="$options.STORAGE_KEY" /> + <gl-banner + v-if="showBanner" + :svg-path="$options.ILLUSTRATION_URL" + :title="$options.I18N_TITLE" + :button-text="$options.I18N_LINK" + :button-link="$options.ISSUE_URL" + class="gl-my-5" + @close="onClose" + > + <p>{{ $options.I18N_DESCRIPTION }}</p> + </gl-banner> + </div> +</template> diff --git a/app/assets/javascripts/runner/group_runners/group_runners_app.vue b/app/assets/javascripts/runner/group_runners/group_runners_app.vue index a2b666f4c6a..70826a6bfa1 100644 --- a/app/assets/javascripts/runner/group_runners/group_runners_app.vue +++ b/app/assets/javascripts/runner/group_runners/group_runners_app.vue @@ -13,6 +13,7 @@ import { import groupRunnersQuery from 'ee_else_ce/runner/graphql/list/group_runners.query.graphql'; import RegistrationDropdown from '../components/registration/registration_dropdown.vue'; +import RunnerStackedLayoutBanner from '../components/runner_stacked_layout_banner.vue'; import RunnerFilteredSearchBar from '../components/runner_filtered_search_bar.vue'; import RunnerList from '../components/runner_list.vue'; import RunnerListEmptyState from '../components/runner_list_empty_state.vue'; @@ -37,6 +38,7 @@ export default { components: { GlLink, RegistrationDropdown, + RunnerStackedLayoutBanner, RunnerFilteredSearchBar, RunnerList, RunnerListEmptyState, @@ -179,6 +181,8 @@ export default { <template> <div> + <runner-stacked-layout-banner /> + <div class="gl-display-flex gl-align-items-center"> <runner-type-tabs ref="runner-type-tabs" diff --git a/app/assets/javascripts/work_items/components/work_item_assignees.vue b/app/assets/javascripts/work_items/components/work_item_assignees.vue index 9e5403bb416..3d88275c0ef 100644 --- a/app/assets/javascripts/work_items/components/work_item_assignees.vue +++ b/app/assets/javascripts/work_items/components/work_item_assignees.vue @@ -266,7 +266,7 @@ export default { </script> <template> - <div class="form-row gl-mb-5 work-item-assignees gl-relative"> + <div class="form-row gl-mb-5 work-item-assignees gl-relative gl-flex-nowrap"> <span class="gl-font-weight-bold col-lg-2 col-3 gl-pt-2 min-w-fit-content gl-overflow-wrap-break" data-testid="assignees-title" diff --git a/app/assets/javascripts/work_items/components/work_item_labels.vue b/app/assets/javascripts/work_items/components/work_item_labels.vue index e608e4ad57e..837f79a9a03 100644 --- a/app/assets/javascripts/work_items/components/work_item_labels.vue +++ b/app/assets/javascripts/work_items/components/work_item_labels.vue @@ -192,7 +192,7 @@ export default { </script> <template> - <div class="form-row gl-mb-5 work-item-labels gl-relative"> + <div class="form-row gl-mb-5 work-item-labels gl-relative gl-flex-nowrap"> <span class="gl-font-weight-bold gl-mt-2 col-lg-2 col-3 gl-pt-2 min-w-fit-content gl-overflow-wrap-break" data-testid="labels-title" diff --git a/app/assets/stylesheets/page_bundles/work_items.scss b/app/assets/stylesheets/page_bundles/work_items.scss index 9220fa82b46..85fa3a974e4 100644 --- a/app/assets/stylesheets/page_bundles/work_items.scss +++ b/app/assets/stylesheets/page_bundles/work_items.scss @@ -19,8 +19,10 @@ display: none; } - .assignees-selector:hover .assign-myself { - display: block; + @include media-breakpoint-up(sm) { + .assignees-selector:hover .assign-myself { + display: block; + } } } diff --git a/app/assets/stylesheets/pages/notes.scss b/app/assets/stylesheets/pages/notes.scss index 27d01b38a2a..fc1b78bf730 100644 --- a/app/assets/stylesheets/pages/notes.scss +++ b/app/assets/stylesheets/pages/notes.scss @@ -334,7 +334,11 @@ $system-note-svg-size: 16px; border-radius: 0; @media (min-width: map-get($grid-breakpoints, md)) { - --initial-top: calc(#{$header-height} + #{$mr-tabs-height + 28px}); + --initial-top: calc(#{$header-height} + #{$mr-tabs-height}); + + &.is-sidebar-moved { + --initial-top: calc(#{$header-height} + #{$mr-tabs-height + 28px}); + } .with-performance-bar & { --top: 123px; diff --git a/app/helpers/projects_helper.rb b/app/helpers/projects_helper.rb index a65dd6703f2..65259122417 100644 --- a/app/helpers/projects_helper.rb +++ b/app/helpers/projects_helper.rb @@ -172,6 +172,7 @@ module ProjectsHelper def project_list_cache_key(project, pipeline_status: true) key = [ + project.star_count, project.route.cache_key, project.cache_key, project.last_activity_date, diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index 12c296070fc..a08fdf3652a 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -706,24 +706,6 @@ module Ci job_artifacts.of_report_type(:test).exists? end - def has_old_trace? - old_trace.present? - end - - def trace=(data) - raise NotImplementedError - end - - def old_trace - read_attribute(:trace) - end - - def erase_old_trace! - return unless has_old_trace? - - update_column(:trace, nil) - end - def ensure_trace_metadata! Ci::BuildTraceMetadata.find_or_upsert_for!(id) end diff --git a/app/models/commit_status.rb b/app/models/commit_status.rb index 3b197398349..d8ca68eb2a5 100644 --- a/app/models/commit_status.rb +++ b/app/models/commit_status.rb @@ -8,8 +8,10 @@ class CommitStatus < Ci::ApplicationRecord include EnumWithNil include BulkInsertableAssociations include TaggableQueries + include IgnorableColumns self.table_name = 'ci_builds' + ignore_column :trace, remove_with: '15.6', remove_after: '2022-10-22' belongs_to :user belongs_to :project diff --git a/app/services/ci/resource_groups/assign_resource_from_resource_group_service.rb b/app/services/ci/resource_groups/assign_resource_from_resource_group_service.rb index dfd97498fc8..d7078200c14 100644 --- a/app/services/ci/resource_groups/assign_resource_from_resource_group_service.rb +++ b/app/services/ci/resource_groups/assign_resource_from_resource_group_service.rb @@ -9,8 +9,10 @@ module Ci free_resources = resource_group.resources.free.count - resource_group.upcoming_processables.take(free_resources).each do |processable| - processable.enqueue_waiting_for_resource + resource_group.upcoming_processables.take(free_resources).each do |upcoming| + Gitlab::OptimisticLocking.retry_lock(upcoming, name: 'enqueue_waiting_for_resource') do |processable| + processable.enqueue_waiting_for_resource + end end end # rubocop: enable CodeReuse/ActiveRecord diff --git a/app/services/projects/destroy_service.rb b/app/services/projects/destroy_service.rb index c16b14ba152..2a58ee7a868 100644 --- a/app/services/projects/destroy_service.rb +++ b/app/services/projects/destroy_service.rb @@ -134,6 +134,8 @@ module Projects destroy_ci_records! destroy_mr_diff_relations! + destroy_merge_request_diffs! if ::Feature.enabled?(:extract_mr_diff_deletions) + # Rails attempts to load all related records into memory before # destroying: https://github.com/rails/rails/issues/22510 # This ensures we delete records in batches. @@ -180,6 +182,24 @@ module Projects end # rubocop: enable CodeReuse/ActiveRecord + # rubocop: disable CodeReuse/ActiveRecord + def destroy_merge_request_diffs! + mr_batch_size = 100 + delete_batch_size = 1000 + + project.merge_requests.each_batch(column: :iid, of: mr_batch_size) do |relation_ids| + loop do + deleted_rows = MergeRequestDiff + .where(merge_request_id: relation_ids) + .limit(delete_batch_size) + .delete_all + + break if deleted_rows == 0 + end + end + end + # rubocop: enable CodeReuse/ActiveRecord + def destroy_ci_records! # Make sure to destroy this first just in case the project is undergoing stats refresh. # This is to avoid logging the artifact deletion in Ci::JobArtifacts::DestroyBatchService. diff --git a/config/feature_flags/development/escape_gitaly_refs.yml b/config/feature_flags/development/escape_gitaly_refs.yml index bee62c669ee..b42cc4c07e5 100644 --- a/config/feature_flags/development/escape_gitaly_refs.yml +++ b/config/feature_flags/development/escape_gitaly_refs.yml @@ -5,4 +5,4 @@ rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/366437 milestone: '15.2' type: development group: group::source code -default_enabled: false +default_enabled: true diff --git a/config/feature_flags/development/extract_mr_diff_deletions.yml b/config/feature_flags/development/extract_mr_diff_deletions.yml new file mode 100644 index 00000000000..24067f95074 --- /dev/null +++ b/config/feature_flags/development/extract_mr_diff_deletions.yml @@ -0,0 +1,8 @@ +--- +name: extract_mr_diff_deletions +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/96455 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/372060 +milestone: '15.4' +type: development +group: group::source code +default_enabled: false diff --git a/doc/.vale/gitlab/Markdown_emoji.yml b/doc/.vale/gitlab/Markdown_emoji.yml new file mode 100644 index 00000000000..ac0dab2d69d --- /dev/null +++ b/doc/.vale/gitlab/Markdown_emoji.yml @@ -0,0 +1,13 @@ +--- +# Warning: gitlab.Markdown_emoji +# +# Check for use of GLFM emoji syntax (https://docs.gitlab.com/ee/user/markdown.html#emojis), which doesn't render correctly in documentation. +# +# For a list of all options, see https://errata-ai.gitbook.io/vale/getting-started/styles +extends: existence +message: 'This appears to be GLFM emoji syntax. Replace "%s" with GitLab SVGs or Unicode emojis.' +link: https://docs.gitlab.com/ee/development/documentation/styleguide/#gitlab-svg-icons +level: warning +scope: text +raw: + - '(?:\s+|^):[a-zA-Z0-9\-_\+]+:(?:\s+|$|\.)' diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 089c6e0d766..45fa85b3454 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -5756,6 +5756,7 @@ Input type: `WorkItemUpdateInput` | <a id="mutationworkitemupdatedescriptionwidget"></a>`descriptionWidget` | [`WorkItemWidgetDescriptionInput`](#workitemwidgetdescriptioninput) | Input for description widget. | | <a id="mutationworkitemupdatehierarchywidget"></a>`hierarchyWidget` | [`WorkItemWidgetHierarchyUpdateInput`](#workitemwidgethierarchyupdateinput) | Input for hierarchy widget. | | <a id="mutationworkitemupdateid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. | +| <a id="mutationworkitemupdateiterationwidget"></a>`iterationWidget` | [`WorkItemWidgetIterationInput`](#workitemwidgetiterationinput) | Input for iteration widget. | | <a id="mutationworkitemupdatestartandduedatewidget"></a>`startAndDueDateWidget` | [`WorkItemWidgetStartAndDueDateUpdateInput`](#workitemwidgetstartandduedateupdateinput) | Input for start and due date widget. | | <a id="mutationworkitemupdatestateevent"></a>`stateEvent` | [`WorkItemStateEvent`](#workitemstateevent) | Close or reopen a work item. | | <a id="mutationworkitemupdatetitle"></a>`title` | [`String`](#string) | Title of the work item. | @@ -19162,6 +19163,17 @@ Represents a hierarchy widget. | <a id="workitemwidgethierarchyparent"></a>`parent` | [`WorkItem`](#workitem) | Parent work item. | | <a id="workitemwidgethierarchytype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. | +### `WorkItemWidgetIteration` + +Represents an iteration widget. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="workitemwidgetiterationiteration"></a>`iteration` | [`Iteration`](#iteration) | Iteration of the work item. | +| <a id="workitemwidgetiterationtype"></a>`type` | [`WorkItemWidgetType`](#workitemwidgettype) | Widget type. | + ### `WorkItemWidgetLabels` Represents the labels widget. @@ -21171,6 +21183,7 @@ Type of a work item widget. | <a id="workitemwidgettypeassignees"></a>`ASSIGNEES` | Assignees widget. | | <a id="workitemwidgettypedescription"></a>`DESCRIPTION` | Description widget. | | <a id="workitemwidgettypehierarchy"></a>`HIERARCHY` | Hierarchy widget. | +| <a id="workitemwidgettypeiteration"></a>`ITERATION` | Iteration widget. | | <a id="workitemwidgettypelabels"></a>`LABELS` | Labels widget. | | <a id="workitemwidgettypestart_and_due_date"></a>`START_AND_DUE_DATE` | Start And Due Date widget. | | <a id="workitemwidgettypeverification_status"></a>`VERIFICATION_STATUS` | Verification Status widget. | @@ -22433,6 +22446,7 @@ Implementations: - [`WorkItemWidgetAssignees`](#workitemwidgetassignees) - [`WorkItemWidgetDescription`](#workitemwidgetdescription) - [`WorkItemWidgetHierarchy`](#workitemwidgethierarchy) +- [`WorkItemWidgetIteration`](#workitemwidgetiteration) - [`WorkItemWidgetLabels`](#workitemwidgetlabels) - [`WorkItemWidgetStartAndDueDate`](#workitemwidgetstartandduedate) - [`WorkItemWidgetVerificationStatus`](#workitemwidgetverificationstatus) @@ -22986,6 +23000,14 @@ A time-frame defined as a closed inclusive range of two dates. | <a id="workitemwidgethierarchyupdateinputchildrenids"></a>`childrenIds` | [`[WorkItemID!]`](#workitemid) | Global IDs of children work items. | | <a id="workitemwidgethierarchyupdateinputparentid"></a>`parentId` | [`WorkItemID`](#workitemid) | Global ID of the parent work item. Use `null` to remove the association. | +### `WorkItemWidgetIterationInput` + +#### Arguments + +| Name | Type | Description | +| ---- | ---- | ----------- | +| <a id="workitemwidgetiterationinputiterationid"></a>`iterationId` | [`IterationID`](#iterationid) | Iteration to assign to the work item. | + ### `WorkItemWidgetStartAndDueDateUpdateInput` #### Arguments diff --git a/doc/api/personal_access_tokens.md b/doc/api/personal_access_tokens.md index 620b5c2ed0b..7dc31c3f9f0 100644 --- a/doc/api/personal_access_tokens.md +++ b/doc/api/personal_access_tokens.md @@ -134,9 +134,13 @@ curl --request DELETE --header "PRIVATE-TOKEN: <your_access_token>" "https://git ### Using a request header -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/350240) in GitLab 15.0. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/350240) in GitLab 15.0. Limited to tokens with `api` scope. +> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/369103) in GitLab 15.4, any token can use this endpoint. -Revokes a personal access token that is passed in using a request header. +Revokes a personal access token that is passed in using a request header. Requires: + +- `api` scope in GitLab 15.0 to GitLab 15.3. +- Any scope in GitLab 15.4 and later. ```plaintext DELETE /personal_access_tokens/self diff --git a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md index d46eef0b9fc..4e3abcdae09 100644 --- a/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md +++ b/doc/architecture/blueprints/ci_data_decay/pipeline_partitioning.md @@ -74,6 +74,11 @@ violates our [principle of 100 GB max size](../database_scaling/size-limits.md). We also want to [build alerting](https://gitlab.com/gitlab-com/gl-infra/tamland/-/issues/5) to notify us when this number is exceeded. +Large SQL tables increase index maintenance time, during which freshly deleted tuples +cannot be cleaned by `autovacuum`. This highlight the need for small tables. +We will measure how much bloat we accumulate when [re]indexing huge tables. Base on this analysis, +we will be able to set up SLO (dead tuples / bloat), associated with [re]indexing. + We’ve seen numerous S1 and S2 database-related production environment incidents, over the last couple of months, for example: diff --git a/doc/development/code_review.md b/doc/development/code_review.md index 35897012b60..79146e0b8bc 100644 --- a/doc/development/code_review.md +++ b/doc/development/code_review.md @@ -147,7 +147,7 @@ with [domain expertise](#domain-experts). | `~workhorse` changes | [Workhorse maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab_maintainers_workhorse). | | `~frontend` changes (*1*) | [Frontend maintainer](https://about.gitlab.com/handbook/engineering/projects/#gitlab_maintainers_frontend). | | `~UX` user-facing changes (*3*) | [Product Designer](https://about.gitlab.com/handbook/engineering/projects/#gitlab_reviewers_UX). Refer to the [design and user interface guidelines](contributing/design.md) for details. | -| Adding a new JavaScript library (*1*) | <ul><li>[Frontend foundations member](https://about.gitlab.com/direction/ecosystem/foundations/) if the library significantly increases the [bundle size](https://gitlab.com/gitlab-org/frontend/playground/webpack-memory-metrics/-/blob/master/doc/report.md)</li><li>A [legal department member](https://about.gitlab.com/handbook/legal/) if the license used by the new library hasn't been approved for use in GitLab</li></ul> More information about license compatibility can be found in our [GitLab Licensing and Compatibility documentation](licensing.md). | +| Adding a new JavaScript library (*1*) | - [Frontend foundations member](https://about.gitlab.com/direction/ecosystem/foundations/) if the library significantly increases the [bundle size](https://gitlab.com/gitlab-org/frontend/playground/webpack-memory-metrics/-/blob/master/doc/report.md).<br/>- A [legal department member](https://about.gitlab.com/handbook/legal/) if the license used by the new library hasn't been approved for use in GitLab.<br/><br/>More information about license compatibility can be found in our [GitLab Licensing and Compatibility documentation](licensing.md). | | A new dependency or a file system change | [Distribution team member](https://about.gitlab.com/company/team/). See how to work with the [Distribution team](https://about.gitlab.com/handbook/engineering/development/enablement/systems/distribution/#how-to-work-with-distribution) for more details. | | `~documentation` changes | [Technical writer](https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments) based on assignments in the appropriate [DevOps stage group](https://about.gitlab.com/handbook/product/categories/#devops-stages). | | Changes to development guidelines | Follow the [review process](development_processes.md#development-guidelines-review) and get the approvals accordingly. | diff --git a/doc/user/permissions.md b/doc/user/permissions.md index 79d87cddb47..a14a3843d4f 100644 --- a/doc/user/permissions.md +++ b/doc/user/permissions.md @@ -95,7 +95,7 @@ The following table lists project permissions available for each role: | [Issues](project/issues/index.md):<br>View [Design Management](project/issues/design_management.md) pages | ✓ | ✓ | ✓ | ✓ | ✓ | | [Issues](project/issues/index.md):<br>View [related issues](project/issues/related_issues.md) | ✓ | ✓ | ✓ | ✓ | ✓ | | [Issues](project/issues/index.md):<br>Set [weight](project/issues/issue_weight.md) | ✓ (*15*) | ✓ | ✓ | ✓ | ✓ | -| [Issues]](project/issues/index.md):<br>Set [parent epic](group/epics/manage_epics.md#add-an-existing-issue-to-an-epic) | | ✓ | ✓ | ✓ | ✓ | +| [Issues](project/issues/index.md):<br>Set [parent epic](group/epics/manage_epics.md#add-an-existing-issue-to-an-epic) | | ✓ | ✓ | ✓ | ✓ | | [Issues](project/issues/index.md):<br>View [confidential issues](project/issues/confidential_issues.md) | (*2*) | ✓ | ✓ | ✓ | ✓ | | [Issues](project/issues/index.md):<br>Close / reopen (*19*) | | ✓ | ✓ | ✓ | ✓ | | [Issues](project/issues/index.md):<br>Lock threads | | ✓ | ✓ | ✓ | ✓ | diff --git a/lib/api/api.rb b/lib/api/api.rb index 1edbb1336ed..5a8772d6c56 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -263,6 +263,7 @@ module API mount ::API::PackageFiles mount ::API::Pages mount ::API::PagesDomains + mount ::API::PersonalAccessTokens::SelfRevocation mount ::API::PersonalAccessTokens mount ::API::ProjectClusters mount ::API::ProjectContainerRepositories diff --git a/lib/api/helpers/personal_access_tokens_helpers.rb b/lib/api/helpers/personal_access_tokens_helpers.rb new file mode 100644 index 00000000000..db28daa5396 --- /dev/null +++ b/lib/api/helpers/personal_access_tokens_helpers.rb @@ -0,0 +1,35 @@ +# frozen_string_literal: true + +module API + module Helpers + module PersonalAccessTokensHelpers + def finder_params(current_user) + if current_user.can_admin_all_resources? + { user: user(params[:user_id]) } + else + { user: current_user, impersonation: false } + end + end + + def user(user_id) + UserFinder.new(user_id).find_by_id + end + + def restrict_non_admins! + return if params[:user_id].blank? + + unauthorized! unless Ability.allowed?(current_user, :read_user_personal_access_tokens, user(params[:user_id])) + end + + def find_token(id) + PersonalAccessToken.find(id) || not_found! + end + + def revoke_token(token) + service = ::PersonalAccessTokens::RevokeService.new(current_user, token: token).execute + + service.success? ? no_content! : bad_request!(nil) + end + end + end +end diff --git a/lib/api/personal_access_tokens.rb b/lib/api/personal_access_tokens.rb index 0d7d2dc6a0c..1c00569bba2 100644 --- a/lib/api/personal_access_tokens.rb +++ b/lib/api/personal_access_tokens.rb @@ -18,34 +18,10 @@ module API before do authenticate! - restrict_non_admins! unless current_user.admin? + restrict_non_admins! unless current_user.can_admin_all_resources? end - helpers do - def finder_params(current_user) - current_user.admin? ? { user: user(params[:user_id]) } : { user: current_user, impersonation: false } - end - - def user(user_id) - UserFinder.new(user_id).find_by_id - end - - def restrict_non_admins! - return if params[:user_id].blank? - - unauthorized! unless Ability.allowed?(current_user, :read_user_personal_access_tokens, user(params[:user_id])) - end - - def find_token(id) - PersonalAccessToken.find(id) || not_found! - end - - def revoke_token(token) - service = ::PersonalAccessTokens::RevokeService.new(current_user, token: token).execute - - service.success? ? no_content! : bad_request!(nil) - end - end + helpers ::API::Helpers::PersonalAccessTokensHelpers resources :personal_access_tokens do get do @@ -63,14 +39,10 @@ module API present token, with: Entities::PersonalAccessToken else # Only admins should be informed if the token doesn't exist - current_user.admin? ? not_found! : unauthorized! + current_user.can_admin_all_resources? ? not_found! : unauthorized! end end - delete 'self' do - revoke_token(access_token) - end - delete ':id' do token = find_token(params[:id]) diff --git a/lib/api/personal_access_tokens/self_revocation.rb b/lib/api/personal_access_tokens/self_revocation.rb new file mode 100644 index 00000000000..22e07f4cc7b --- /dev/null +++ b/lib/api/personal_access_tokens/self_revocation.rb @@ -0,0 +1,26 @@ +# frozen_string_literal: true + +module API + class PersonalAccessTokens + class SelfRevocation < ::API::Base + include APIGuard + + feature_category :authentication_and_authorization + + helpers ::API::Helpers::PersonalAccessTokensHelpers + + # As any token regardless of `scope` should be able to revoke itself + # all availabe scopes are allowed for this API class. + # Please be aware of the permissive scope when adding new endpoints to this class. + allow_access_with_scope(Gitlab::Auth.all_available_scopes) + + before { authenticate! } + + resource :personal_access_tokens do + delete 'self' do + revoke_token(access_token) + end + end + end + end +end diff --git a/lib/gitlab/ci/trace.rb b/lib/gitlab/ci/trace.rb index 95a60b852b8..c5664ef1cfb 100644 --- a/lib/gitlab/ci/trace.rb +++ b/lib/gitlab/ci/trace.rb @@ -23,7 +23,6 @@ module Gitlab attr_reader :job - delegate :old_trace, to: :job delegate :can_attempt_archival_now?, :increment_archival_attempts!, :archival_attempts_message, :archival_attempts_available?, to: :trace_metadata @@ -82,7 +81,7 @@ module Gitlab end def live? - job.trace_chunks.any? || current_path.present? || old_trace.present? + job.trace_chunks.any? || current_path.present? end def read(&block) @@ -111,7 +110,6 @@ module Gitlab # Erase the live trace erase_trace_chunks! FileUtils.rm_f(current_path) if current_path # Remove a trace file of a live trace - job.erase_old_trace! if job.has_old_trace? # Remove a trace in database of a live trace ensure @current_path = nil end @@ -162,8 +160,6 @@ module Gitlab Gitlab::Ci::Trace::ChunkedIO.new(job) elsif current_path File.open(current_path, "rb") - elsif old_trace - StringIO.new(old_trace) end end @@ -210,11 +206,6 @@ module Gitlab archive_stream!(stream) FileUtils.rm(current_path) end - elsif old_trace - StringIO.new(old_trace, 'rb').tap do |stream| - archive_stream!(stream) - job.erase_old_trace! - end end end diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 870bf4d2466..c4e6a38f750 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -33795,6 +33795,9 @@ msgstr "" msgid "Runners|Add notes, like who owns the runner or what it should be used for." msgstr "" +msgid "Runners|Add your feedback in the issue" +msgstr "" + msgid "Runners|All" msgstr "" @@ -34230,6 +34233,12 @@ msgstr "" msgid "Runners|View installation instructions" msgstr "" +msgid "Runners|We want you to be able to manage your runners easily and efficiently from this page, and we are making changes to get there. Give us feedback on how we're doing!" +msgstr "" + +msgid "Runners|We've made some changes and want your feedback" +msgstr "" + msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot." msgstr "" diff --git a/spec/controllers/projects/jobs_controller_spec.rb b/spec/controllers/projects/jobs_controller_spec.rb index 0793e790301..556dd23c135 100644 --- a/spec/controllers/projects/jobs_controller_spec.rb +++ b/spec/controllers/projects/jobs_controller_spec.rb @@ -5,9 +5,25 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do include ApiHelpers include HttpIOHelpers - let(:project) { create(:project, :public, :repository) } + let_it_be(:project) { create(:project, :public, :repository) } + let_it_be(:owner) { create(:owner) } + let_it_be(:admin) { create(:admin) } + let_it_be(:maintainer) { create(:user) } + let_it_be(:developer) { create(:user) } + let_it_be(:reporter) { create(:user) } + let_it_be(:guest) { create(:user) } + + before_all do + project.add_owner(owner) + project.add_maintainer(maintainer) + project.add_developer(developer) + project.add_reporter(reporter) + project.add_guest(guest) + end + + let(:user) { developer } + let(:pipeline) { create(:ci_pipeline, project: project) } - let(:user) { create(:user) } before do stub_feature_flags(ci_enable_live_trace: true) @@ -136,9 +152,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'when requesting JSON' do let(:merge_request) { create(:merge_request, source_project: project) } + let(:user) { developer } before do - project.add_developer(user) sign_in(user) allow_any_instance_of(Ci::Build) @@ -307,9 +323,10 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do let(:environment) { create(:environment, project: project, name: 'staging', state: :available) } let(:job) { create(:ci_build, :running, environment: environment.name, pipeline: pipeline) } + let(:user) { maintainer } + before do create(:deployment, :success, :on_cluster, environment: environment, project: project) - project.add_maintainer(user) # Need to be a maintianer to view cluster.path end it 'exposes the deployment information' do @@ -330,9 +347,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'that belongs to the project' do let(:runner) { create(:ci_runner, :project, projects: [project]) } let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) } + let(:user) { maintainer } before do - project.add_maintainer(user) sign_in(user) end @@ -349,10 +366,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do let(:group) { create(:group) } let(:runner) { create(:ci_runner, :group, groups: [group]) } let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) } - let(:user) { create(:user, :admin) } + let(:user) { maintainer } before do - project.add_maintainer(user) sign_in(user) end @@ -368,10 +384,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'that belongs to instance' do let(:runner) { create(:ci_runner, :instance) } let(:job) { create(:ci_build, :success, pipeline: pipeline, runner: runner) } - let(:user) { create(:user, :admin) } + let(:user) { maintainer } before do - project.add_maintainer(user) sign_in(user) end @@ -421,6 +436,8 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'when user is developer' do + let(:user) { developer } + it 'settings_path is not available' do expect(response).to have_gitlab_http_status(:ok) expect(response).to match_response_schema('job/job_details') @@ -429,10 +446,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'when user is maintainer' do - let(:user) { create(:user, :admin) } + let(:user) { admin } before do - project.add_maintainer(user) sign_in(user) end @@ -499,9 +515,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do let(:trigger) { create(:ci_trigger, project: project) } let(:trigger_request) { create(:ci_trigger_request, pipeline: pipeline, trigger: trigger) } let(:job) { create(:ci_build, pipeline: pipeline, trigger_request: trigger_request) } + let(:user) { developer } before do - project.add_developer(user) sign_in(user) allow_any_instance_of(Ci::Build) @@ -526,9 +542,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'user is a maintainer' do - before do - project.add_maintainer(user) + let(:user) { maintainer } + before do get_show_json end @@ -579,7 +595,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do def get_show_json expect { get_show(id: job.id, format: :json) } - .to change { Gitlab::GitalyClient.get_request_count }.by_at_most(2) + .to change { Gitlab::GitalyClient.get_request_count }.by_at_most(3) end def get_show(**extra_params) @@ -617,8 +633,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do let!(:variable) { create(:ci_instance_variable, key: 'CI_DEBUG_TRACE', value: 'true') } context 'with proper permissions on a project' do + let(:user) { developer } + before do - project.add_developer(user) sign_in(user) end @@ -630,8 +647,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'without proper permissions for debug logging' do + let(:user) { guest } + before do - project.add_guest(user) sign_in(user) end @@ -753,8 +771,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end describe 'POST retry' do + let(:user) { developer } + before do - project.add_developer(user) sign_in(user) end @@ -817,12 +836,13 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do describe 'POST play' do let(:variable_attributes) { [] } + let(:user) { developer } before do project.add_developer(user) create(:protected_branch, :developers_can_merge, - name: 'master', project: project) + name: 'protected-branch', project: project) sign_in(user) end @@ -899,8 +919,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do describe 'POST cancel' do context 'when user is authorized to cancel the build' do + let(:user) { developer } + before do - project.add_developer(user) sign_in(user) end @@ -965,8 +986,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'when user is not authorized to cancel the build' do let!(:job) { create(:ci_build, :cancelable, pipeline: pipeline) } + let(:user) { guest } + before do - project.add_reporter(user) sign_in(user) post_cancel @@ -990,12 +1012,13 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do describe 'POST unschedule' do before do - create(:protected_branch, :developers_can_merge, name: 'master', project: project) + create(:protected_branch, :developers_can_merge, name: 'protected-branch', project: project) end context 'when user is authorized to unschedule the build' do + let(:user) { developer } + before do - project.add_developer(user) sign_in(user) post_unschedule @@ -1025,9 +1048,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do context 'when user is not authorized to unschedule the build' do let(:job) { create(:ci_build, :scheduled, pipeline: pipeline) } + let(:user) { guest } before do - project.add_reporter(user) sign_in(user) post_unschedule @@ -1048,10 +1071,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end describe 'POST erase' do - let(:role) { :maintainer } + let(:user) { maintainer } before do - project.add_role(user, role) sign_in(user) end @@ -1097,7 +1119,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'when user is developer' do - let(:role) { :developer } + let(:user) { developer } let(:job) { create(:ci_build, :erasable, :trace_artifact, pipeline: pipeline, user: triggered_by) } context 'when triggered by same user' do @@ -1109,7 +1131,7 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'when triggered by different user' do - let(:triggered_by) { create(:user) } + let(:triggered_by) { maintainer } it 'does not have successful status' do expect(response).not_to have_gitlab_http_status(:found) @@ -1168,8 +1190,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'with proper permissions for debug logging on a project' do + let(:user) { developer } + before do - project.add_developer(user) sign_in(user) end @@ -1181,8 +1204,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end context 'without proper permissions for debug logging on a project' do + let(:user) { reporter } + before do - project.add_reporter(user) sign_in(user) end @@ -1218,37 +1242,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end end - context "when job has a trace in database" do - let(:job) { create(:ci_build, pipeline: pipeline) } - - before do - job.update_column(:trace, "Sample trace") - end - - it 'sends a trace file' do - response = subject - - expect(response).to have_gitlab_http_status(:ok) - expect(response.headers['Content-Type']).to eq('text/plain; charset=utf-8') - expect(response.headers['Content-Disposition']).to match(/^inline/) - expect(response.body).to eq('Sample trace') - end - - context 'when trace format is not text/plain' do - before do - job.update_column(:trace, '<html></html>') - end - - it 'sets content disposition to attachment' do - response = subject - - expect(response).to have_gitlab_http_status(:ok) - expect(response.headers['Content-Type']).to eq('text/plain; charset=utf-8') - expect(response.headers['Content-Disposition']).to match(/^attachment/) - end - end - end - context 'when job does not have a trace file' do let(:job) { create(:ci_build, pipeline: pipeline) } @@ -1274,8 +1267,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end describe 'GET #terminal' do + let(:user) { developer } + before do - project.add_developer(user) sign_in(user) end @@ -1323,8 +1317,9 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do describe 'GET #terminal_websocket_authorize' do let!(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline, user: user) } + let(:user) { developer } + before do - project.add_developer(user) sign_in(user) end @@ -1375,14 +1370,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do end describe 'GET #proxy_websocket_authorize' do - let_it_be(:owner) { create(:owner) } - let_it_be(:admin) { create(:admin) } - let_it_be(:maintainer) { create(:user) } - let_it_be(:developer) { create(:user) } - let_it_be(:reporter) { create(:user) } - let_it_be(:guest) { create(:user) } - let_it_be(:project) { create(:project, :private, :repository, namespace: owner.namespace) } - let(:user) { maintainer } let(:pipeline) { create(:ci_pipeline, project: project, source: :webide, config_source: :webide_source, user: user) } let(:job) { create(:ci_build, :running, :with_runner_session, pipeline: pipeline, user: user) } @@ -1407,11 +1394,6 @@ RSpec.describe Projects::JobsController, :clean_gitlab_redis_shared_state do stub_feature_flags(build_service_proxy: true) allow(job).to receive(:has_terminal?).and_return(true) - project.add_maintainer(maintainer) - project.add_developer(developer) - project.add_reporter(reporter) - project.add_guest(guest) - sign_in(user) end diff --git a/spec/features/projects/show/user_interacts_with_stars_spec.rb b/spec/features/projects/show/user_interacts_with_stars_spec.rb index aa61b629d92..e0dd4f65010 100644 --- a/spec/features/projects/show/user_interacts_with_stars_spec.rb +++ b/spec/features/projects/show/user_interacts_with_stars_spec.rb @@ -14,14 +14,36 @@ RSpec.describe 'Projects > Show > User interacts with project stars' do end it 'toggles the star' do - find('.star-btn').click + star_project expect(page).to have_css('.star-count', text: 1) - find('.star-btn').click + unstar_project expect(page).to have_css('.star-count', text: 0) end + + it 'validates starring a project' do + project.add_owner(user) + + star_project + + visit(dashboard_projects_path) + + expect(page).to have_css('.stars', text: 1) + end + + it 'validates un-starring a project' do + project.add_owner(user) + + star_project + + unstar_project + + visit(dashboard_projects_path) + + expect(page).to have_css('.stars', text: 0) + end end context 'when user is not signed in' do @@ -38,3 +60,15 @@ RSpec.describe 'Projects > Show > User interacts with project stars' do end end end + +private + +def star_project + click_button(_('Star')) + wait_for_requests +end + +def unstar_project + click_button(_('Unstar')) + wait_for_requests +end diff --git a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js index ebbb6ed27c7..55a298e1695 100644 --- a/spec/frontend/runner/admin_runners/admin_runners_app_spec.js +++ b/spec/frontend/runner/admin_runners/admin_runners_app_spec.js @@ -17,6 +17,7 @@ import { updateHistory } from '~/lib/utils/url_utility'; import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config'; import { createLocalState } from '~/runner/graphql/list/local_state'; import AdminRunnersApp from '~/runner/admin_runners/admin_runners_app.vue'; +import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue'; import RunnerTypeTabs from '~/runner/components/runner_type_tabs.vue'; import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue'; import RunnerBulkDelete from '~/runner/components/runner_bulk_delete.vue'; @@ -86,6 +87,7 @@ describe('AdminRunnersApp', () => { let localMutations; let showToast; + const findRunnerStackedLayoutBanner = () => wrapper.findComponent(RunnerStackedLayoutBanner); const findRunnerStats = () => wrapper.findComponent(RunnerStats); const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell); const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown); @@ -145,6 +147,11 @@ describe('AdminRunnersApp', () => { wrapper.destroy(); }); + it('shows the feedback banner', () => { + createComponent(); + expect(findRunnerStackedLayoutBanner().exists()).toBe(true); + }); + it('shows the runner setup instructions', () => { createComponent(); diff --git a/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js b/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js new file mode 100644 index 00000000000..b892cfc7d3d --- /dev/null +++ b/spec/frontend/runner/components/runner_stacked_layout_banner_spec.js @@ -0,0 +1,57 @@ +import Vue from 'vue'; +import { GlBanner } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue'; +import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; + +describe('RunnerStackedLayoutBanner', () => { + let wrapper; + + const findBanner = () => wrapper.findComponent(GlBanner); + const findLocalStorageSync = () => wrapper.findComponent(LocalStorageSync); + + const createComponent = ({ ...options } = {}, mountFn = shallowMount) => { + wrapper = mountFn(RunnerStackedLayoutBanner, { + ...options, + }); + }; + + it('Does not display a banner', () => { + createComponent(); + + expect(findBanner().exists()).toBe(false); + }); + + describe.each` + glFeatures + ${{ runnerListStackedLayoutAdmin: true }} + ${{ runnerListStackedLayout: true }} + `('When glFeatures = $glFeatures', ({ glFeatures }) => { + beforeEach(() => { + createComponent({ + provide: { + glFeatures, + }, + }); + }); + + it('Displays a banner', () => { + expect(findBanner().props()).toMatchObject({ + svgPath: expect.stringContaining('data:image/svg+xml;utf8,'), + title: expect.any(String), + buttonText: expect.any(String), + buttonLink: expect.stringContaining('https://gitlab.com/gitlab-org/gitlab/-/issues/'), + }); + expect(findLocalStorageSync().exists()).toBe(true); + }); + + it('Does not display a banner when dismissed', async () => { + findLocalStorageSync().vm.$emit('input', true); + + await Vue.nextTick(); + + expect(findBanner().exists()).toBe(false); + expect(findLocalStorageSync().exists()).toBe(true); // continues syncing after removal + }); + }); +}); diff --git a/spec/frontend/runner/group_runners/group_runners_app_spec.js b/spec/frontend/runner/group_runners/group_runners_app_spec.js index 2335cd5d7d6..a17502c7eec 100644 --- a/spec/frontend/runner/group_runners/group_runners_app_spec.js +++ b/spec/frontend/runner/group_runners/group_runners_app_spec.js @@ -15,6 +15,7 @@ import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { updateHistory } from '~/lib/utils/url_utility'; import { upgradeStatusTokenConfig } from 'ee_else_ce/runner/components/search_tokens/upgrade_status_token_config'; +import RunnerStackedLayoutBanner from '~/runner/components/runner_stacked_layout_banner.vue'; import RunnerTypeTabs from '~/runner/components/runner_type_tabs.vue'; import RunnerFilteredSearchBar from '~/runner/components/runner_filtered_search_bar.vue'; import RunnerList from '~/runner/components/runner_list.vue'; @@ -77,6 +78,7 @@ jest.mock('~/lib/utils/url_utility', () => ({ describe('GroupRunnersApp', () => { let wrapper; + const findRunnerStackedLayoutBanner = () => wrapper.findComponent(RunnerStackedLayoutBanner); const findRunnerStats = () => wrapper.findComponent(RunnerStats); const findRunnerActionsCell = () => wrapper.findComponent(RunnerActionsCell); const findRegistrationDropdown = () => wrapper.findComponent(RegistrationDropdown); @@ -125,6 +127,11 @@ describe('GroupRunnersApp', () => { wrapper.destroy(); }); + it('shows the feedback banner', () => { + createComponent(); + expect(findRunnerStackedLayoutBanner().exists()).toBe(true); + }); + it('shows the runner tabs with a runner count for each type', async () => { await createComponent({ mountFn: mountExtended }); diff --git a/spec/lib/gitlab/ci/config/external/mapper_spec.rb b/spec/lib/gitlab/ci/config/external/mapper_spec.rb index e74fdc2071b..9eaba12f388 100644 --- a/spec/lib/gitlab/ci/config/external/mapper_spec.rb +++ b/spec/lib/gitlab/ci/config/external/mapper_spec.rb @@ -210,7 +210,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do { 'local' => local_file }, { 'local' => local_file } ], - image: 'image:1.0' } + image: 'image:1.0' } end it 'does not raise an exception' do @@ -427,7 +427,7 @@ RSpec.describe Gitlab::Ci::Config::External::Mapper do { 'local' => 'hello/secret-file1.yml' }, { 'local' => 'hello/secret-file2.yml' } ], - image: 'ruby:2.7' } + image: 'ruby:2.7' } end it 'has expanset with two' do diff --git a/spec/lib/gitlab/ci/lint_spec.rb b/spec/lib/gitlab/ci/lint_spec.rb index 7e0b2b5aa8e..3d46d266c13 100644 --- a/spec/lib/gitlab/ci/lint_spec.rb +++ b/spec/lib/gitlab/ci/lint_spec.rb @@ -341,9 +341,9 @@ RSpec.describe Gitlab::Ci::Lint do let(:counters) do { 'count' => a_kind_of(Numeric), - 'avg' => a_kind_of(Numeric), - 'max' => a_kind_of(Numeric), - 'min' => a_kind_of(Numeric) + 'avg' => a_kind_of(Numeric), + 'max' => a_kind_of(Numeric), + 'min' => a_kind_of(Numeric) } end diff --git a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb index 51185be3e74..6569ce937ac 100644 --- a/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb +++ b/spec/lib/gitlab/ci/pipeline/seed/deployment_spec.rb @@ -6,8 +6,7 @@ RSpec.describe Gitlab::Ci::Pipeline::Seed::Deployment do let_it_be(:project, refind: true) { create(:project, :repository) } let(:pipeline) do - create(:ci_pipeline, project: project, - sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0') + create(:ci_pipeline, project: project, sha: 'b83d6e391c22777fca1ed3012fce84f633d7fed0') end let(:job) { build(:ci_build, project: project, pipeline: pipeline) } diff --git a/spec/lib/gitlab/ci/trace_spec.rb b/spec/lib/gitlab/ci/trace_spec.rb index 888ceb7ff9a..3043c8c5467 100644 --- a/spec/lib/gitlab/ci/trace_spec.rb +++ b/spec/lib/gitlab/ci/trace_spec.rb @@ -10,7 +10,6 @@ RSpec.describe Gitlab::Ci::Trace, :clean_gitlab_redis_shared_state, factory_defa describe "associations" do it { expect(trace).to respond_to(:job) } - it { expect(trace).to delegate_method(:old_trace).to(:job) } end context 'when trace is migrated to object storage' do diff --git a/spec/lib/gitlab/ci/variables/builder_spec.rb b/spec/lib/gitlab/ci/variables/builder_spec.rb index fc6211a7ba3..4833ccf9093 100644 --- a/spec/lib/gitlab/ci/variables/builder_spec.rb +++ b/spec/lib/gitlab/ci/variables/builder_spec.rb @@ -138,11 +138,11 @@ RSpec.describe Gitlab::Ci::Variables::Builder, :clean_gitlab_redis_cache do { key: 'GITLAB_USER_ID', value: user.id.to_s }, { key: 'GITLAB_USER_EMAIL', - value: user.email }, + value: user.email }, { key: 'GITLAB_USER_LOGIN', - value: user.username }, + value: user.username }, { key: 'GITLAB_USER_NAME', - value: user.name } + value: user.name } ].map { |var| var.merge(public: true, masked: false) } end diff --git a/spec/lib/gitlab/ci/yaml_processor_spec.rb b/spec/lib/gitlab/ci/yaml_processor_spec.rb index bffdd370179..b68b12d8f43 100644 --- a/spec/lib/gitlab/ci/yaml_processor_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor_spec.rb @@ -298,8 +298,8 @@ module Gitlab context 'when delayed is defined' do let(:config) do YAML.dump(rspec: { - script: 'rollout 10%', - when: 'delayed', + script: 'rollout 10%', + when: 'delayed', start_in: '1 day' }) end @@ -315,7 +315,7 @@ module Gitlab context 'when resource group is defined' do let(:config) do YAML.dump(rspec: { - script: 'test', + script: 'test', resource_group: 'iOS' }) end @@ -1676,10 +1676,10 @@ module Gitlab describe "Artifacts" do it "returns artifacts when defined" do config = YAML.dump({ - image: "image:1.0", - services: ["mysql"], + image: "image:1.0", + services: ["mysql"], before_script: ["pwd"], - rspec: { + rspec: { artifacts: { paths: ["logs/", "binaries/"], expose_as: "Exposed artifacts", @@ -1935,7 +1935,7 @@ module Gitlab let(:config) do { deploy_to_production: { - stage: 'deploy', + stage: 'deploy', script: 'test' } } @@ -2304,15 +2304,15 @@ module Gitlab let(:config) do { - var_default: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null' }] }, - var_when: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null', when: 'always' }] }, + var_default: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null' }] }, + var_when: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null', when: 'always' }] }, var_and_changes: { stage: 'build', script: 'test', rules: [{ if: '$VAR == null', changes: %w[README], when: 'always' }] }, changes_not_var: { stage: 'test', script: 'test', rules: [{ if: '$VAR != null', changes: %w[README] }] }, var_not_changes: { stage: 'test', script: 'test', rules: [{ if: '$VAR == null', changes: %w[other/file.rb], when: 'always' }] }, - nothing: { stage: 'test', script: 'test', rules: [{ when: 'manual' }] }, - var_never: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'never' }] }, - var_delayed: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'delayed', start_in: '3 hours' }] }, - two_rules: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'on_success' }, { changes: %w[README], when: 'manual' }] } + nothing: { stage: 'test', script: 'test', rules: [{ when: 'manual' }] }, + var_never: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'never' }] }, + var_delayed: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'delayed', start_in: '3 hours' }] }, + two_rules: { stage: 'deploy', script: 'test', rules: [{ if: '$VAR == null', when: 'on_success' }, { changes: %w[README], when: 'manual' }] } } end diff --git a/spec/lib/gitlab/data_builder/issuable_spec.rb b/spec/lib/gitlab/data_builder/issuable_spec.rb index f0802f335f4..455800a3f7d 100644 --- a/spec/lib/gitlab/data_builder/issuable_spec.rb +++ b/spec/lib/gitlab/data_builder/issuable_spec.rb @@ -73,7 +73,7 @@ RSpec.describe Gitlab::DataBuilder::Issuable do }, assignees: { previous: [], - current: [{ + current: [{ name: "Foo Bar", username: "foobar", avatar_url: "http://www.example.com/my-avatar.jpg" diff --git a/spec/lib/gitlab/data_builder/note_spec.rb b/spec/lib/gitlab/data_builder/note_spec.rb index 3fa535dd800..8e8b8ce6681 100644 --- a/spec/lib/gitlab/data_builder/note_spec.rb +++ b/spec/lib/gitlab/data_builder/note_spec.rb @@ -49,8 +49,7 @@ RSpec.describe Gitlab::DataBuilder::Note do let(:label) { create(:label, project: project) } let(:issue) do - create(:labeled_issue, created_at: fixed_time, updated_at: fixed_time, - project: project, labels: [label]) + create(:labeled_issue, created_at: fixed_time, updated_at: fixed_time, project: project, labels: [label]) end let(:note) do @@ -84,15 +83,15 @@ RSpec.describe Gitlab::DataBuilder::Note do describe 'When asking for a note on merge request' do let(:label) { create(:label, project: project) } let(:merge_request) do - create(:labeled_merge_request, created_at: fixed_time, - updated_at: fixed_time, - source_project: project, - labels: [label]) + create(:labeled_merge_request, + created_at: fixed_time, + updated_at: fixed_time, + source_project: project, + labels: [label]) end let(:note) do - create(:note_on_merge_request, noteable: merge_request, - project: project) + create(:note_on_merge_request, noteable: merge_request, project: project) end it_behaves_like 'includes general data' @@ -112,14 +111,15 @@ RSpec.describe Gitlab::DataBuilder::Note do describe 'When asking for a note on merge request diff' do let(:label) { create(:label, project: project) } let(:merge_request) do - create(:labeled_merge_request, created_at: fixed_time, updated_at: fixed_time, - source_project: project, - labels: [label]) + create(:labeled_merge_request, + created_at: fixed_time, + updated_at: fixed_time, + source_project: + project, labels: [label]) end let(:note) do - create(:diff_note_on_merge_request, noteable: merge_request, - project: project) + create(:diff_note_on_merge_request, noteable: merge_request, project: project) end it_behaves_like 'includes general data' @@ -138,13 +138,11 @@ RSpec.describe Gitlab::DataBuilder::Note do describe 'When asking for a note on project snippet' do let!(:snippet) do - create(:project_snippet, created_at: fixed_time, updated_at: fixed_time, - project: project) + create(:project_snippet, created_at: fixed_time, updated_at: fixed_time, project: project) end let!(:note) do - create(:note_on_project_snippet, noteable: snippet, - project: project) + create(:note_on_project_snippet, noteable: snippet, project: project) end it_behaves_like 'includes general data' diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index dd5ad40d8ef..d73b478ee7c 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -667,7 +667,7 @@ RSpec.describe Gitlab::Database::MigrationHelpers do column: :user_id, on_delete: :cascade, name: name, - primary_key: :id).and_return(true) + primary_key: :id).and_return(true) expect(model).not_to receive(:execute).with(/ADD CONSTRAINT/) expect(model).to receive(:execute).with(/VALIDATE CONSTRAINT/) diff --git a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb index 04b9fba5b2f..1768f97de54 100644 --- a/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb +++ b/spec/lib/gitlab/database/partitioning/sliding_list_strategy_spec.rb @@ -181,9 +181,10 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy do Class.new(ApplicationRecord) do include PartitionedTable - partitioned_by :partition, strategy: :sliding_list, - next_partition_if: proc { false }, - detach_partition_if: proc { false } + partitioned_by :partition, + strategy: :sliding_list, + next_partition_if: proc { false }, + detach_partition_if: proc { false } end end.to raise_error(/ignored_columns/) end @@ -195,7 +196,8 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy do self.ignored_columns = [:partition] - partitioned_by :partition, strategy: :sliding_list, + partitioned_by :partition, + strategy: :sliding_list, next_partition_if: proc { false }, detach_partition_if: proc { false } end @@ -221,7 +223,8 @@ RSpec.describe Gitlab::Database::Partitioning::SlidingListStrategy do def self.detach_partition_if_wrapper(...) detach_partition?(...) end - partitioned_by :partition, strategy: :sliding_list, + partitioned_by :partition, + strategy: :sliding_list, next_partition_if: method(:next_partition_if_wrapper), detach_partition_if: method(:detach_partition_if_wrapper) diff --git a/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb b/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb index 3072c413246..1885e84ac4c 100644 --- a/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb +++ b/spec/lib/gitlab/database/partitioning_migration_helpers/backfill_partitioned_table_spec.rb @@ -97,7 +97,8 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::BackfillPartition end it 'marks each job record as succeeded after processing' do - create(:background_migration_job, class_name: "::#{described_class.name}", + create(:background_migration_job, + class_name: "::#{described_class.name}", arguments: [source1.id, source3.id, source_table, destination_table, unique_key]) expect(::Gitlab::Database::BackgroundMigrationJob).to receive(:mark_all_as_succeeded).and_call_original @@ -108,7 +109,8 @@ RSpec.describe Gitlab::Database::PartitioningMigrationHelpers::BackfillPartition end it 'returns the number of job records marked as succeeded' do - create(:background_migration_job, class_name: "::#{described_class.name}", + create(:background_migration_job, + class_name: "::#{described_class.name}", arguments: [source1.id, source3.id, source_table, destination_table, unique_key]) jobs_updated = backfill_job.perform(source1.id, source3.id, source_table, destination_table, unique_key) diff --git a/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb b/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb index 6601b6658d5..ad91320c6eb 100644 --- a/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb +++ b/spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb @@ -181,8 +181,8 @@ RSpec.describe Gitlab::DatabaseImporters::SelfMonitoring::Project::CreateService let(:existing_project) { create(:project, namespace: existing_group) } before do - application_setting.update!(instance_administrators_group_id: existing_group.id, - self_monitoring_project_id: existing_project.id) + application_setting.update!( + instance_administrators_group_id: existing_group.id, self_monitoring_project_id: existing_project.id) end it 'returns success' do diff --git a/spec/lib/gitlab/diff/highlight_cache_spec.rb b/spec/lib/gitlab/diff/highlight_cache_spec.rb index 68a2b17840c..53e74748234 100644 --- a/spec/lib/gitlab/diff/highlight_cache_spec.rb +++ b/spec/lib/gitlab/diff/highlight_cache_spec.rb @@ -9,33 +9,33 @@ RSpec.describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do { ".gitignore-false-false-false" => [{ line_code: nil, rich_text: nil, text: "@@ -17,3 +17,4 @@ rerun.txt", type: "match", index: 0, old_pos: 17, new_pos: 17 }, { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_17_17", - rich_text: " <span id=\"LC17\" class=\"line\" lang=\"plaintext\">pickle-email-*.html</span>\n", - text: " pickle-email-*.html", - type: nil, - index: 1, - old_pos: 17, - new_pos: 17 }, + rich_text: " <span id=\"LC17\" class=\"line\" lang=\"plaintext\">pickle-email-*.html</span>\n", + text: " pickle-email-*.html", + type: nil, + index: 1, + old_pos: 17, + new_pos: 17 }, { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_18_18", - rich_text: " <span id=\"LC18\" class=\"line\" lang=\"plaintext\">.project</span>\n", - text: " .project", - type: nil, - index: 2, - old_pos: 18, - new_pos: 18 }, + rich_text: " <span id=\"LC18\" class=\"line\" lang=\"plaintext\">.project</span>\n", + text: " .project", + type: nil, + index: 2, + old_pos: 18, + new_pos: 18 }, { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_19_19", - rich_text: " <span id=\"LC19\" class=\"line\" lang=\"plaintext\">config/initializers/secret_token.rb</span>\n", - text: " config/initializers/secret_token.rb", - type: nil, - index: 3, - old_pos: 19, - new_pos: 19 }, + rich_text: " <span id=\"LC19\" class=\"line\" lang=\"plaintext\">config/initializers/secret_token.rb</span>\n", + text: " config/initializers/secret_token.rb", + type: nil, + index: 3, + old_pos: 19, + new_pos: 19 }, { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_20_20", - rich_text: "+<span id=\"LC20\" class=\"line\" lang=\"plaintext\">.DS_Store</span>", - text: "+.DS_Store", - type: "new", - index: 4, - old_pos: 20, - new_pos: 20 }] } + rich_text: "+<span id=\"LC20\" class=\"line\" lang=\"plaintext\">.DS_Store</span>", + text: "+.DS_Store", + type: "new", + index: 4, + old_pos: 20, + new_pos: 20 }] } end let(:cache_key) { cache.key } diff --git a/spec/lib/gitlab/diff/lines_unfolder_spec.rb b/spec/lib/gitlab/diff/lines_unfolder_spec.rb index f0e710be2e4..98f0c4df204 100644 --- a/spec/lib/gitlab/diff/lines_unfolder_spec.rb +++ b/spec/lib/gitlab/diff/lines_unfolder_spec.rb @@ -189,14 +189,14 @@ RSpec.describe Gitlab::Diff::LinesUnfolder do let(:diff) do Gitlab::Git::Diff.new({ diff: raw_diff, - new_path: "build-aux/flatpak/org.gnome.Nautilus.json", - old_path: "build-aux/flatpak/org.gnome.Nautilus.json", - a_mode: "100644", - b_mode: "100644", - new_file: false, - renamed_file: false, - deleted_file: false, - too_large: false }) + new_path: "build-aux/flatpak/org.gnome.Nautilus.json", + old_path: "build-aux/flatpak/org.gnome.Nautilus.json", + a_mode: "100644", + b_mode: "100644", + new_file: false, + renamed_file: false, + deleted_file: false, + too_large: false }) end let(:diff_file) do diff --git a/spec/lib/gitlab/diff/position_spec.rb b/spec/lib/gitlab/diff/position_spec.rb index bb3522eb579..00a468bfef6 100644 --- a/spec/lib/gitlab/diff/position_spec.rb +++ b/spec/lib/gitlab/diff/position_spec.rb @@ -684,7 +684,7 @@ RSpec.describe Gitlab::Diff::Position do "old_line" => 18, "new_line" => 18 }, - "end" => { + "end" => { "line_code" => end_line_code, "type" => nil, "old_line" => end_old_line, diff --git a/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb index 210829056c8..c9b632b50e1 100644 --- a/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb +++ b/spec/lib/gitlab/error_tracking/processor/context_payload_processor_spec.rb @@ -38,10 +38,10 @@ RSpec.describe Gitlab::ErrorTracking::Processor::ContextPayloadProcessor do expect(result_hash[:tags]) .to include(priority: 'high', - locale: 'en', - program: 'test', - feature_category: 'feature_a', - correlation_id: 'cid') + locale: 'en', + program: 'test', + feature_category: 'feature_a', + correlation_id: 'cid') expect(result_hash[:extra]) .to include(some_info: 'info', diff --git a/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb b/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb index 577d59798da..3d23249d00d 100644 --- a/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb +++ b/spec/lib/gitlab/error_tracking/stack_trace_highlight_decorator_spec.rb @@ -52,7 +52,7 @@ RSpec.describe Gitlab::ErrorTracking::StackTraceHighlightDecorator do 'function' => 'print', 'lineNo' => 3, 'filename' => 'hello_world.php', - 'context' => [ + 'context' => [ [1, '<span id="LC1" class="line" lang="hack"><span class="c1">// PHP/Hack example</span></span>'], [2, '<span id="LC1" class="line" lang="hack"><span class="cp"><?php</span></span>'], [3, '<span id="LC1" class="line" lang="hack"><span class="k">echo</span> <span class="s1">\'Hello, World!\'</span><span class="p">;</span></span>'] diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb index 8228f95dd5e..da5eaf2e4ab 100644 --- a/spec/lib/gitlab/etag_caching/middleware_spec.rb +++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb @@ -119,11 +119,11 @@ RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state let(:expected_items) do { etag_route: endpoint, - params: {}, - format: :html, - method: 'GET', - path: enabled_path, - status: status_code + params: {}, + format: :html, + method: 'GET', + path: enabled_path, + status: status_code } end diff --git a/spec/lib/gitlab/etag_caching/router/graphql_spec.rb b/spec/lib/gitlab/etag_caching/router/graphql_spec.rb index 9a6787e3640..792f02f8cda 100644 --- a/spec/lib/gitlab/etag_caching/router/graphql_spec.rb +++ b/spec/lib/gitlab/etag_caching/router/graphql_spec.rb @@ -21,7 +21,7 @@ RSpec.describe Gitlab::EtagCaching::Router::Graphql do def match_route(path, header) described_class.match( double(path_info: path, - headers: { 'X-GITLAB-GRAPHQL-RESOURCE-ETAG' => header })) + headers: { 'X-GITLAB-GRAPHQL-RESOURCE-ETAG' => header })) end describe '.cache_key' do diff --git a/spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb b/spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb index 487b19a98e0..5006d27c356 100644 --- a/spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb +++ b/spec/lib/gitlab/grape_logging/formatters/lograge_with_timestamp_spec.rb @@ -6,7 +6,7 @@ RSpec.describe Gitlab::GrapeLogging::Formatters::LogrageWithTimestamp do let(:log_entry) do { status: 200, - time: { + time: { total: 758.58, db: 77.06, view: 681.52 diff --git a/spec/lib/gitlab/import_export/attributes_finder_spec.rb b/spec/lib/gitlab/import_export/attributes_finder_spec.rb index 428d8d605ee..6536b895b2f 100644 --- a/spec/lib/gitlab/import_export/attributes_finder_spec.rb +++ b/spec/lib/gitlab/import_export/attributes_finder_spec.rb @@ -123,7 +123,7 @@ RSpec.describe Gitlab::ImportExport::AttributesFinder do is_expected.to match( include: [{ merge_requests: { include: [{ notes: { include: [{ author: { include: [] } }], - preload: { author: nil } } }], + preload: { author: nil } } }], preload: { notes: { author: nil } } } }], preload: { merge_requests: { notes: { author: nil } } } @@ -132,7 +132,7 @@ RSpec.describe Gitlab::ImportExport::AttributesFinder do it 'generates the correct hash for a relation with included attributes' do setup_yaml(tree: { project: [:issues] }, - included_attributes: { issues: [:name, :description] }) + included_attributes: { issues: [:name, :description] }) is_expected.to match( include: [{ issues: { include: [], @@ -143,7 +143,7 @@ RSpec.describe Gitlab::ImportExport::AttributesFinder do it 'generates the correct hash for a relation with excluded attributes' do setup_yaml(tree: { project: [:issues] }, - excluded_attributes: { issues: [:name] }) + excluded_attributes: { issues: [:name] }) is_expected.to match( include: [{ issues: { except: [:name], @@ -154,8 +154,8 @@ RSpec.describe Gitlab::ImportExport::AttributesFinder do it 'generates the correct hash for a relation with both excluded and included attributes' do setup_yaml(tree: { project: [:issues] }, - excluded_attributes: { issues: [:name] }, - included_attributes: { issues: [:description] }) + excluded_attributes: { issues: [:name] }, + included_attributes: { issues: [:description] }) is_expected.to match( include: [{ issues: { except: [:name], @@ -167,7 +167,7 @@ RSpec.describe Gitlab::ImportExport::AttributesFinder do it 'generates the correct hash for a relation with custom methods' do setup_yaml(tree: { project: [:issues] }, - methods: { issues: [:name] }) + methods: { issues: [:name] }) is_expected.to match( include: [{ issues: { include: [], diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index eac8115742d..3a656c4a42d 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -1225,70 +1225,6 @@ RSpec.describe Ci::Build do end end - describe '#has_old_trace?' do - subject { build.has_old_trace? } - - context 'when old trace exists' do - before do - build.update_column(:trace, 'old trace') - end - - it { is_expected.to be_truthy } - end - - context 'when old trace does not exist' do - it { is_expected.to be_falsy } - end - end - - describe '#trace=' do - it "expect to fail trace=" do - expect { build.trace = "new" }.to raise_error(NotImplementedError) - end - end - - describe '#old_trace' do - subject { build.old_trace } - - before do - build.update_column(:trace, 'old trace') - end - - it "expect to receive data from database" do - is_expected.to eq('old trace') - end - end - - describe '#erase_old_trace!' do - subject { build.erase_old_trace! } - - context 'when old trace exists' do - before do - build.update_column(:trace, 'old trace') - end - - it "erases old trace" do - subject - - expect(build.old_trace).to be_nil - end - - it "executes UPDATE query" do - recorded = ActiveRecord::QueryRecorder.new { subject } - - expect(recorded.log.count { |l| l.match?(/UPDATE.*ci_builds/) }).to eq(1) - end - end - - context 'when old trace does not exist' do - it 'does not execute UPDATE query' do - recorded = ActiveRecord::QueryRecorder.new { subject } - - expect(recorded.log.count { |l| l.match?(/UPDATE.*ci_builds/) }).to eq(0) - end - end - end - describe '#hide_secrets' do let(:metrics) { spy('metrics') } let(:subject) { build.hide_secrets(data) } diff --git a/spec/models/ci/processable_spec.rb b/spec/models/ci/processable_spec.rb index 594f9b679ec..61e2864a518 100644 --- a/spec/models/ci/processable_spec.rb +++ b/spec/models/ci/processable_spec.rb @@ -55,8 +55,7 @@ RSpec.describe Ci::Processable do let(:clone_accessors) { ::Ci::Build.clone_accessors.without(::Ci::Build.extra_accessors) } let(:reject_accessors) do - %i[id status user token_encrypted coverage trace runner - artifacts_expire_at + %i[id status user token_encrypted coverage runner artifacts_expire_at created_at updated_at started_at finished_at queued_at erased_by erased_at auto_canceled_by job_artifacts job_artifacts_archive job_artifacts_metadata job_artifacts_trace job_artifacts_junit diff --git a/spec/requests/api/graphql/group/work_item_types_spec.rb b/spec/requests/api/graphql/group/work_item_types_spec.rb index a33e3ae5427..d6b0673e4f8 100644 --- a/spec/requests/api/graphql/group/work_item_types_spec.rb +++ b/spec/requests/api/graphql/group/work_item_types_spec.rb @@ -46,7 +46,7 @@ RSpec.describe 'getting a list of work item types for a group' do end end - context "when user doesn't have acces to the group" do + context "when user doesn't have access to the group" do let(:current_user) { create(:user) } before do diff --git a/spec/requests/api/personal_access_tokens/self_revocation_spec.rb b/spec/requests/api/personal_access_tokens/self_revocation_spec.rb new file mode 100644 index 00000000000..f829b39cc1e --- /dev/null +++ b/spec/requests/api/personal_access_tokens/self_revocation_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe API::PersonalAccessTokens::SelfRevocation do + let_it_be(:current_user) { create(:user) } + + describe 'DELETE /personal_access_tokens/self' do + let(:path) { '/personal_access_tokens/self' } + let(:token) { create(:personal_access_token, user: current_user) } + + subject(:delete_token) { delete api(path, personal_access_token: token) } + + shared_examples 'revoking token succeeds' do + it 'revokes token' do + delete_token + + expect(response).to have_gitlab_http_status(:no_content) + expect(token.reload).to be_revoked + end + end + + shared_examples 'revoking token denied' do |status| + it 'cannot revoke token' do + delete_token + + expect(response).to have_gitlab_http_status(status) + end + end + + context 'when current_user is an administrator', :enable_admin_mode do + let(:current_user) { create(:admin) } + + it_behaves_like 'revoking token succeeds' + + context 'with impersonated token' do + let(:token) { create(:personal_access_token, :impersonation, user: current_user) } + + it_behaves_like 'revoking token succeeds' + end + end + + context 'when current_user is not an administrator' do + let(:current_user) { create(:user) } + + it_behaves_like 'revoking token succeeds' + + context 'with impersonated token' do + let(:token) { create(:personal_access_token, :impersonation, user: current_user) } + + it_behaves_like 'revoking token denied', :bad_request + end + + context 'with already revoked token' do + let(:token) { create(:personal_access_token, :revoked, user: current_user) } + + it_behaves_like 'revoking token denied', :unauthorized + end + end + + Gitlab::Auth.all_available_scopes.each do |scope| + context "with a '#{scope}' scoped token" do + let(:token) { create(:personal_access_token, scopes: [scope], user: current_user) } + + it_behaves_like 'revoking token succeeds' + end + end + end +end diff --git a/spec/requests/api/personal_access_tokens_spec.rb b/spec/requests/api/personal_access_tokens_spec.rb index 8d8998cfdd6..37b5a594f2a 100644 --- a/spec/requests/api/personal_access_tokens_spec.rb +++ b/spec/requests/api/personal_access_tokens_spec.rb @@ -75,6 +75,7 @@ RSpec.describe API::PersonalAccessTokens do describe 'GET /personal_access_tokens/:id' do let_it_be(:user_token) { create(:personal_access_token, user: current_user) } + let_it_be(:user_read_only_token) { create(:personal_access_token, scopes: ['read_repository'], user: current_user) } let_it_be(:user_token_path) { "/personal_access_tokens/#{user_token.id}" } let_it_be(:invalid_path) { "/personal_access_tokens/#{non_existing_record_id}" } @@ -125,53 +126,11 @@ RSpec.describe API::PersonalAccessTokens do expect(response).to have_gitlab_http_status(:unauthorized) end - end - end - - describe 'DELETE /personal_access_tokens/self' do - let(:path) { '/personal_access_tokens/self' } - let(:token) { create(:personal_access_token, user: current_user) } - - subject { delete api(path, current_user, personal_access_token: token) } - - shared_examples 'revoking token succeeds' do - it 'revokes token' do - subject - - expect(response).to have_gitlab_http_status(:no_content) - expect(token.reload).to be_revoked - end - end - shared_examples 'revoking token denied' do |status| - it 'cannot revoke token' do - subject + it 'fails to return own PAT by id with read_repository token' do + get api(user_token_path, current_user, personal_access_token: user_read_only_token) - expect(response).to have_gitlab_http_status(status) - end - end - - context 'when current_user is an administrator', :enable_admin_mode do - let(:current_user) { create(:admin) } - - it_behaves_like 'revoking token succeeds' - end - - context 'when current_user is not an administrator' do - let(:current_user) { create(:user) } - - it_behaves_like 'revoking token succeeds' - - context 'with impersonated token' do - let(:token) { create(:personal_access_token, :impersonation, user: current_user) } - - it_behaves_like 'revoking token denied', :bad_request - end - - context 'with already revoked token' do - let(:token) { create(:personal_access_token, :revoked, user: current_user) } - - it_behaves_like 'revoking token denied', :unauthorized + expect(response).to have_gitlab_http_status(:forbidden) end end end @@ -183,6 +142,9 @@ RSpec.describe API::PersonalAccessTokens do let_it_be(:admin_user) { create(:admin) } let_it_be(:admin_token) { create(:personal_access_token, user: admin_user) } let_it_be(:admin_path) { "/personal_access_tokens/#{admin_token.id}" } + let_it_be(:admin_read_only_token) do + create(:personal_access_token, scopes: ['read_repository'], user: admin_user) + end it 'revokes a different users token' do delete api(path, admin_user) @@ -196,6 +158,12 @@ RSpec.describe API::PersonalAccessTokens do expect(response).to have_gitlab_http_status(:no_content) end + + it 'fails to revoke a different user token using a readonly scope' do + delete api(path, personal_access_token: admin_read_only_token) + + expect(token1.reload.revoked?).to be false + end end context 'when current_user is not an administrator' do diff --git a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb index 194203a422c..3d1abe290bc 100644 --- a/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb +++ b/spec/services/ci/resource_groups/assign_resource_from_resource_group_service_spec.rb @@ -3,6 +3,8 @@ require 'spec_helper' RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService do + include ConcurrentHelpers + let_it_be(:project) { create(:project) } let_it_be(:user) { create(:user) } @@ -134,6 +136,19 @@ RSpec.describe Ci::ResourceGroups::AssignResourceFromResourceGroupService do end end end + + context 'when parallel services are running' do + it 'can run the same command in parallel' do + parallel_num = 4 + + blocks = Array.new(parallel_num).map do + -> { subject } + end + + run_parallel(blocks) + expect(build.reload).to be_pending + end + end end context 'when there are no available resources' do diff --git a/spec/services/projects/destroy_service_spec.rb b/spec/services/projects/destroy_service_spec.rb index 94320320407..8269dbebccb 100644 --- a/spec/services/projects/destroy_service_spec.rb +++ b/spec/services/projects/destroy_service_spec.rb @@ -135,6 +135,33 @@ RSpec.describe Projects::DestroyService, :aggregate_failures, :event_store_publi end end + context 'deleting a project with merge request diffs' do + let!(:merge_request) { create(:merge_request, source_project: project) } + let!(:another_project_mr) { create(:merge_request, source_project: create(:project)) } + + it 'deletes merge request diffs' do + merge_request_diffs = merge_request.merge_request_diffs + expect(merge_request_diffs.size).to eq(1) + + expect { destroy_project(project, user, {}) }.to change(MergeRequestDiff, :count).by(-1) + expect { another_project_mr.reload }.not_to raise_error + end + + context 'when extract_mr_diff_deletions feature flag is disabled' do + before do + stub_feature_flags(extract_mr_diff_deletions: false) + end + + it 'also deletes merge request diffs' do + merge_request_diffs = merge_request.merge_request_diffs + expect(merge_request_diffs.size).to eq(1) + + expect { destroy_project(project, user, {}) }.to change(MergeRequestDiff, :count).by(-1) + expect { another_project_mr.reload }.not_to raise_error + end + end + end + it_behaves_like 'deleting the project' it 'invalidates personal_project_count cache' do diff --git a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb index c388a3a2c7f..10f58748698 100644 --- a/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb +++ b/spec/support/shared_examples/lib/gitlab/ci/ci_trace_shared_examples.rb @@ -370,15 +370,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do end end - shared_examples 'read successfully with StringIO' do - it 'yields with source' do - trace.read do |stream| - expect(stream).to be_a(Gitlab::Ci::Trace::Stream) - expect(stream.stream).to be_a(StringIO) - end - end - end - shared_examples 'failed to read' do it 'yields without source' do trace.read do |stream| @@ -404,14 +395,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do it_behaves_like 'read successfully with IO' end - context 'when db trace exists' do - before do - build.send(:write_attribute, :trace, "data") - end - - it_behaves_like 'read successfully with StringIO' - end - context 'when no sources exist' do it_behaves_like 'failed to read' end @@ -462,25 +445,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do expect(trace.exist?).to be(false) end end - - context 'stored in database' do - before do - build.send(:write_attribute, :trace, "data") - end - - it "trace exist" do - expect(trace.exist?).to be(true) - end - - it "can be erased" do - trace.erase! - expect(trace.exist?).to be(false) - end - - it "returns database data" do - expect(trace.raw).to eq("data") - end - end end describe '#archive!' do @@ -520,24 +484,12 @@ RSpec.shared_examples 'trace with disabled live trace feature' do expect(build.trace.exist?).to be_truthy expect(build.job_artifacts_trace.file.exists?).to be_truthy expect(build.job_artifacts_trace.file.filename).to eq('job.log') - expect(build.old_trace).to be_nil expect(src_checksum) .to eq(described_class.sha256_hexdigest(build.job_artifacts_trace.file.path)) expect(build.job_artifacts_trace.file_sha256).to eq(src_checksum) end end - shared_examples 'source trace in database stays intact' do |error:| - it do - expect { subject }.to raise_error(error) - - build.reload - expect(build.trace.exist?).to be_truthy - expect(build.job_artifacts_trace).to be_nil - expect(build.old_trace).to eq(trace_content) - end - end - context 'when job does not have trace artifact' do context 'when trace file stored in default path' do let!(:build) { create(:ci_build, :success, :trace_live) } @@ -564,58 +516,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do it_behaves_like 'source trace file stays intact', error: ActiveRecord::RecordInvalid end end - - context 'when trace is stored in database' do - let(:build) { create(:ci_build, :success) } - let(:trace_content) { 'Sample trace' } - let(:src_checksum) { Digest::SHA256.hexdigest(trace_content) } - - before do - build.update_column(:trace, trace_content) - end - - it_behaves_like 'archive trace in database' - - context 'when failed to create clone file' do - before do - allow(IO).to receive(:copy_stream).and_return(0) - end - - it_behaves_like 'source trace in database stays intact', error: Gitlab::Ci::Trace::ArchiveError - end - - context 'when failed to create job artifact record' do - before do - allow_any_instance_of(Ci::JobArtifact).to receive(:save).and_return(false) - allow_any_instance_of(Ci::JobArtifact).to receive_message_chain(:errors, :full_messages) - .and_return(%w[Error Error]) - end - - it_behaves_like 'source trace in database stays intact', error: ActiveRecord::RecordInvalid - end - - context 'when there is a validation error on Ci::Build' do - before do - allow_any_instance_of(Ci::Build).to receive(:save).and_return(false) - allow_any_instance_of(Ci::Build).to receive_message_chain(:errors, :full_messages) - .and_return(%w[Error Error]) - end - - context "when erase old trace with 'save'" do - before do - build.send(:write_attribute, :trace, nil) - build.save # rubocop:disable Rails/SaveBang - end - - it 'old trace is not deleted' do - build.reload - expect(build.trace.raw).to eq(trace_content) - end - end - - it_behaves_like 'archive trace in database' - end - end end context 'when job has trace artifact' do @@ -645,22 +545,6 @@ RSpec.shared_examples 'trace with disabled live trace feature' do subject { trace.erase! } context 'when it is a live trace' do - context 'when trace is stored in database' do - let(:build) { create(:ci_build) } - - before do - build.update_column(:trace, 'sample trace') - end - - it { expect(trace.raw).not_to be_nil } - - it "removes trace" do - subject - - expect(trace.raw).to be_nil - end - end - context 'when trace is stored in file storage' do let(:build) { create(:ci_build, :trace_live) } |