Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
686f1c3361
commit
dcaa8f80fb
|
|
@ -123,17 +123,17 @@ config/bounded_contexts.yml @fabiopitino @grzesiek @stanhu @cwoolley-gitlab @tku
|
|||
/.gitlab/ci/test-on-gdk/ @gl-dx/pipeline-maintainers @gl-dx/maintainers
|
||||
/gems/gem.gitlab-ci.yml
|
||||
|
||||
[Tooling] @gl-dx/eng-prod
|
||||
[Tooling] @gl-dx/tooling-maintainers
|
||||
Dangerfile
|
||||
/danger/
|
||||
/tooling/
|
||||
/spec/tooling/
|
||||
/scripts/
|
||||
/scripts/**/*.rb @gl-dx/eng-prod @gitlab-org/maintainers/rails-backend
|
||||
/scripts/**/*.js @gl-dx/eng-prod @gitlab-org/maintainers/frontend
|
||||
/scripts/frontend/ @gl-dx/eng-prod @gitlab-org/maintainers/frontend
|
||||
/scripts/remote_development/ @gl-dx/eng-prod @gitlab-org/maintainers/workspaces/backend @gitlab-org/maintainers/workspaces/frontend
|
||||
/scripts/review_apps/seed-dast-test-data.sh @gl-dx/eng-prod @dappelt @ngeorge1
|
||||
/scripts/**/*.rb @gl-dx/tooling-maintainers @gitlab-org/maintainers/rails-backend
|
||||
/scripts/**/*.js @gl-dx/tooling-maintainers @gitlab-org/maintainers/frontend
|
||||
/scripts/frontend/ @gl-dx/tooling-maintainers @gitlab-org/maintainers/frontend
|
||||
/scripts/remote_development/ @gl-dx/tooling-maintainers @gitlab-org/maintainers/workspaces/backend @gitlab-org/maintainers/workspaces/frontend
|
||||
/scripts/review_apps/seed-dast-test-data.sh @gl-dx/tooling-maintainers @dappelt @ngeorge1
|
||||
/.dockerignore
|
||||
/.editorconfig
|
||||
/.gitpod.yml
|
||||
|
|
@ -145,7 +145,7 @@ Dangerfile
|
|||
/lefthook.yml
|
||||
/tests.yml
|
||||
|
||||
^[Backend Static Code Analysis] @gl-dx/eng-prod @dstull
|
||||
^[Backend Static Code Analysis] @gl-dx/tooling-maintainers @dstull
|
||||
.rubocop*.yml
|
||||
/gems/config/rubocop.yml
|
||||
/rubocop/
|
||||
|
|
@ -990,7 +990,7 @@ lib/gitlab/checks/**
|
|||
/doc/development/fe_guide/keyboard_shortcuts.md @gitlab-org/foundations/personal-productivity/engineering
|
||||
/doc/development/git_object_deduplication.md @proglottis @toon
|
||||
/doc/development/gitaly.md @proglottis @toon
|
||||
/doc/development/gitpod_internals.md @gl-dx/eng-prod
|
||||
/doc/development/gitpod_internals.md @gl-dx/tooling-maintainers
|
||||
/doc/development/identity_verification.md @gitlab-org/software-supply-chain-security/authorization/approvers
|
||||
/doc/development/image_scaling.md @abdwdd @alexpooley
|
||||
/doc/development/internal_analytics/ @gitlab-org/analytics-section/product-analytics/engineers/frontend @gitlab-org/analytics-section/analytics-instrumentation/engineers
|
||||
|
|
@ -1004,12 +1004,12 @@ lib/gitlab/checks/**
|
|||
/doc/development/organization/ @abdwdd @alexpooley
|
||||
/doc/development/permissions.md @gitlab-org/software-supply-chain-security/authorization/approvers
|
||||
/doc/development/permissions/ @gitlab-org/software-supply-chain-security/authorization/approvers
|
||||
/doc/development/pipelines/ @gl-dx/eng-prod
|
||||
/doc/development/pipelines/ @gl-dx/pipeline-maintainers
|
||||
/doc/development/policies.md @gitlab-org/software-supply-chain-security/authentication/approvers
|
||||
/doc/development/prometheus_metrics.md @gitlab-org/analytics-section/product-analytics/engineers/frontend
|
||||
/doc/development/search/ @gitlab-org/search-team/migration-maintainers
|
||||
/doc/development/sec/ @gitlab-org/secure/composition-analysis-be @gitlab-org/secure/static-analysis
|
||||
/doc/development/software_design.md @gl-dx/eng-prod
|
||||
/doc/development/software_design.md @gl-dx/pipeline-maintainers
|
||||
/doc/development/spam_protection_and_captcha/ @gitlab-org/software-supply-chain-security/authorization/approvers
|
||||
/doc/development/stage_group_observability/ @gitlab-org/analytics-section/product-analytics/engineers/frontend
|
||||
/doc/development/tracing.md @gitlab-org/analytics-section/product-analytics/engineers/frontend
|
||||
|
|
@ -1252,7 +1252,7 @@ lib/gitlab/checks/**
|
|||
[Localization Team] @gitlab-com/localization/maintainers
|
||||
/doc-locale/**
|
||||
/doc/development/i18n/proofreader.md
|
||||
/argo_translation.yml
|
||||
/argo_translation.yml
|
||||
|
||||
[Authorization] @gitlab-org/software-supply-chain-security/authorization/approvers
|
||||
/config/initializers/declarative_policy.rb
|
||||
|
|
|
|||
|
|
@ -112,8 +112,22 @@ docs hugo_build:
|
|||
stage: lint
|
||||
needs: []
|
||||
dependencies: []
|
||||
variables:
|
||||
DOCS_BRANCH: "main"
|
||||
before_script:
|
||||
- git clone --depth 1 --filter=tree:0 https://gitlab.com/gitlab-org/technical-writing/docs-gitlab-com.git
|
||||
# Check if this a release branch, which would be the case for a backport.
|
||||
# If this is a backport MR, we need to checkout the appropriate version
|
||||
# of the Docs website.
|
||||
- |
|
||||
if [[ $CI_MERGE_REQUEST_TARGET_BRANCH_NAME =~ [0-9]+-[0-9]+-stable ]]; then
|
||||
MAJOR=$(echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME | cut -d '-' -f 1)
|
||||
MINOR=$(echo $CI_MERGE_REQUEST_TARGET_BRANCH_NAME | cut -d '-' -f 2)
|
||||
# Convert GitLab style (17-9-stable-ee) to Docs style (17.9)
|
||||
DOCS_BRANCH="$MAJOR.$MINOR"
|
||||
echo "Using docs-gitlab-com branch $DOCS_BRANCH for release branch"
|
||||
fi
|
||||
# Clone the Docs website project
|
||||
- git clone --depth 1 --filter=tree:0 --branch $DOCS_BRANCH https://gitlab.com/gitlab-org/technical-writing/docs-gitlab-com.git
|
||||
- cd docs-gitlab-com
|
||||
- make add-latest-icons
|
||||
# Copy the current project's docs to the appropriate location in the docs website
|
||||
|
|
|
|||
|
|
@ -40,12 +40,8 @@
|
|||
# - tooling/lib/tooling/glci/failure_analyzer.rb
|
||||
.failure_category_after_script:
|
||||
after_script:
|
||||
# We need this at the very top, because the section_start/section_end logic is defined there.
|
||||
- source scripts/utils.sh
|
||||
- |
|
||||
section_start "failure-analyzer" "Report failure category"
|
||||
tooling/lib/tooling/glci/failure_analyzer.rb $CI_JOB_ID || true
|
||||
section_end "failure-analyzer"
|
||||
- execute_failure_analyzer
|
||||
|
||||
.repo-from-artifacts:
|
||||
variables:
|
||||
|
|
|
|||
|
|
@ -48,12 +48,8 @@ stages:
|
|||
# Taken from .gitlab/ci/global.gitlab-ci.yml, but adapted the paths
|
||||
.failure_category_after_script:
|
||||
after_script:
|
||||
# We need this at the very top, because the section_start/section_end logic is defined there.
|
||||
- source $CI_PROJECT_DIR/scripts/utils.sh
|
||||
- |
|
||||
section_start "failure-analyzer" "Report failure category"
|
||||
$CI_PROJECT_DIR/tooling/lib/tooling/glci/failure_analyzer.rb $CI_JOB_ID || true
|
||||
section_end "failure-analyzer"
|
||||
- execute_failure_analyzer
|
||||
|
||||
.qa-install:
|
||||
extends:
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ include:
|
|||
inputs:
|
||||
cng_path: 'charts/components/images'
|
||||
- project: 'gitlab-org/quality/pipeline-common'
|
||||
ref: '10.0.0'
|
||||
ref: '10.1.0'
|
||||
file: ci/base.gitlab-ci.yml
|
||||
|
||||
stages:
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
include:
|
||||
- project: gitlab-org/quality/pipeline-common
|
||||
ref: 10.0.0
|
||||
ref: 10.1.0
|
||||
file:
|
||||
- /ci/base.gitlab-ci.yml
|
||||
|
||||
|
|
|
|||
|
|
@ -1595,14 +1595,12 @@ Gitlab/BoundedContexts:
|
|||
- 'app/services/issues/after_create_service.rb'
|
||||
- 'app/services/issues/base_service.rb'
|
||||
- 'app/services/issues/build_service.rb'
|
||||
- 'app/services/issues/clone_service.rb'
|
||||
- 'app/services/issues/close_service.rb'
|
||||
- 'app/services/issues/convert_to_ticket_service.rb'
|
||||
- 'app/services/issues/create_service.rb'
|
||||
- 'app/services/issues/duplicate_service.rb'
|
||||
- 'app/services/issues/export_csv_service.rb'
|
||||
- 'app/services/issues/import_csv_service.rb'
|
||||
- 'app/services/issues/move_service.rb'
|
||||
- 'app/services/issues/prepare_import_csv_service.rb'
|
||||
- 'app/services/issues/referenced_merge_requests_service.rb'
|
||||
- 'app/services/issues/related_branches_service.rb'
|
||||
|
|
@ -3132,12 +3130,10 @@ Gitlab/BoundedContexts:
|
|||
- 'ee/app/services/ee/issues/after_create_service.rb'
|
||||
- 'ee/app/services/ee/issues/base_service.rb'
|
||||
- 'ee/app/services/ee/issues/build_service.rb'
|
||||
- 'ee/app/services/ee/issues/clone_service.rb'
|
||||
- 'ee/app/services/ee/issues/close_service.rb'
|
||||
- 'ee/app/services/ee/issues/create_service.rb'
|
||||
- 'ee/app/services/ee/issues/export_csv_service.rb'
|
||||
- 'ee/app/services/ee/issues/import_csv_service.rb'
|
||||
- 'ee/app/services/ee/issues/move_service.rb'
|
||||
- 'ee/app/services/ee/issues/reopen_service.rb'
|
||||
- 'ee/app/services/ee/issues/update_service.rb'
|
||||
- 'ee/app/services/ee/jira_connect/sync_service.rb'
|
||||
|
|
|
|||
|
|
@ -540,7 +540,6 @@ Layout/EmptyLineAfterMagicComment:
|
|||
- 'spec/services/dependency_proxy/head_manifest_service_spec.rb'
|
||||
- 'spec/services/dependency_proxy/request_token_service_spec.rb'
|
||||
- 'spec/services/design_management/copy_design_collection/copy_service_spec.rb'
|
||||
- 'spec/services/design_management/copy_design_collection/queue_service_spec.rb'
|
||||
- 'spec/services/design_management/delete_designs_service_spec.rb'
|
||||
- 'spec/services/design_management/move_designs_service_spec.rb'
|
||||
- 'spec/services/design_management/save_designs_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -236,7 +236,6 @@ Layout/LineLength:
|
|||
- 'app/services/dependency_proxy/group_settings/update_service.rb'
|
||||
- 'app/services/dependency_proxy/image_ttl_group_policies/update_service.rb'
|
||||
- 'app/services/design_management/copy_design_collection/copy_service.rb'
|
||||
- 'app/services/design_management/copy_design_collection/queue_service.rb'
|
||||
- 'app/services/design_management/generate_image_versions_service.rb'
|
||||
- 'app/services/design_management/save_designs_service.rb'
|
||||
- 'app/services/discussions/resolve_service.rb'
|
||||
|
|
@ -253,10 +252,8 @@ Layout/LineLength:
|
|||
- 'app/services/import/bitbucket_server_service.rb'
|
||||
- 'app/services/issuable/process_assignees.rb'
|
||||
- 'app/services/issuable_base_service.rb'
|
||||
- 'app/services/issues/clone_service.rb'
|
||||
- 'app/services/issues/close_service.rb'
|
||||
- 'app/services/issues/duplicate_service.rb'
|
||||
- 'app/services/issues/move_service.rb'
|
||||
- 'app/services/issues/relative_position_rebalancing_service.rb'
|
||||
- 'app/services/issues/set_crm_contacts_service.rb'
|
||||
- 'app/services/issues/update_service.rb'
|
||||
|
|
@ -668,7 +665,6 @@ Layout/LineLength:
|
|||
- 'ee/app/services/ee/groups/update_service.rb'
|
||||
- 'ee/app/services/ee/ip_restrictions/update_service.rb'
|
||||
- 'ee/app/services/ee/issues/base_service.rb'
|
||||
- 'ee/app/services/ee/issues/clone_service.rb'
|
||||
- 'ee/app/services/ee/merge_requests/merge_base_service.rb'
|
||||
- 'ee/app/services/ee/merge_requests/refresh_service.rb'
|
||||
- 'ee/app/services/ee/personal_access_tokens/revoke_service.rb'
|
||||
|
|
@ -1647,7 +1643,6 @@ Layout/LineLength:
|
|||
- 'ee/spec/services/ee/ip_restrictions/update_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issuable/common_system_notes_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issue_links/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/clone_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/update_service_spec.rb'
|
||||
- 'ee/spec/services/ee/members/destroy_service_spec.rb'
|
||||
|
|
@ -3796,12 +3791,10 @@ Layout/LineLength:
|
|||
- 'spec/services/issue_links/create_service_spec.rb'
|
||||
- 'spec/services/issues/after_create_service_spec.rb'
|
||||
- 'spec/services/issues/build_service_spec.rb'
|
||||
- 'spec/services/issues/clone_service_spec.rb'
|
||||
- 'spec/services/issues/close_service_spec.rb'
|
||||
- 'spec/services/issues/create_service_spec.rb'
|
||||
- 'spec/services/issues/duplicate_service_spec.rb'
|
||||
- 'spec/services/issues/export_csv_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/issues/referenced_merge_requests_service_spec.rb'
|
||||
- 'spec/services/issues/relative_position_rebalancing_service_spec.rb'
|
||||
- 'spec/services/issues/resolve_discussions_spec.rb'
|
||||
|
|
|
|||
|
|
@ -102,8 +102,6 @@ Lint/AssignmentInCondition:
|
|||
- 'ee/app/services/deployments/approval_service.rb'
|
||||
- 'ee/app/services/dora/aggregate_metrics_service.rb'
|
||||
- 'ee/app/services/ee/application_settings/update_service.rb'
|
||||
- 'ee/app/services/ee/issues/clone_service.rb'
|
||||
- 'ee/app/services/ee/issues/move_service.rb'
|
||||
- 'ee/app/services/ee/projects/operations/update_service.rb'
|
||||
- 'ee/app/services/gitlab_subscriptions/fetch_subscription_plans_service.rb'
|
||||
- 'ee/app/services/incident_management/issuable_resource_links/zoom_link_service.rb'
|
||||
|
|
|
|||
|
|
@ -140,7 +140,6 @@ Lint/UnusedMethodArgument:
|
|||
- 'app/services/groups/update_service.rb'
|
||||
- 'app/services/import/gitlab_projects/file_acquisition_strategies/file_upload.rb'
|
||||
- 'app/services/issues/export_csv_service.rb'
|
||||
- 'app/services/issues/move_service.rb'
|
||||
- 'app/services/jira/requests/base.rb'
|
||||
- 'app/services/keys/destroy_service.rb'
|
||||
- 'app/services/merge_requests/close_service.rb'
|
||||
|
|
|
|||
|
|
@ -202,7 +202,6 @@ Rails/Date:
|
|||
- 'spec/services/import/reassign_placeholder_user_records_service_spec.rb'
|
||||
- 'spec/services/issuable/callbacks/time_tracking_spec.rb'
|
||||
- 'spec/services/issuable/common_system_notes_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/members/invitation_reminder_email_service_spec.rb'
|
||||
- 'spec/services/members/update_service_spec.rb'
|
||||
- 'spec/services/milestones/find_or_create_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1310,10 +1310,8 @@ RSpec/BeEq:
|
|||
- 'spec/services/incident_management/issuable_escalation_statuses/create_service_spec.rb'
|
||||
- 'spec/services/incident_management/timeline_events/create_service_spec.rb'
|
||||
- 'spec/services/issuable/callbacks/time_tracking_spec.rb'
|
||||
- 'spec/services/issues/clone_service_spec.rb'
|
||||
- 'spec/services/issues/create_service_spec.rb'
|
||||
- 'spec/services/issues/export_csv_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/issues/update_service_spec.rb'
|
||||
- 'spec/services/issues/zoom_link_service_spec.rb'
|
||||
- 'spec/services/jira_connect_installations/update_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -534,7 +534,6 @@ RSpec/BeforeAllRoleAssignment:
|
|||
- 'ee/spec/services/ee/groups/deploy_tokens/revoke_service_spec.rb'
|
||||
- 'ee/spec/services/ee/groups/group_links/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issuable/bulk_update_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/clone_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/close_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/reopen_service_spec.rb'
|
||||
|
|
@ -1210,9 +1209,7 @@ RSpec/BeforeAllRoleAssignment:
|
|||
- 'spec/services/integrations/slack_options/user_search_handler_spec.rb'
|
||||
- 'spec/services/issuable/bulk_update_service_spec.rb'
|
||||
- 'spec/services/issue_links/create_service_spec.rb'
|
||||
- 'spec/services/issues/clone_service_spec.rb'
|
||||
- 'spec/services/issues/create_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/issues/reorder_service_spec.rb'
|
||||
- 'spec/services/issues/set_crm_contacts_service_spec.rb'
|
||||
- 'spec/services/issues/update_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -616,9 +616,7 @@ RSpec/ContextWording:
|
|||
- 'ee/spec/services/ee/integrations/test/project_service_spec.rb'
|
||||
- 'ee/spec/services/ee/ip_restrictions/update_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issuable/bulk_update_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/clone_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/move_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/update_service_spec.rb'
|
||||
- 'ee/spec/services/ee/keys/destroy_service_spec.rb'
|
||||
- 'ee/spec/services/ee/members/create_service_spec.rb'
|
||||
|
|
@ -2387,11 +2385,9 @@ RSpec/ContextWording:
|
|||
- 'spec/services/integrations/test/project_service_spec.rb'
|
||||
- 'spec/services/issue_links/list_service_spec.rb'
|
||||
- 'spec/services/issues/build_service_spec.rb'
|
||||
- 'spec/services/issues/clone_service_spec.rb'
|
||||
- 'spec/services/issues/close_service_spec.rb'
|
||||
- 'spec/services/issues/create_service_spec.rb'
|
||||
- 'spec/services/issues/export_csv_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/issues/referenced_merge_requests_service_spec.rb'
|
||||
- 'spec/services/issues/related_branches_service_spec.rb'
|
||||
- 'spec/services/issues/relative_position_rebalancing_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -270,7 +270,6 @@ RSpec/ExpectChange:
|
|||
- 'spec/services/clusters/agents/create_activity_event_service_spec.rb'
|
||||
- 'spec/services/clusters/agents/delete_expired_events_service_spec.rb'
|
||||
- 'spec/services/clusters/kubernetes/create_or_update_namespace_service_spec.rb'
|
||||
- 'spec/services/design_management/copy_design_collection/queue_service_spec.rb'
|
||||
- 'spec/services/design_management/save_designs_service_spec.rb'
|
||||
- 'spec/services/event_create_service_spec.rb'
|
||||
- 'spec/services/events/destroy_service_spec.rb'
|
||||
|
|
@ -285,7 +284,6 @@ RSpec/ExpectChange:
|
|||
- 'spec/services/issuable/bulk_update_service_spec.rb'
|
||||
- 'spec/services/issues/create_service_spec.rb'
|
||||
- 'spec/services/issues/export_csv_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/issues/update_service_spec.rb'
|
||||
- 'spec/services/jira_connect_installations/destroy_service_spec.rb'
|
||||
- 'spec/services/keys/destroy_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -854,7 +854,6 @@ RSpec/NamedSubject:
|
|||
- 'ee/spec/services/ee/issuable/common_system_notes_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issuable/destroy_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issue_links/create_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/clone_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/update_service_spec.rb'
|
||||
- 'ee/spec/services/ee/keys/destroy_service_spec.rb'
|
||||
- 'ee/spec/services/ee/members/create_service_spec.rb'
|
||||
|
|
@ -2884,7 +2883,6 @@ RSpec/NamedSubject:
|
|||
- 'spec/services/deployments/archive_in_project_service_spec.rb'
|
||||
- 'spec/services/deployments/update_environment_service_spec.rb'
|
||||
- 'spec/services/design_management/copy_design_collection/copy_service_spec.rb'
|
||||
- 'spec/services/design_management/copy_design_collection/queue_service_spec.rb'
|
||||
- 'spec/services/design_management/design_user_notes_count_service_spec.rb'
|
||||
- 'spec/services/design_management/move_designs_service_spec.rb'
|
||||
- 'spec/services/discussions/capture_diff_note_position_service_spec.rb'
|
||||
|
|
@ -2941,12 +2939,10 @@ RSpec/NamedSubject:
|
|||
- 'spec/services/issuable/import_csv/base_service_spec.rb'
|
||||
- 'spec/services/issue_links/list_service_spec.rb'
|
||||
- 'spec/services/issues/build_service_spec.rb'
|
||||
- 'spec/services/issues/clone_service_spec.rb'
|
||||
- 'spec/services/issues/create_service_spec.rb'
|
||||
- 'spec/services/issues/duplicate_service_spec.rb'
|
||||
- 'spec/services/issues/export_csv_service_spec.rb'
|
||||
- 'spec/services/issues/import_csv_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/issues/prepare_import_csv_service_spec.rb'
|
||||
- 'spec/services/issues/relative_position_rebalancing_service_spec.rb'
|
||||
- 'spec/services/issues/reorder_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -136,7 +136,6 @@ RSpec/ReceiveMessages:
|
|||
- 'ee/spec/services/compliance_management/frameworks/update_project_service_spec.rb'
|
||||
- 'ee/spec/services/ee/ci/job_token_scope/remove_group_service_spec.rb'
|
||||
- 'ee/spec/services/ee/ci/job_token_scope/remove_project_service_spec.rb'
|
||||
- 'ee/spec/services/ee/issues/move_service_spec.rb'
|
||||
- 'ee/spec/services/ee/post_receive_service_spec.rb'
|
||||
- 'ee/spec/services/ee/spam/spam_verdict_service_spec.rb'
|
||||
- 'ee/spec/services/ee/work_items/related_work_item_links/create_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -85,8 +85,6 @@ RSpec/SubjectDeclaration:
|
|||
- 'spec/serializers/pipeline_details_entity_spec.rb'
|
||||
- 'spec/services/concerns/exclusive_lease_guard_spec.rb'
|
||||
- 'spec/services/concerns/rate_limited_service_spec.rb'
|
||||
- 'spec/services/issues/clone_service_spec.rb'
|
||||
- 'spec/services/issues/move_service_spec.rb'
|
||||
- 'spec/services/issues/prepare_import_csv_service_spec.rb'
|
||||
- 'spec/services/merge_requests/delete_non_latest_diffs_service_spec.rb'
|
||||
- 'spec/services/merge_requests/reload_diffs_service_spec.rb'
|
||||
|
|
|
|||
|
|
@ -19,7 +19,6 @@ Style/AccessorGrouping:
|
|||
- 'app/models/integrations/chat_message/wiki_page_message.rb'
|
||||
- 'app/models/project.rb'
|
||||
- 'app/services/deployments/update_environment_service.rb'
|
||||
- 'app/services/issues/clone_service.rb'
|
||||
- 'app/services/note_summary.rb'
|
||||
- 'app/services/notification_recipients/builder/default.rb'
|
||||
- 'app/services/task_list_toggle_service.rb'
|
||||
|
|
|
|||
|
|
@ -58,9 +58,7 @@ Style/FormatString:
|
|||
- 'app/services/import/bitbucket_server_service.rb'
|
||||
- 'app/services/import/fogbugz_service.rb'
|
||||
- 'app/services/issuable_links/create_service.rb'
|
||||
- 'app/services/issues/clone_service.rb'
|
||||
- 'app/services/issues/close_service.rb'
|
||||
- 'app/services/issues/move_service.rb'
|
||||
- 'app/services/issues/set_crm_contacts_service.rb'
|
||||
- 'app/services/jira/requests/base.rb'
|
||||
- 'app/services/milestones/promote_service.rb'
|
||||
|
|
|
|||
|
|
@ -130,8 +130,6 @@ Style/GuardClause:
|
|||
- 'app/services/issuable/bulk_update_service.rb'
|
||||
- 'app/services/issuable/common_system_notes_service.rb'
|
||||
- 'app/services/issuable_base_service.rb'
|
||||
- 'app/services/issues/clone_service.rb'
|
||||
- 'app/services/issues/move_service.rb'
|
||||
- 'app/services/issues/update_service.rb'
|
||||
- 'app/services/markdown_content_rewriter_service.rb'
|
||||
- 'app/services/merge_requests/add_spent_time_service.rb'
|
||||
|
|
@ -263,7 +261,6 @@ Style/GuardClause:
|
|||
- 'ee/app/services/ee/groups/update_service.rb'
|
||||
- 'ee/app/services/ee/issuable/common_system_notes_service.rb'
|
||||
- 'ee/app/services/ee/issues/base_service.rb'
|
||||
- 'ee/app/services/ee/issues/clone_service.rb'
|
||||
- 'ee/app/services/ee/merge_requests/merge_base_service.rb'
|
||||
- 'ee/app/services/ee/merge_requests/refresh_service.rb'
|
||||
- 'ee/app/services/ee/projects/create_service.rb'
|
||||
|
|
|
|||
|
|
@ -93,7 +93,6 @@ Style/IfUnlessModifier:
|
|||
- 'app/services/concerns/merge_requests/assigns_merge_params.rb'
|
||||
- 'app/services/dependency_proxy/group_settings/update_service.rb'
|
||||
- 'app/services/dependency_proxy/image_ttl_group_policies/update_service.rb'
|
||||
- 'app/services/design_management/copy_design_collection/queue_service.rb'
|
||||
- 'app/services/discussions/resolve_service.rb'
|
||||
- 'app/services/discussions/update_diff_position_service.rb'
|
||||
- 'app/services/draft_notes/create_service.rb'
|
||||
|
|
@ -108,7 +107,6 @@ Style/IfUnlessModifier:
|
|||
- 'app/services/issuable/bulk_update_service.rb'
|
||||
- 'app/services/issuable_base_service.rb'
|
||||
- 'app/services/issuable_links/create_service.rb'
|
||||
- 'app/services/issues/move_service.rb'
|
||||
- 'app/services/issues/relative_position_rebalancing_service.rb'
|
||||
- 'app/services/issues/update_service.rb'
|
||||
- 'app/services/lfs/lock_file_service.rb'
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
db0830c3c2751e55a8a4702cf08ff756f09e7dc8
|
||||
1be1a77766ed02eefd5fc8e64e99e7b69e5ed91b
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
/* eslint-disable no-underscore-dangle,@gitlab/require-i18n-strings,no-console */
|
||||
|
||||
function getPersistedCoverage() {
|
||||
const storedPaths = localStorage.getItem('__coverage_paths__');
|
||||
if (storedPaths) {
|
||||
return JSON.parse(storedPaths);
|
||||
}
|
||||
return [];
|
||||
}
|
||||
|
||||
function getCoverage() {
|
||||
if (!window.__coverage__) {
|
||||
console.warn(
|
||||
'Coverage object is missing on the page. Did you install Istanbul babel plugin and enable Webpack?',
|
||||
);
|
||||
}
|
||||
const filePaths = Object.keys(window.__coverage__);
|
||||
const existingPaths = getPersistedCoverage();
|
||||
return [...new Set([...existingPaths, ...filePaths])];
|
||||
}
|
||||
|
||||
function persistCoverage(coverage = getCoverage()) {
|
||||
localStorage.setItem('__coverage_paths__', JSON.stringify(coverage));
|
||||
console.log(`Coverage paths saved: ${coverage.length} files tracked`);
|
||||
}
|
||||
|
||||
function updateCoverage() {
|
||||
const coverage = getCoverage();
|
||||
persistCoverage(coverage);
|
||||
window.__coverageFilePaths = coverage;
|
||||
}
|
||||
|
||||
window.addEventListener('beforeunload', () => {
|
||||
updateCoverage();
|
||||
});
|
||||
|
||||
window.__coveragePathsPersistence = {
|
||||
update: updateCoverage,
|
||||
getPaths() {
|
||||
return window.__coverageFilePaths || [];
|
||||
},
|
||||
reset() {
|
||||
localStorage.removeItem('__coverage_paths__');
|
||||
window.__coverageFilePaths = [];
|
||||
console.log('Coverage paths reset.');
|
||||
},
|
||||
};
|
||||
|
|
@ -35,22 +35,11 @@ const i18n = {
|
|||
helpString: __('Why am I seeing this warning?'),
|
||||
};
|
||||
|
||||
const redactString = (inputString) => {
|
||||
if (inputString.length <= 9) return inputString;
|
||||
|
||||
const prefix = inputString.substring(0, 5); // Keep the first 5 characters
|
||||
const suffix = inputString.substring(inputString.length - 4); // Keep the last 4 characters
|
||||
const redactLength = Math.min(inputString.length - prefix.length - suffix.length, 22);
|
||||
|
||||
return `${prefix}${'*'.repeat(redactLength)}${suffix}`;
|
||||
};
|
||||
|
||||
const formatMessage = (findings, contentType) => {
|
||||
const header = sprintf(i18n.promptMessage(findings.length), { contentType });
|
||||
|
||||
const matchedPatterns = findings.map(({ patternName, matchedString }) => {
|
||||
const redactedString = redactString(matchedString);
|
||||
return `<li>${escape(patternName)}: ${escape(redactedString)}</li>`;
|
||||
return `<li>${escape(patternName)}: ${escape(matchedString)}</li>`;
|
||||
});
|
||||
|
||||
const message = `
|
||||
|
|
@ -74,10 +63,10 @@ const containsSensitiveToken = (message) => {
|
|||
|
||||
for (const rule of sensitiveDataPatterns()) {
|
||||
const regex = new RegExp(rule.regex, 'gi');
|
||||
const matches = message.match(regex);
|
||||
const uniqueMatches = new Set(message.match(regex));
|
||||
|
||||
if (matches) {
|
||||
matches.forEach((match) => {
|
||||
if (uniqueMatches) {
|
||||
uniqueMatches.forEach((match) => {
|
||||
findings.push({
|
||||
patternName: rule.name,
|
||||
matchedString: match,
|
||||
|
|
|
|||
|
|
@ -16,10 +16,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.oneline {
|
||||
line-height: 35px;
|
||||
}
|
||||
|
||||
.row-content-block {
|
||||
margin-top: 0;
|
||||
@apply gl-bg-subtle;
|
||||
|
|
|
|||
|
|
@ -199,13 +199,9 @@ class Projects::IssuesController < Projects::ApplicationController
|
|||
new_project = Project.find(params[:move_to_project_id])
|
||||
return render_404 unless issue.can_move?(current_user, new_project)
|
||||
|
||||
@issue = if project.work_item_move_and_clone_flag_enabled?
|
||||
::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: new_project.project_namespace
|
||||
).execute[:work_item]
|
||||
else
|
||||
::Issues::MoveService.new(container: project, current_user: current_user).execute(issue, new_project)
|
||||
end
|
||||
@issue = ::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: new_project.project_namespace
|
||||
).execute[:work_item]
|
||||
end
|
||||
|
||||
respond_to do |format|
|
||||
|
|
|
|||
|
|
@ -14,25 +14,16 @@ module Mutations
|
|||
Gitlab::QueryLimiting.disable!('https://gitlab.com/gitlab-org/gitlab/-/issues/20816')
|
||||
|
||||
issue = authorized_find!(project_path: project_path, iid: iid)
|
||||
source_project = issue.project
|
||||
target_project = resolve_project(full_path: target_project_path).sync
|
||||
|
||||
begin
|
||||
moved_issue = if source_project.work_item_move_and_clone_flag_enabled?
|
||||
response = ::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user,
|
||||
target_namespace: target_project.project_namespace
|
||||
).execute
|
||||
response = ::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user,
|
||||
target_namespace: target_project.project_namespace
|
||||
).execute
|
||||
|
||||
errors = response.message if response.error?
|
||||
response.payload[:work_item]
|
||||
else
|
||||
::Issues::MoveService.new(
|
||||
container: source_project, current_user: current_user
|
||||
).execute(issue, target_project)
|
||||
end
|
||||
rescue ::Issues::MoveService::MoveError => e
|
||||
errors = e.message
|
||||
errors = response.message if response.error?
|
||||
moved_issue = response.payload[:work_item]
|
||||
end
|
||||
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,17 +14,17 @@ module Resolvers
|
|||
type ::Types::WorkItems::LinkedItemType.connection_type, null: true
|
||||
|
||||
def resolve_with_lookahead(**args)
|
||||
apply_lookahead(related_work_items(args))
|
||||
if Feature.enabled?(:batch_load_linked_items, work_item.resource_parent, type: :wip)
|
||||
bulk_load_linked_items(args[:filter])
|
||||
else
|
||||
offset_pagination(
|
||||
work_item.linked_work_items(authorize: false, link_type: args[:filter])
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def related_work_items(args)
|
||||
offset_pagination(
|
||||
work_item.linked_work_items(authorize: false, link_type: args[:filter])
|
||||
)
|
||||
end
|
||||
|
||||
def work_item
|
||||
object.is_a?(Issue) ? WorkItem.find_by_id(object.id) : object.work_item
|
||||
end
|
||||
|
|
@ -33,6 +33,34 @@ module Resolvers
|
|||
def node_selection(selection = lookahead)
|
||||
super.selection(:work_item)
|
||||
end
|
||||
|
||||
def bulk_load_linked_items(link_type)
|
||||
# Calculate the current nesting level of linked items in the context path
|
||||
nesting_level = context[:current_path].count('linkedItems')
|
||||
batch_key = "linked_items_level_#{nesting_level}"
|
||||
|
||||
BatchLoader::GraphQL.for(work_item.id).batch(key: batch_key, cache: false) do |item_ids, loader, _args|
|
||||
preloads = [:author, :work_item_type, { project: [:route, { namespace: :route }] }]
|
||||
linked_items = apply_lookahead(WorkItem.linked_items_for(item_ids, preload: preloads, link_type: link_type))
|
||||
grouped_by_source = linked_items_grouped_by_source(linked_items, item_ids)
|
||||
|
||||
# Assign the grouped items to each work item ID in the batch loader
|
||||
item_ids.each do |id|
|
||||
loader.call(id, grouped_by_source[id] || [])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def linked_items_grouped_by_source(linked_items, item_ids)
|
||||
linked_items.each_with_object({}) do |item, result|
|
||||
# Find the ID of the item that this item links to
|
||||
target_id = [item.issue_link_source_id, item.issue_link_target_id].find { |id| id != item.id }
|
||||
next unless item_ids.include?(target_id)
|
||||
|
||||
result[target_id] ||= []
|
||||
result[target_id] << item
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -7,13 +7,10 @@ module Types
|
|||
|
||||
value 'IDLE',
|
||||
description: "Runner is idle.",
|
||||
value: :idle,
|
||||
experiment: { milestone: '15.7' }
|
||||
|
||||
value: :idle
|
||||
value 'ACTIVE',
|
||||
description: 'Runner is busy.',
|
||||
value: :active,
|
||||
experiment: { milestone: '17.2' }
|
||||
value: :active
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -27,8 +27,7 @@ module Types
|
|||
field :job_execution_status,
|
||||
Types::Ci::RunnerJobExecutionStatusEnum,
|
||||
null: true,
|
||||
description: 'Job execution status of the runner manager.',
|
||||
experiment: { milestone: '16.3' }
|
||||
description: 'Job execution status of the runner manager.'
|
||||
field :platform_name, GraphQL::Types::String, null: true,
|
||||
description: 'Platform provided by the runner manager.',
|
||||
method: :platform
|
||||
|
|
|
|||
|
|
@ -61,8 +61,7 @@ module Types
|
|||
field :job_execution_status,
|
||||
Types::Ci::RunnerJobExecutionStatusEnum,
|
||||
null: true,
|
||||
description: 'Job execution status of the runner.',
|
||||
experiment: { milestone: '15.7' }
|
||||
description: 'Job execution status of the runner.'
|
||||
field :jobs, ::Types::Ci::JobInterface.connection_type, null: true,
|
||||
description: 'Jobs assigned to the runner. This field can only be resolved for one runner in any single request.',
|
||||
authorize: :read_builds,
|
||||
|
|
|
|||
|
|
@ -41,10 +41,6 @@ module TreeHelper
|
|||
# `username-branchname-patch-epoch`
|
||||
# where `epoch` is the last 5 digits of the time since epoch (in
|
||||
# milliseconds)
|
||||
#
|
||||
# Note: this correlates with how the WebIDE formats the branch name
|
||||
# and if this implementation changes, so should the `placeholderBranchName`
|
||||
# definition in app/assets/javascripts/ide/stores/modules/commit/getters.js
|
||||
def patch_branch_name(ref)
|
||||
return unless current_user
|
||||
|
||||
|
|
|
|||
|
|
@ -1048,10 +1048,6 @@ class Group < Namespace
|
|||
].compact.min
|
||||
end
|
||||
|
||||
def work_item_move_and_clone_flag_enabled?
|
||||
feature_flag_enabled_for_self_or_ancestor?(:work_item_move_and_clone, type: :beta)
|
||||
end
|
||||
|
||||
def work_items_feature_flag_enabled?
|
||||
feature_flag_enabled_for_self_or_ancestor?(:work_items)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -71,10 +71,6 @@ module Namespaces
|
|||
assign_attributes(attributes_to_sync)
|
||||
end
|
||||
|
||||
def work_item_move_and_clone_flag_enabled?
|
||||
project.work_item_move_and_clone_flag_enabled?
|
||||
end
|
||||
|
||||
# It's always 1 project but it has to be an AR relation
|
||||
def all_projects
|
||||
Project.where(id: project.id)
|
||||
|
|
|
|||
|
|
@ -3367,10 +3367,6 @@ class Project < ApplicationRecord
|
|||
pending_delete? || hidden?
|
||||
end
|
||||
|
||||
def work_item_move_and_clone_flag_enabled?
|
||||
Feature.enabled?(:work_item_move_and_clone, self, type: :beta) || group&.work_item_move_and_clone_flag_enabled?
|
||||
end
|
||||
|
||||
def work_items_feature_flag_enabled?
|
||||
group&.work_items_feature_flag_enabled? || Feature.enabled?(:work_items, self)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -130,6 +130,19 @@ class WorkItem < Issue
|
|||
])
|
||||
end
|
||||
|
||||
def linked_items_for(target_ids, preload: nil, link_type: nil)
|
||||
select_query =
|
||||
select('issues.*,
|
||||
issue_links.id AS issue_link_id,
|
||||
issue_links.link_type AS issue_link_type_value,
|
||||
issue_links.target_id AS issue_link_source_id,
|
||||
issue_links.source_id AS issue_link_target_id,
|
||||
issue_links.created_at AS issue_link_created_at,
|
||||
issue_links.updated_at AS issue_link_updated_at')
|
||||
|
||||
ordered_linked_items(select_query, ids: target_ids, link_type: link_type, preload: preload)
|
||||
end
|
||||
|
||||
override :related_link_class
|
||||
def related_link_class
|
||||
WorkItems::RelatedWorkItemLink
|
||||
|
|
@ -144,6 +157,25 @@ class WorkItem < Issue
|
|||
def non_widgets
|
||||
[:pending_escalations]
|
||||
end
|
||||
|
||||
def ordered_linked_items(select_query, ids: [], link_type: nil, preload: nil)
|
||||
type_condition =
|
||||
if link_type == WorkItems::RelatedWorkItemLink::TYPE_RELATES_TO
|
||||
" AND issue_links.link_type = #{WorkItems::RelatedWorkItemLink.link_types[link_type]}"
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
query_ids = sanitize_sql_array(['?', Array.wrap(ids)])
|
||||
|
||||
select_query
|
||||
.joins("INNER JOIN issue_links ON
|
||||
(issue_links.source_id = issues.id AND issue_links.target_id IN (#{query_ids})#{type_condition})
|
||||
OR
|
||||
(issue_links.target_id = issues.id AND issue_links.source_id IN (#{query_ids})#{type_condition})")
|
||||
.preload(preload)
|
||||
.reorder(linked_items_keyset_order)
|
||||
end
|
||||
end
|
||||
|
||||
def create_dates_source_from_current_dates
|
||||
|
|
@ -254,14 +286,14 @@ class WorkItem < Issue
|
|||
def linked_work_items(current_user = nil, authorize: true, preload: nil, link_type: nil)
|
||||
return [] if new_record?
|
||||
|
||||
linked_work_items = linked_work_items_query(link_type)
|
||||
.preload(preload)
|
||||
.reorder(self.class.linked_items_keyset_order)
|
||||
return linked_work_items unless authorize
|
||||
linked_items =
|
||||
self.class.ordered_linked_items(linked_issues_select, ids: id, link_type: link_type, preload: preload)
|
||||
|
||||
return linked_items unless authorize
|
||||
|
||||
cross_project_filter = ->(work_items) { work_items.where(project: project) }
|
||||
Ability.work_items_readable_by_user(
|
||||
linked_work_items,
|
||||
linked_items,
|
||||
current_user,
|
||||
filters: { read_cross_project: cross_project_filter }
|
||||
)
|
||||
|
|
@ -400,21 +432,6 @@ class WorkItem < Issue
|
|||
end
|
||||
end
|
||||
|
||||
def linked_work_items_query(link_type)
|
||||
type_condition =
|
||||
if link_type == WorkItems::RelatedWorkItemLink::TYPE_RELATES_TO
|
||||
" AND issue_links.link_type = #{WorkItems::RelatedWorkItemLink.link_types[link_type]}"
|
||||
else
|
||||
""
|
||||
end
|
||||
|
||||
linked_issues_select
|
||||
.joins("INNER JOIN issue_links ON
|
||||
(issue_links.source_id = issues.id AND issue_links.target_id = #{id}#{type_condition})
|
||||
OR
|
||||
(issue_links.target_id = issues.id AND issue_links.source_id = #{id}#{type_condition})")
|
||||
end
|
||||
|
||||
def hierarchy_supports_parent?
|
||||
::WorkItems::HierarchyRestriction.find_by_child_type_id(work_item_type_id).present?
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1,42 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
# Service for setting the initial copy_state on the target DesignCollection
|
||||
# and queuing a CopyDesignCollectionWorker.
|
||||
module DesignManagement
|
||||
module CopyDesignCollection
|
||||
class QueueService
|
||||
def initialize(current_user, issue, target_issue)
|
||||
@current_user = current_user
|
||||
@issue = issue
|
||||
@target_issue = target_issue
|
||||
@target_design_collection = target_issue.design_collection
|
||||
end
|
||||
|
||||
def execute
|
||||
return error('User cannot copy designs to issue') unless user_can_copy?
|
||||
return error('Target design collection copy state must be `ready`') unless target_design_collection.can_start_copy?
|
||||
|
||||
target_design_collection.start_copy!
|
||||
|
||||
DesignManagement::CopyDesignCollectionWorker.perform_async(current_user.id, issue.id, target_issue.id)
|
||||
|
||||
ServiceResponse.success
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
delegate :design_collection, to: :issue
|
||||
|
||||
attr_reader :current_user, :issue, :target_design_collection, :target_issue
|
||||
|
||||
def error(message)
|
||||
ServiceResponse.error(message: message)
|
||||
end
|
||||
|
||||
def user_can_copy?
|
||||
current_user.can?(:read_design, issue) &&
|
||||
current_user.can?(:admin_issue, target_issue)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Issues
|
||||
class CloneService < Issuable::Clone::BaseService
|
||||
CloneError = Class.new(StandardError)
|
||||
|
||||
def execute(issue, target_project, with_notes: false)
|
||||
@target_project = target_project
|
||||
@with_notes = with_notes
|
||||
|
||||
verify_can_clone_issue!(issue, target_project)
|
||||
|
||||
super(issue, target_project)
|
||||
|
||||
notify_participants
|
||||
|
||||
queue_copy_designs
|
||||
|
||||
new_entity
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :target_project
|
||||
attr_reader :with_notes
|
||||
|
||||
def verify_can_clone_issue!(issue, target_project)
|
||||
unless issue.supports_move_and_clone?
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issues of \'%{issue_type}\' type.') % { issue_type: issue.issue_type }
|
||||
end
|
||||
|
||||
unless issue.can_clone?(current_user, target_project)
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issue due to insufficient permissions.')
|
||||
end
|
||||
|
||||
if target_project.pending_delete?
|
||||
raise CloneError, s_('CloneIssue|Cannot clone issue to target project as it is pending deletion.')
|
||||
end
|
||||
end
|
||||
|
||||
def update_new_entity
|
||||
# we don't call `super` because we want to be able to decide whether or not to copy all comments over.
|
||||
update_new_entity_description
|
||||
|
||||
if with_notes
|
||||
copy_notes
|
||||
copy_resource_events
|
||||
end
|
||||
end
|
||||
|
||||
def update_old_entity
|
||||
# no-op
|
||||
# The base_service closes the old issue, we don't want that, so we override here so nothing happens.
|
||||
end
|
||||
|
||||
def create_new_entity
|
||||
new_params = {
|
||||
id: nil,
|
||||
iid: nil,
|
||||
relative_position: relative_position,
|
||||
project: target_project,
|
||||
author: current_user,
|
||||
assignee_ids: original_entity.assignee_ids
|
||||
}
|
||||
|
||||
new_params = original_entity.serializable_hash.symbolize_keys.except(:project_id, :author_id).merge(new_params)
|
||||
new_params = new_params.merge(rewritten_old_entity_attributes)
|
||||
new_params.delete(:imported_from)
|
||||
new_params.delete(:created_at)
|
||||
new_params.delete(:updated_at)
|
||||
|
||||
# spam checking is not necessary, as no new content is being created.
|
||||
|
||||
# Skip creation of system notes for existing attributes of the issue when cloning with notes.
|
||||
# The system notes of the old issue are copied over so we don't want to end up with duplicate notes.
|
||||
# When cloning without notes, we want to generate system notes for the attributes that were copied.
|
||||
create_result = CreateService.new(
|
||||
container: target_project,
|
||||
current_user: current_user,
|
||||
params: new_params,
|
||||
perform_spam_check: false
|
||||
).execute(skip_system_notes: with_notes)
|
||||
|
||||
raise CloneError, create_result.errors.join(', ') if create_result.error? && create_result[:issue].blank?
|
||||
|
||||
create_result[:issue]
|
||||
end
|
||||
|
||||
def queue_copy_designs
|
||||
return unless original_entity.designs.present?
|
||||
|
||||
response = DesignManagement::CopyDesignCollection::QueueService.new(
|
||||
current_user,
|
||||
original_entity,
|
||||
new_entity
|
||||
).execute
|
||||
|
||||
log_error(response.message) if response.error?
|
||||
end
|
||||
|
||||
def notify_participants
|
||||
notification_service.async.issue_cloned(original_entity, new_entity, current_user)
|
||||
end
|
||||
|
||||
def add_note_from
|
||||
SystemNoteService.noteable_cloned(
|
||||
new_entity,
|
||||
target_project,
|
||||
original_entity,
|
||||
current_user,
|
||||
direction: :from,
|
||||
created_at: new_entity.created_at
|
||||
)
|
||||
end
|
||||
|
||||
def add_note_to
|
||||
SystemNoteService.noteable_cloned(original_entity, old_project,
|
||||
new_entity, current_user,
|
||||
direction: :to)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Issues::CloneService.prepend_mod_with('Issues::CloneService')
|
||||
|
|
@ -1,224 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Issues
|
||||
class MoveService < Issuable::Clone::BaseService
|
||||
extend ::Gitlab::Utils::Override
|
||||
|
||||
BATCH_SIZE = 100
|
||||
|
||||
MoveError = Class.new(StandardError)
|
||||
|
||||
def execute(issue, target_project, move_any_issue_type = false)
|
||||
@move_any_issue_type = move_any_issue_type
|
||||
@target_project = target_project
|
||||
|
||||
verify_can_move_issue!(issue, target_project)
|
||||
|
||||
super(issue, target_project)
|
||||
|
||||
notify_participants
|
||||
|
||||
# Updates old issue sent notifications allowing
|
||||
# to receive service desk emails on the new moved issue.
|
||||
update_service_desk_sent_notifications
|
||||
|
||||
copy_email_participants
|
||||
queue_copy_designs
|
||||
copy_timelogs
|
||||
|
||||
new_entity
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :target_project, :move_any_issue_type
|
||||
|
||||
override :after_clone_actions
|
||||
def after_clone_actions
|
||||
move_children
|
||||
end
|
||||
|
||||
def move_children
|
||||
WorkItems::ParentLink.for_parents(original_entity).each do |link|
|
||||
new_child = self.class.new(
|
||||
container: container,
|
||||
current_user: current_user
|
||||
).execute(
|
||||
::Issue.find(link.work_item_id),
|
||||
target_project,
|
||||
true
|
||||
)
|
||||
|
||||
WorkItems::ParentLink.create!(work_item_id: new_child.id, work_item_parent_id: new_entity.id)
|
||||
end
|
||||
end
|
||||
|
||||
def verify_can_move_issue!(issue, target_project)
|
||||
unless issue.supports_move_and_clone? || move_any_issue_type
|
||||
raise MoveError, s_('MoveIssue|Cannot move issues of \'%{issue_type}\' type.') % { issue_type: issue.issue_type }
|
||||
end
|
||||
|
||||
unless issue.can_move?(current_user, @target_project)
|
||||
raise MoveError, s_('MoveIssue|Cannot move issue due to insufficient permissions.')
|
||||
end
|
||||
|
||||
if @project == @target_project
|
||||
raise MoveError, s_('MoveIssue|Cannot move issue to project it originates from.')
|
||||
end
|
||||
end
|
||||
|
||||
def update_service_desk_sent_notifications
|
||||
context = { project_id: new_entity.project_id, noteable_id: new_entity.id }
|
||||
|
||||
original_entity.run_after_commit_or_now do
|
||||
next unless from_service_desk?
|
||||
|
||||
sent_notifications.update_all(**context)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_email_participants
|
||||
new_attributes = { id: nil, issue_id: new_entity.id }
|
||||
|
||||
new_participants = original_entity.issue_email_participants.dup
|
||||
|
||||
new_participants.each do |participant|
|
||||
participant.assign_attributes(new_attributes)
|
||||
end
|
||||
|
||||
IssueEmailParticipant.bulk_insert!(new_participants)
|
||||
end
|
||||
|
||||
override :update_old_entity
|
||||
def update_old_entity
|
||||
super
|
||||
|
||||
recreate_related_issues
|
||||
mark_as_moved
|
||||
end
|
||||
|
||||
override :update_new_entity
|
||||
def update_new_entity
|
||||
super
|
||||
|
||||
copy_contacts
|
||||
end
|
||||
|
||||
def create_new_entity
|
||||
new_params = {
|
||||
id: nil,
|
||||
iid: nil,
|
||||
relative_position: relative_position,
|
||||
project: target_project,
|
||||
author: original_entity.author,
|
||||
assignee_ids: original_entity.assignee_ids,
|
||||
moved_issue: true,
|
||||
imported_from: :none
|
||||
}
|
||||
|
||||
new_params = original_entity.serializable_hash.symbolize_keys.merge(new_params)
|
||||
new_params = new_params.merge(rewritten_old_entity_attributes)
|
||||
# spam checking is not necessary, as no new content is being created.
|
||||
|
||||
# Skip creation of system notes for existing attributes of the issue. The system notes of the old
|
||||
# issue are copied over so we don't want to end up with duplicate notes.
|
||||
create_result = CreateService.new(
|
||||
container: @target_project,
|
||||
current_user: @current_user,
|
||||
params: new_params,
|
||||
perform_spam_check: false
|
||||
).execute(skip_system_notes: true)
|
||||
|
||||
raise MoveError, create_result.errors.join(', ') if create_result.error? && create_result[:issue].blank?
|
||||
|
||||
create_result[:issue]
|
||||
end
|
||||
|
||||
def queue_copy_designs
|
||||
return unless original_entity.designs.present?
|
||||
|
||||
response = DesignManagement::CopyDesignCollection::QueueService.new(
|
||||
current_user,
|
||||
original_entity,
|
||||
new_entity
|
||||
).execute
|
||||
|
||||
log_error(response.message) if response.error?
|
||||
end
|
||||
|
||||
def copy_timelogs
|
||||
return if original_entity.timelogs.empty?
|
||||
|
||||
WorkItems::CopyTimelogsWorker.perform_async(original_entity.id, new_entity.id)
|
||||
end
|
||||
|
||||
def mark_as_moved
|
||||
original_entity.update(moved_to: new_entity)
|
||||
end
|
||||
|
||||
def recreate_related_issues
|
||||
source_issue_links = IssueLink.for_source(original_entity)
|
||||
target_issue_links = IssueLink.for_target(original_entity)
|
||||
|
||||
source_issue_links.each_batch(of: BATCH_SIZE) do |links_batch|
|
||||
new_links = new_links(links_batch, reference_attribute: 'source_id')
|
||||
::IssueLink.insert_all!(new_links) if new_links.any?
|
||||
end
|
||||
|
||||
target_issue_links.each_batch(of: BATCH_SIZE) do |links_batch|
|
||||
new_links = new_links(links_batch, reference_attribute: 'target_id')
|
||||
::IssueLink.insert_all!(new_links) if new_links.any?
|
||||
end
|
||||
|
||||
source_issue_links.each_batch(of: BATCH_SIZE) do |links_batch|
|
||||
links_batch.delete_all
|
||||
end
|
||||
|
||||
target_issue_links.each_batch(of: BATCH_SIZE) do |links_batch|
|
||||
links_batch.delete_all
|
||||
end
|
||||
end
|
||||
|
||||
def new_links(links_batch, reference_attribute:)
|
||||
links_batch.map do |link|
|
||||
link.attributes.except('id', 'namespace_id').merge(reference_attribute => new_entity.id)
|
||||
end
|
||||
end
|
||||
|
||||
def copy_contacts
|
||||
return unless original_entity.project.root_ancestor == new_entity.project.root_ancestor
|
||||
|
||||
new_entity.customer_relations_contacts = original_entity.customer_relations_contacts
|
||||
end
|
||||
|
||||
def notify_participants
|
||||
context = { original: original_entity, new: new_entity, user: @current_user, service: notification_service }
|
||||
|
||||
original_entity.run_after_commit_or_now do
|
||||
context[:service].async.issue_moved(context[:original], context[:new], context[:user])
|
||||
end
|
||||
end
|
||||
|
||||
def add_note_from
|
||||
SystemNoteService.noteable_moved(
|
||||
new_entity,
|
||||
target_project,
|
||||
original_entity,
|
||||
current_user,
|
||||
direction: :from
|
||||
)
|
||||
end
|
||||
|
||||
def add_note_to
|
||||
SystemNoteService.noteable_moved(
|
||||
original_entity,
|
||||
old_project,
|
||||
new_entity,
|
||||
current_user,
|
||||
direction: :to
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Issues::MoveService.prepend_mod_with('Issues::MoveService')
|
||||
|
|
@ -103,16 +103,11 @@ module Issues
|
|||
|
||||
update(issue)
|
||||
|
||||
if container.work_item_move_and_clone_flag_enabled?
|
||||
move_service_container = target_container.is_a?(Project) ? target_container.project_namespace : target_container
|
||||
::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: move_service_container
|
||||
).execute[:work_item]
|
||||
elsif target_container.is_a?(Project) || target_container.is_a?(Namespaces::ProjectNamespace)
|
||||
::Issues::MoveService.new(
|
||||
container: project, current_user: current_user
|
||||
).execute(issue, target_container)
|
||||
end
|
||||
move_service_container = target_container.is_a?(Project) ? target_container.project_namespace : target_container
|
||||
|
||||
::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: move_service_container
|
||||
).execute[:work_item]
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -157,17 +152,12 @@ module Issues
|
|||
# we've pre-empted this from running in #execute, so let's go ahead and update the Issue now.
|
||||
update(issue)
|
||||
|
||||
if container.work_item_move_and_clone_flag_enabled?
|
||||
clone_service_container = target_container.is_a?(Project) ? target_container.project_namespace : target_container
|
||||
::WorkItems::DataSync::CloneService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: clone_service_container,
|
||||
params: { clone_with_notes: with_notes }
|
||||
).execute[:work_item]
|
||||
elsif target_container.is_a?(Project) || target_container.is_a?(Namespaces::ProjectNamespace)
|
||||
Issues::CloneService.new(container: project, current_user: current_user).execute(
|
||||
issue, target_container, with_notes: with_notes
|
||||
)
|
||||
end
|
||||
clone_service_container = target_container.is_a?(Project) ? target_container.project_namespace : target_container
|
||||
|
||||
::WorkItems::DataSync::CloneService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: clone_service_container,
|
||||
params: { clone_with_notes: with_notes }
|
||||
).execute[:work_item]
|
||||
end
|
||||
|
||||
def create_merge_request_from_quick_action
|
||||
|
|
|
|||
|
|
@ -65,6 +65,9 @@
|
|||
|
||||
= webpack_bundle_tag 'super_sidebar'
|
||||
|
||||
- if ENV['BABEL_ENV'] == 'istanbul'
|
||||
= webpack_bundle_tag 'coverage_persistence'
|
||||
|
||||
- if vite_enabled?
|
||||
= render 'layouts/vite_main'
|
||||
- else
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ const plugins = [
|
|||
'@babel/plugin-transform-class-static-block',
|
||||
];
|
||||
|
||||
const env = {};
|
||||
// Jest is running in node environment
|
||||
const isJest = Boolean(process.env.JEST_WORKER_ID);
|
||||
if (isJest) {
|
||||
|
|
@ -40,6 +41,22 @@ if (isJest) {
|
|||
},
|
||||
],
|
||||
];
|
||||
} else {
|
||||
env.istanbul = {
|
||||
plugins: [
|
||||
[
|
||||
'istanbul',
|
||||
{
|
||||
extension: ['.js', '.vue', '.mjs', '.cjs'],
|
||||
},
|
||||
],
|
||||
],
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = { presets, plugins, sourceType: 'unambiguous' };
|
||||
module.exports = {
|
||||
presets,
|
||||
plugins,
|
||||
sourceType: 'unambiguous',
|
||||
env,
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
name: work_item_move_and_clone
|
||||
feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/15470
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/179494
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/525524
|
||||
milestone: '17.10'
|
||||
group: group::project management
|
||||
type: beta
|
||||
default_enabled: true
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
---
|
||||
name: allow_organization_creation
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/441531
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/147930
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/452062
|
||||
milestone: '16.11'
|
||||
type: development
|
||||
type: wip
|
||||
group: group::organizations
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: batch_load_linked_items
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/512056
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/189332
|
||||
rollout_issue_url:
|
||||
milestone: '18.0'
|
||||
group: group::product planning
|
||||
type: wip
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
---
|
||||
name: edit_user_profile_vue
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/389918
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122402
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414552
|
||||
milestone: '16.1'
|
||||
type: development
|
||||
type: wip
|
||||
group: group::organizations
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
---
|
||||
name: explore_topics_cleaned_path
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/393166
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122970
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414793
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414892
|
||||
milestone: '16.1'
|
||||
type: development
|
||||
type: wip
|
||||
group: group::organizations
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
---
|
||||
name: optional_personal_namespace
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/427730
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/137713
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/431978
|
||||
milestone: '16.8'
|
||||
type: development
|
||||
type: wip
|
||||
group: group::organizations
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
---
|
||||
name: profile_tabs_vue
|
||||
feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/9056
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/109422
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/388708
|
||||
milestone: '15.9'
|
||||
type: development
|
||||
type: wip
|
||||
group: group::organizations
|
||||
default_enabled: false
|
||||
|
|
@ -1,8 +1,9 @@
|
|||
---
|
||||
name: ui_for_organizations
|
||||
feature_issue_url: https://gitlab.com/groups/gitlab-org/-/epics/17432
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/122866
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/414592
|
||||
milestone: '16.1'
|
||||
type: development
|
||||
type: wip
|
||||
group: group::organizations
|
||||
default_enabled: false
|
||||
|
|
@ -278,6 +278,7 @@ module.exports = {
|
|||
return {
|
||||
default: defaultEntries,
|
||||
sentry: './sentry/index.js',
|
||||
coverage_persistence: './entrypoints/coverage_persistence.js',
|
||||
performance_bar: './entrypoints/performance_bar.js',
|
||||
jira_connect_app: './jira_connect/subscriptions/index.js',
|
||||
sandboxed_mermaid: './lib/mermaid.js',
|
||||
|
|
|
|||
|
|
@ -0,0 +1,8 @@
|
|||
---
|
||||
migration_job_name: MarkAdminBotRunnersAsHosted
|
||||
description: Mark runners created by admin bot as hosted on GitLab Dedicated
|
||||
feature_category: hosted_runners
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/183329
|
||||
milestone: '18.0'
|
||||
queued_migration_version: 20250505095336
|
||||
finalized_by: # version of the migration that finalized this BBM
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class QueueMarkAdminBotRunnersAsHosted < Gitlab::Database::Migration[2.3]
|
||||
milestone '18.0'
|
||||
|
||||
# Select the applicable gitlab schema for your batched background migration
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_ci
|
||||
|
||||
MIGRATION = "MarkAdminBotRunnersAsHosted"
|
||||
DELAY_INTERVAL = 2.minutes
|
||||
BATCH_SIZE = 1000
|
||||
SUB_BATCH_SIZE = 100
|
||||
|
||||
def up
|
||||
queue_batched_background_migration(
|
||||
MIGRATION,
|
||||
:ci_runners,
|
||||
:id,
|
||||
job_interval: DELAY_INTERVAL,
|
||||
batch_size: BATCH_SIZE,
|
||||
sub_batch_size: SUB_BATCH_SIZE
|
||||
)
|
||||
end
|
||||
|
||||
def down
|
||||
delete_batched_background_migration(MIGRATION, :ci_runners, :id, [])
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
75166bbf5d04065b48b810200cada005c73109b8da8ccebc6ed9f3195951928a
|
||||
|
|
@ -200,9 +200,9 @@ gitlab:
|
|||
memory: 32Mi
|
||||
```
|
||||
|
||||
#### Configure concurrency rate limiting
|
||||
#### Configure concurrency limiting
|
||||
|
||||
As well as using cgroups, you can use concurrency limits to further help protect the service from abnormal traffic patterns. For more information, see
|
||||
You can use concurrency limits to help protect the service from abnormal traffic patterns. For more information, see
|
||||
[concurrency configuration documentation](concurrency_limiting.md) and [how to monitor limits](monitoring.md#monitor-gitaly-concurrency-limiting).
|
||||
|
||||
#### Isolate Gitaly pods
|
||||
|
|
|
|||
|
|
@ -16,22 +16,19 @@ Metric definitions are available:
|
|||
|
||||
<!--- start_remove The following content will be removed on remove_date: '2025-08-01' -->
|
||||
|
||||
## Monitor Gitaly rate limiting (deprecated)
|
||||
## Monitor Gitaly rate limiting (removed)
|
||||
|
||||
{{< alert type="warning" >}}
|
||||
|
||||
This feature was [deprecated](https://gitlab.com/gitlab-org/gitaly/-/issues/5011) in GitLab 17.7
|
||||
and is planned for removal in 18.0. Use [concurrency limiting](concurrency_limiting.md) instead.
|
||||
and was removed in 18.0. Use [concurrency limiting](concurrency_limiting.md) instead.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
Gitaly can be configured to limit requests based on:
|
||||
|
||||
- Concurrency of requests.
|
||||
- A rate limit.
|
||||
|
||||
<!--- end_remove -->
|
||||
|
||||
Gitaly can be configured to limit requests based on concurrency of requests (adaptive or non-adaptive).
|
||||
|
||||
## Monitor Gitaly concurrency limiting
|
||||
|
||||
You can observe specific behavior of [concurrency-queued requests](concurrency_limiting.md#limit-rpc-concurrency) using Gitaly logs and Prometheus.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Get started with GitLab Duo Self-Hosted.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Get started with GitLab Duo Self-Hosted.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Configure your GitLab instance to use GitLab Duo Self-Hosted.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Enable logging for self-hosted models.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Supported LLM Serving Platforms.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Supported models and hardware requirements.
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Troubleshooting tips for deploying GitLab Duo Self-Hosted
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Custom Models
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Self-Hosted model setup Related topics
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: Duo Chat
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Documentation for the REST API for Duo Chat.
|
||||
|
|
|
|||
|
|
@ -23156,7 +23156,7 @@ CI/CD variables for a project.
|
|||
| <a id="cirunnerephemeralregisterurl"></a>`ephemeralRegisterUrl` {{< icon name="warning-solid" >}} | [`String`](#string) | **Introduced** in GitLab 15.11. **Status**: Experiment. URL of the registration page of the runner manager. Only available for the creator of the runner for a limited time during registration. |
|
||||
| <a id="cirunnergroups"></a>`groups` | [`GroupInterfaceConnection`](#groupinterfaceconnection) | Groups the runner is associated with. For group runners only. (see [Connections](#connections)) |
|
||||
| <a id="cirunnerid"></a>`id` | [`CiRunnerID!`](#cirunnerid) | ID of the runner. |
|
||||
| <a id="cirunnerjobexecutionstatus"></a>`jobExecutionStatus` {{< icon name="warning-solid" >}} | [`CiRunnerJobExecutionStatus`](#cirunnerjobexecutionstatus) | **Introduced** in GitLab 15.7. **Status**: Experiment. Job execution status of the runner. |
|
||||
| <a id="cirunnerjobexecutionstatus"></a>`jobExecutionStatus` | [`CiRunnerJobExecutionStatus`](#cirunnerjobexecutionstatus) | Job execution status of the runner. |
|
||||
| <a id="cirunnerlocked"></a>`locked` | [`Boolean`](#boolean) | Indicates the runner is locked. |
|
||||
| <a id="cirunnermaintenancenote"></a>`maintenanceNote` | [`String`](#string) | Runner's maintenance notes. |
|
||||
| <a id="cirunnermaintenancenotehtml"></a>`maintenanceNoteHtml` | [`String`](#string) | GitLab Flavored Markdown rendering of `maintenance_note`. |
|
||||
|
|
@ -23335,7 +23335,7 @@ Returns [`[CiRunnerCloudProvisioningStep!]`](#cirunnercloudprovisioningstep).
|
|||
| <a id="cirunnermanagerexecutorname"></a>`executorName` | [`String`](#string) | Executor last advertised by the runner. |
|
||||
| <a id="cirunnermanagerid"></a>`id` | [`CiRunnerManagerID!`](#cirunnermanagerid) | ID of the runner manager. |
|
||||
| <a id="cirunnermanageripaddress"></a>`ipAddress` | [`String`](#string) | IP address of the runner manager. |
|
||||
| <a id="cirunnermanagerjobexecutionstatus"></a>`jobExecutionStatus` {{< icon name="warning-solid" >}} | [`CiRunnerJobExecutionStatus`](#cirunnerjobexecutionstatus) | **Introduced** in GitLab 16.3. **Status**: Experiment. Job execution status of the runner manager. |
|
||||
| <a id="cirunnermanagerjobexecutionstatus"></a>`jobExecutionStatus` | [`CiRunnerJobExecutionStatus`](#cirunnerjobexecutionstatus) | Job execution status of the runner manager. |
|
||||
| <a id="cirunnermanagerplatformname"></a>`platformName` | [`String`](#string) | Platform provided by the runner manager. |
|
||||
| <a id="cirunnermanagerrevision"></a>`revision` | [`String`](#string) | Revision of the runner. |
|
||||
| <a id="cirunnermanagerrunner"></a>`runner` | [`CiRunner`](#cirunner) | Runner configuration for the runner manager. |
|
||||
|
|
@ -42827,8 +42827,8 @@ Runner cloud provider.
|
|||
|
||||
| Value | Description |
|
||||
| ----- | ----------- |
|
||||
| <a id="cirunnerjobexecutionstatusactive"></a>`ACTIVE` {{< icon name="warning-solid" >}} | **Introduced** in GitLab 17.2. **Status**: Experiment. Runner is busy. |
|
||||
| <a id="cirunnerjobexecutionstatusidle"></a>`IDLE` {{< icon name="warning-solid" >}} | **Introduced** in GitLab 15.7. **Status**: Experiment. Runner is idle. |
|
||||
| <a id="cirunnerjobexecutionstatusactive"></a>`ACTIVE` | Runner is busy. |
|
||||
| <a id="cirunnerjobexecutionstatusidle"></a>`IDLE` | Runner is idle. |
|
||||
|
||||
### `CiRunnerMembershipFilter`
|
||||
|
||||
|
|
@ -48896,6 +48896,7 @@ Field that are available while modifying the custom mapping attributes for an HT
|
|||
| <a id="boardissueinputor"></a>`or` | [`UnionedIssueFilterInput`](#unionedissuefilterinput) | List of arguments with inclusive OR. |
|
||||
| <a id="boardissueinputreleasetag"></a>`releaseTag` | [`String`](#string) | Filter by release tag. |
|
||||
| <a id="boardissueinputsearch"></a>`search` | [`String`](#string) | Search query for issue title or description. |
|
||||
| <a id="boardissueinputstatus"></a>`status` {{< icon name="warning-solid" >}} | [`WorkItemWidgetStatusFilterInput`](#workitemwidgetstatusfilterinput) | **Deprecated:** **Status**: Experiment. Introduced in GitLab 18.0. |
|
||||
| <a id="boardissueinputtypes"></a>`types` | [`[IssueType!]`](#issuetype) | Filter by the given issue types. |
|
||||
| <a id="boardissueinputweight"></a>`weight` | [`String`](#string) | Filter by weight. |
|
||||
| <a id="boardissueinputweightwildcardid"></a>`weightWildcardId` | [`WeightWildcardId`](#weightwildcardid) | Filter by weight ID wildcard. Incompatible with weight. |
|
||||
|
|
|
|||
|
|
@ -941,6 +941,44 @@ path.Clean("../../etc/passwd")
|
|||
// renders the path to "../../etc/passwd"; the file path will look back up to two parent directories!
|
||||
```
|
||||
|
||||
#### Safe File Operations in Go
|
||||
|
||||
The Go standard library provides basic file operations like `os.Open`, `os.ReadFile`, `os.WriteFile`, and `os.Readlink`. However, these functions do not prevent path traversal attacks, where user-supplied paths can escape the intended directory and access sensitive system files.
|
||||
|
||||
Example of unsafe usage:
|
||||
|
||||
```go
|
||||
// Vulnerable: user input is directly used in the path
|
||||
os.Open(filepath.Join("/app/data", userInput))
|
||||
os.ReadFile(filepath.Join("/app/data", userInput))
|
||||
os.WriteFile(filepath.Join("/app/data", userInput), []byte("data"), 0644)
|
||||
os.Readlink(filepath.Join("/app/data", userInput))
|
||||
```
|
||||
|
||||
To mitigate these risks, use the [`safeopen`](https://pkg.go.dev/github.com/google/safeopen) library functions. These functions enforce a secure root directory and sanitize file paths:
|
||||
|
||||
Example of safe usage:
|
||||
|
||||
```go
|
||||
safeopen.OpenBeneath("/app/data", userInput)
|
||||
safeopen.ReadFileBeneath("/app/data", userInput)
|
||||
safeopen.WriteFileBeneath("/app/data", []byte("data"), 0644)
|
||||
safeopen.ReadlinkBeneath("/app/data", userInput)
|
||||
```
|
||||
|
||||
Benefits:
|
||||
|
||||
- Prevents path traversal attacks (`../` sequences).
|
||||
- Restricts file operations to trusted root directories.
|
||||
- Secures against unauthorized file reads, writes, and symlink resolutions.
|
||||
- Provides simple, developer-friendly replacements.
|
||||
|
||||
References:
|
||||
|
||||
- [Go Standard Library os Package](https://pkg.go.dev/os)
|
||||
- [Safe Go Libraries Announcement](https://bughunters.google.com/blog/4925068200771584/the-family-of-safe-golang-libraries-is-growing)
|
||||
- [OWASP Path Traversal Cheat Sheet](https://owasp.org/www-community/attacks/Path_Traversal)
|
||||
|
||||
## OS command injection guidelines
|
||||
|
||||
Command injection is an issue in which an attacker is able to execute arbitrary commands on the host
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
---
|
||||
stage: AI-Powered
|
||||
stage: AI-powered
|
||||
group: AI Framework
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
description: Set up your self-hosted model GitLab AI gateway
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ This table shows the features available with the Jira issues integration and the
|
|||
| [View a list of Jira issues](configure.md#view-jira-issues). | {{< icon name="check-circle" >}} Yes | {{< icon name="dotted-circle" >}} No |
|
||||
| [Create a Jira issue for a vulnerability](configure.md#create-a-jira-issue-for-a-vulnerability). | {{< icon name="check-circle" >}} Yes | {{< icon name="dotted-circle" >}} No |
|
||||
| Create a GitLab branch from a Jira issue. | {{< icon name="dotted-circle" >}} No | {{< icon name="check-circle" >}} Yes, in the Jira issue's development panel. |
|
||||
| Mention a Jira issue ID in a GitLab merge request, branch name, or any of the last 5,000 commits to the branch after the last successful deployment to the environment to sync a GitLab deployment to a Jira issue. | {{< icon name="dotted-circle" >}} No | {{< icon name="check-circle" >}} Yes, in the Jira issue's development panel. |
|
||||
| Mention a Jira issue ID in a GitLab merge request, branch name, or any of the last 2,000 commits to the branch after the last successful deployment to the environment to sync a GitLab deployment to a Jira issue. | {{< icon name="dotted-circle" >}} No | {{< icon name="check-circle" >}} Yes, in the Jira issue's development panel. |
|
||||
|
||||
## Privacy considerations
|
||||
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ For the [GitLab for Jira Cloud app](connect-app.md), the following information i
|
|||
|---------------------------------------------|-------------------------------------------------------|
|
||||
| Merge request title or description | Link to the merge request<br>Link to the deployment<br>Link to the pipeline through the merge request title<br>Link to the pipeline through the merge request description ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/390888) in GitLab 15.10)<br>Link to the branch ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/354373) in GitLab 15.11)<br>Reviewer information and approval status ([introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/364273) in GitLab 16.5) |
|
||||
| Branch name | Link to the branch<br>Link to the deployment |
|
||||
| Commit message | Link to the commit<br>Link to the deployment from up to 5,000 commits after the last successful deployment to the environment <sup>1</sup> <sup>2</sup> |
|
||||
| Commit message | Link to the commit<br>Link to the deployment from up to 2,000 commits after the last successful deployment to the environment <sup>1</sup> <sup>2</sup> |
|
||||
| [Jira Smart Commit](#jira-smart-commits) | Custom comment, logged time, or workflow transition |
|
||||
|
||||
**Footnotes:**
|
||||
|
|
|
|||
|
|
@ -79,7 +79,7 @@ Details of each dependency are listed, sorted by decreasing severity of vulnerab
|
|||
| Packager | The packager used to install the dependency. |
|
||||
| Location | For system dependencies, this field lists the image that was scanned. For application dependencies, this field shows a link to the packager-specific lock file in your project that declared the dependency. It also shows the direct [dependents](#dependency-paths), if any. If there are transitive dependencies, selecting **View dependency paths** shows the full path of all dependents. Transitive dependencies are indirect dependents that have a direct dependent as an ancestor. |
|
||||
| License (for projects only) | Links to dependency's software licenses. A warning badge that includes the number of vulnerabilities detected in the dependency. |
|
||||
| Projects (for groups only) | Links to the project with the dependency. If multiple projects have the same dependency, the total number of these projects is shown. To go to a project with this dependency, select the **Projects** number, then search for and select its name. The project search feature is supported only on groups that have up to 600 occurrences in their group hierarchy. |
|
||||
| Projects (for groups only) | Links to the project with the dependency. If multiple projects have the same dependency, the total number of these projects is shown. To go to a project with this dependency, select the **Projects** number, then search for and select its name. |
|
||||
|
||||
## Filter dependency list
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ If this does not work, you can also check the following troubleshooting document
|
|||
- [Microsoft Visual Studio](../../editor_extensions/visual_studio/visual_studio_troubleshooting.md).
|
||||
- [JetBrains IDEs](../../editor_extensions/jetbrains_ide/jetbrains_troubleshooting.md).
|
||||
- [Neovim](../../editor_extensions/neovim/neovim_troubleshooting.md).
|
||||
- [Eclipse](../../editor_extensions/eclipse/troubleshooting.md).
|
||||
- [Troubleshooting GitLab Duo](../gitlab_duo/troubleshooting.md).
|
||||
- [Troubleshooting GitLab Duo Self-Hosted](../../administration/gitlab_duo_self_hosted/troubleshooting.md).
|
||||
|
||||
|
|
|
|||
|
|
@ -53,12 +53,8 @@ default:
|
|||
- bundle config # Show bundler configuration
|
||||
- bundle install --jobs=$(nproc) --retry=3
|
||||
after_script:
|
||||
# We need this at the very top, because the section_start/section_end logic is defined there.
|
||||
- source $CI_PROJECT_DIR/scripts/utils.sh
|
||||
- |
|
||||
section_start "failure-analyzer" "Report failure category"
|
||||
$CI_PROJECT_DIR/tooling/lib/tooling/glci/failure_analyzer.rb $CI_JOB_ID || true
|
||||
section_end "failure-analyzer"
|
||||
- execute_failure_analyzer
|
||||
|
||||
.ruby_matrix:
|
||||
parallel:
|
||||
|
|
|
|||
|
|
@ -53,12 +53,8 @@ include:
|
|||
- bundle config # Show bundler configuration
|
||||
- bundle install --jobs=$(nproc) --retry=3
|
||||
after_script:
|
||||
# We need this at the very top, because the section_start/section_end logic is defined there.
|
||||
- source $CI_PROJECT_DIR/scripts/utils.sh
|
||||
- |
|
||||
section_start "failure-analyzer" "Report failure category"
|
||||
$CI_PROJECT_DIR/tooling/lib/tooling/glci/failure_analyzer.rb $CI_JOB_ID || true
|
||||
section_end "failure-analyzer"
|
||||
- execute_failure_analyzer
|
||||
|
||||
default:
|
||||
<<: *default
|
||||
|
|
|
|||
|
|
@ -381,23 +381,15 @@ module API
|
|||
not_found!('Project') unless new_project
|
||||
|
||||
begin
|
||||
issue = if user_project.work_item_move_and_clone_flag_enabled?
|
||||
response = ::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: new_project.project_namespace
|
||||
).execute
|
||||
response = ::WorkItems::DataSync::MoveService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: new_project.project_namespace
|
||||
).execute
|
||||
|
||||
render_api_error!(response.message, 400) if response.error?
|
||||
render_api_error!(response.message, 400) if response.error?
|
||||
|
||||
response.payload[:work_item]
|
||||
else
|
||||
::Issues::MoveService.new(
|
||||
container: user_project, current_user: current_user
|
||||
).execute(issue, new_project)
|
||||
end
|
||||
issue = response.payload[:work_item]
|
||||
|
||||
present issue, with: Entities::Issue, current_user: current_user, project: user_project
|
||||
rescue ::Issues::MoveService::MoveError => error
|
||||
render_api_error!(error.message, 400)
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
@ -421,23 +413,16 @@ module API
|
|||
not_found!('Project') unless target_project
|
||||
|
||||
begin
|
||||
issue = if user_project.work_item_move_and_clone_flag_enabled?
|
||||
response = ::WorkItems::DataSync::CloneService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: target_project.project_namespace,
|
||||
params: { clone_with_notes: params[:with_notes] }
|
||||
).execute
|
||||
response = ::WorkItems::DataSync::CloneService.new(
|
||||
work_item: issue, current_user: current_user, target_namespace: target_project.project_namespace,
|
||||
params: { clone_with_notes: params[:with_notes] }
|
||||
).execute
|
||||
|
||||
render_api_error!(response.message, 400) if response.error?
|
||||
render_api_error!(response.message, 400) if response.error?
|
||||
|
||||
response.payload[:work_item]
|
||||
else
|
||||
::Issues::CloneService.new(container: user_project, current_user: current_user)
|
||||
.execute(issue, target_project, with_notes: params[:with_notes])
|
||||
end
|
||||
issue = response.payload[:work_item]
|
||||
|
||||
present issue, with: Entities::Issue, current_user: current_user, project: target_project
|
||||
rescue ::Issues::CloneService::CloneError => error
|
||||
render_api_error!(error.message, 400)
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@ module Atlassian
|
|||
include Gitlab::Routing
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
COMMITS_LIMIT = 5_000
|
||||
COMMITS_LIMIT = 2000
|
||||
ISSUE_KEY_LIMIT = 500
|
||||
|
||||
format_with(:iso8601, &:iso8601)
|
||||
|
||||
|
|
@ -26,7 +27,8 @@ module Atlassian
|
|||
expose :generate_deployment_commands_from_integration_configuration, as: :commands
|
||||
|
||||
def issue_keys
|
||||
@issue_keys ||= (issue_keys_from_pipeline + issue_keys_from_commits_since_last_deploy).uniq
|
||||
@issue_keys ||= (issue_keys_from_pipeline + issue_keys_from_commits_since_last_deploy)
|
||||
.uniq.first(ISSUE_KEY_LIMIT)
|
||||
end
|
||||
|
||||
def associations
|
||||
|
|
@ -109,20 +111,21 @@ module Atlassian
|
|||
.successful_deployments
|
||||
.id_not_in(deployment.id)
|
||||
.ordered
|
||||
.find_by_ref(deployment.ref)
|
||||
.first
|
||||
&.commit
|
||||
|
||||
commit_range = if last_deployed_commit
|
||||
"#{last_deployed_commit.id}..#{deployment.commit.id}"
|
||||
else
|
||||
deployment.commit.id
|
||||
end
|
||||
|
||||
commits = project.repository.commits(
|
||||
deployment.ref,
|
||||
before: deployment.commit.created_at,
|
||||
after: last_deployed_commit&.created_at,
|
||||
commit_range,
|
||||
skip_merges: true,
|
||||
limit: COMMITS_LIMIT
|
||||
)
|
||||
|
||||
# Include this deploy's commit, as the `before:` param in `Repository#list_commits_by` excluded it.
|
||||
commits << deployment.commit
|
||||
|
||||
commits.flat_map do |commit|
|
||||
JiraIssueKeyExtractor.new(commit.message).issue_keys
|
||||
end.compact
|
||||
|
|
|
|||
|
|
@ -0,0 +1,17 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module BackgroundMigration
|
||||
# This class doesn't create SecuritySetting
|
||||
# as this feature exists only in EE
|
||||
class MarkAdminBotRunnersAsHosted < BatchedMigrationJob
|
||||
feature_category :hosted_runners
|
||||
|
||||
def perform; end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# rubocop:disable Layout/LineLength -- If I do multiline, another cop complains about prepend should be last line
|
||||
Gitlab::BackgroundMigration::MarkAdminBotRunnersAsHosted.prepend_mod_with('Gitlab::BackgroundMigration::MarkAdminBotRunnersAsHosted')
|
||||
# rubocop:enable Layout/LineLength
|
||||
|
|
@ -109,8 +109,7 @@ module Gitlab
|
|||
types Issue, WorkItem
|
||||
condition do
|
||||
quick_action_target.persisted? &&
|
||||
current_user.can?(:"clone_#{quick_action_target.to_ability_name}", quick_action_target) &&
|
||||
can_be_moved_or_cloned?
|
||||
current_user.can?(:"clone_#{quick_action_target.to_ability_name}", quick_action_target)
|
||||
end
|
||||
command :clone do |params = ''|
|
||||
params = params.split(' ')
|
||||
|
|
@ -147,8 +146,7 @@ module Gitlab
|
|||
types Issue, WorkItem
|
||||
condition do
|
||||
quick_action_target.persisted? &&
|
||||
current_user.can?(:"move_#{quick_action_target.to_ability_name}", quick_action_target) &&
|
||||
can_be_moved_or_cloned?
|
||||
current_user.can?(:"move_#{quick_action_target.to_ability_name}", quick_action_target)
|
||||
end
|
||||
command :move do |target_container_path|
|
||||
target_container = fetch_target_container(target_container_path)
|
||||
|
|
@ -449,12 +447,6 @@ module Gitlab
|
|||
Group.find_by_full_path(target_container_path)
|
||||
end
|
||||
end
|
||||
|
||||
def can_be_moved_or_cloned?
|
||||
return true unless quick_action_target.is_a?(WorkItem) && quick_action_target.work_item_type.epic?
|
||||
|
||||
container.work_item_move_and_clone_flag_enabled?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -304,8 +304,20 @@ module Gitlab
|
|||
if reviewers.blank?
|
||||
_("Failed to assign a reviewer because no user was specified.")
|
||||
else
|
||||
_('Assigned %{reviewer_users_sentence} as %{reviewer_text}.') % { reviewer_users_sentence: reviewer_users_sentence(users),
|
||||
reviewer_text: 'reviewer'.pluralize(reviewers.size) }
|
||||
processed_users = process_reviewer_users(users)
|
||||
processed_msg = process_reviewer_users_message
|
||||
|
||||
if processed_users.present?
|
||||
[
|
||||
processed_msg,
|
||||
_('Assigned %{reviewer_users_sentence} as %{reviewer_text}.') % {
|
||||
reviewer_users_sentence: reviewer_users_sentence(processed_users),
|
||||
reviewer_text: 'reviewer'.pluralize(processed_users.size)
|
||||
}
|
||||
].compact.join(' ')
|
||||
else
|
||||
processed_msg
|
||||
end
|
||||
end
|
||||
end
|
||||
params do
|
||||
|
|
@ -319,13 +331,15 @@ module Gitlab
|
|||
extract_users(reviewer_param)
|
||||
end
|
||||
command :assign_reviewer, :reviewer do |users|
|
||||
next if users.empty?
|
||||
processed_users = process_reviewer_users(users)
|
||||
|
||||
next if processed_users.empty?
|
||||
|
||||
if quick_action_target.allows_multiple_reviewers?
|
||||
@updates[:reviewer_ids] ||= quick_action_target.reviewers.map(&:id)
|
||||
@updates[:reviewer_ids] |= users.map(&:id)
|
||||
@updates[:reviewer_ids] |= processed_users.map(&:id)
|
||||
else
|
||||
@updates[:reviewer_ids] = [users.first.id]
|
||||
@updates[:reviewer_ids] = [processed_users.first.id]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -347,7 +361,19 @@ module Gitlab
|
|||
if users.blank?
|
||||
_("Failed to request a review because no user was specified.")
|
||||
else
|
||||
_('Requested a review from %{reviewer_users_sentence}.') % { reviewer_users_sentence: reviewer_users_sentence(users) }
|
||||
processed_users = process_reviewer_users(users)
|
||||
processed_msg = process_reviewer_users_message
|
||||
|
||||
if processed_users.present?
|
||||
[
|
||||
processed_msg,
|
||||
_('Requested a review from %{reviewer_users_sentence}.') % {
|
||||
reviewer_users_sentence: reviewer_users_sentence(processed_users)
|
||||
}
|
||||
].compact.join(' ')
|
||||
else
|
||||
processed_msg
|
||||
end
|
||||
end
|
||||
end
|
||||
params do
|
||||
|
|
@ -361,7 +387,9 @@ module Gitlab
|
|||
extract_users(reviewer_param)
|
||||
end
|
||||
command :request_review do |users|
|
||||
next if users.empty?
|
||||
processed_users = process_reviewer_users(users)
|
||||
|
||||
next if processed_users.empty?
|
||||
|
||||
@updates[:reviewer_ids] ||= quick_action_target.reviewers.map(&:id)
|
||||
|
||||
|
|
@ -370,7 +398,7 @@ module Gitlab
|
|||
current_user: current_user
|
||||
)
|
||||
|
||||
reviewers_to_add(users).each do |user|
|
||||
reviewers_to_add(processed_users).each do |user|
|
||||
if @updates[:reviewer_ids].include?(user.id)
|
||||
# Request a new review from the reviewer if they are already assigned
|
||||
service.execute(quick_action_target, user)
|
||||
|
|
@ -479,6 +507,16 @@ module Gitlab
|
|||
def preferred_auto_merge_strategy(merge_request)
|
||||
merge_orchestration_service.preferred_auto_merge_strategy(merge_request)
|
||||
end
|
||||
|
||||
# Overriden in EE
|
||||
def process_reviewer_users(users)
|
||||
users
|
||||
end
|
||||
|
||||
# Overriden in EE
|
||||
def process_reviewer_users_message
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -29,24 +29,16 @@ module Gitlab
|
|||
return Gitlab::SlashCommands::Presenters::Access.new.not_found
|
||||
end
|
||||
|
||||
new_issue = if project.work_item_move_and_clone_flag_enabled?
|
||||
response = ::WorkItems::DataSync::MoveService.new(
|
||||
work_item: old_issue, current_user: current_user,
|
||||
target_namespace: target_project.project_namespace
|
||||
).execute
|
||||
response = ::WorkItems::DataSync::MoveService.new(
|
||||
work_item: old_issue, current_user: current_user,
|
||||
target_namespace: target_project.project_namespace
|
||||
).execute
|
||||
|
||||
return presenter(old_issue).display_move_error(response.message) if response.error?
|
||||
return presenter(old_issue).display_move_error(response.message) if response.error?
|
||||
|
||||
response[:work_item]
|
||||
else
|
||||
::Issues::MoveService.new(
|
||||
container: project, current_user: current_user
|
||||
).execute(old_issue, target_project)
|
||||
end
|
||||
new_issue = response[:work_item]
|
||||
|
||||
presenter(new_issue).present(old_issue)
|
||||
rescue ::Issues::MoveService::MoveError => e
|
||||
presenter(old_issue).display_move_error(e.message)
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -13232,15 +13232,6 @@ msgstr ""
|
|||
msgid "Clone with SSH"
|
||||
msgstr ""
|
||||
|
||||
msgid "CloneIssue|Cannot clone issue due to insufficient permissions."
|
||||
msgstr ""
|
||||
|
||||
msgid "CloneIssue|Cannot clone issue to target project as it is pending deletion."
|
||||
msgstr ""
|
||||
|
||||
msgid "CloneIssue|Cannot clone issues of '%{issue_type}' type."
|
||||
msgstr ""
|
||||
|
||||
msgid "CloneWorkItem|Unable to clone. Cloning '%{work_item_type}' is not supported."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21024,9 +21015,6 @@ msgstr ""
|
|||
msgid "Dependencies|Export as JSON"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dependencies|Filtering unavailable"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dependencies|Follow the link below to download the export."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21051,9 +21039,6 @@ msgstr ""
|
|||
msgid "Dependencies|Packager"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dependencies|Project list unavailable"
|
||||
msgstr ""
|
||||
|
||||
msgid "Dependencies|Projects"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -21090,12 +21075,6 @@ msgstr ""
|
|||
msgid "Dependencies|There was an error fetching the versions for the selected component. Please try again later."
|
||||
msgstr ""
|
||||
|
||||
msgid "Dependencies|This group exceeds the maximum number of 600 sub-groups. We cannot accurately filter or search the dependency list above this maximum. To view or filter a subset of this information, go to a subgroup's dependency list."
|
||||
msgstr ""
|
||||
|
||||
msgid "Dependencies|This group exceeds the maximum number of sub-groups of 600. We cannot accurately display a project list at this time. Please access a sub-group dependency list to view this information or see the %{linkStart}dependency list help %{linkEnd} page to learn more."
|
||||
msgstr ""
|
||||
|
||||
msgid "Dependencies|This link will expire in %{number} days."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -23041,6 +23020,9 @@ msgstr ""
|
|||
msgid "DuoCodeReview|I've received your Duo Code Review request, and will review your code shortly."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoCodeReview|Your account doesn't have GitLab Duo access. Please contact your system administrator for access."
|
||||
msgstr ""
|
||||
|
||||
msgid "DuoCodeReview|is reviewing your merge request and will let you know when it's finished"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -39128,15 +39110,6 @@ msgstr ""
|
|||
msgid "Move up"
|
||||
msgstr ""
|
||||
|
||||
msgid "MoveIssue|Cannot move issue due to insufficient permissions."
|
||||
msgstr ""
|
||||
|
||||
msgid "MoveIssue|Cannot move issue to project it originates from."
|
||||
msgstr ""
|
||||
|
||||
msgid "MoveIssue|Cannot move issues of '%{issue_type}' type."
|
||||
msgstr ""
|
||||
|
||||
msgid "MoveWorkItem|Unable to move. Moving '%{work_item_type}' is not supported."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -40459,6 +40432,9 @@ msgstr ""
|
|||
msgid "Non-admin users are restricted to read-only access, in both GitLab UI and API."
|
||||
msgstr ""
|
||||
|
||||
msgid "Non-archived"
|
||||
msgstr ""
|
||||
|
||||
msgid "None"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -46951,6 +46927,9 @@ msgstr ""
|
|||
msgid "Project ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "Project Status"
|
||||
msgstr ""
|
||||
|
||||
msgid "Project Templates"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -270,6 +270,7 @@
|
|||
"ajv-formats": "^2.1.1",
|
||||
"axios-mock-adapter": "^1.15.0",
|
||||
"babel-jest": "^29.7.0",
|
||||
"babel-plugin-istanbul": "^7.0.0",
|
||||
"chalk": "^2.4.1",
|
||||
"chokidar": "^3.5.3",
|
||||
"crypto": "^1.0.1",
|
||||
|
|
|
|||
|
|
@ -76,12 +76,8 @@ module QA
|
|||
click_element 'new-file-menu-item'
|
||||
end
|
||||
|
||||
# Click by JS is needed to bypass the VSCode Web IDE popover
|
||||
# Change back to regular click_element when vscode_web_ide FF is removed
|
||||
# Rollout issue: https://gitlab.com/gitlab-org/gitlab/-/issues/371084
|
||||
def fork_project
|
||||
fork_button = find_element('fork-button')
|
||||
click_by_javascript(fork_button)
|
||||
click_element 'fork-button'
|
||||
end
|
||||
|
||||
def forked_from?(parent_project_name)
|
||||
|
|
|
|||
|
|
@ -167,7 +167,7 @@ module QA
|
|||
end
|
||||
end
|
||||
|
||||
# Used for stability, due to feature_caching of vscode_web_ide
|
||||
# Used for stability
|
||||
# @param file_name [string] wait for file to be loaded (optional)
|
||||
def wait_for_ide_to_load(file_name = nil)
|
||||
page.driver.browser.switch_to.window(page.driver.browser.window_handles.last)
|
||||
|
|
|
|||
|
|
@ -98,6 +98,10 @@ module QA
|
|||
enabled?(ENV['COVERBAND_ENABLED'], default: false)
|
||||
end
|
||||
|
||||
def istanbul_coverage_enabled?
|
||||
ENV['BABEL_ENV'] == 'istanbul'
|
||||
end
|
||||
|
||||
def selective_execution_improved_enabled?
|
||||
enabled?(ENV['SELECTIVE_EXECUTION_IMPROVED'], default: false)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -26,6 +26,20 @@ RSpec.configure(&:disable_monkey_patching!)
|
|||
# For JH additionally process when `jh/` exists
|
||||
require_relative('../../../jh/qa/qa/specs/spec_helper') if GitlabEdition.jh?
|
||||
|
||||
front_end_coverage_by_example = {}
|
||||
|
||||
def save_front_end_coverage_mapping(map_to_save)
|
||||
return if map_to_save.empty?
|
||||
|
||||
file = "tmp/js-coverage-by-example-#{ENV['CI_JOB_NAME_SLUG'] || 'local'}-#{SecureRandom.hex(6)}.json"
|
||||
|
||||
# Write the mapping data
|
||||
File.write(file, map_to_save.to_json)
|
||||
QA::Runtime::Logger.info("Saved test coverage mapping data to #{file}")
|
||||
rescue StandardError => e
|
||||
QA::Runtime::Logger.error("Failed to save JS coverage mapping data, error: #{e}")
|
||||
end
|
||||
|
||||
RSpec.configure do |config|
|
||||
config.include ActiveSupport::Testing::TimeHelpers
|
||||
config.include QA::Support::Matchers::EventuallyMatcher
|
||||
|
|
@ -53,6 +67,11 @@ RSpec.configure do |config|
|
|||
|
||||
visit(QA::Runtime::Scenario.gitlab_address) if QA::Runtime::Env.mobile_layout?
|
||||
|
||||
# Reset coverage persistence at the start of each test
|
||||
if Capybara::Session.instance_created? && QA::Runtime::Env.istanbul_coverage_enabled?
|
||||
Capybara.current_session.execute_script("window.__coveragePathsPersistence.reset()")
|
||||
end
|
||||
|
||||
# Reset fabrication counters tracked in resource base
|
||||
Thread.current[:api_fabrication] = 0
|
||||
Thread.current[:browser_ui_fabrication] = 0
|
||||
|
|
@ -78,6 +97,19 @@ RSpec.configure do |config|
|
|||
QA::Support::PageErrorChecker.log_request_errors(page)
|
||||
QA::Support::PageErrorChecker.check_page_for_error_code(page) if example.exception
|
||||
end
|
||||
# Get coverage paths and store in metadata
|
||||
if Capybara::Session.instance_created? && QA::Runtime::Env.istanbul_coverage_enabled?
|
||||
begin
|
||||
Capybara.current_session.execute_script("window.__coveragePathsPersistence.update()")
|
||||
coverage_paths = Capybara.current_session.evaluate_script("window.__coveragePathsPersistence.getPaths()")
|
||||
QA::Runtime::Logger.debug("Coverage paths count: #{coverage_paths.length}")
|
||||
|
||||
example.metadata[:coverage_paths] = coverage_paths
|
||||
front_end_coverage_by_example[example.metadata[:location]] = coverage_paths
|
||||
rescue StandardError => e
|
||||
QA::Runtime::Logger.warn("Failed to collect coverage paths: #{e.message}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
config.append_after do |example|
|
||||
|
|
@ -98,6 +130,8 @@ RSpec.configure do |config|
|
|||
config.after(:suite) do |suite|
|
||||
# Write all test created resources to JSON file
|
||||
QA::Tools::TestResourceDataProcessor.write_to_file(suite.reporter.failed_examples.any?)
|
||||
|
||||
save_front_end_coverage_mapping(front_end_coverage_by_example) if QA::Runtime::Env.istanbul_coverage_enabled?
|
||||
end
|
||||
|
||||
config.expect_with :rspec do |expectations|
|
||||
|
|
|
|||
|
|
@ -718,3 +718,13 @@ JSON
|
|||
-H 'Content-type: application/json' \
|
||||
-d "${json_payload}"
|
||||
}
|
||||
|
||||
function execute_failure_analyzer() {
|
||||
# IMPORTANT - If you want to change the "failure-analyzer" string,
|
||||
# please also change the logic for the failure categories, as we rely on this marker.
|
||||
#
|
||||
# Class relying on the marker: tooling/lib/tooling/glci/failure_categories/download_job_trace.rb
|
||||
section_start "failure-analyzer" "Report failure category"
|
||||
$CI_PROJECT_DIR/tooling/lib/tooling/glci/failure_analyzer.rb $CI_JOB_ID || true
|
||||
section_end "failure-analyzer"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -545,21 +545,7 @@ RSpec.describe Projects::IssuesController, :request_store, feature_category: :te
|
|||
end
|
||||
end
|
||||
|
||||
context 'with work_item_move_and_clone disabled' do
|
||||
it_behaves_like 'move issue request' do
|
||||
before do
|
||||
stub_feature_flags(work_item_move_and_clone: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with work_item_move_and_clone enabled' do
|
||||
it_behaves_like 'move issue request' do
|
||||
before do
|
||||
stub_feature_flags(work_item_move_and_clone: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
it_behaves_like 'move issue request'
|
||||
end
|
||||
|
||||
describe 'PUT #reorder' do
|
||||
|
|
|
|||
|
|
@ -3,13 +3,13 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'IDE merge request', :js, feature_category: :web_ide do
|
||||
include Features::WebIdeSpecHelpers
|
||||
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :public, :repository, namespace: user.namespace) }
|
||||
let_it_be(:merge_request) { create(:merge_request, :simple, source_project: project) }
|
||||
|
||||
before do
|
||||
stub_feature_flags(vscode_web_ide: false)
|
||||
|
||||
sign_in(user)
|
||||
|
||||
visit(merge_request_path(merge_request))
|
||||
|
|
@ -19,10 +19,16 @@ RSpec.describe 'IDE merge request', :js, feature_category: :web_ide do
|
|||
within '.merge-request' do
|
||||
click_button 'Code'
|
||||
end
|
||||
click_link 'Open in Web IDE'
|
||||
new_tab = window_opened_by { click_link 'Open in Web IDE' }
|
||||
|
||||
switch_to_window new_tab
|
||||
|
||||
wait_for_requests
|
||||
|
||||
expect(page).not_to have_selector('.monaco-diff-editor')
|
||||
within_window new_tab do
|
||||
within_web_ide do
|
||||
expect(page).to have_css('a[aria-label^="Next Change"]')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -81,18 +81,24 @@ export const secretDetectionFindings = [
|
|||
{
|
||||
message: 'Hello world! glpat-mGYFaXBmNLvLmrEb7xdf',
|
||||
type: 'GitLab personal access token',
|
||||
redactedString: 'glpat*****************7xdf',
|
||||
secret: 'glpat-mGYFaXBmNLvLmrEb7xdf',
|
||||
},
|
||||
|
||||
{
|
||||
message: 'Second token: gldt-cgyKc1k_AsnEpmP-5fRL',
|
||||
type: 'GitLab Deploy Token',
|
||||
redactedString: 'gldt-****************5fRL',
|
||||
secret: 'gldt-cgyKc1k_AsnEpmP-5fRL',
|
||||
},
|
||||
|
||||
{
|
||||
message: 'third token: feed_token=ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
message: 'Third token: feed_token=ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
type: 'Feed Token',
|
||||
redactedString: 'feed_**********************QRST',
|
||||
secret: 'feed_token=ABCDEFGHIJKLMNOPQRST',
|
||||
},
|
||||
|
||||
{
|
||||
message: 'Repeated token: glpat-mGYFaXBmNLvLmrEb7xdf glpat-mGYFaXBmNLvLmrEb7xdf',
|
||||
type: 'GitLab personal access token',
|
||||
secret: 'glpat-mGYFaXBmNLvLmrEb7xdf',
|
||||
},
|
||||
];
|
||||
|
|
|
|||
|
|
@ -115,15 +115,15 @@ describe('detectAndConfirmSensitiveTokens', () => {
|
|||
modalHtmlMessage: expect.any(String),
|
||||
};
|
||||
|
||||
describe('with single findings', () => {
|
||||
const [{ message, type, redactedString }] = findings;
|
||||
describe('with single finding', () => {
|
||||
const [{ message, type, secret }] = findings;
|
||||
it('should call confirmAction with correct parameters', async () => {
|
||||
await detectAndConfirmSensitiveTokens({ content: message });
|
||||
|
||||
const confirmActionArgs = confirmAction.mock.calls[0][1];
|
||||
expect(confirmActionArgs).toMatchObject(baseConfirmActionParams);
|
||||
expect(confirmActionArgs.title).toBe('Warning: Potential secret detected');
|
||||
expect(confirmActionArgs.modalHtmlMessage).toContain(`${type}: ${redactedString}`);
|
||||
expect(confirmActionArgs.modalHtmlMessage).toContain(`${type}: ${secret}`);
|
||||
});
|
||||
});
|
||||
|
||||
|
|
@ -137,12 +137,28 @@ describe('detectAndConfirmSensitiveTokens', () => {
|
|||
expect(confirmActionArgs).toMatchObject(baseConfirmActionParams);
|
||||
expect(confirmActionArgs.title).toBe('Warning: Potential secrets detected');
|
||||
|
||||
findings.forEach(({ type, redactedString }) => {
|
||||
expect(confirmActionArgs.modalHtmlMessage).toContain(`${type}: ${redactedString}`);
|
||||
findings.forEach(({ type, secret }) => {
|
||||
expect(confirmActionArgs.modalHtmlMessage).toContain(`${type}: ${secret}`);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('with repeated finding', () => {
|
||||
const { message, type, secret } = findings.at(-1);
|
||||
it('should call confirmAction with correct parameters', async () => {
|
||||
await detectAndConfirmSensitiveTokens({ content: message });
|
||||
|
||||
const confirmActionArgs = confirmAction.mock.calls[0][1];
|
||||
const stringToMatch = `${type}: ${secret}`;
|
||||
expect(confirmActionArgs).toMatchObject(baseConfirmActionParams);
|
||||
expect(confirmActionArgs.title).toBe('Warning: Potential secret detected');
|
||||
const tokenRegex = new RegExp(stringToMatch, 'g');
|
||||
const matches = confirmActionArgs.modalHtmlMessage.match(tokenRegex);
|
||||
|
||||
expect(matches).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('with different content type', () => {
|
||||
const testCases = [
|
||||
[
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ RSpec.describe Mutations::Issues::Move, feature_category: :api do
|
|||
|
||||
it 'returns error message' do
|
||||
expect(resolve[:issue]).to eq(nil)
|
||||
expect(resolve[:errors].first).to eq(permissions_error_message)
|
||||
expect(resolve[:errors].first).to eq("Unable to move. You have insufficient permissions.")
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -43,23 +43,5 @@ RSpec.describe Mutations::Issues::Move, feature_category: :api do
|
|||
end
|
||||
end
|
||||
|
||||
context 'with work_item_move_and_clone disabled' do
|
||||
it_behaves_like 'moving work item mutation' do
|
||||
let(:permissions_error_message) { "Cannot move issue due to insufficient permissions." }
|
||||
|
||||
before do
|
||||
stub_feature_flags(work_item_move_and_clone: false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with work_item_move_and_clone enabled' do
|
||||
it_behaves_like 'moving work item mutation' do
|
||||
let(:permissions_error_message) { "Unable to move. You have insufficient permissions." }
|
||||
|
||||
before do
|
||||
stub_feature_flags(work_item_move_and_clone: true)
|
||||
end
|
||||
end
|
||||
end
|
||||
it_behaves_like 'moving work item mutation'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -330,7 +330,9 @@ RSpec.describe Atlassian::JiraConnect::Serializers::DeploymentEntity, feature_ca
|
|||
last_deploy.update!(ref: 'foo')
|
||||
end
|
||||
|
||||
it_behaves_like 'ignores that deployment'
|
||||
it 'extracts issue keys from commits made since the last deploy regardless of ref' do
|
||||
expect(subject.issue_keys).to contain_exactly('add a', 'add d')
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the deploy was not successful' do
|
||||
|
|
|
|||
|
|
@ -18,33 +18,30 @@ RSpec.describe Gitlab::Doctor::EncryptionKeys, feature_category: :shared do
|
|||
|
||||
context 'when no encrypted attributes exist' do
|
||||
it 'outputs "NONE"' do
|
||||
expect(logger).to receive(:info).with(/Encryption keys usage for DependencyProxy::GroupSetting: NONE/)
|
||||
expect(logger).to receive(:info).with("Encryption keys usage for DependencyProxy::GroupSetting: NONE")
|
||||
|
||||
doctor_encryption_secrets
|
||||
end
|
||||
end
|
||||
|
||||
context 'when encrypted attributes exist' do
|
||||
# This will work in Rails 7.1.4, see https://github.com/rails/rails/issues/52003#issuecomment-2149673942
|
||||
#
|
||||
# let!(:key_provider1) { ActiveRecord::Encryption::DerivedSecretKeyProvider.new(SecureRandom.base64(32)) }
|
||||
#
|
||||
# before do
|
||||
# ActiveRecord::Encryption.with_encryption_context(key_provider: key_provider1) do
|
||||
# create(:dependency_proxy_group_setting)
|
||||
# end
|
||||
# end
|
||||
#
|
||||
# Until then, we can only use the default key provider
|
||||
let!(:key_provider1) { ActiveRecord::Encryption.key_provider }
|
||||
let(:current_key_provider) { ActiveRecord::Encryption.key_provider }
|
||||
let(:unknown_key_provider) { ActiveRecord::Encryption::DerivedSecretKeyProvider.new(SecureRandom.base64(32)) }
|
||||
|
||||
before do
|
||||
# Create a record with the current encryption key
|
||||
create(:dependency_proxy_group_setting)
|
||||
|
||||
# Create a record with a different encryption key
|
||||
ActiveRecord::Encryption.with_encryption_context(key_provider: unknown_key_provider) do
|
||||
create(:dependency_proxy_group_setting)
|
||||
end
|
||||
end
|
||||
|
||||
it 'detects decryptable secrets' do
|
||||
expect(logger).to receive(:info).with(/Encryption keys usage for DependencyProxy::GroupSetting:/)
|
||||
expect(logger).to receive(:info).with(/- `#{key_provider1.encryption_key.id}` => 2/)
|
||||
expect(logger).to receive(:info).with("Encryption keys usage for DependencyProxy::GroupSetting:")
|
||||
expect(logger).to receive(:info).with("- `#{current_key_provider.encryption_key.id}` => 2")
|
||||
expect(logger).to receive(:info).with("- `#{unknown_key_provider.encryption_key.id}` (UNKNOWN KEY!) => 2")
|
||||
|
||||
doctor_encryption_secrets
|
||||
end
|
||||
|
|
|
|||
|
|
@ -44,14 +44,9 @@ RSpec.describe Gitlab::SlashCommands::IssueMove, :service, feature_category: :te
|
|||
it 'returns the error message' do
|
||||
message = "issue move #{issue.iid} #{project.full_path}"
|
||||
|
||||
if issue.project.work_item_move_and_clone_flag_enabled?
|
||||
process_message(message)
|
||||
# move does not happen, as moving issue to same project results in same issue, but we do not show an error
|
||||
expect(issue.reload.moved_to).to be_nil
|
||||
else
|
||||
expect(process_message(message)).to include(response_type: :ephemeral,
|
||||
text: a_string_matching(same_project_error_message))
|
||||
end
|
||||
process_message(message)
|
||||
# move does not happen, as moving issue to same project results in same issue, but we do not show an error
|
||||
expect(issue.reload.moved_to).to be_nil
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -119,30 +114,11 @@ RSpec.describe Gitlab::SlashCommands::IssueMove, :service, feature_category: :te
|
|||
other_project.team.add_guest(user)
|
||||
|
||||
expect(process_message(message)).to include(response_type: :ephemeral,
|
||||
text: a_string_matching(permissions_error_message))
|
||||
text: a_string_matching("Unable to move. You have insufficient permissions."))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with work_item_move_and_clone disabled' do
|
||||
before do
|
||||
stub_feature_flags(work_item_move_and_clone: false)
|
||||
end
|
||||
|
||||
it_behaves_like 'move issue slash command' do
|
||||
let(:same_project_error_message) { "Cannot move issue to project it originates from." }
|
||||
let(:permissions_error_message) { "Cannot move issue due to insufficient permissions." }
|
||||
end
|
||||
end
|
||||
|
||||
context 'with work_item_move_and_clone enabled' do
|
||||
before do
|
||||
stub_feature_flags(work_item_move_and_clone: true)
|
||||
end
|
||||
|
||||
it_behaves_like 'move issue slash command' do
|
||||
let(:permissions_error_message) { "Unable to move. You have insufficient permissions." }
|
||||
end
|
||||
end
|
||||
it_behaves_like 'move issue slash command'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2,14 +2,18 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::SlashCommands::Presenters::IssueMove do
|
||||
RSpec.describe Gitlab::SlashCommands::Presenters::IssueMove, feature_category: :team_planning do
|
||||
let_it_be(:user) { create(:user) }
|
||||
let_it_be(:project, reload: true) { create(:project, developers: user) }
|
||||
let_it_be(:other_project) { create(:project, developers: user) }
|
||||
let_it_be(:old_issue, reload: true) { create(:issue, project: project) }
|
||||
|
||||
let(:new_issue) { Issues::MoveService.new(container: project, current_user: user).execute(old_issue, other_project) }
|
||||
let(:attachment) { subject[:attachments].first }
|
||||
let(:new_issue) do
|
||||
::WorkItems::DataSync::MoveService.new(
|
||||
work_item: old_issue, current_user: user, target_namespace: other_project.project_namespace
|
||||
).execute[:work_item]
|
||||
end
|
||||
|
||||
subject { described_class.new(new_issue).present(old_issue) }
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
require_migration!
|
||||
|
||||
RSpec.describe QueueMarkAdminBotRunnersAsHosted, migration: :gitlab_ci, feature_category: :hosted_runners do
|
||||
let!(:batched_migration) { described_class::MIGRATION }
|
||||
|
||||
it 'schedules a new batched migration' do
|
||||
reversible_migration do |migration|
|
||||
migration.before -> {
|
||||
expect(batched_migration).not_to have_scheduled_batched_migration
|
||||
}
|
||||
|
||||
migration.after -> {
|
||||
expect(batched_migration).to have_scheduled_batched_migration(
|
||||
gitlab_schema: :gitlab_ci,
|
||||
table_name: :ci_runners,
|
||||
column_name: :id,
|
||||
interval: described_class::DELAY_INTERVAL,
|
||||
batch_size: described_class::BATCH_SIZE,
|
||||
sub_batch_size: described_class::SUB_BATCH_SIZE
|
||||
)
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -575,12 +575,33 @@ RSpec.describe WorkItem, feature_category: :portfolio_management do
|
|||
end
|
||||
end
|
||||
|
||||
describe '#linked_items_keyset_order' do
|
||||
describe '.linked_items_keyset_order' do
|
||||
subject { described_class.linked_items_keyset_order }
|
||||
|
||||
it { is_expected.to eq('"issue_links"."id" DESC') }
|
||||
end
|
||||
|
||||
describe '.linked_items_for' do
|
||||
let_it_be(:items) { create_list(:work_item, 3, project: reusable_project) }
|
||||
let_it_be(:linked_items) { create_list(:work_item, 3, project: reusable_project) }
|
||||
|
||||
let(:work_item_ids) { items.pluck(:id) }
|
||||
|
||||
subject(:linked) { described_class.linked_items_for(work_item_ids) }
|
||||
|
||||
before do
|
||||
items.each_with_index do |item, i|
|
||||
create(:work_item_link, source: item, target: linked_items[i])
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns the linked items' do
|
||||
expect(linked.map(&:issue_link_target_id)).to match_array(work_item_ids)
|
||||
expect(linked.map(&:issue_link_source_id)).to match_array(linked_items.map(&:id))
|
||||
expect(linked.map(&:issue_link_type).uniq).to contain_exactly('relates_to')
|
||||
end
|
||||
end
|
||||
|
||||
context 'with hierarchy' do
|
||||
let_it_be(:type1) { create(:work_item_type, :non_default) }
|
||||
let_it_be(:type2) { create(:work_item_type, :non_default) }
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue