Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
a527e81858
commit
7eb03d3ceb
|
|
@ -47,10 +47,15 @@ docs-lint markdown:
|
|||
needs: []
|
||||
script:
|
||||
- source ./scripts/utils.sh
|
||||
- yarn_install_script
|
||||
- install_gitlab_gem
|
||||
- scripts/lint-doc.sh
|
||||
- scripts/lint/check_mermaid.mjs
|
||||
- |
|
||||
function docs_lint_markdown() {
|
||||
yarn_install_script
|
||||
install_gitlab_gem
|
||||
scripts/lint-doc.sh
|
||||
scripts/lint/check_mermaid.mjs
|
||||
}
|
||||
|
||||
run_with_custom_exit_code docs_lint_markdown
|
||||
|
||||
docs code_quality:
|
||||
extends:
|
||||
|
|
@ -97,8 +102,10 @@ docs-lint links:
|
|||
- .docs-markdown-lint-image
|
||||
stage: lint
|
||||
needs: []
|
||||
before_script:
|
||||
- source scripts/utils.sh
|
||||
script:
|
||||
- lychee --offline --no-progress --include-fragments doc
|
||||
- run_with_custom_exit_code lychee --offline --no-progress --include-fragments doc
|
||||
|
||||
docs-lint deprecations-and-removals:
|
||||
variables:
|
||||
|
|
@ -111,8 +118,13 @@ docs-lint deprecations-and-removals:
|
|||
stage: lint
|
||||
needs: []
|
||||
script:
|
||||
- bundle exec rake gitlab:docs:check_deprecations
|
||||
- bundle exec rake gitlab:docs:check_windows
|
||||
- |
|
||||
function docs_lint_deprecations_and_removals() {
|
||||
bundle exec rake gitlab:docs:check_deprecations
|
||||
bundle exec rake gitlab:docs:check_windows
|
||||
}
|
||||
|
||||
run_with_custom_exit_code docs_lint_deprecations_and_removals
|
||||
|
||||
docs-lint redirects:
|
||||
image: ${GITLAB_DEPENDENCY_PROXY_ADDRESS}ruby:${RUBY_VERSION}-alpine
|
||||
|
|
@ -121,5 +133,7 @@ docs-lint redirects:
|
|||
- .default-retry
|
||||
- .docs:rules:redirect-check
|
||||
needs: []
|
||||
before_script:
|
||||
- source scripts/utils.sh
|
||||
script:
|
||||
- ./scripts/lint-docs-redirects.rb
|
||||
- run_with_custom_exit_code ./scripts/lint-docs-redirects.rb
|
||||
|
|
|
|||
|
|
@ -334,7 +334,7 @@ jest:
|
|||
junit: junit_jest.xml
|
||||
parallel: 11
|
||||
script:
|
||||
- run_timed_command scripts/frontend/jest_ci.js
|
||||
- run_with_custom_exit_code run_timed_command scripts/frontend/jest_ci.js
|
||||
|
||||
jest-with-fixtures:
|
||||
extends:
|
||||
|
|
@ -348,7 +348,7 @@ jest-with-fixtures:
|
|||
- !reference [.with-fixtures-needs, needs]
|
||||
parallel: 2
|
||||
script:
|
||||
- run_timed_command "scripts/frontend/jest_ci.js --fixtures"
|
||||
- run_with_custom_exit_code run_timed_command "scripts/frontend/jest_ci.js --fixtures"
|
||||
|
||||
jest vue3:
|
||||
extends:
|
||||
|
|
@ -388,7 +388,7 @@ jest vue3 mr:
|
|||
- junit_jest.xml
|
||||
parallel: 6
|
||||
script:
|
||||
- run_timed_command "scripts/frontend/jest_ci.js --vue3"
|
||||
- run_with_custom_exit_code run_timed_command "scripts/frontend/jest_ci.js --vue3"
|
||||
allow_failure: false
|
||||
|
||||
jest-with-fixtures vue3 mr:
|
||||
|
|
@ -408,7 +408,7 @@ jest-with-fixtures vue3 mr:
|
|||
- junit_jest.xml
|
||||
parallel: 1
|
||||
script:
|
||||
- run_timed_command "scripts/frontend/jest_ci.js --vue3 --fixtures"
|
||||
- run_with_custom_exit_code run_timed_command "scripts/frontend/jest_ci.js --vue3 --fixtures"
|
||||
|
||||
jest predictive:
|
||||
extends:
|
||||
|
|
@ -418,7 +418,15 @@ jest predictive:
|
|||
- !reference [jest, needs]
|
||||
- "detect-tests"
|
||||
script:
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "scripts/frontend/jest_ci.js --predictive"; fi
|
||||
- |
|
||||
function jest_predictive() {
|
||||
if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then
|
||||
run_timed_command "scripts/frontend/jest_ci.js --predictive"
|
||||
fi
|
||||
}
|
||||
|
||||
run_with_custom_exit_code jest_predictive
|
||||
|
||||
parallel: 4
|
||||
|
||||
jest-with-fixtures predictive:
|
||||
|
|
@ -429,7 +437,14 @@ jest-with-fixtures predictive:
|
|||
- !reference [jest-with-fixtures, needs]
|
||||
- "detect-tests"
|
||||
script:
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "scripts/frontend/jest_ci.js --predictive --fixtures"; fi
|
||||
- |
|
||||
function jest_with_fixtures_predictive() {
|
||||
if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then
|
||||
run_timed_command "scripts/frontend/jest_ci.js --predictive --fixtures"
|
||||
fi
|
||||
}
|
||||
|
||||
run_with_custom_exit_code jest_with_fixtures_predictive
|
||||
|
||||
jest vue3 predictive:
|
||||
extends:
|
||||
|
|
@ -439,7 +454,14 @@ jest vue3 predictive:
|
|||
- !reference [jest vue3 mr, needs]
|
||||
- "detect-tests"
|
||||
script:
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "scripts/frontend/jest_ci.js --vue3 --predictive"; fi
|
||||
- |
|
||||
function jest_vue3_predictive() {
|
||||
if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then
|
||||
run_timed_command "scripts/frontend/jest_ci.js --vue3 --predictive"
|
||||
fi
|
||||
}
|
||||
|
||||
run_with_custom_exit_code jest_vue3_predictive
|
||||
|
||||
jest-with-fixtures vue3 predictive:
|
||||
extends:
|
||||
|
|
@ -449,7 +471,14 @@ jest-with-fixtures vue3 predictive:
|
|||
- !reference [jest-with-fixtures vue3 mr, needs]
|
||||
- "detect-tests"
|
||||
script:
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "scripts/frontend/jest_ci.js --vue3 --predictive --fixtures"; fi
|
||||
- |
|
||||
function jest_with_fixtures_vue3_predictive() {
|
||||
if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then
|
||||
run_timed_command "scripts/frontend/jest_ci.js --vue3 --predictive --fixtures";
|
||||
fi
|
||||
}
|
||||
|
||||
run_with_custom_exit_code jest_with_fixtures_vue3_predictive
|
||||
allow_failure: false
|
||||
|
||||
jest vue3 check quarantined predictive:
|
||||
|
|
@ -460,7 +489,14 @@ jest vue3 check quarantined predictive:
|
|||
- !reference [jest vue3 mr, needs]
|
||||
- "detect-tests"
|
||||
script:
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "./scripts/frontend/check_jest_vue3_quarantine.js"; fi
|
||||
- |
|
||||
function jest_vue_check_quarantined_predictive() {
|
||||
if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then
|
||||
run_timed_command "./scripts/frontend/check_jest_vue3_quarantine.js"
|
||||
fi
|
||||
}
|
||||
|
||||
run_with_custom_exit_code jest_vue_check_quarantined_predictive
|
||||
parallel: 4
|
||||
artifacts:
|
||||
name: quarantined_tests_output
|
||||
|
|
@ -483,7 +519,14 @@ jest vue3 check quarantined:
|
|||
- .frontend:rules:jest-vue3-check-quarantined
|
||||
parallel: 4
|
||||
script:
|
||||
- if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then run_timed_command "./scripts/frontend/check_jest_vue3_quarantine.js --all"; fi
|
||||
- |
|
||||
function jest_vue3_check_quarantined() {
|
||||
if [[ -s "$RSPEC_CHANGED_FILES_PATH" ]] || [[ -s "$RSPEC_MATCHING_JS_FILES_PATH" ]]; then
|
||||
run_timed_command "./scripts/frontend/check_jest_vue3_quarantine.js --all"
|
||||
fi
|
||||
}
|
||||
|
||||
run_with_custom_exit_code jest_vue3_check_quarantined
|
||||
|
||||
jest-with-fixtures vue3 check quarantined:
|
||||
extends:
|
||||
|
|
@ -498,7 +541,7 @@ jest-integration:
|
|||
- .repo-from-artifacts
|
||||
- .frontend:rules:jest-integration
|
||||
script:
|
||||
- run_timed_command "yarn jest:integration --ci"
|
||||
- run_with_custom_exit_code run_timed_command "yarn jest:integration --ci"
|
||||
needs:
|
||||
# it's ok to wait for the repo artifact as we're waiting for the fixtures (which wait for the repo artifact) anyway
|
||||
- !reference [.repo-from-artifacts, needs]
|
||||
|
|
@ -550,7 +593,7 @@ jest-linters:
|
|||
- .frontend:rules:jest-linters
|
||||
needs: []
|
||||
script:
|
||||
- run_timed_command "yarn jest:eslint --ci"
|
||||
- run_with_custom_exit_code run_timed_command "yarn jest:eslint --ci"
|
||||
|
||||
coverage-frontend:
|
||||
extends:
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ export default {
|
|||
<template>
|
||||
<div class="gl-flex gl-flex-col gl-gap-3 md:gl-flex-row">
|
||||
<gl-filtered-search
|
||||
class="gl-min-w-0 gl-grow"
|
||||
:value="tokens"
|
||||
:placeholder="s__('CredentialsInventory|Search or filter credentials...')"
|
||||
:available-tokens="availableTokens"
|
||||
|
|
@ -66,7 +67,7 @@ export default {
|
|||
<gl-sorting
|
||||
v-if="!hasKey"
|
||||
block
|
||||
dropdown-class="gl-w-full"
|
||||
dropdown-class="gl-w-full !gl-flex"
|
||||
:is-ascending="sorting.isAsc"
|
||||
:sort-by="sorting.value"
|
||||
:sort-options="$options.SORT_OPTIONS"
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module DiffsStreamResource
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def diffs_stream_url(resource, offset = nil, diff_view = nil)
|
||||
return if offset && offset > resource.diffs_for_streaming.diff_files.count
|
||||
|
||||
diffs_stream_resource_url(resource, offset, diff_view)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def diffs_stream_resource_url(resource, offset, diff_view)
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module RapidDiffsResource
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def diffs_stream_url(resource, offset = nil, diff_view = nil)
|
||||
return if offset && offset > resource.diffs_for_streaming.diff_files.count
|
||||
|
||||
diffs_stream_resource_url(resource, offset, diff_view)
|
||||
end
|
||||
|
||||
def diff_files_metadata
|
||||
return render_404 unless rapid_diffs_enabled?
|
||||
return render_404 unless diffs_resource.present?
|
||||
|
||||
render json: {
|
||||
diff_files: DiffFileMetadataEntity.represent(diffs_resource.raw_diff_files(sorted: true))
|
||||
}
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def rapid_diffs_enabled?
|
||||
::Feature.enabled?(:rapid_diffs, current_user, type: :wip)
|
||||
end
|
||||
|
||||
def diffs_resource
|
||||
raise NotImplementedError
|
||||
end
|
||||
|
||||
def diffs_stream_resource_url(resource, offset, diff_view)
|
||||
raise NotImplementedError
|
||||
end
|
||||
end
|
||||
|
|
@ -9,7 +9,7 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
include DiffForPath
|
||||
include DiffHelper
|
||||
include SourcegraphDecorator
|
||||
include DiffsStreamResource
|
||||
include RapidDiffsResource
|
||||
|
||||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
|
|
@ -298,6 +298,10 @@ class Projects::CommitController < Projects::ApplicationController
|
|||
|
||||
check_rate_limit!(:expanded_diff_files, scope: current_user || request.ip)
|
||||
end
|
||||
|
||||
def diffs_resource
|
||||
commit&.diffs(commit_diff_options)
|
||||
end
|
||||
end
|
||||
|
||||
Projects::CommitController.prepend_mod_with('Projects::CommitController')
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
include DiffHelper
|
||||
include RendersCommits
|
||||
include CompareHelper
|
||||
include RapidDiffsResource
|
||||
|
||||
# Authorize
|
||||
before_action :require_non_empty_project
|
||||
|
|
@ -195,4 +196,8 @@ class Projects::CompareController < Projects::ApplicationController
|
|||
def compare_params
|
||||
@compare_params ||= params.permit(:from, :to, :from_project_id, :straight, :to_project_id)
|
||||
end
|
||||
|
||||
def diffs_resource
|
||||
compare&.diffs(diff_options)
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
|
|||
include DiffHelper
|
||||
include RendersCommits
|
||||
include ProductAnalyticsTracking
|
||||
include RapidDiffsResource
|
||||
|
||||
skip_before_action :merge_request
|
||||
before_action :authorize_create_merge_request_from!
|
||||
|
|
@ -105,6 +106,10 @@ class Projects::MergeRequests::CreationsController < Projects::MergeRequests::Ap
|
|||
render json: ProjectSerializer.new.represent(get_target_projects)
|
||||
end
|
||||
|
||||
def diffs_resource
|
||||
@merge_request&.compare&.diffs
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def get_target_projects
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
include Gitlab::Cache::Helpers
|
||||
include MergeRequestsHelper
|
||||
include ParseCommitDate
|
||||
include DiffsStreamResource
|
||||
include RapidDiffsResource
|
||||
|
||||
prepend_before_action(only: [:index]) { authenticate_sessionless_user!(:rss) }
|
||||
skip_before_action :merge_request, only: [:index, :bulk_update, :export_csv]
|
||||
|
|
@ -693,6 +693,10 @@ class Projects::MergeRequestsController < Projects::MergeRequests::ApplicationCo
|
|||
_("This merge request has reached the maximum limit of %{limit} versions and cannot be updated further. " \
|
||||
"Close this merge request and create a new one instead."), limit: MergeRequest::DIFF_VERSION_LIMIT)
|
||||
end
|
||||
|
||||
def diffs_resource
|
||||
@merge_request.latest_diffs
|
||||
end
|
||||
end
|
||||
|
||||
Projects::MergeRequestsController.prepend_mod_with('Projects::MergeRequestsController')
|
||||
|
|
|
|||
|
|
@ -1,17 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
module WorkItems
|
||||
module Widgets
|
||||
class StatusResolver < BaseResolver
|
||||
type ::Types::WorkItems::Widgets::StatusType.connection_type, null: true
|
||||
|
||||
def resolve
|
||||
[]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Resolvers::WorkItems::Widgets::StatusResolver.prepend_mod
|
||||
|
|
@ -347,10 +347,6 @@ module Types
|
|||
method: :linked_to_subscription?,
|
||||
description: 'Indicates if group is linked to a subscription.'
|
||||
|
||||
field :allowed_statuses, Types::WorkItems::Widgets::StatusType.connection_type,
|
||||
null: true, description: 'Allowed statuses for the group.',
|
||||
experiment: { milestone: '17.8' }, resolver: Resolvers::WorkItems::Widgets::StatusResolver
|
||||
|
||||
def label(title:)
|
||||
BatchLoader::GraphQL.for(title).batch(key: group) do |titles, loader, args|
|
||||
LabelsFinder
|
||||
|
|
|
|||
|
|
@ -133,10 +133,6 @@ module Types
|
|||
calls_gitaly: true,
|
||||
description: 'Work item description templates available to the namespace.'
|
||||
|
||||
field :allowed_statuses, Types::WorkItems::Widgets::StatusType.connection_type,
|
||||
null: true, description: 'Allowed statuses for the namespace.',
|
||||
experiment: { milestone: '17.8' }, resolver: Resolvers::WorkItems::Widgets::StatusResolver
|
||||
|
||||
markdown_field :description_html, null: true
|
||||
|
||||
def achievements_path
|
||||
|
|
|
|||
|
|
@ -805,10 +805,6 @@ module Types
|
|||
connection: true,
|
||||
description: "List of the project's Pages Deployments."
|
||||
|
||||
field :allowed_statuses, Types::WorkItems::Widgets::StatusType.connection_type,
|
||||
null: true, description: 'Allowed statuses for the project.',
|
||||
experiment: { milestone: '17.8' }, resolver: Resolvers::WorkItems::Widgets::StatusResolver
|
||||
|
||||
field :pages_force_https, GraphQL::Types::Boolean,
|
||||
null: false,
|
||||
description: "Project's Pages site redirects unsecured connections to HTTPS."
|
||||
|
|
|
|||
|
|
@ -14,14 +14,12 @@ module Types
|
|||
ORPHAN_TYPES = [
|
||||
::Types::WorkItems::WidgetDefinitions::AssigneesType,
|
||||
::Types::WorkItems::WidgetDefinitions::GenericType,
|
||||
::Types::WorkItems::WidgetDefinitions::HierarchyType,
|
||||
::Types::WorkItems::WidgetDefinitions::StatusType
|
||||
::Types::WorkItems::WidgetDefinitions::HierarchyType
|
||||
].freeze
|
||||
|
||||
TYPE_MAPPING = {
|
||||
::WorkItems::Widgets::Assignees => ::Types::WorkItems::WidgetDefinitions::AssigneesType,
|
||||
::WorkItems::Widgets::Hierarchy => ::Types::WorkItems::WidgetDefinitions::HierarchyType,
|
||||
::WorkItems::Widgets::Status => ::Types::WorkItems::WidgetDefinitions::StatusType
|
||||
::WorkItems::Widgets::Hierarchy => ::Types::WorkItems::WidgetDefinitions::HierarchyType
|
||||
}.freeze
|
||||
|
||||
def self.ce_orphan_types
|
||||
|
|
|
|||
|
|
@ -1,21 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module WorkItems
|
||||
module WidgetDefinitions
|
||||
# rubocop:disable Graphql/AuthorizeTypes -- Authorization too granular, parent type is authorized
|
||||
class StatusType < BaseObject
|
||||
graphql_name 'WorkItemWidgetDefinitionStatus'
|
||||
description 'Represents a Status widget definition'
|
||||
|
||||
implements ::Types::WorkItems::WidgetDefinitionInterface
|
||||
|
||||
field :allowed_statuses, ::Types::WorkItems::Widgets::StatusType.connection_type,
|
||||
null: true, experiment: { milestone: '17.8' },
|
||||
description: 'Allowed statuses for the work item type.',
|
||||
resolver: Resolvers::WorkItems::Widgets::StatusResolver
|
||||
end
|
||||
# rubocop:enable Graphql/AuthorizeTypes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -33,7 +33,6 @@ module Types
|
|||
::WorkItems::Widgets::Development => ::Types::WorkItems::Widgets::DevelopmentType,
|
||||
::WorkItems::Widgets::CrmContacts => ::Types::WorkItems::Widgets::CrmContactsType,
|
||||
::WorkItems::Widgets::EmailParticipants => ::Types::WorkItems::Widgets::EmailParticipantsType,
|
||||
::WorkItems::Widgets::Status => ::Types::WorkItems::Widgets::StatusType,
|
||||
::WorkItems::Widgets::LinkedResources => ::Types::WorkItems::Widgets::LinkedResourcesType,
|
||||
::WorkItems::Widgets::ErrorTracking => ::Types::WorkItems::Widgets::ErrorTrackingType
|
||||
}.freeze
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Types
|
||||
module WorkItems
|
||||
module Widgets
|
||||
# Disabling widget level authorization as it might be too granular
|
||||
# and we already authorize the parent work item
|
||||
# rubocop:disable Graphql/AuthorizeTypes -- reason above
|
||||
class StatusType < BaseObject
|
||||
graphql_name 'WorkItemWidgetStatus'
|
||||
description 'Represents status widget'
|
||||
|
||||
implements ::Types::WorkItems::WidgetInterface
|
||||
|
||||
field :id, Types::GlobalIDType,
|
||||
null: true,
|
||||
experiment: { milestone: '17.8' },
|
||||
description: 'ID of the status.'
|
||||
|
||||
field :name, GraphQL::Types::String,
|
||||
null: true,
|
||||
experiment: { milestone: '17.8' },
|
||||
description: 'Name of the status.'
|
||||
|
||||
field :icon_name, GraphQL::Types::String,
|
||||
null: true,
|
||||
experiment: { milestone: '17.8' },
|
||||
description: 'Icon name of the status.'
|
||||
|
||||
field :color, GraphQL::Types::String,
|
||||
null: true,
|
||||
experiment: { milestone: '17.10' },
|
||||
description: 'Color of the status.'
|
||||
|
||||
field :position, GraphQL::Types::Int,
|
||||
null: true,
|
||||
experiment: { milestone: '17.10' },
|
||||
description: 'Position of the status within its category.'
|
||||
end
|
||||
# rubocop:enable Graphql/AuthorizeTypes
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -901,6 +901,12 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
end
|
||||
|
||||
def latest_diffs
|
||||
diff = diffable_merge_ref? ? merge_head_diff : merge_request_diff
|
||||
|
||||
diff.diffs(diff_options)
|
||||
end
|
||||
|
||||
def diffs(diff_options = {})
|
||||
if compare
|
||||
# When saving MR diffs, `expanded` is implicitly added (because we need
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ module WorkItems
|
|||
development: 23,
|
||||
crm_contacts: 24,
|
||||
email_participants: 25,
|
||||
status: 26,
|
||||
status: 26, # EE-only
|
||||
linked_resources: 27,
|
||||
custom_fields: 28, # EE-only
|
||||
error_tracking: 29,
|
||||
|
|
|
|||
|
|
@ -1,25 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module WorkItems
|
||||
module Widgets
|
||||
class Status < Base
|
||||
# TODO - remove this once the widget table is implementeed
|
||||
# https://gitlab.com/gitlab-org/gitlab/-/issues/498393
|
||||
include GlobalID::Identification
|
||||
|
||||
# TODO - remove this once the widget table is implementeed
|
||||
# All the below fields gets delegated to the model https://gitlab.com/gitlab-org/gitlab/-/issues/498393
|
||||
def id
|
||||
'10'
|
||||
end
|
||||
|
||||
def name
|
||||
'Status'
|
||||
end
|
||||
|
||||
def icon_name
|
||||
'status icon'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,12 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module WorkItems
|
||||
module DataSync
|
||||
module Widgets
|
||||
class Status < Base
|
||||
# Need this class to make spec pass at https://gitlab.com/gitlab-org/gitlab/-/blob/master/ee/spec/models/ee/work_items/widget_definition_spec.rb#L49
|
||||
# Will be implemented as part of https://gitlab.com/groups/gitlab-org/-/epics/14793
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -6,5 +6,5 @@ introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/139851
|
|||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/435391
|
||||
milestone: '16.9'
|
||||
type: ops
|
||||
group: group::global search
|
||||
group: group::durability
|
||||
default_enabled: true
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ resources :merge_requests, concerns: :awardable, except: [:new, :create, :show],
|
|||
get :diff_for_path, controller: 'merge_requests/diffs'
|
||||
get 'diff_by_file_hash/:file_hash', to: 'merge_requests/diffs#diff_by_file_hash', as: :diff_by_file_hash
|
||||
get :diffs_stream, to: 'merge_requests/diffs_stream#diffs'
|
||||
get :diff_files_metadata
|
||||
|
||||
# NOTE: Fallback to `merge_requests/diffs#diff_for_path` to handle `collapsed_diff_url` from the collapsed partial
|
||||
scope controller: 'merge_requests/diffs_stream' do
|
||||
|
|
@ -95,5 +96,6 @@ scope path: 'merge_requests', controller: 'merge_requests/creations' do
|
|||
get :branch_from
|
||||
get :branch_to
|
||||
get :diffs_stream, to: 'merge_requests/creations_diffs_stream#diffs'
|
||||
get :diff_files_metadata
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ scope format: false do
|
|||
get :diff_for_path
|
||||
get :signatures
|
||||
get :diffs_stream, to: 'compare_diffs_stream#diffs'
|
||||
get :diff_files_metadata
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -112,6 +113,7 @@ resources :commit, only: [:show], constraints: { id: Gitlab::Git::Commit::SHA_PA
|
|||
get :diff_for_path
|
||||
get :diff_files
|
||||
get :merge_requests
|
||||
get :diff_files_metadata
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -9,6 +9,5 @@ feature_categories:
|
|||
description: Information about runner managers associated to instance Ci::Runner models
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/168131
|
||||
milestone: '17.6'
|
||||
gitlab_schema: gitlab_ci
|
||||
exempt_from_sharding: true
|
||||
gitlab_schema: gitlab_ci_cell_local
|
||||
table_size: small
|
||||
|
|
|
|||
|
|
@ -16,7 +16,13 @@ class AddProjectIdToMergeRequestDiffFiles < Gitlab::Database::Migration[2.2]
|
|||
add_column SOURCE_TABLE, :project_id, :bigint, if_not_exists: true
|
||||
end
|
||||
|
||||
add_concurrent_foreign_key SOURCE_TABLE, :projects, column: :project_id, on_delete: :cascade
|
||||
# This caused the incident https://gitlab.com/gitlab-com/gl-infra/production/-/issues/19474
|
||||
# We must first add the index before adding a foreign key. We also explicitly removed it in
|
||||
# db/post_migrate/20250312061803_remove_project_id_fk_from_merge_request_diff_files.rb to clean up any installations
|
||||
# that ran this.
|
||||
#
|
||||
# no-op:
|
||||
# add_concurrent_foreign_key SOURCE_TABLE, :projects, column: :project_id, on_delete: :cascade
|
||||
end
|
||||
|
||||
def down
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class RemoveProjectIdFkFromMergeRequestDiffFiles < Gitlab::Database::Migration[2.2]
|
||||
milestone '17.10'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
FK_NAME = 'fk_0e3ba01603'
|
||||
|
||||
def up
|
||||
with_lock_retries do
|
||||
remove_foreign_key_if_exists(:merge_request_diff_files, :projects, name: FK_NAME, reverse_lock_order: true)
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
# no-op
|
||||
# we won't add this again, as it may create problems without an index
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
c643bd5a8781d57cf943170020f44972ad0e06faa1f602b80409eea7704310ee
|
||||
|
|
@ -39401,9 +39401,6 @@ ALTER TABLE ONLY subscription_user_add_on_assignments
|
|||
ALTER TABLE ONLY approval_project_rules_users
|
||||
ADD CONSTRAINT fk_0dfcd9e339 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY merge_request_diff_files
|
||||
ADD CONSTRAINT fk_0e3ba01603 FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE;
|
||||
|
||||
ALTER TABLE ONLY ci_runner_projects
|
||||
ADD CONSTRAINT fk_0e743433ff FOREIGN KEY (runner_id) REFERENCES ci_runners_archived(id) ON DELETE CASCADE;
|
||||
|
||||
|
|
|
|||
|
|
@ -27148,7 +27148,7 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| <a id="groupcustomfieldsactive"></a>`active` | [`Boolean`](#boolean) | Filter for active fields. If `false`, excludes active fields. If `true`, returns only active fields. |
|
||||
| <a id="groupcustomfieldsfieldtype"></a>`fieldType` | [`CustomFieldType`](#customfieldtype) | Filter for selected field type. |
|
||||
| <a id="groupcustomfieldssearch"></a>`search` | [`String`](#string) | Search query for custom field name. |
|
||||
| <a id="groupcustomfieldsworkitemtypeids"></a>`workItemTypeIds` | [`[WorkItemsTypeID!]`](#workitemstypeid) | Filter custom fields associated to any of the given work item types. If empty, returns custom fields not associated to any work item type. |
|
||||
| <a id="groupcustomfieldsworkitemtypeid"></a>`workItemTypeId` | [`WorkItemsTypeID`](#workitemstypeid) | Filter custom fields associated to the given work item type. |
|
||||
|
||||
##### `Group.customizableDashboardVisualizations`
|
||||
|
||||
|
|
@ -32174,7 +32174,7 @@ four standard [pagination arguments](#pagination-arguments):
|
|||
| <a id="namespacecustomfieldsactive"></a>`active` | [`Boolean`](#boolean) | Filter for active fields. If `false`, excludes active fields. If `true`, returns only active fields. |
|
||||
| <a id="namespacecustomfieldsfieldtype"></a>`fieldType` | [`CustomFieldType`](#customfieldtype) | Filter for selected field type. |
|
||||
| <a id="namespacecustomfieldssearch"></a>`search` | [`String`](#string) | Search query for custom field name. |
|
||||
| <a id="namespacecustomfieldsworkitemtypeids"></a>`workItemTypeIds` | [`[WorkItemsTypeID!]`](#workitemstypeid) | Filter custom fields associated to any of the given work item types. If empty, returns custom fields not associated to any work item type. |
|
||||
| <a id="namespacecustomfieldsworkitemtypeid"></a>`workItemTypeId` | [`WorkItemsTypeID`](#workitemstypeid) | Filter custom fields associated to the given work item type. |
|
||||
|
||||
##### `Namespace.importSourceUsers`
|
||||
|
||||
|
|
|
|||
|
|
@ -367,7 +367,7 @@ On GitLab Self-Managed, by default the `fallback_behavior` field is available. T
|
|||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/498624) support for use in pipeline execution policies in GitLab 17.10 [with a flag](../../../administration/feature_flags.md) named `unblock_rules_using_pipeline_execution_policies`. Disabled by default.
|
||||
- [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/498624) support for use in pipeline execution policies in GitLab 17.10 [with a flag](../../../administration/feature_flags.md) named `unblock_rules_using_pipeline_execution_policies`. Enabled by default.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
|
|
|
|||
|
|
@ -546,9 +546,11 @@ function run_with_custom_exit_code() {
|
|||
set +e # temporarily disable exit on error to prevent premature exit
|
||||
|
||||
# runs command passed in as argument, save standard error and standard output
|
||||
output=$("$@" 2>&1)
|
||||
output=$(set -e; "$@" 2>&1)
|
||||
initial_exit_code=$?
|
||||
|
||||
echo "initial_exit_code: $initial_exit_code"
|
||||
|
||||
local trace_file="stdout_stderr_log.out"
|
||||
|
||||
echo "$output" | tee "$trace_file"
|
||||
|
|
|
|||
|
|
@ -2,10 +2,10 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe DiffsStreamResource, type: :controller, feature_category: :source_code_management do
|
||||
RSpec.describe RapidDiffsResource, type: :controller, feature_category: :source_code_management do
|
||||
subject(:controller) do
|
||||
Class.new(ApplicationController) do
|
||||
include DiffsStreamResource
|
||||
include RapidDiffsResource
|
||||
|
||||
def call_diffs_stream_resource_url(resource, offset, diff_view)
|
||||
diffs_stream_resource_url(resource, offset, diff_view)
|
||||
|
|
@ -14,6 +14,10 @@ RSpec.describe DiffsStreamResource, type: :controller, feature_category: :source
|
|||
def call_diffs_stream_url(resource, offset, diff_view)
|
||||
diffs_stream_url(resource, offset, diff_view)
|
||||
end
|
||||
|
||||
def call_diffs_resource
|
||||
diffs_resource
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -40,4 +44,12 @@ RSpec.describe DiffsStreamResource, type: :controller, feature_category: :source
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#diffs_resource' do
|
||||
it 'raises NotImplementedError' do
|
||||
expect do
|
||||
controller.new.call_diffs_resource
|
||||
end.to raise_error(NotImplementedError)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -771,5 +771,32 @@ RSpec.describe Projects::CompareController, feature_category: :source_code_manag
|
|||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'Get #diff_files_metadata' do
|
||||
let(:params) do
|
||||
{
|
||||
namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
from: from,
|
||||
to: to
|
||||
}
|
||||
end
|
||||
|
||||
let(:send_request) { get :diff_files_metadata, params: params }
|
||||
|
||||
context 'with valid params' do
|
||||
let(:from) { '6f6d7e7ed97bb5f0054f2b1df789b39ca89b6ff9' }
|
||||
let(:to) { '5937ac0a7beb003549fc5fd26fc247adbce4a52e' }
|
||||
|
||||
include_examples 'diff files metadata'
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
let(:from) { '0123456789' }
|
||||
let(:to) { '987654321' }
|
||||
|
||||
include_examples 'missing diff files metadata'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ RSpec.describe 'Database schema',
|
|||
ci_sources_pipelines: [%w[source_partition_id source_pipeline_id], %w[partition_id pipeline_id]],
|
||||
ci_sources_projects: [%w[partition_id pipeline_id]], # index on pipeline_id is sufficient
|
||||
ci_stages: [%w[partition_id pipeline_id]], # the index on pipeline_id is sufficient
|
||||
merge_request_diff_files: [%w[project_id]], # async index to be created - https://gitlab.com/gitlab-org/gitlab/-/issues/523103
|
||||
notes: %w[namespace_id], # this index is added in an async manner, hence it needs to be ignored in the first phase.
|
||||
p_ci_build_trace_metadata: [%w[partition_id build_id], %w[partition_id trace_artifact_id]], # the index on build_id is enough
|
||||
p_ci_builds: [%w[partition_id stage_id], %w[partition_id execution_config_id], %w[auto_canceled_by_partition_id auto_canceled_by_id], %w[upstream_pipeline_partition_id upstream_pipeline_id], %w[partition_id commit_id]], # https://gitlab.com/gitlab-org/gitlab/-/merge_requests/142804#note_1745483081
|
||||
|
|
@ -172,6 +171,7 @@ RSpec.describe 'Database schema',
|
|||
merge_request_cleanup_schedules: %w[project_id],
|
||||
merge_requests_compliance_violations: %w[target_project_id],
|
||||
merge_request_diffs: %w[project_id],
|
||||
merge_request_diff_files: %w[project_id],
|
||||
merge_request_diff_commits: %w[commit_author_id committer_id],
|
||||
# merge_request_diff_commits_b5377a7a34 is the temporary table for the merge_request_diff_commits partitioning
|
||||
# backfill. It will get foreign keys after the partitioning is finished.
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Resolvers::WorkItems::Widgets::StatusResolver, feature_category: :team_planning do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:project) { create(:project, group: group) }
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:task_type) { create(:work_item_type, :task) }
|
||||
let_it_be(:widget_definition) do
|
||||
create(:widget_definition, widget_type: :status, work_item_type: task_type, name: 'TesT Widget')
|
||||
end
|
||||
|
||||
shared_examples 'does not return system defined statuses' do
|
||||
it 'returns an empty array' do
|
||||
expect(resolve_statuses&.items).to eq([])
|
||||
end
|
||||
end
|
||||
|
||||
describe '#resolve' do
|
||||
let(:resource_parent) { group }
|
||||
|
||||
context 'with group' do
|
||||
it_behaves_like 'does not return system defined statuses'
|
||||
end
|
||||
|
||||
context 'with project' do
|
||||
let(:resource_parent) { project }
|
||||
|
||||
it_behaves_like 'does not return system defined statuses'
|
||||
end
|
||||
|
||||
context 'with unsupported namespace' do
|
||||
let(:resource_parent) { current_user.namespace }
|
||||
|
||||
it_behaves_like 'does not return system defined statuses'
|
||||
end
|
||||
|
||||
context 'with work_item_status feature flag disabled' do
|
||||
before do
|
||||
stub_feature_flags(work_item_status: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'does not return system defined statuses'
|
||||
end
|
||||
end
|
||||
|
||||
def resolve_statuses(args = {}, context = { current_user: current_user, resource_parent: resource_parent })
|
||||
resolve(described_class, obj: widget_definition, args: args, ctx: context)
|
||||
end
|
||||
end
|
||||
|
|
@ -29,7 +29,7 @@ RSpec.describe GitlabSchema.types['Group'], feature_category: :groups_and_projec
|
|||
contact_state_counts contacts work_item_types
|
||||
recent_issue_boards ci_variables releases environment_scopes work_items autocomplete_users
|
||||
lock_math_rendering_limits_enabled math_rendering_limits_enabled created_at updated_at
|
||||
organization_edit_path is_linked_to_subscription allowed_statuses
|
||||
organization_edit_path is_linked_to_subscription
|
||||
]
|
||||
|
||||
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ RSpec.describe GitlabSchema.types['Namespace'] do
|
|||
id name path full_name full_path achievements_path description description_html visibility
|
||||
lfs_enabled request_access_enabled projects root_storage_statistics shared_runners_setting
|
||||
timelog_categories achievements work_item pages_deployments import_source_users work_item_types
|
||||
sidebar work_item_description_templates allowed_statuses ci_cd_settings avatar_url
|
||||
sidebar work_item_description_templates ci_cd_settings avatar_url
|
||||
]
|
||||
|
||||
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||
|
|
|
|||
|
|
@ -46,8 +46,8 @@ RSpec.describe GitlabSchema.types['Project'], feature_category: :groups_and_proj
|
|||
ci_cd_settings detailed_import_status value_streams ml_models
|
||||
allows_multiple_merge_request_assignees allows_multiple_merge_request_reviewers is_forked
|
||||
protectable_branches available_deploy_keys explore_catalog_path
|
||||
container_protection_tag_rules allowed_statuses
|
||||
pages_force_https pages_use_unique_domain ci_pipeline_creation_request ci_pipeline_creation_inputs
|
||||
container_protection_tag_rules pages_force_https pages_use_unique_domain ci_pipeline_creation_request
|
||||
ci_pipeline_creation_inputs
|
||||
]
|
||||
|
||||
expect(described_class).to include_graphql_fields(*expected_fields)
|
||||
|
|
|
|||
|
|
@ -26,12 +26,6 @@ RSpec.describe Types::WorkItems::WidgetDefinitionInterface, feature_category: :t
|
|||
it { is_expected.to eq(Types::WorkItems::WidgetDefinitions::HierarchyType) }
|
||||
end
|
||||
|
||||
context 'for status widget' do
|
||||
let(:object) { build(:widget_definition, widget_type: 'status') }
|
||||
|
||||
it { is_expected.to eq(Types::WorkItems::WidgetDefinitions::StatusType) }
|
||||
end
|
||||
|
||||
context 'for other widgets' do
|
||||
let(:object) { build(:widget_definition, widget_type: 'description') }
|
||||
|
||||
|
|
|
|||
|
|
@ -30,7 +30,6 @@ RSpec.describe Types::WorkItems::WidgetInterface, feature_category: :team_planni
|
|||
WorkItems::Widgets::Designs | Types::WorkItems::Widgets::DesignsType
|
||||
WorkItems::Widgets::CrmContacts | Types::WorkItems::Widgets::CrmContactsType
|
||||
WorkItems::Widgets::EmailParticipants | Types::WorkItems::Widgets::EmailParticipantsType
|
||||
WorkItems::Widgets::Status | Types::WorkItems::Widgets::StatusType
|
||||
WorkItems::Widgets::ErrorTracking | Types::WorkItems::Widgets::ErrorTrackingType
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Types::WorkItems::Widgets::StatusType, feature_category: :team_planning do
|
||||
it 'exposes the expected fields' do
|
||||
expected_fields = %i[id name icon_name color position]
|
||||
|
||||
expected_fields.each do |field|
|
||||
expect(described_class).to have_graphql_field(field)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -22,7 +22,6 @@ RSpec.describe WorkItems::WidgetDefinition, feature_category: :team_planning do
|
|||
::WorkItems::Widgets::Development,
|
||||
::WorkItems::Widgets::CrmContacts,
|
||||
::WorkItems::Widgets::EmailParticipants,
|
||||
::WorkItems::Widgets::Status,
|
||||
::WorkItems::Widgets::ErrorTracking
|
||||
]
|
||||
|
||||
|
|
@ -37,7 +36,8 @@ RSpec.describe WorkItems::WidgetDefinition, feature_category: :team_planning do
|
|||
::WorkItems::Widgets::TestReports,
|
||||
::WorkItems::Widgets::Color,
|
||||
::WorkItems::Widgets::CustomFields,
|
||||
::WorkItems::Widgets::Vulnerabilities
|
||||
::WorkItems::Widgets::Vulnerabilities,
|
||||
::WorkItems::Widgets::Status
|
||||
]
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1513,37 +1513,6 @@ RSpec.describe 'Query.work_item(id)', feature_category: :team_planning do
|
|||
end
|
||||
end
|
||||
|
||||
describe 'status widget' do
|
||||
let_it_be(:task_work_item) { create(:work_item, :task, project: project) }
|
||||
let_it_be(:global_id) { task_work_item.to_global_id }
|
||||
let(:work_item_fields) do
|
||||
<<~GRAPHQL
|
||||
id
|
||||
widgets {
|
||||
type
|
||||
... on WorkItemWidgetStatus {
|
||||
id
|
||||
name
|
||||
iconName
|
||||
}
|
||||
}
|
||||
GRAPHQL
|
||||
end
|
||||
|
||||
it 'returns mock status data' do
|
||||
expect(work_item_data).to include(
|
||||
'widgets' => array_including(
|
||||
hash_including(
|
||||
'type' => 'STATUS',
|
||||
'id' => 'gid://gitlab/WorkItems::Widgets::Status/10',
|
||||
'name' => 'Status',
|
||||
'iconName' => 'status icon'
|
||||
)
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when an Issue Global ID is provided' do
|
||||
let(:global_id) { Issue.find(work_item.id).to_gid.to_s }
|
||||
|
||||
|
|
|
|||
|
|
@ -210,17 +210,16 @@ RSpec.describe Organizations::OrganizationsController, feature_category: :cell d
|
|||
|
||||
context 'when organization has multiple projects' do
|
||||
let_it_be(:stale_project) do
|
||||
create(:project, organization: organization, last_activity_at: Date.yesterday)
|
||||
create(:project, :public, organization: organization, last_activity_at: 3.days.ago)
|
||||
.tap { |project| create(:project_member, :developer, user:, project:) }
|
||||
end
|
||||
|
||||
let_it_be(:recently_updated_project) do
|
||||
create(:project, organization: organization, last_activity_at: Date.current)
|
||||
create(:project, :public, organization: organization, last_activity_at: Date.current)
|
||||
.tap { |project| create(:project_member, :developer, user:, project:) }
|
||||
end
|
||||
|
||||
before_all do
|
||||
stale_project.add_developer(user)
|
||||
recently_updated_project.add_developer(user)
|
||||
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,34 @@ RSpec.describe Projects::CommitController, feature_category: :source_code_manage
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET #diff_files_metadata' do
|
||||
let(:params) do
|
||||
{
|
||||
namespace_id: project.namespace,
|
||||
project_id: project,
|
||||
id: sha
|
||||
}
|
||||
end
|
||||
|
||||
let(:send_request) { get diff_files_metadata_namespace_project_commit_path(params) }
|
||||
|
||||
before do
|
||||
sign_in(user)
|
||||
end
|
||||
|
||||
context 'with valid params' do
|
||||
let(:sha) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' }
|
||||
|
||||
include_examples 'diff files metadata'
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
let(:sha) { '0123456789' }
|
||||
|
||||
include_examples 'missing diff files metadata'
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET #diff_files' do
|
||||
let(:master_pickable_sha) { '7d3b0f7cff5f37573aea97cebfd5692ea1689924' }
|
||||
let(:format) { :html }
|
||||
|
|
|
|||
|
|
@ -76,6 +76,36 @@ RSpec.describe 'merge requests creations', feature_category: :code_review_workfl
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'GET new/diff_files_metadata' do
|
||||
let(:send_request) { get namespace_project_new_merge_request_diff_files_metadata_path(params) }
|
||||
|
||||
context 'with valid params' do
|
||||
let(:params) do
|
||||
{
|
||||
namespace_id: project.namespace.to_param,
|
||||
project_id: project,
|
||||
merge_request: {
|
||||
source_branch: 'fix',
|
||||
target_branch: 'master'
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
include_examples 'diff files metadata'
|
||||
end
|
||||
|
||||
context 'with invalid params' do
|
||||
let(:params) do
|
||||
{
|
||||
namespace_id: project.namespace.to_param,
|
||||
project_id: project
|
||||
}
|
||||
end
|
||||
|
||||
include_examples 'missing diff files metadata'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /:namespace/:project/merge_requests' do
|
||||
|
|
|
|||
|
|
@ -286,6 +286,28 @@ RSpec.describe Projects::MergeRequestsController, feature_category: :source_code
|
|||
end
|
||||
end
|
||||
|
||||
describe 'GET #diff_files_metadata' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
login_as(user)
|
||||
end
|
||||
|
||||
let(:send_request) { get diff_files_metadata_project_merge_request_path(project, merge_request) }
|
||||
|
||||
include_examples 'diff files metadata'
|
||||
|
||||
context 'when merge_request_diff does not exist' do
|
||||
let(:merge_request) { create(:merge_request, :skip_diff_creation, author: user) }
|
||||
let(:project) { merge_request.project }
|
||||
|
||||
it 'returns an empty array' do
|
||||
send_request
|
||||
|
||||
expect(json_response['diff_files']).to be_empty
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'PUT #update' do
|
||||
before do
|
||||
project.add_developer(user)
|
||||
|
|
|
|||
|
|
@ -19,11 +19,6 @@ RSpec.shared_context 'with work item types request context' do
|
|||
nodes { id name }
|
||||
}
|
||||
}
|
||||
... on WorkItemWidgetDefinitionStatus {
|
||||
allowedStatuses {
|
||||
nodes { id name iconName color position }
|
||||
}
|
||||
}
|
||||
}
|
||||
supportedConversionTypes {
|
||||
id
|
||||
|
|
@ -70,11 +65,6 @@ RSpec.shared_context 'with work item types request context' do
|
|||
next hierarchy_widget_attributes(work_item_type, base_attributes, resource_parent)
|
||||
end
|
||||
|
||||
if widget == WorkItems::Widgets::Status
|
||||
next status_widget_attributes(work_item_type,
|
||||
base_attributes, resource_parent)
|
||||
end
|
||||
|
||||
next base_attributes unless widget_attributes[widget.type]
|
||||
|
||||
base_attributes.merge(widget_attributes[widget.type])
|
||||
|
|
@ -95,50 +85,4 @@ RSpec.shared_context 'with work item types request context' do
|
|||
base_attributes
|
||||
.merge({ 'allowedChildTypes' => { 'nodes' => child_types }, 'allowedParentTypes' => { 'nodes' => parent_types } })
|
||||
end
|
||||
|
||||
def status_widget_attributes(_work_item_type, base_attributes, resource_parent)
|
||||
unless resource_parent&.root_ancestor&.try(:work_item_status_feature_available?)
|
||||
return base_attributes.merge({ 'allowedStatuses' => { 'nodes' => [] } })
|
||||
end
|
||||
|
||||
statuses = [
|
||||
{
|
||||
'id' => 'gid://gitlab/WorkItems::Statuses::SystemDefined::Status/1',
|
||||
'name' => 'To do',
|
||||
'iconName' => 'status-waiting',
|
||||
'color' => '#535158',
|
||||
'position' => 0
|
||||
},
|
||||
{
|
||||
'id' => 'gid://gitlab/WorkItems::Statuses::SystemDefined::Status/2',
|
||||
'name' => 'In progress',
|
||||
'iconName' => 'status-running',
|
||||
'color' => '#0b5cad',
|
||||
'position' => 0
|
||||
},
|
||||
{
|
||||
'id' => 'gid://gitlab/WorkItems::Statuses::SystemDefined::Status/3',
|
||||
'name' => 'Done',
|
||||
'iconName' => 'status-success',
|
||||
'color' => '#23663b',
|
||||
'position' => 0
|
||||
},
|
||||
{
|
||||
'id' => 'gid://gitlab/WorkItems::Statuses::SystemDefined::Status/4',
|
||||
'name' => "Won't do",
|
||||
'iconName' => 'status-cancelled',
|
||||
'color' => '#ae1901',
|
||||
'position' => 0
|
||||
},
|
||||
{
|
||||
'id' => 'gid://gitlab/WorkItems::Statuses::SystemDefined::Status/5',
|
||||
'name' => 'Duplicate',
|
||||
'iconName' => 'status-cancelled',
|
||||
'color' => '#ae1901',
|
||||
'position' => 10
|
||||
}
|
||||
]
|
||||
|
||||
base_attributes.merge({ 'allowedStatuses' => { 'nodes' => statuses } })
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
RSpec.shared_examples 'diff files metadata' do
|
||||
it 'returns a json response' do
|
||||
send_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:success)
|
||||
expect(json_response['diff_files']).to be_an Array
|
||||
end
|
||||
|
||||
context 'when the rapid_diffs feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(rapid_diffs: false)
|
||||
end
|
||||
|
||||
it 'returns a 404 status' do
|
||||
send_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
RSpec.shared_examples 'missing diff files metadata' do
|
||||
it 'returns a 404 status' do
|
||||
send_request
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
end
|
||||
end
|
||||
|
|
@ -33,25 +33,6 @@ RSpec.shared_examples 'graphql work item type list request spec' do |context_nam
|
|||
)
|
||||
end
|
||||
|
||||
if Gitlab.ee?
|
||||
it 'returns the allowed custom statuses' do
|
||||
stub_licensed_features(work_item_custom_status: true)
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
work_item_types = graphql_data_at(parent_key, :workItemTypes, :nodes)
|
||||
status_widgets = work_item_types.flat_map do |work_item_type|
|
||||
work_item_type['widgetDefinitions'].select { |widget| widget['type'] == 'STATUS' }
|
||||
end
|
||||
|
||||
expect(status_widgets).to be_present
|
||||
status_widgets.each do |widget|
|
||||
expect(widget['allowedStatuses']).to be_present
|
||||
expect(widget['allowedStatuses']['nodes']).to all(include('id', 'name', 'iconName', 'color',
|
||||
'position'))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
it 'prevents N+1 queries' do
|
||||
# Destroy 2 existing types
|
||||
WorkItems::Type.by_type([:issue, :task]).delete_all
|
||||
|
|
|
|||
Loading…
Reference in New Issue