diff --git a/.rubocop_todo/gitlab/delegate_predicate_methods.yml b/.rubocop_todo/gitlab/delegate_predicate_methods.yml index 408eb6b6860..7ed3fc3e4fb 100644 --- a/.rubocop_todo/gitlab/delegate_predicate_methods.yml +++ b/.rubocop_todo/gitlab/delegate_predicate_methods.yml @@ -5,4 +5,3 @@ Gitlab/DelegatePredicateMethods: - app/models/concerns/integrations/base_data_fields.rb - app/models/project.rb - ee/app/models/concerns/ee/ci/metadatable.rb - - lib/gitlab/ci/trace/stream.rb diff --git a/.rubocop_todo/graphql/argument_name.yml b/.rubocop_todo/graphql/argument_name.yml deleted file mode 100644 index 29d2ae7d4ae..00000000000 --- a/.rubocop_todo/graphql/argument_name.yml +++ /dev/null @@ -1,4 +0,0 @@ ---- -GraphQL/ArgumentName: - Exclude: - - ee/app/graphql/mutations/audit_events/external_audit_event_destinations/update.rb diff --git a/.rubocop_todo/rails/save_bang.yml b/.rubocop_todo/rails/save_bang.yml index c6345b5eda1..870e085eb28 100644 --- a/.rubocop_todo/rails/save_bang.yml +++ b/.rubocop_todo/rails/save_bang.yml @@ -31,11 +31,6 @@ Rails/SaveBang: - spec/lib/gitlab/database/custom_structure_spec.rb - spec/lib/gitlab/database/partitioning_migration_helpers/table_management_helpers_spec.rb - spec/lib/gitlab/database_importers/self_monitoring/project/create_service_spec.rb - - spec/lib/gitlab/gfm/reference_rewriter_spec.rb - - spec/lib/gitlab/git_access_spec.rb - - spec/lib/gitlab/import_export/avatar_saver_spec.rb - - spec/lib/gitlab/import_export/base/relation_factory_spec.rb - - spec/lib/gitlab/import_export/design_repo_restorer_spec.rb - spec/lib/gitlab/import_export/fast_hash_serializer_spec.rb - spec/lib/gitlab/import_export/fork_spec.rb - spec/lib/gitlab/import_export/group/legacy_tree_saver_spec.rb diff --git a/Gemfile.lock b/Gemfile.lock index e6b3673c6e9..bed748288a0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1673,4 +1673,4 @@ DEPENDENCIES yajl-ruby (~> 1.4.1) BUNDLED WITH - 2.1.4 + 2.3.5 diff --git a/app/assets/javascripts/blob/components/blob_header.vue b/app/assets/javascripts/blob/components/blob_header.vue index 933ad448c77..6c7d963ae39 100644 --- a/app/assets/javascripts/blob/components/blob_header.vue +++ b/app/assets/javascripts/blob/components/blob_header.vue @@ -81,7 +81,7 @@ export default { -
+
diff --git a/app/assets/javascripts/pages/projects/planning_hierarchy/index.js b/app/assets/javascripts/pages/projects/planning_hierarchy/index.js deleted file mode 100644 index d5dfe2d5f37..00000000000 --- a/app/assets/javascripts/pages/projects/planning_hierarchy/index.js +++ /dev/null @@ -1,3 +0,0 @@ -import { initWorkItemsHierarchy } from '~/work_items_hierarchy/work_items_hierarchy_bundle'; - -initWorkItemsHierarchy(); diff --git a/app/assets/javascripts/repository/components/blob_controls.vue b/app/assets/javascripts/repository/components/blob_controls.vue index bde1b217ec9..c36f5201a87 100644 --- a/app/assets/javascripts/repository/components/blob_controls.vue +++ b/app/assets/javascripts/repository/components/blob_controls.vue @@ -3,6 +3,7 @@ import { GlButton } from '@gitlab/ui'; import { __ } from '~/locale'; import createFlash from '~/flash'; import getRefMixin from '~/repository/mixins/get_ref'; +import initSourcegraph from '~/sourcegraph'; import { updateElementsVisibility } from '../utils/dom'; import blobControlsQuery from '../queries/blob_controls.query.graphql'; @@ -76,6 +77,9 @@ export default { showBlobControls(shouldShow) { updateElementsVisibility('.tree-controls', !shouldShow); }, + blobInfo() { + initSourcegraph(); + }, }, }; @@ -97,6 +101,7 @@ export default { data-testid="permalink" :href="blobInfo.permalinkPath" :class="$options.buttonClassList" + class="js-data-file-blob-permalink-url" > {{ $options.i18n.permalink }} diff --git a/app/assets/javascripts/vue_shared/components/source_viewer.vue b/app/assets/javascripts/vue_shared/components/source_viewer.vue index 51fef7823f9..c92ab77b34f 100644 --- a/app/assets/javascripts/vue_shared/components/source_viewer.vue +++ b/app/assets/javascripts/vue_shared/components/source_viewer.vue @@ -2,7 +2,6 @@ import { GlSafeHtmlDirective } from '@gitlab/ui'; import LineNumbers from '~/vue_shared/components/line_numbers.vue'; import { sanitize } from '~/lib/dompurify'; -import '~/sourcegraph/load'; const LINE_SELECT_CLASS_NAME = 'hll'; diff --git a/app/assets/javascripts/work_items/constants.js b/app/assets/javascripts/work_items/constants.js index 6b72c89bb29..995c02a2c5b 100644 --- a/app/assets/javascripts/work_items/constants.js +++ b/app/assets/javascripts/work_items/constants.js @@ -1,54 +1,5 @@ -import { __ } from '~/locale'; - export const widgetTypes = { title: 'TITLE', }; export const WI_TITLE_TRACK_LABEL = 'item_title'; - -export const workItemTypes = { - EPIC: { - title: __('Epic'), - icon: 'epic', - color: '#694CC0', - backgroundColor: '#E1D8F9', - }, - ISSUE: { - title: __('Issue'), - icon: 'issues', - color: '#1068BF', - backgroundColor: '#CBE2F9', - }, - TASK: { - title: __('Task'), - icon: 'task-done', - color: '#217645', - backgroundColor: '#C3E6CD', - }, - INCIDENT: { - title: __('Incident'), - icon: 'issue-type-incident', - backgroundColor: '#db2a0f', - color: '#FDD4CD', - iconSize: 16, - }, - SUB_EPIC: { - title: __('Child epic'), - icon: 'epic', - color: '#AB6100', - backgroundColor: '#F5D9A8', - }, - REQUIREMENT: { - title: __('Requirement'), - icon: 'requirements', - color: '#0068c5', - backgroundColor: '#c5e3fb', - }, - TEST_CASE: { - title: __('Test case'), - icon: 'issue-type-test-case', - backgroundColor: '#007a3f', - color: '#bae8cb', - iconSize: 16, - }, -}; diff --git a/app/assets/javascripts/work_items_hierarchy/components/app.vue b/app/assets/javascripts/work_items_hierarchy/components/app.vue deleted file mode 100644 index ef8632df3be..00000000000 --- a/app/assets/javascripts/work_items_hierarchy/components/app.vue +++ /dev/null @@ -1,96 +0,0 @@ - - - diff --git a/app/assets/javascripts/work_items_hierarchy/components/hierarchy.vue b/app/assets/javascripts/work_items_hierarchy/components/hierarchy.vue deleted file mode 100644 index 9b81218b6e4..00000000000 --- a/app/assets/javascripts/work_items_hierarchy/components/hierarchy.vue +++ /dev/null @@ -1,119 +0,0 @@ - - diff --git a/app/assets/javascripts/work_items_hierarchy/constants.js b/app/assets/javascripts/work_items_hierarchy/constants.js deleted file mode 100644 index f001f556c0e..00000000000 --- a/app/assets/javascripts/work_items_hierarchy/constants.js +++ /dev/null @@ -1,12 +0,0 @@ -export const WORK_ITEMS_SURVEY_COOKIE_NAME = 'hide_work_items_hierarchy_survey'; - -/** - * Hard-coded strings since we're rendering hierarchy - * items from mock responses. Remove this when we - * have a real hierarchy endpoint. - */ -export const LICENSE_PLAN = { - FREE: 'free', - PREMIUM: 'premium', - ULTIMATE: 'ultimate', -}; diff --git a/app/assets/javascripts/work_items_hierarchy/hierarchy_util.js b/app/assets/javascripts/work_items_hierarchy/hierarchy_util.js deleted file mode 100644 index 61d93acdb91..00000000000 --- a/app/assets/javascripts/work_items_hierarchy/hierarchy_util.js +++ /dev/null @@ -1,10 +0,0 @@ -import { LICENSE_PLAN } from './constants'; - -export function inferLicensePlan({ hasSubEpics, hasEpics }) { - if (hasSubEpics) { - return LICENSE_PLAN.ULTIMATE; - } else if (hasEpics) { - return LICENSE_PLAN.PREMIUM; - } - return LICENSE_PLAN.FREE; -} diff --git a/app/assets/javascripts/work_items_hierarchy/static_response.js b/app/assets/javascripts/work_items_hierarchy/static_response.js deleted file mode 100644 index d1e2e486082..00000000000 --- a/app/assets/javascripts/work_items_hierarchy/static_response.js +++ /dev/null @@ -1,142 +0,0 @@ -const FREE_TIER = 'free'; -const ULTIMATE_TIER = 'ultimate'; -const PREMIUM_TIER = 'premium'; - -const RESPONSE = { - [FREE_TIER]: [ - { - id: '1', - type: 'ISSUE', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '2', - type: 'TASK', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '3', - type: 'INCIDENT', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '4', - type: 'EPIC', - available: false, - license: 'Premium', // eslint-disable-line @gitlab/require-i18n-strings - nestedTypes: null, - }, - { - id: '5', - type: 'SUB_EPIC', - available: false, - license: 'Ultimate', // eslint-disable-line @gitlab/require-i18n-strings - nestedTypes: null, - }, - { - id: '6', - type: 'REQUIREMENT', - available: false, - license: 'Ultimate', // eslint-disable-line @gitlab/require-i18n-strings - nestedTypes: null, - }, - { - id: '7', - type: 'TEST_CASE', - available: false, - license: 'Ultimate', // eslint-disable-line @gitlab/require-i18n-strings - nestedTypes: null, - }, - ], - - [PREMIUM_TIER]: [ - { - id: '1', - type: 'EPIC', - available: true, - license: null, - nestedTypes: ['ISSUE'], - }, - { - id: '2', - type: 'TASK', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '3', - type: 'INCIDENT', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '5', - type: 'SUB_EPIC', - available: false, - license: 'Ultimate', // eslint-disable-line @gitlab/require-i18n-strings - nestedTypes: null, - }, - { - id: '6', - type: 'REQUIREMENT', - available: false, - license: 'Ultimate', // eslint-disable-line @gitlab/require-i18n-strings - nestedTypes: null, - }, - { - id: '7', - type: 'TEST_CASE', - available: false, - license: 'Ultimate', // eslint-disable-line @gitlab/require-i18n-strings - nestedTypes: null, - }, - ], - - [ULTIMATE_TIER]: [ - { - id: '1', - type: 'EPIC', - available: true, - license: null, - nestedTypes: ['SUB_EPIC', 'ISSUE'], - }, - { - id: '2', - type: 'TASK', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '3', - type: 'INCIDENT', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '6', - type: 'REQUIREMENT', - available: true, - license: null, - nestedTypes: null, - }, - { - id: '7', - type: 'TEST_CASE', - available: true, - license: null, - nestedTypes: null, - }, - ], -}; - -export default RESPONSE; diff --git a/app/assets/javascripts/work_items_hierarchy/work_items_hierarchy_bundle.js b/app/assets/javascripts/work_items_hierarchy/work_items_hierarchy_bundle.js deleted file mode 100644 index 2258c725301..00000000000 --- a/app/assets/javascripts/work_items_hierarchy/work_items_hierarchy_bundle.js +++ /dev/null @@ -1,26 +0,0 @@ -import Vue from 'vue'; -import { parseBoolean } from '~/lib/utils/common_utils'; -import App from './components/app.vue'; -import { inferLicensePlan } from './hierarchy_util'; - -export const initWorkItemsHierarchy = () => { - const el = document.querySelector('#js-work-items-hierarchy'); - - const { illustrationPath, hasEpics, hasSubEpics } = el.dataset; - - const licensePlan = inferLicensePlan({ - hasEpics: parseBoolean(hasEpics), - hasSubEpics: parseBoolean(hasSubEpics), - }); - - return new Vue({ - el, - provide: { - illustrationPath, - licensePlan, - }, - render(createElement) { - return createElement(App); - }, - }); -}; diff --git a/app/assets/stylesheets/_page_specific_files.scss b/app/assets/stylesheets/_page_specific_files.scss index 072b78305a9..8f3b5b3b7cc 100644 --- a/app/assets/stylesheets/_page_specific_files.scss +++ b/app/assets/stylesheets/_page_specific_files.scss @@ -32,4 +32,3 @@ @import './pages/storage_quota'; @import './pages/tree'; @import './pages/users'; -@import './pages/hierarchy'; diff --git a/app/assets/stylesheets/highlight/white_base.scss b/app/assets/stylesheets/highlight/white_base.scss index c0f8475323a..80052f4a4d5 100644 --- a/app/assets/stylesheets/highlight/white_base.scss +++ b/app/assets/stylesheets/highlight/white_base.scss @@ -255,18 +255,23 @@ span.highlight_word { .hll { background-color: $white-hll-bg; } -.c { color: $white-c; +.c, +.hljs-comment { color: $white-c; font-style: italic; } .err { color: $white-err; background-color: $white-err-bg; } -.k { font-weight: $gl-font-weight-bold; } + +.k, +.hljs-variable.language_, +.hljs-built_in { font-weight: $gl-font-weight-bold; } .o { font-weight: $gl-font-weight-bold; } .cm { color: $white-cm; font-style: italic; } -.cp { color: $white-cp; +.cp, +.hljs-meta { color: $white-cp; font-weight: $gl-font-weight-bold; } .c1 { color: $white-c1; @@ -310,20 +315,34 @@ span.highlight_word { font-weight: $gl-font-weight-bold; } .gt { color: $white-gt; } .kc { font-weight: $gl-font-weight-bold; } -.kd { font-weight: $gl-font-weight-bold; } + +.kd, +.hljs-keyword { font-weight: $gl-font-weight-bold; } .kn { font-weight: $gl-font-weight-bold; } .kp { font-weight: $gl-font-weight-bold; } .kr { font-weight: $gl-font-weight-bold; } -.kt { color: $white-kt; +.kt, +.hljs-type { color: $white-kt; font-weight: $gl-font-weight-bold; } .m { color: $white-m; } .s { color: $white-s; } -.n { color: $white-n; } -.na { color: $white-na; } -.nb { color: $white-nb; } -.nc { color: $white-nc; +.n, +.hljs-built_in { color: $white-n; } + +.na, +.hljs-attr, +.hljs-property, +.hljs-title.function_ { color: $white-na; } + +.nb, +.hljs-title.class_, +.hljs-literal { color: $white-nb; } + +.nc, +.hljs-title.class_, +.hljs-built_in { color: $white-nc; font-weight: $gl-font-weight-bold; } .no { color: $white-no; } .ni { color: $white-ni; } @@ -331,7 +350,9 @@ span.highlight_word { .ne { color: $white-ne; font-weight: $gl-font-weight-bold; } -.nf { color: $white-nf; +.nf, +.hljs-title, +.hljs-title.function_ { color: $white-nf; font-weight: $gl-font-weight-bold; } .nn { color: $white-nn; } .nt { color: $white-nt; } @@ -340,7 +361,9 @@ span.highlight_word { .w { color: $white-w; } .mf { color: $white-mf; } .mh { color: $white-mh; } -.mi { color: $white-mi; } + +.mi, +.hljs-number { color: $white-mi; } .mo { color: $white-mo; } .sb { color: $white-sb; } .sc { color: $white-sc; } @@ -351,7 +374,9 @@ span.highlight_word { .si { color: $white-si; } .sx { color: $white-sx; } .sr { color: $white-sr; } -.s1 { color: $white-s1; } + +.s1, +.hljs-string { color: $white-s1; } .ss { color: $white-ss; } .bp { color: $white-bp; } .vc { color: $white-vc; } diff --git a/app/assets/stylesheets/pages/hierarchy.scss b/app/assets/stylesheets/pages/hierarchy.scss deleted file mode 100644 index 0812e4cc41e..00000000000 --- a/app/assets/stylesheets/pages/hierarchy.scss +++ /dev/null @@ -1,15 +0,0 @@ -.hierarchy-rounded-arrow-tail { - position: absolute; - top: 4px; - left: 5px; - height: calc(100% - 20px); -} - -.hierarchy-icon-wrapper { - height: $default-icon-size; - width: $default-icon-size; -} - -.hierarchy-rounded-arrow { - transform: scale(1, -1) rotate(90deg); -} diff --git a/app/controllers/concerns/work_items_hierarchy.rb b/app/controllers/concerns/work_items_hierarchy.rb deleted file mode 100644 index 6008256408c..00000000000 --- a/app/controllers/concerns/work_items_hierarchy.rb +++ /dev/null @@ -1,15 +0,0 @@ -# frozen_string_literal: true - -module WorkItemsHierarchy - extend ActiveSupport::Concern - - # rubocop:disable Gitlab/ModuleWithInstanceVariables - def planning_hierarchy - return render_404 unless Feature.enabled?(:work_items_hierarchy, @project, default_enabled: :yaml) - - render 'shared/planning_hierarchy' - end - # rubocop:enable Gitlab/ModuleWithInstanceVariables -end - -WorkItemsHierarchy.prepend_mod_with('WorkItemsHierarchy') diff --git a/app/controllers/projects/tree_controller.rb b/app/controllers/projects/tree_controller.rb index 482ae2c35f5..c48f3352530 100644 --- a/app/controllers/projects/tree_controller.rb +++ b/app/controllers/projects/tree_controller.rb @@ -6,6 +6,7 @@ class Projects::TreeController < Projects::ApplicationController include CreatesCommit include ActionView::Helpers::SanitizeHelper include RedirectsForMissingPathOnTree + include SourcegraphDecorator around_action :allow_gitaly_ref_name_caching, only: [:show] diff --git a/app/controllers/projects_controller.rb b/app/controllers/projects_controller.rb index 27483d455b1..369fdbee089 100644 --- a/app/controllers/projects_controller.rb +++ b/app/controllers/projects_controller.rb @@ -9,7 +9,7 @@ class ProjectsController < Projects::ApplicationController include RecordUserLastActivity include ImportUrlParams include FiltersEvents - include WorkItemsHierarchy + include SourcegraphDecorator prepend_before_action(only: [:show]) { authenticate_sessionless_user!(:rss) } @@ -53,7 +53,6 @@ class ProjectsController < Projects::ApplicationController feature_category :team_planning, [:preview_markdown, :new_issuable_address] feature_category :importers, [:export, :remove_export, :generate_new_export, :download_export] feature_category :code_review, [:unfoldered_environment_names] - feature_category :portfolio_management, [:planning_hierarchy] urgency :low, [:refs] urgency :high, [:unfoldered_environment_names] diff --git a/app/models/ci/pipeline.rb b/app/models/ci/pipeline.rb index 7ae301cdf73..52a4d2ca736 100644 --- a/app/models/ci/pipeline.rb +++ b/app/models/ci/pipeline.rb @@ -69,6 +69,7 @@ module Ci has_many :builds, foreign_key: :commit_id, inverse_of: :pipeline has_many :generic_commit_statuses, foreign_key: :commit_id, inverse_of: :pipeline, class_name: 'GenericCommitStatus' has_many :job_artifacts, through: :builds + has_many :build_trace_chunks, class_name: 'Ci::BuildTraceChunk', through: :builds, source: :trace_chunks has_many :trigger_requests, dependent: :destroy, foreign_key: :commit_id # rubocop:disable Cop/ActiveRecordDependent has_many :variables, class_name: 'Ci::PipelineVariable' has_many :deployments, through: :builds @@ -130,6 +131,7 @@ module Ci after_create :keep_around_commits, unless: :importing? use_fast_destroy :job_artifacts + use_fast_destroy :build_trace_chunks # We use `Enums::Ci::Pipeline.sources` here so that EE can more easily extend # this `Hash` with new values. diff --git a/app/policies/project_policy.rb b/app/policies/project_policy.rb index d89a449bdd5..55f43cd9f7b 100644 --- a/app/policies/project_policy.rb +++ b/app/policies/project_policy.rb @@ -240,7 +240,6 @@ class ProjectPolicy < BasePolicy enable :read_wiki enable :read_issue enable :read_label - enable :read_work_items_hierarchy enable :read_milestone enable :read_snippet enable :read_project_member @@ -573,7 +572,6 @@ class ProjectPolicy < BasePolicy enable :read_issue_board_list enable :read_wiki enable :read_label - enable :read_work_items_hierarchy enable :read_milestone enable :read_snippet enable :read_project_member diff --git a/app/services/ci/after_requeue_job_service.rb b/app/services/ci/after_requeue_job_service.rb index 9101ae91967..ee0ae6651ca 100644 --- a/app/services/ci/after_requeue_job_service.rb +++ b/app/services/ci/after_requeue_job_service.rb @@ -3,39 +3,50 @@ module Ci class AfterRequeueJobService < ::BaseService def execute(processable) - process_subsequent_jobs(processable) - reset_source_bridge(processable) + @processable = processable + + process_subsequent_jobs + reset_source_bridge end private - def process_subsequent_jobs(processable) - (stage_dependent_jobs(processable) | needs_dependent_jobs(processable)) - .each do |processable| - process(processable) + def process_subsequent_jobs + dependent_jobs.each do |job| + process(job) end end - def reset_source_bridge(processable) - processable.pipeline.reset_source_bridge!(current_user) + def reset_source_bridge + @processable.pipeline.reset_source_bridge!(current_user) end - def process(processable) - Gitlab::OptimisticLocking.retry_lock(processable, name: 'ci_requeue_job') do |processable| - processable.process(current_user) + def dependent_jobs + if ::Feature.enabled?(:ci_order_subsequent_jobs_by_stage, @processable.pipeline.project, default_enabled: :yaml) + stage_dependent_jobs + .or(needs_dependent_jobs.except(:preload)) + .ordered_by_stage + else + stage_dependent_jobs | needs_dependent_jobs end end - def skipped_jobs(processable) - processable.pipeline.processables.skipped + def process(job) + Gitlab::OptimisticLocking.retry_lock(job, name: 'ci_requeue_job') do |job| + job.process(current_user) + end end - def stage_dependent_jobs(processable) - skipped_jobs(processable).after_stage(processable.stage_idx) + def stage_dependent_jobs + skipped_jobs.after_stage(@processable.stage_idx) end - def needs_dependent_jobs(processable) - skipped_jobs(processable).scheduling_type_dag.with_needs([processable.name]) + def needs_dependent_jobs + skipped_jobs.scheduling_type_dag.with_needs([@processable.name]) + end + + def skipped_jobs + @skipped_jobs ||= @processable.pipeline.processables.skipped end end end diff --git a/app/services/ci/destroy_pipeline_service.rb b/app/services/ci/destroy_pipeline_service.rb index 476c7523d60..d85e52e1312 100644 --- a/app/services/ci/destroy_pipeline_service.rb +++ b/app/services/ci/destroy_pipeline_service.rb @@ -9,9 +9,11 @@ module Ci pipeline.cancel_running if pipeline.cancelable? - # Ci::Pipeline#destroy triggers `use_fast_destroy :job_artifacts` and - # ci_builds has ON DELETE CASCADE to ci_pipelines. The pipeline, the builds, - # job and pipeline artifacts all get destroyed here. + # The pipeline, the builds, job and pipeline artifacts all get destroyed here. + # Ci::Pipeline#destroy triggers fast destroy on job_artifacts and + # build_trace_chunks to remove the records and data stored in object storage. + # ci_builds records are deleted using ON DELETE CASCADE from ci_pipelines + # pipeline.reset.destroy! ServiceResponse.success(message: 'Pipeline not found') diff --git a/app/views/shared/planning_hierarchy.html.haml b/app/views/shared/planning_hierarchy.html.haml deleted file mode 100644 index d67ecc6ee48..00000000000 --- a/app/views/shared/planning_hierarchy.html.haml +++ /dev/null @@ -1,5 +0,0 @@ -- page_title _("Planning hierarchy") -- has_sub_epics = Gitlab.ee? && @project&.feature_available?(:subepics) -- has_epics = Gitlab.ee? && @project&.feature_available?(:epics) - -#js-work-items-hierarchy{ data: { has_sub_epics: has_sub_epics.to_s, has_epics: has_epics.to_s, illustration_path: image_path('illustrations/rocket-launch-md.svg') } } diff --git a/config/feature_flags/development/work_items_hierarchy.yml b/config/feature_flags/development/ci_order_subsequent_jobs_by_stage.yml similarity index 66% rename from config/feature_flags/development/work_items_hierarchy.yml rename to config/feature_flags/development/ci_order_subsequent_jobs_by_stage.yml index 8699511ea63..dfc4ab3bad3 100644 --- a/config/feature_flags/development/work_items_hierarchy.yml +++ b/config/feature_flags/development/ci_order_subsequent_jobs_by_stage.yml @@ -1,8 +1,8 @@ --- -name: work_items_hierarchy -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/76720 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/350451 +name: ci_order_subsequent_jobs_by_stage +introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77528 +rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/349977 milestone: '14.7' type: development -group: group::product planning +group: group::pipeline authoring default_enabled: false diff --git a/config/routes/project.rb b/config/routes/project.rb index 004206e0ae2..702ef64a2ca 100644 --- a/config/routes/project.rb +++ b/config/routes/project.rb @@ -641,7 +641,6 @@ constraints(::Constraints::ProjectUrlConstrainer.new) do post :generate_new_export get :download_export get :activity - get :planning_hierarchy get :refs put :new_issuable_address get :unfoldered_environment_names diff --git a/doc/development/snowplow/schemas.md b/doc/development/snowplow/schemas.md index 6bda026b9a7..eb57e7d98a5 100644 --- a/doc/development/snowplow/schemas.md +++ b/doc/development/snowplow/schemas.md @@ -19,6 +19,7 @@ The [`StandardContext`](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/g | `project_id` | **{dotted-circle}** | integer | | | `namespace_id` | **{dotted-circle}** | integer | | | `user_id` | **{dotted-circle}** | integer | User database record ID attribute. This file undergoes a pseudonymization process at the collector level. | +| `context_generated_at` | **{dotted-circle}** | string (date time format) | Timestamp indicating when context was generated. | | `environment` | **{check-circle}** | string (max 32 chars) | Name of the source environment, such as `production` or `staging` | | `source` | **{check-circle}** | string (max 32 chars) | Name of the source application, such as `gitlab-rails` or `gitlab-javascript` | | `plan` | **{dotted-circle}** | string (max 32 chars) | Name of the plan for the namespace, such as `free`, `premium`, or `ultimate`. Automatically picked from the `namespace`. | diff --git a/doc/user/admin_area/geo_nodes.md b/doc/user/admin_area/geo_nodes.md index 87ac75bdd7e..b3b2c14adbd 100644 --- a/doc/user/admin_area/geo_nodes.md +++ b/doc/user/admin_area/geo_nodes.md @@ -55,14 +55,21 @@ you can increase the values to complete backfill in a shorter time. If it's under heavy load and backfill reduces its availability for normal requests, you can decrease them. -## Using a different URL for synchronization +## Set up the internal URLs + +> Setting up internal URLs in secondary sites was [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/77179) in GitLab 14.7. + +You can set up a different URL for synchronization between the primary and secondary site. The **primary** site's Internal URL is used by **secondary** sites to contact it (to sync repositories, for example). The name Internal URL distinguishes it from [External URL](https://docs.gitlab.com/omnibus/settings/configuration.html#configuring-the-external-url-for-gitlab), which is used by users. Internal URL does not need to be a private address. -Internal URL defaults to external URL, but you can also customize it: +When [Geo secondary proxying](../../administration/geo/secondary_proxy/index.md) is enabled, +the primary uses the secondary's internal URL to contact it directly. + +The internal URL defaults to external URL. To change it: 1. On the top bar, select **Menu > Admin**. 1. On the left sidebar, select **Geo > Nodes**. @@ -70,6 +77,9 @@ Internal URL defaults to external URL, but you can also customize it: 1. Edit the internal URL. 1. Select **Save changes**. +When enabled, the Admin Area for Geo shows replication details for each site directly +from the primary site's UI, and through the Geo secondary proxy, if enabled. + WARNING: We recommend using an HTTPS connection while configuring the Geo sites. To avoid breaking communication between **primary** and **secondary** sites when using diff --git a/doc/user/application_security/policies/index.md b/doc/user/application_security/policies/index.md index c433ad67c6f..11f2b91177a 100644 --- a/doc/user/application_security/policies/index.md +++ b/doc/user/application_security/policies/index.md @@ -313,10 +313,10 @@ Use this schema to define `clusters` objects in the [`schedule` rule type](#sche | Field | Type | Possible values | Description | |--------------|---------------------|--------------------------|-------------| -| `containers` | `array` of `string` | | The container name to be scanned (only the first value is currently supported). | -| `resources` | `array` of `string` | | The resource name to be scanned (only the first value is currently supported). | -| `namespaces` | `array` of `string` | | The namespace to be scanned (only the first value is currently supported). | -| `kinds` | `array` of `string` | `deployment`/`daemonset` | The resource kind to be scanned (only the first value is currently supported). | +| `containers` | `array` of `string` | | The container name that is scanned (only the first value is currently supported). | +| `resources` | `array` of `string` | | The resource name that is scanned (only the first value is currently supported). | +| `namespaces` | `array` of `string` | | The namespace that is scanned (only the first value is currently supported). | +| `kinds` | `array` of `string` | `deployment`/`daemonset` | The resource kind that should be scanned (only the first value is currently supported). | ### `scan` action type diff --git a/doc/user/group/index.md b/doc/user/group/index.md index 4102b4ffbf1..56c4c82494c 100644 --- a/doc/user/group/index.md +++ b/doc/user/group/index.md @@ -100,6 +100,14 @@ You can give a user access to all projects in a group. 1. Fill in the fields. - The role applies to all projects in the group. [Learn more about permissions](../permissions.md). - On the **Access expiration date**, the user can no longer access projects in the group. +1. Select **Invite**. + +Members that are not automatically added are displayed on the **Invited** tab. +Users can be on this tab because they: + +- Have not yet accepted the invitation. +- Are waiting for [approval from an administrator](../admin_area/moderate_users.md). +- [Exceed the group user cap](#user-cap-for-groups). ## Request access to a group @@ -508,6 +516,74 @@ To prevent a project from being shared with other groups: This setting applies to all subgroups unless overridden by a group owner. Groups already added to a project lose access when the setting is enabled. +## User cap for groups + +> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/330027) in GitLab 14.7. + +FLAG: +On self-managed GitLab, this feature is not available. On GitLab.com, this feature is available for some groups. +This feature is not ready for production use. + +When the number of billable members reaches the user cap, new users can't be added to the group +without being approved by the group owner. + +Groups with the user cap feature enabled have [group sharing](#share-a-group-with-another-group) +disabled for the group and its subgroups. + +### Specify a user cap for a group + +Prerequisite: + +- You must be assigned the [Owner role](../permissions.md#group-members-permissions) for the group. + +To specify a user cap: + +1. On the top bar, select **Menu > Groups** and find your group. + You can set a cap on the top-level group only. +1. On the left sidebar, select **Settings > General**. +1. Expand **Permissions and group features**. +1. In the **User cap** box, enter the desired number of users. +1. Select **Save changes**. + +If you already have more users in the group than the user cap value, users +are not removed. However, you can't add more without approval. + +Increasing the user cap does not approve pending members. + +### Remove the user cap for a group + +You can remove the user cap, so there is no limit on the number of members you can add to a group. + +Prerequisite: + +- You must be assigned the [Owner role](../permissions.md#group-members-permissions) for the group. + +To remove the user cap: + +1. On the top bar, select **Menu > Groups** and find your group. +1. On the left sidebar, select **Settings > General**. +1. Expand **Permissions and group features**. +1. In the **User cap** box, delete the value. +1. Select **Save changes**. + +Decreasing the user cap does not approve pending members. + +### Approve pending members for a group + +When the number of billable users reaches the user cap, any new member is put in a pending state +and must be approved. + +Prerequisite: + +- You must be assigned the [Owner role](../permissions.md#group-members-permissions) for the group. + +To approve members that are pending because they've exceeded the user cap: + +1. On the top bar, select **Menu > Groups** and find your group. +1. On the left sidebar, select **Settings > Usage Quotas**. +1. On the **Seats** tab, under the alert, select **View pending approvals**. +1. For each member you want to approve, select **Approve**. + ## Prevent members from being added to projects in a group **(PREMIUM)** As a group owner, you can prevent any new project membership for all diff --git a/doc/user/group/planning_hierarchy/img/view-project-work-item-hierarchy_v14_7.png b/doc/user/group/planning_hierarchy/img/view-project-work-item-hierarchy_v14_7.png deleted file mode 100644 index 2ddd551ee46..00000000000 Binary files a/doc/user/group/planning_hierarchy/img/view-project-work-item-hierarchy_v14_7.png and /dev/null differ diff --git a/doc/user/group/planning_hierarchy/index.md b/doc/user/group/planning_hierarchy/index.md index 0525246b812..5887328abe4 100644 --- a/doc/user/group/planning_hierarchy/index.md +++ b/doc/user/group/planning_hierarchy/index.md @@ -20,20 +20,6 @@ To learn about hierarchies in general, common frameworks, and using GitLab for portfolio management, see [How to use GitLab for Agile portfolio planning and project management](https://about.gitlab.com/blog/2020/11/11/gitlab-for-agile-portfolio-planning-project-management/). -## View planning hierarchies - -> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/340844/) in GitLab 14.7 and is behind the feature flag `work_items_hierarchy`. - -To view the planning hierarchy in a project: - -1. On the top bar, select **Menu > Projects** and find your project. -1. On the left sidebar, select **Project information > Planning hierarchy**. - -Under **Current structure**, you can see a hierarchy diagram that matches your current planning hierarchy. -The work items outside your subscription plan show up below **Unavailable structure**. - -![Screenshot showing hierarchy page](img/view-project-work-item-hierarchy_v14_7.png) - ## Hierarchies with epics With epics, you can achieve the following hierarchy: diff --git a/lib/gitlab/ci/trace/stream.rb b/lib/gitlab/ci/trace/stream.rb index 2d31049a0c9..dd435ba05b7 100644 --- a/lib/gitlab/ci/trace/stream.rb +++ b/lib/gitlab/ci/trace/stream.rb @@ -11,10 +11,6 @@ module Gitlab delegate :close, :tell, :seek, :size, :url, :truncate, to: :stream, allow_nil: true - delegate :valid?, to: :stream, allow_nil: true - - alias_method :present?, :valid? - def initialize(metrics = Trace::Metrics.new) @stream = yield @stream&.binmode @@ -24,6 +20,7 @@ module Gitlab def valid? self.stream.present? end + alias_method :present?, :valid? def file? self.path.present? diff --git a/lib/gitlab/tracking/standard_context.rb b/lib/gitlab/tracking/standard_context.rb index 837390b91fb..542dc476526 100644 --- a/lib/gitlab/tracking/standard_context.rb +++ b/lib/gitlab/tracking/standard_context.rb @@ -3,7 +3,7 @@ module Gitlab module Tracking class StandardContext - GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-7' + GITLAB_STANDARD_SCHEMA_URL = 'iglu:com.gitlab/gitlab_standard/jsonschema/1-0-8' GITLAB_RAILS_SOURCE = 'gitlab-rails' def initialize(namespace: nil, project: nil, user: nil, **extra) @@ -46,7 +46,8 @@ module Gitlab extra: extra, user_id: user&.id, namespace_id: namespace&.id, - project_id: project_id + project_id: project_id, + context_generated_at: Time.current } end diff --git a/lib/sidebars/concerns/work_item_hierarchy.rb b/lib/sidebars/concerns/work_item_hierarchy.rb deleted file mode 100644 index f88e24b205d..00000000000 --- a/lib/sidebars/concerns/work_item_hierarchy.rb +++ /dev/null @@ -1,27 +0,0 @@ -# frozen_string_literal: true - -# This module has the necessary methods to render -# work items hierarchy menu -module Sidebars - module Concerns - module WorkItemHierarchy - def hierarchy_menu_item(container, url, path) - unless show_hierarachy_menu_item?(container) - return ::Sidebars::NilMenuItem.new(item_id: :hierarchy) - end - - ::Sidebars::MenuItem.new( - title: _('Planning hierarchy'), - link: url, - active_routes: { path: path }, - item_id: :hierarchy - ) - end - - def show_hierarachy_menu_item?(container) - Feature.enabled?(:work_items_hierarchy, container, default_enabled: :yaml) && - can?(context.current_user, :read_work_items_hierarchy, container) - end - end - end -end diff --git a/lib/sidebars/projects/menus/project_information_menu.rb b/lib/sidebars/projects/menus/project_information_menu.rb index ad11a383757..44b94ee3522 100644 --- a/lib/sidebars/projects/menus/project_information_menu.rb +++ b/lib/sidebars/projects/menus/project_information_menu.rb @@ -4,13 +4,10 @@ module Sidebars module Projects module Menus class ProjectInformationMenu < ::Sidebars::Menu - include ::Sidebars::Concerns::WorkItemHierarchy - override :configure_menu_items def configure_menu_items add_item(activity_menu_item) add_item(labels_menu_item) - add_item(hierarchy_menu_item(context.project, planning_hierarchy_project_path(context.project), 'projects#planning_hierarchy')) add_item(members_menu_item) true diff --git a/locale/gitlab.pot b/locale/gitlab.pot index d2fcecb165b..b02a7f1f805 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -722,6 +722,9 @@ msgstr "" msgid "%{level_name} is not allowed since the fork source project has lower visibility." msgstr "" +msgid "%{linkStart}Learn more.%{linkEnd}" +msgstr "" + msgid "%{link_start}Learn more%{link_end} about roles." msgstr "" @@ -2480,6 +2483,12 @@ msgstr "" msgid "AdminDashboard|Error loading the statistics. Please try again" msgstr "" +msgid "AdminGeo|The URL of the primary site that is used internally by the secondary sites." +msgstr "" + +msgid "AdminGeo|The URL of the secondary site that is used internally by the primary site." +msgstr "" + msgid "AdminLabels|Define your default set of project labels" msgstr "" @@ -7071,9 +7080,6 @@ msgstr "" msgid "Child" msgstr "" -msgid "Child epic" -msgstr "" - msgid "Child epic does not exist." msgstr "" @@ -17619,33 +17625,6 @@ msgstr[1] "" msgid "Hide values" msgstr "" -msgid "Hierarchy|Current structure" -msgstr "" - -msgid "Hierarchy|Deliver value more efficiently by breaking down necessary work into a hierarchical structure. This structure helps teams understand scope, priorities, and how work cascades up toward larger goals." -msgstr "" - -msgid "Hierarchy|Help us improve work items in GitLab!" -msgstr "" - -msgid "Hierarchy|Is there a framework or type of work item you wish you had access to in GitLab? Give us your feedback and help us build the experiences valuable to you." -msgstr "" - -msgid "Hierarchy|Planning hierarchy" -msgstr "" - -msgid "Hierarchy|Take the work items survey" -msgstr "" - -msgid "Hierarchy|These items are unavailable in the current structure." -msgstr "" - -msgid "Hierarchy|Unavailable structure" -msgstr "" - -msgid "Hierarchy|You can start using these items now." -msgstr "" - msgid "High or unknown vulnerabilities present" msgstr "" @@ -26530,9 +26509,6 @@ msgstr "" msgid "Plan:" msgstr "" -msgid "Planning hierarchy" -msgstr "" - msgid "PlantUML" msgstr "" @@ -30256,9 +30232,6 @@ msgstr "" msgid "Required only if you are not using role instance credentials." msgstr "" -msgid "Requirement" -msgstr "" - msgid "Requirement %{reference} has been added" msgstr "" @@ -34942,9 +34915,6 @@ msgstr "" msgid "Target-Branch" msgstr "" -msgid "Task" -msgstr "" - msgid "Task ID: %{elastic_task}" msgstr "" @@ -35190,9 +35160,6 @@ msgstr "" msgid "Test Cases" msgstr "" -msgid "Test case" -msgstr "" - msgid "Test coverage parsing" msgstr "" @@ -35406,12 +35373,6 @@ msgstr "" msgid "The Snowplow cookie domain." msgstr "" -msgid "The URL defined on the primary node that secondary nodes should use to contact it." -msgstr "" - -msgid "The URL defined on the primary node that secondary nodes should use to contact it. %{linkStart}Learn more%{linkEnd}" -msgstr "" - msgid "The URL of the Jenkins server." msgstr "" diff --git a/qa/Dockerfile b/qa/Dockerfile index 54de6509518..7e199093c92 100644 --- a/qa/Dockerfile +++ b/qa/Dockerfile @@ -63,6 +63,7 @@ WORKDIR /home/gitlab/qa # Install qa dependencies or fetch from cache if unchanged COPY ./qa/Gemfile* /home/gitlab/qa/ +RUN gem install bundler --no-document --conservative --version 2.3.5 RUN bundle install --jobs=$(nproc) --retry=3 --without=development --quiet ## diff --git a/qa/Gemfile.lock b/qa/Gemfile.lock index 3e85a33f2a2..1e0415f1ee4 100644 --- a/qa/Gemfile.lock +++ b/qa/Gemfile.lock @@ -355,4 +355,4 @@ DEPENDENCIES zeitwerk (~> 2.4) BUNDLED WITH - 2.2.33 + 2.3.5 diff --git a/scripts/utils.sh b/scripts/utils.sh index 15047d35fc3..849e8f77fd5 100644 --- a/scripts/utils.sh +++ b/scripts/utils.sh @@ -36,6 +36,7 @@ function bundle_install_script() { exit 1; fi; + gem install bundler --no-document --conservative --version 2.3.5 bundle --version bundle config set path "$(pwd)/vendor" bundle config set clean 'true' diff --git a/spec/commands/metrics_server/metrics_server_spec.rb b/spec/commands/metrics_server/metrics_server_spec.rb index b755801bb65..0178017ee37 100644 --- a/spec/commands/metrics_server/metrics_server_spec.rb +++ b/spec/commands/metrics_server/metrics_server_spec.rb @@ -47,7 +47,7 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do if @pid pgrp = Process.getpgid(@pid) - Timeout.timeout(5) do + Timeout.timeout(10) do Process.kill('TERM', -pgrp) Process.waitpid(@pid) end @@ -63,7 +63,7 @@ RSpec.describe 'bin/metrics-server', :aggregate_failures do it 'serves /metrics endpoint' do expect do - Timeout.timeout(5) do + Timeout.timeout(10) do http_ok = false until http_ok sleep 1 diff --git a/spec/controllers/concerns/work_items_hierarchy_spec.rb b/spec/controllers/concerns/work_items_hierarchy_spec.rb deleted file mode 100644 index 270e30cb5f9..00000000000 --- a/spec/controllers/concerns/work_items_hierarchy_spec.rb +++ /dev/null @@ -1,39 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe WorkItemsHierarchy do - controller(ApplicationController) do - include WorkItemsHierarchy - end - - let_it_be(:user) { create(:user) } - let_it_be(:group) { create(:group) } - let_it_be(:project) { create(:project, group: group) } - - render_views - - before do - sign_in user - routes.draw { get :planning_hierarchy, to: "anonymous#planning_hierarchy" } - controller.instance_variable_set(:@project, project) - end - - it 'renders hierarchy' do - stub_feature_flags(work_items_hierarchy: true) - - get :planning_hierarchy - - expect(response).to have_gitlab_http_status(:ok) - expect(response.body).to match(/id="js-work-items-hierarchy"/) - end - - it 'renders 404' do - stub_feature_flags(work_items_hierarchy: false) - - get :planning_hierarchy - - expect(response).to have_gitlab_http_status(:not_found) - expect(response.body).not_to match(/id="js-work-items-hierarchy"/) - end -end diff --git a/spec/factories/ci/builds.rb b/spec/factories/ci/builds.rb index 1d5df505743..011021f6320 100644 --- a/spec/factories/ci/builds.rb +++ b/spec/factories/ci/builds.rb @@ -5,6 +5,7 @@ FactoryBot.define do name { 'test' } add_attribute(:protected) { false } created_at { 'Di 29. Okt 09:50:00 CET 2013' } + scheduling_type { 'stage' } pending options do @@ -33,6 +34,8 @@ FactoryBot.define do end trait :dependent do + scheduling_type { 'dag' } + transient do sequence(:needed_name) { |n| "dependency #{n}" } needed { association(:ci_build, name: needed_name, pipeline: pipeline) } diff --git a/spec/frontend/__helpers__/wait_using_real_timer.js b/spec/frontend/__helpers__/wait_using_real_timer.js deleted file mode 100644 index 110d5f46c08..00000000000 --- a/spec/frontend/__helpers__/wait_using_real_timer.js +++ /dev/null @@ -1,7 +0,0 @@ -/* useful for timing promises when jest fakeTimers are not reliable enough */ -export default (timeout) => - new Promise((resolve) => { - jest.useRealTimers(); - setTimeout(resolve, timeout); - jest.useFakeTimers(); - }); diff --git a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap index db9684239a1..ad2f8aca55c 100644 --- a/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap +++ b/spec/frontend/blob/components/__snapshots__/blob_header_spec.js.snap @@ -17,7 +17,7 @@ exports[`Blob Header Default Actions rendering matches the snapshot 1`] = `
{ }, }); await vm.$nextTick(); - await vm.$nextTick(); expect(vm.initEditor).toHaveBeenCalled(); }); @@ -567,8 +565,8 @@ describe('RepoEditor', () => { // switching from edit to diff mode usually triggers editor initialization vm.$store.state.viewer = viewerTypes.diff; - // we delay returning the file to make sure editor doesn't initialize before we fetch file content - await waitUsingRealTimer(30); + jest.runOnlyPendingTimers(); + return 'rawFileData123\n'; }); @@ -598,8 +596,9 @@ describe('RepoEditor', () => { return aContent; }) .mockImplementationOnce(async () => { - // we delay returning fileB content to make sure the editor doesn't initialize prematurely - await waitUsingRealTimer(30); + // we delay returning fileB content + // to make sure the editor doesn't initialize prematurely + jest.advanceTimersByTime(30); return bContent; }); diff --git a/spec/frontend/work_items_hierarchy/components/__snapshots__/app_spec.js.snap b/spec/frontend/work_items_hierarchy/components/__snapshots__/app_spec.js.snap deleted file mode 100644 index f4979e4e707..00000000000 --- a/spec/frontend/work_items_hierarchy/components/__snapshots__/app_spec.js.snap +++ /dev/null @@ -1,1197 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`WorkItemsHierarchy App when licensePlan is free matches the snapshot 1`] = ` -
-
- - -
-
- -
- -
-

- Help us improve work items in GitLab! -

- -

- - Is there a framework or type of work item you wish you had access to in GitLab? Give us your feedback and help us build the experiences valuable to you. - -

- - - - - - - - Take the work items survey - - - -
- - -
- - -
- -

- Planning hierarchy -

- -

- - Deliver value more efficiently by breaking down necessary work into a hierarchical structure. This structure helps teams understand scope, priorities, and how work cascades up toward larger goals. - -

- -
- Current structure -
- -

- You can start using these items now. -

- -
-
- - - - - - - Issue - - - - - - -
-
- - - - - - - Task - - - - - - -
-
- - - - - - - Incident - - - - - - -
-
- -
- - Unavailable structure - -
- -

- - These items are unavailable in the current structure. - -

- -
-
- - - - - - - Epic - - - - - - Premium - - - -
-
- - - - - - - Child epic - - - - - - Ultimate - - - -
-
- - - - - - - Requirement - - - - - - Ultimate - - - -
-
- - - - - - - Test case - - - - - - Ultimate - - - -
-
-
-`; - -exports[`WorkItemsHierarchy App when licensePlan is premium matches the snapshot 1`] = ` -
-
- - -
-
- -
- -
-

- Help us improve work items in GitLab! -

- -

- - Is there a framework or type of work item you wish you had access to in GitLab? Give us your feedback and help us build the experiences valuable to you. - -

- - - - - - - - Take the work items survey - - - -
- - -
- - -
- -

- Planning hierarchy -

- -

- - Deliver value more efficiently by breaking down necessary work into a hierarchical structure. This structure helps teams understand scope, priorities, and how work cascades up toward larger goals. - -

- -
- Current structure -
- -

- You can start using these items now. -

- -
-
- - - - - - - Epic - - - - - -
- - -
- -
- - - - - - - - - - Issue - - -
-
-
- - - - - - - Task - - - - - - -
-
- - - - - - - Incident - - - - - - -
-
- -
- - Unavailable structure - -
- -

- - These items are unavailable in the current structure. - -

- -
-
- - - - - - - Child epic - - - - - - Ultimate - - - -
-
- - - - - - - Requirement - - - - - - Ultimate - - - -
-
- - - - - - - Test case - - - - - - Ultimate - - - -
-
-
-`; - -exports[`WorkItemsHierarchy App when licensePlan is ultimate matches the snapshot 1`] = ` -
-
- - -
-
- -
- -
-

- Help us improve work items in GitLab! -

- -

- - Is there a framework or type of work item you wish you had access to in GitLab? Give us your feedback and help us build the experiences valuable to you. - -

- - - - - - - - Take the work items survey - - - -
- - -
- - -
- -

- Planning hierarchy -

- -

- - Deliver value more efficiently by breaking down necessary work into a hierarchical structure. This structure helps teams understand scope, priorities, and how work cascades up toward larger goals. - -

- -
- Current structure -
- -

- You can start using these items now. -

- -
-
- - - - - - - Epic - - - - - -
- - - - -
- -
- - - - - - - - - - Child epic - - -
- -
- - - - - - - - - - Issue - - -
-
-
- - - - - - - Task - - - - - - -
-
- - - - - - - Incident - - - - - - -
-
- - - - - - - Requirement - - - - - - -
-
- - - - - - - Test case - - - - - - -
-
- - - - - -
-
-`; diff --git a/spec/frontend/work_items_hierarchy/components/app_spec.js b/spec/frontend/work_items_hierarchy/components/app_spec.js deleted file mode 100644 index c22c0fcb21c..00000000000 --- a/spec/frontend/work_items_hierarchy/components/app_spec.js +++ /dev/null @@ -1,78 +0,0 @@ -import { nextTick } from 'vue'; -import { createLocalVue, mount } from '@vue/test-utils'; -import VueApollo from 'vue-apollo'; -import { GlBanner } from '@gitlab/ui'; -import App from '~/work_items_hierarchy/components/app.vue'; -import { extendedWrapper } from 'helpers/vue_test_utils_helper'; - -const localVue = createLocalVue(); -localVue.use(VueApollo); - -describe('WorkItemsHierarchy App', () => { - let wrapper; - const createComponent = (props = {}, data = {}) => { - wrapper = extendedWrapper( - mount(App, { - localVue, - provide: { - illustrationPath: '/foo.svg', - licensePlan: 'free', - ...props, - }, - data() { - return data; - }, - }), - ); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe.each` - licensePlan - ${'free'} - ${'premium'} - ${'ultimate'} - `('when licensePlan is $licensePlan', ({ licensePlan }) => { - beforeEach(() => { - createComponent({ licensePlan }); - }); - - it('matches the snapshot', () => { - expect(wrapper.element).toMatchSnapshot(); - }); - }); - - describe('survey banner', () => { - it('shows when the banner is visible', () => { - createComponent({}, { bannerVisible: true }); - - expect(wrapper.find(GlBanner).exists()).toBe(true); - }); - - it('hide when close is called', async () => { - createComponent({}, { bannerVisible: true }); - - wrapper.findByTestId('close-icon').trigger('click'); - - await nextTick(); - - expect(wrapper.find(GlBanner).exists()).toBe(false); - }); - }); - - describe('Unavailable structure', () => { - it.each` - licensePlan | visible - ${'free'} | ${true} - ${'premium'} | ${true} - ${'ultimate'} | ${false} - `('visibility is $visible when plan is $licensePlan', ({ licensePlan, visible }) => { - createComponent({ licensePlan }); - - expect(wrapper.findByTestId('unavailable-structure').exists()).toBe(visible); - }); - }); -}); diff --git a/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js b/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js deleted file mode 100644 index 14c15fb5cbe..00000000000 --- a/spec/frontend/work_items_hierarchy/components/hierarchy_spec.js +++ /dev/null @@ -1,118 +0,0 @@ -import { createLocalVue, mount } from '@vue/test-utils'; -import VueApollo from 'vue-apollo'; -import { GlBadge } from '@gitlab/ui'; -import Hierarchy from '~/work_items_hierarchy/components/hierarchy.vue'; -import { extendedWrapper } from 'helpers/vue_test_utils_helper'; -import RESPONSE from '~/work_items_hierarchy/static_response'; -import { workItemTypes } from '~/work_items/constants'; - -const localVue = createLocalVue(); -localVue.use(VueApollo); - -describe('WorkItemsHierarchy Hierarchy', () => { - let wrapper; - - const workItemsFromResponse = (response) => { - return response.reduce( - (itemTypes, item) => { - const key = item.available ? 'available' : 'unavailable'; - itemTypes[key].push({ - ...item, - ...workItemTypes[item.type], - nestedTypes: item.nestedTypes - ? item.nestedTypes.map((type) => workItemTypes[type]) - : null, - }); - return itemTypes; - }, - { available: [], unavailable: [] }, - ); - }; - - const createComponent = (props = {}) => { - wrapper = extendedWrapper( - mount(Hierarchy, { - localVue, - propsData: { - workItemTypes: props.workItemTypes, - ...props, - }, - }), - ); - }; - - afterEach(() => { - wrapper.destroy(); - }); - - describe('available structure', () => { - let items = []; - - beforeEach(() => { - items = workItemsFromResponse(RESPONSE.ultimate).available; - createComponent({ workItemTypes: items }); - }); - - it('renders all work items', () => { - expect(wrapper.findAllByTestId('work-item-wrapper')).toHaveLength(items.length); - }); - - it('does not render badges', () => { - expect(wrapper.find(GlBadge).exists()).toBe(false); - }); - }); - - describe('unavailable structure', () => { - let items = []; - - beforeEach(() => { - items = workItemsFromResponse(RESPONSE.premium).unavailable; - createComponent({ workItemTypes: items }); - }); - - it('renders all work items', () => { - expect(wrapper.findAllByTestId('work-item-wrapper')).toHaveLength(items.length); - }); - - it('renders license badges for all work items', () => { - expect(wrapper.findAll(GlBadge)).toHaveLength(items.length); - }); - - it('does not render svg icon for linking', () => { - expect(wrapper.findByTestId('hierarchy-rounded-arrow-tail').exists()).toBe(false); - expect(wrapper.findByTestId('level-up-icon').exists()).toBe(false); - }); - }); - - describe('nested work items', () => { - describe.each` - licensePlan | arrowTailVisible | levelUpIconVisible | arrowDownIconVisible - ${'ultimate'} | ${true} | ${true} | ${true} - ${'premium'} | ${false} | ${false} | ${true} - ${'free'} | ${false} | ${false} | ${false} - `( - 'when $licensePlan license', - ({ licensePlan, arrowTailVisible, levelUpIconVisible, arrowDownIconVisible }) => { - let items = []; - beforeEach(() => { - items = workItemsFromResponse(RESPONSE[licensePlan]).available; - createComponent({ workItemTypes: items }); - }); - - it(`${arrowTailVisible ? 'render' : 'does not render'} arrow tail svg`, () => { - expect(wrapper.findByTestId('hierarchy-rounded-arrow-tail').exists()).toBe( - arrowTailVisible, - ); - }); - - it(`${levelUpIconVisible ? 'render' : 'does not render'} arrow tail svg`, () => { - expect(wrapper.findByTestId('level-up-icon').exists()).toBe(levelUpIconVisible); - }); - - it(`${arrowDownIconVisible ? 'render' : 'does not render'} arrow tail svg`, () => { - expect(wrapper.findByTestId('arrow-down-icon').exists()).toBe(arrowDownIconVisible); - }); - }, - ); - }); -}); diff --git a/spec/frontend/work_items_hierarchy/hierarchy_util_spec.js b/spec/frontend/work_items_hierarchy/hierarchy_util_spec.js deleted file mode 100644 index 9042fa27d16..00000000000 --- a/spec/frontend/work_items_hierarchy/hierarchy_util_spec.js +++ /dev/null @@ -1,16 +0,0 @@ -import { inferLicensePlan } from '~/work_items_hierarchy/hierarchy_util'; -import { LICENSE_PLAN } from '~/work_items_hierarchy/constants'; - -describe('inferLicensePlan', () => { - it.each` - epics | subEpics | licensePlan - ${true} | ${true} | ${LICENSE_PLAN.ULTIMATE} - ${true} | ${false} | ${LICENSE_PLAN.PREMIUM} - ${false} | ${false} | ${LICENSE_PLAN.FREE} - `( - 'returns $licensePlan when epic is $epics and sub-epic is $subEpics', - ({ epics, subEpics, licensePlan }) => { - expect(inferLicensePlan({ hasEpics: epics, hasSubEpics: subEpics })).toBe(licensePlan); - }, - ); -}); diff --git a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb index f4875aa0ebc..7d4a3655be6 100644 --- a/spec/lib/gitlab/gfm/reference_rewriter_spec.rb +++ b/spec/lib/gitlab/gfm/reference_rewriter_spec.rb @@ -92,7 +92,7 @@ RSpec.describe Gitlab::Gfm::ReferenceRewriter do let!(:group_label) { create(:group_label, id: 321, name: 'group label', group: old_group) } before do - old_project.update(namespace: old_group) + old_project.update!(namespace: old_group) end context 'label referenced by id' do diff --git a/spec/lib/gitlab/git_access_spec.rb b/spec/lib/gitlab/git_access_spec.rb index bf2e3c7f5f8..4bf7994f4dd 100644 --- a/spec/lib/gitlab/git_access_spec.rb +++ b/spec/lib/gitlab/git_access_spec.rb @@ -96,7 +96,7 @@ RSpec.describe Gitlab::GitAccess do context 'when the DeployKey has access to the project' do before do - deploy_key.deploy_keys_projects.create(project: project, can_push: true) + deploy_key.deploy_keys_projects.create!(project: project, can_push: true) end it 'allows push and pull access' do @@ -820,7 +820,7 @@ RSpec.describe Gitlab::GitAccess do project.add_role(user, role) end - protected_branch.save + protected_branch.save! aggregate_failures do matrix.each do |action, allowed| @@ -1090,7 +1090,7 @@ RSpec.describe Gitlab::GitAccess do context 'when deploy_key can push' do context 'when project is authorized' do before do - key.deploy_keys_projects.create(project: project, can_push: true) + key.deploy_keys_projects.create!(project: project, can_push: true) end it { expect { push_access_check }.not_to raise_error } @@ -1120,7 +1120,7 @@ RSpec.describe Gitlab::GitAccess do context 'when deploy_key cannot push' do context 'when project is authorized' do before do - key.deploy_keys_projects.create(project: project, can_push: false) + key.deploy_keys_projects.create!(project: project, can_push: false) end it { expect { push_access_check }.to raise_forbidden(described_class::ERROR_MESSAGES[:deploy_key_upload]) } diff --git a/spec/lib/gitlab/import_export/all_models.yml b/spec/lib/gitlab/import_export/all_models.yml index 625e94e3d77..e00af614cff 100644 --- a/spec/lib/gitlab/import_export/all_models.yml +++ b/spec/lib/gitlab/import_export/all_models.yml @@ -281,6 +281,7 @@ ci_pipelines: - dast_site_profiles_pipeline - package_build_infos - package_file_build_infos +- build_trace_chunks ci_refs: - project - ci_pipelines diff --git a/spec/lib/gitlab/import_export/avatar_saver_spec.rb b/spec/lib/gitlab/import_export/avatar_saver_spec.rb index 334d930c47c..d897ce76da0 100644 --- a/spec/lib/gitlab/import_export/avatar_saver_spec.rb +++ b/spec/lib/gitlab/import_export/avatar_saver_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Gitlab::ImportExport::AvatarSaver do end it 'saves a project avatar' do - described_class.new(project: project_with_avatar, shared: shared).save + described_class.new(project: project_with_avatar, shared: shared).save # rubocop:disable Rails/SaveBang expect(File).to exist(Dir["#{shared.export_path}/avatar/**/dk.png"].first) end diff --git a/spec/lib/gitlab/import_export/base/relation_factory_spec.rb b/spec/lib/gitlab/import_export/base/relation_factory_spec.rb index bd8873fe20e..b8999f608b1 100644 --- a/spec/lib/gitlab/import_export/base/relation_factory_spec.rb +++ b/spec/lib/gitlab/import_export/base/relation_factory_spec.rb @@ -11,7 +11,7 @@ RSpec.describe Gitlab::ImportExport::Base::RelationFactory do let(:excluded_keys) { [] } subject do - described_class.create(relation_sym: relation_sym, + described_class.create(relation_sym: relation_sym, # rubocop:disable Rails/SaveBang relation_hash: relation_hash, relation_index: 1, object_builder: Gitlab::ImportExport::Project::ObjectBuilder, diff --git a/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb b/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb index 6680f4e7a03..346f653acd4 100644 --- a/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb +++ b/spec/lib/gitlab/import_export/design_repo_restorer_spec.rb @@ -24,7 +24,7 @@ RSpec.describe Gitlab::ImportExport::DesignRepoRestorer do allow(instance).to receive(:storage_path).and_return(export_path) end - bundler.save + bundler.save # rubocop:disable Rails/SaveBang end after do diff --git a/spec/lib/gitlab/tracking/standard_context_spec.rb b/spec/lib/gitlab/tracking/standard_context_spec.rb index 7d678db5ec8..c88b0af30f6 100644 --- a/spec/lib/gitlab/tracking/standard_context_spec.rb +++ b/spec/lib/gitlab/tracking/standard_context_spec.rb @@ -58,6 +58,10 @@ RSpec.describe Gitlab::Tracking::StandardContext do expect(snowplow_context.to_json.dig(:data, :source)).to eq(described_class::GITLAB_RAILS_SOURCE) end + it 'contains context_generated_at timestamp', :freeze_time do + expect(snowplow_context.to_json.dig(:data, :context_generated_at)).to eq(Time.current) + end + context 'plan' do context 'when namespace is not available' do it 'is nil' do diff --git a/spec/lib/sidebars/concerns/work_item_hierarchy_spec.rb b/spec/lib/sidebars/concerns/work_item_hierarchy_spec.rb deleted file mode 100644 index f0a5e032764..00000000000 --- a/spec/lib/sidebars/concerns/work_item_hierarchy_spec.rb +++ /dev/null @@ -1,36 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe Sidebars::Concerns::WorkItemHierarchy do - shared_examples 'hierarchy menu' do - let(:item_id) { :hierarchy } - - context 'when the feature is disabled does not render' do - before do - stub_feature_flags(work_items_hierarchy: false) - end - - specify { is_expected.to be_nil } - end - - context 'when the feature is enabled does render' do - before do - stub_feature_flags(work_items_hierarchy: true) - end - - specify { is_expected.not_to be_nil } - end - end - - describe 'Project hierarchy menu item' do - let_it_be_with_reload(:project) { create(:project, :repository) } - - let(:user) { project.owner } - let(:context) { Sidebars::Projects::Context.new(current_user: user, container: project) } - - subject { Sidebars::Projects::Menus::ProjectInformationMenu.new(context).renderable_items.index { |e| e.item_id == item_id } } - - it_behaves_like 'hierarchy menu' - end -end diff --git a/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb b/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb index 5cbf0a13b66..7e8d0ab0518 100644 --- a/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb +++ b/spec/lib/sidebars/projects/menus/project_information_menu_spec.rb @@ -59,25 +59,5 @@ RSpec.describe Sidebars::Projects::Menus::ProjectInformationMenu do specify { is_expected.to be_nil } end end - - describe 'Hierarchy' do - let(:item_id) { :hierarchy } - - context 'when the feature is disabled' do - before do - stub_feature_flags(work_items_hierarchy: false) - end - - specify { is_expected.to be_nil } - end - - context 'when the feature is enabled' do - before do - stub_feature_flags(work_items_hierarchy: true) - end - - specify { is_expected.not_to be_nil } - end - end end end diff --git a/spec/models/ci/build_trace_chunk_spec.rb b/spec/models/ci/build_trace_chunk_spec.rb index 5c76d43d753..31c7c7a44bc 100644 --- a/spec/models/ci/build_trace_chunk_spec.rb +++ b/spec/models/ci/build_trace_chunk_spec.rb @@ -49,9 +49,8 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state, :clean_git end context 'FastDestroyAll' do - let(:project) { create(:project) } - let(:pipeline) { create(:ci_pipeline, project: project) } - let!(:build) { create(:ci_build, :running, :trace_live, pipeline: pipeline, project: project) } + let(:pipeline) { create(:ci_pipeline) } + let!(:build) { create(:ci_build, :running, :trace_live, pipeline: pipeline) } let(:subjects) { build.trace_chunks } describe 'Forbid #destroy and #destroy_all' do @@ -84,13 +83,7 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state, :clean_git expect(external_data_counter).to be > 0 expect(subjects.count).to be > 0 - ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.allow_cross_database_modification_within_transaction(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/350185') do - # This should use to prevent cross-DB modification - # but due to https://gitlab.com/gitlab-org/gitlab/-/issues/350185 - # the build trace chunks are not destroyed by Projects::DestroyService - # Change to: expect { Projects::DestroyService.new(project, project.owner).execute }.to eq(true) - expect { project.destroy! }.not_to raise_error - end + expect { pipeline.destroy! }.not_to raise_error expect(subjects.count).to eq(0) expect(external_data_counter).to eq(0) @@ -858,13 +851,7 @@ RSpec.describe Ci::BuildTraceChunk, :clean_gitlab_redis_shared_state, :clean_git context 'when project is destroyed' do let(:subject) do - ::Gitlab::Database::QueryAnalyzers::PreventCrossDatabaseModification.allow_cross_database_modification_within_transaction(url: 'https://gitlab.com/gitlab-org/gitlab/-/issues/350185') do - # This should use to prevent cross-DB modification - # but due to https://gitlab.com/gitlab-org/gitlab/-/issues/350185 - # the build trace chunks are not destroyed by Projects::DestroyService - # Change to: Projects::DestroyService.new(project, project.owner).execute - project.destroy! - end + Projects::DestroyService.new(project, project.owner).execute end it_behaves_like 'deletes all build_trace_chunk and data in redis' diff --git a/spec/models/ci/pipeline_spec.rb b/spec/models/ci/pipeline_spec.rb index 04d12913828..e740b9d823c 100644 --- a/spec/models/ci/pipeline_spec.rb +++ b/spec/models/ci/pipeline_spec.rb @@ -31,6 +31,7 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep do it { is_expected.to have_many(:statuses_order_id_desc) } it { is_expected.to have_many(:bridges) } it { is_expected.to have_many(:job_artifacts).through(:builds) } + it { is_expected.to have_many(:build_trace_chunks).through(:builds) } it { is_expected.to have_many(:auto_canceled_pipelines) } it { is_expected.to have_many(:auto_canceled_jobs) } it { is_expected.to have_many(:sourced_pipelines) } diff --git a/spec/services/ci/after_requeue_job_service_spec.rb b/spec/services/ci/after_requeue_job_service_spec.rb index 2a5a971fdac..2465bac7d10 100644 --- a/spec/services/ci/after_requeue_job_service_spec.rb +++ b/spec/services/ci/after_requeue_job_service_spec.rb @@ -8,46 +8,56 @@ RSpec.describe Ci::AfterRequeueJobService do let(:pipeline) { create(:ci_pipeline, project: project) } - let!(:build) { create(:ci_build, pipeline: pipeline, stage_idx: 0, name: 'build') } - let!(:test1) { create(:ci_build, :success, pipeline: pipeline, stage_idx: 1) } - let!(:test2) { create(:ci_build, :skipped, pipeline: pipeline, stage_idx: 1) } - let!(:test3) { create(:ci_build, :skipped, :dependent, pipeline: pipeline, stage_idx: 1, needed: build) } - let!(:deploy) { create(:ci_build, :skipped, :dependent, pipeline: pipeline, stage_idx: 2, needed: test3) } + let!(:build1) { create(:ci_build, name: 'build1', pipeline: pipeline, stage_idx: 0) } + let!(:test1) { create(:ci_build, :success, name: 'test1', pipeline: pipeline, stage_idx: 1) } + let!(:test2) { create(:ci_build, :skipped, name: 'test2', pipeline: pipeline, stage_idx: 1) } + let!(:test3) { create(:ci_build, :skipped, :dependent, name: 'test3', pipeline: pipeline, stage_idx: 1, needed: build1) } + let!(:deploy) { create(:ci_build, :skipped, :dependent, name: 'deploy', pipeline: pipeline, stage_idx: 2, needed: test3) } - subject(:execute_service) { described_class.new(project, user).execute(build) } + subject(:execute_service) { described_class.new(project, user).execute(build1) } - it 'marks subsequent skipped jobs as processable' do - expect(test1.reload).to be_success - expect(test2.reload).to be_skipped - expect(test3.reload).to be_skipped - expect(deploy.reload).to be_skipped + shared_examples 'processing subsequent skipped jobs' do + it 'marks subsequent skipped jobs as processable' do + expect(test1.reload).to be_success + expect(test2.reload).to be_skipped + expect(test3.reload).to be_skipped + expect(deploy.reload).to be_skipped - execute_service + execute_service - expect(test1.reload).to be_success - expect(test2.reload).to be_created - expect(test3.reload).to be_created - expect(deploy.reload).to be_created + expect(test1.reload).to be_success + expect(test2.reload).to be_created + expect(test3.reload).to be_created + expect(deploy.reload).to be_created + end end + it_behaves_like 'processing subsequent skipped jobs' + context 'when there is a job need from the same stage' do - let!(:test4) do + let!(:build2) do create(:ci_build, :skipped, :dependent, + name: 'build2', pipeline: pipeline, stage_idx: 0, scheduling_type: :dag, - needed: build) + needed: build1) end - it 'marks subsequent skipped jobs as processable' do - expect { execute_service }.to change { test4.reload.status }.from('skipped').to('created') + shared_examples 'processing the same stage job' do + it 'marks subsequent skipped jobs as processable' do + expect { execute_service }.to change { build2.reload.status }.from('skipped').to('created') + end end + + it_behaves_like 'processing subsequent skipped jobs' + it_behaves_like 'processing the same stage job' end context 'when the pipeline is a downstream pipeline and the bridge is depended' do - let!(:trigger_job) { create(:ci_bridge, :strategy_depend, status: 'success') } + let!(:trigger_job) { create(:ci_bridge, :strategy_depend, name: 'trigger_job', status: 'success') } before do create(:ci_sources_pipeline, pipeline: pipeline, source_job: trigger_job) diff --git a/spec/services/ci/destroy_pipeline_service_spec.rb b/spec/services/ci/destroy_pipeline_service_spec.rb index 6c1c02b2875..166c4c4bd80 100644 --- a/spec/services/ci/destroy_pipeline_service_spec.rb +++ b/spec/services/ci/destroy_pipeline_service_spec.rb @@ -66,6 +66,28 @@ RSpec.describe ::Ci::DestroyPipelineService do expect { subject }.to change { Ci::DeletedObject.count } end end + + context 'when job has trace chunks' do + let(:connection_params) { Gitlab.config.artifacts.object_store.connection.symbolize_keys } + let(:connection) { ::Fog::Storage.new(connection_params) } + + before do + stub_object_storage(connection_params: connection_params, remote_directory: 'artifacts') + stub_artifacts_object_storage + end + + let!(:trace_chunk) { create(:ci_build_trace_chunk, :fog_with_data, build: build) } + + it 'destroys associated trace chunks' do + subject + + expect { trace_chunk.reload }.to raise_error(ActiveRecord::RecordNotFound) + end + + it 'removes data from object store' do + expect { subject }.to change { Ci::BuildTraceChunks::Fog.new.data(trace_chunk) } + end + end end context 'when pipeline is in cancelable state' do diff --git a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb index 02f8f2dd99f..31e1b0a896d 100644 --- a/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb +++ b/spec/services/ci/pipeline_processing/atomic_processing_service_spec.rb @@ -1004,6 +1004,63 @@ RSpec.describe Ci::PipelineProcessing::AtomicProcessingService do end end + context 'when the dependency is stage-independent', :sidekiq_inline do + let(:config) do + <<-EOY + stages: [A, B] + + A1: + stage: A + script: exit 0 + when: manual + + A2: + stage: A + script: exit 0 + needs: [A1] + + B: + stage: B + needs: [A2] + script: exit 0 + EOY + end + + let(:pipeline) do + Ci::CreatePipelineService.new(project, user, { ref: 'master' }).execute(:push).payload + end + + before do + stub_ci_pipeline_yaml_file(config) + end + + it 'processes subsequent jobs in the correct order when playing first job' do + expect(all_builds_names).to eq(%w[A1 A2 B]) + expect(all_builds_statuses).to eq(%w[manual skipped skipped]) + + play_manual_action('A1') + + expect(all_builds_names).to eq(%w[A1 A2 B]) + expect(all_builds_statuses).to eq(%w[pending created created]) + end + + context 'when the FF ci_order_subsequent_jobs_by_stage is disabled' do + before do + stub_feature_flags(ci_order_subsequent_jobs_by_stage: false) + end + + it 'processes subsequent jobs in an incorrect order when playing first job' do + expect(all_builds_names).to eq(%w[A1 A2 B]) + expect(all_builds_statuses).to eq(%w[manual skipped skipped]) + + play_manual_action('A1') + + expect(all_builds_names).to eq(%w[A1 A2 B]) + expect(all_builds_statuses).to eq(%w[pending created skipped]) + end + end + end + private def all_builds diff --git a/spec/support/helpers/test_env.rb b/spec/support/helpers/test_env.rb index 0ea51785863..c571962f739 100644 --- a/spec/support/helpers/test_env.rb +++ b/spec/support/helpers/test_env.rb @@ -212,9 +212,7 @@ module TestEnv spawn_script = Rails.root.join('scripts/gitaly-test-spawn').to_s Bundler.with_original_env do unless system(spawn_script) - message = 'gitaly spawn failed' - message += " (try `rm -rf #{gitaly_dir}` ?)" unless ci? - raise message + raise gitaly_failure_message end end @@ -616,6 +614,39 @@ module TestEnv expected_version == sha.chomp end + + def gitaly_failure_message + message = "gitaly spawn failed\n\n" + + message += "- The `gitaly` binary does not exist: #{gitaly_binary}\n" unless File.exist?(gitaly_binary) + message += "- The `praefect` binary does not exist: #{praefect_binary}\n" unless File.exist?(praefect_binary) + message += "- The `git` binary does not exist: #{git_binary}\n" unless File.exist?(git_binary) + + message += "\nCheck log/gitaly-test.log for errors.\n" + + unless ci? + message += "\nIf binaries are missing, try running `make -C tmp/tests/gitaly build git.`\n" + message += "\nOtherwise, try running `rm -rf #{gitaly_dir}`." + end + + message + end + + def git_binary + File.join(gitaly_dir, "_build", "deps", "git", "install", "bin", "git") + end + + def gitaly_binary + File.join(gitaly_dir, "_build", "bin", "gitaly") + end + + def praefect_binary + File.join(gitaly_dir, "_build", "bin", "praefect") + end + + def git_binary_exists? + File.exist?(git_binary) + end end require_relative('../../../ee/spec/support/helpers/ee/test_env') if Gitlab.ee? diff --git a/spec/support/shared_contexts/navbar_structure_context.rb b/spec/support/shared_contexts/navbar_structure_context.rb index 576a8aa44fa..27967850389 100644 --- a/spec/support/shared_contexts/navbar_structure_context.rb +++ b/spec/support/shared_contexts/navbar_structure_context.rb @@ -22,7 +22,6 @@ RSpec.shared_context 'project navbar structure' do nav_sub_items: [ _('Activity'), _('Labels'), - _('Planning hierarchy'), _('Members') ] }, diff --git a/spec/support/shared_contexts/policies/project_policy_shared_context.rb b/spec/support/shared_contexts/policies/project_policy_shared_context.rb index aabd6454b88..c39252cef13 100644 --- a/spec/support/shared_contexts/policies/project_policy_shared_context.rb +++ b/spec/support/shared_contexts/policies/project_policy_shared_context.rb @@ -17,7 +17,7 @@ RSpec.shared_context 'ProjectPolicy context' do %i[ award_emoji create_issue create_merge_request_in create_note create_project read_issue_board read_issue read_issue_iid read_issue_link - read_label read_work_items_hierarchy read_issue_board_list read_milestone read_note read_project + read_label read_issue_board_list read_milestone read_note read_project read_project_for_iids read_project_member read_release read_snippet read_wiki upload_file ]