Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
bf03e90e02
commit
aa74b7b4c5
|
|
@ -26,7 +26,6 @@ export const initJobDetails = () => {
|
|||
subscriptionsMoreMinutesUrl,
|
||||
endpoint,
|
||||
pagePath,
|
||||
buildStatus,
|
||||
projectPath,
|
||||
retryOutdatedJobDocsUrl,
|
||||
aiRootCauseAnalysisAvailable,
|
||||
|
|
@ -55,10 +54,6 @@ export const initJobDetails = () => {
|
|||
deploymentHelpUrl,
|
||||
runnerSettingsUrl,
|
||||
subscriptionsMoreMinutesUrl,
|
||||
endpoint,
|
||||
pagePath,
|
||||
buildStatus,
|
||||
projectPath,
|
||||
},
|
||||
});
|
||||
},
|
||||
|
|
|
|||
|
|
@ -56,15 +56,6 @@ export default {
|
|||
required: false,
|
||||
default: null,
|
||||
},
|
||||
terminalPath: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: null,
|
||||
},
|
||||
projectPath: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
subscriptionsMoreMinutesUrl: {
|
||||
type: String,
|
||||
required: false,
|
||||
|
|
@ -261,7 +252,6 @@ export default {
|
|||
v-if="shouldRenderSharedRunnerLimitWarning"
|
||||
:quota-used="job.runners.quota.used"
|
||||
:quota-limit="job.runners.quota.limit"
|
||||
:project-path="projectPath"
|
||||
:subscriptions-more-minutes-url="subscriptionsMoreMinutesUrl"
|
||||
/>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Resolvers
|
||||
class WorkItemReferencesResolver < BaseResolver
|
||||
prepend ::WorkItems::LookAheadPreloads
|
||||
include Gitlab::Graphql::Authorize::AuthorizeResource
|
||||
|
||||
REFERENCES_LIMIT = 10
|
||||
|
||||
authorize :read_work_item
|
||||
|
||||
type ::Types::WorkItemType.connection_type, null: true
|
||||
|
||||
argument :context_namespace_path, GraphQL::Types::ID,
|
||||
required: false,
|
||||
description: 'Full path of the context namespace (project or group).'
|
||||
|
||||
argument :refs, [GraphQL::Types::String], required: true,
|
||||
description: 'Work item references. Can be either a short reference or URL.'
|
||||
|
||||
def ready?(**args)
|
||||
if args[:refs].size > REFERENCES_LIMIT
|
||||
raise Gitlab::Graphql::Errors::ArgumentError,
|
||||
format(
|
||||
_('Number of references exceeds the limit. ' \
|
||||
'Please provide no more than %{refs_limit} references at the same time.'),
|
||||
refs_limit: REFERENCES_LIMIT
|
||||
)
|
||||
end
|
||||
|
||||
super
|
||||
end
|
||||
|
||||
def resolve_with_lookahead(context_namespace_path: nil, refs: [])
|
||||
return WorkItem.none if refs.empty?
|
||||
|
||||
@container = authorized_find!(context_namespace_path)
|
||||
# Only ::Project is supported at the moment, future iterations will include ::Group.
|
||||
# See https://gitlab.com/gitlab-org/gitlab/-/issues/432555
|
||||
return WorkItem.none if container.is_a?(::Group)
|
||||
|
||||
apply_lookahead(find_work_items(refs))
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :container
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord -- #references is not an ActiveRecord method
|
||||
def find_work_items(references)
|
||||
links, short_references = references.partition { |r| r.include?('/work_items/') }
|
||||
|
||||
item_ids = references_extractor(short_references).references(:issue, ids_only: true)
|
||||
item_ids << references_extractor(links).references(:work_item, ids_only: true) if links.any?
|
||||
|
||||
WorkItem.id_in(item_ids.flatten)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def references_extractor(refs)
|
||||
extractor = ::Gitlab::ReferenceExtractor.new(container, context[:current_user])
|
||||
extractor.analyze(refs.join(' '), {})
|
||||
|
||||
extractor
|
||||
end
|
||||
|
||||
def find_object(full_path)
|
||||
Routable.find_by_full_path(full_path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -216,6 +216,13 @@ module Types
|
|||
description: 'Find machine learning models.',
|
||||
resolver: Resolvers::Ml::ModelDetailResolver
|
||||
|
||||
field :work_items_by_reference,
|
||||
null: true,
|
||||
alpha: { milestone: '16.7' },
|
||||
description: 'Find work items by their reference.',
|
||||
extras: [:lookahead],
|
||||
resolver: Resolvers::WorkItemReferencesResolver
|
||||
|
||||
def design_management
|
||||
DesignManagementObject.new(nil)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@ module Ci
|
|||
"artifact_help_url" => help_page_path('user/gitlab_com/index.md', anchor: 'gitlab-cicd'),
|
||||
"deployment_help_url" => help_page_path('user/project/clusters/deploy_to_cluster.md', anchor: 'troubleshooting'),
|
||||
"runner_settings_url" => project_runners_path(build.project, anchor: 'js-runners-settings'),
|
||||
"build_status" => build.status,
|
||||
"build_stage" => build.stage_name,
|
||||
"retry_outdated_job_docs_url" => help_page_path('ci/pipelines/settings', anchor: 'retry-outdated-jobs'),
|
||||
"test_report_summary_url" => test_report_summary_project_job_path(project, build, format: :json),
|
||||
"pipeline_test_report_url" => test_report_project_pipeline_path(project, build.pipeline)
|
||||
|
|
|
|||
|
|
@ -38,36 +38,32 @@ module UpdateRepositoryStorageWorker
|
|||
|
||||
container_id ||= repository_storage_move.container_id
|
||||
|
||||
if Feature.enabled?(:use_lock_for_update_repository_storage)
|
||||
# Use exclusive lock to prevent multiple storage migrations at the same time
|
||||
#
|
||||
# Note: instead of using a randomly generated `uuid`, we provide a worker jid value.
|
||||
# That will allow to track a worker that requested a lease.
|
||||
lease_key = [self.class.name.underscore, container_id].join(':')
|
||||
exclusive_lease = Gitlab::ExclusiveLease.new(lease_key, uuid: jid, timeout: LEASE_TIMEOUT)
|
||||
lease = exclusive_lease.try_obtain
|
||||
# Use exclusive lock to prevent multiple storage migrations at the same time
|
||||
#
|
||||
# Note: instead of using a randomly generated `uuid`, we provide a worker jid value.
|
||||
# That will allow to track a worker that requested a lease.
|
||||
lease_key = [self.class.name.underscore, container_id].join(':')
|
||||
exclusive_lease = Gitlab::ExclusiveLease.new(lease_key, uuid: jid, timeout: LEASE_TIMEOUT)
|
||||
lease = exclusive_lease.try_obtain
|
||||
|
||||
if lease
|
||||
begin
|
||||
update_repository_storage(repository_storage_move)
|
||||
ensure
|
||||
exclusive_lease.cancel
|
||||
end
|
||||
else
|
||||
# If there is an ungoing storage migration, then the current one should be marked as failed
|
||||
repository_storage_move.do_fail!
|
||||
|
||||
# A special case
|
||||
# Sidekiq can receive an interrupt signal during the processing.
|
||||
# It kills existing workers and reschedules their jobs using the same jid.
|
||||
# But it can cause a situation when the migration is only half complete (see https://gitlab.com/gitlab-org/gitlab/-/issues/429049#note_1635650597)
|
||||
#
|
||||
# Here we detect this case and release the lock.
|
||||
uuid = Gitlab::ExclusiveLease.get_uuid(lease_key)
|
||||
exclusive_lease.cancel if uuid == jid
|
||||
if lease
|
||||
begin
|
||||
update_repository_storage(repository_storage_move)
|
||||
ensure
|
||||
exclusive_lease.cancel
|
||||
end
|
||||
else
|
||||
update_repository_storage(repository_storage_move)
|
||||
# If there is an ungoing storage migration, then the current one should be marked as failed
|
||||
repository_storage_move.do_fail!
|
||||
|
||||
# A special case
|
||||
# Sidekiq can receive an interrupt signal during the processing.
|
||||
# It kills existing workers and reschedules their jobs using the same jid.
|
||||
# But it can cause a situation when the migration is only half complete (see https://gitlab.com/gitlab-org/gitlab/-/issues/429049#note_1635650597)
|
||||
#
|
||||
# Here we detect this case and release the lock.
|
||||
uuid = Gitlab::ExclusiveLease.get_uuid(lease_key)
|
||||
exclusive_lease.cancel if uuid == jid
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
---
|
||||
name: use_lock_for_update_repository_storage
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/136169
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/431198
|
||||
milestone: '16.6'
|
||||
type: development
|
||||
group: group::source code
|
||||
default_enabled: false
|
||||
|
|
@ -4,3 +4,4 @@ description: Updates default value of code_suggestions on namespace_settings tab
|
|||
feature_category: code_suggestions
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/121126
|
||||
milestone: '16.1'
|
||||
finalized_by: '20231206145850'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class DropUniqueIndexJobIdFileTypeToCiJobArtifact < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.7'
|
||||
disable_ddl_transaction!
|
||||
TABLE_NAME = :ci_job_artifacts
|
||||
INDEX_NAME = :index_ci_job_artifacts_on_job_id_and_file_type
|
||||
|
||||
def up
|
||||
remove_concurrent_index_by_name(TABLE_NAME, INDEX_NAME)
|
||||
end
|
||||
|
||||
def down
|
||||
add_concurrent_index(TABLE_NAME, %i[job_id file_type], unique: true, name: INDEX_NAME)
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class FinalizeBackfillCodeSuggestionsNamespaceSettings < Gitlab::Database::Migration[2.2]
|
||||
milestone '16.7'
|
||||
|
||||
disable_ddl_transaction!
|
||||
|
||||
restrict_gitlab_migration gitlab_schema: :gitlab_main_cell
|
||||
|
||||
def up
|
||||
ensure_batched_background_migration_is_finished(
|
||||
job_class_name: 'BackfillCodeSuggestionsNamespaceSettings',
|
||||
table_name: :namespace_settings,
|
||||
column_name: :namespace_id,
|
||||
job_arguments: [],
|
||||
finalize: true
|
||||
)
|
||||
end
|
||||
|
||||
def down; end
|
||||
end
|
||||
|
|
@ -0,0 +1 @@
|
|||
5ca9bd14a7c69b4b77745303c47c7d11890f3ced97c8a1a68b5b713b29a2dab7
|
||||
|
|
@ -0,0 +1 @@
|
|||
53442f9c3ef0e0f3f31b4be177faf3d073ee8b74d20ede7a1673bedfa097f0b9
|
||||
|
|
@ -32155,8 +32155,6 @@ CREATE INDEX index_ci_job_artifacts_on_id_project_id_and_created_at ON ci_job_ar
|
|||
|
||||
CREATE INDEX index_ci_job_artifacts_on_id_project_id_and_file_type ON ci_job_artifacts USING btree (project_id, file_type, id);
|
||||
|
||||
CREATE UNIQUE INDEX index_ci_job_artifacts_on_job_id_and_file_type ON ci_job_artifacts USING btree (job_id, file_type);
|
||||
|
||||
CREATE INDEX index_ci_job_artifacts_on_partition_id_job_id ON ci_job_artifacts USING btree (partition_id, job_id);
|
||||
|
||||
CREATE INDEX index_ci_job_artifacts_on_project_id ON ci_job_artifacts USING btree (project_id);
|
||||
|
|
|
|||
|
|
@ -1033,6 +1033,27 @@ Returns [`WorkItem`](#workitem).
|
|||
| ---- | ---- | ----------- |
|
||||
| <a id="queryworkitemid"></a>`id` | [`WorkItemID!`](#workitemid) | Global ID of the work item. |
|
||||
|
||||
### `Query.workItemsByReference`
|
||||
|
||||
Find work items by their reference.
|
||||
|
||||
WARNING:
|
||||
**Introduced** in 16.7.
|
||||
This feature is an Experiment. It can be changed or removed at any time.
|
||||
|
||||
Returns [`WorkItemConnection`](#workitemconnection).
|
||||
|
||||
This field returns a [connection](#connections). It accepts the
|
||||
four standard [pagination arguments](#connection-pagination-arguments):
|
||||
`before: String`, `after: String`, `first: Int`, `last: Int`.
|
||||
|
||||
#### Arguments
|
||||
|
||||
| Name | Type | Description |
|
||||
| ---- | ---- | ----------- |
|
||||
| <a id="queryworkitemsbyreferencecontextnamespacepath"></a>`contextNamespacePath` | [`ID`](#id) | Full path of the context namespace (project or group). |
|
||||
| <a id="queryworkitemsbyreferencerefs"></a>`refs` | [`[String!]!`](#string) | Work item references. Can be either a short reference or URL. |
|
||||
|
||||
### `Query.workspace`
|
||||
|
||||
Find a workspace.
|
||||
|
|
|
|||
|
|
@ -16,16 +16,18 @@ Beta users should read about the [known limitations](#known-limitations). We loo
|
|||
|
||||
Write code more efficiently by using generative AI to suggest code while you're developing.
|
||||
|
||||
Code Suggestions supports two distinct types of interactions:
|
||||
With Code Suggestions, you get:
|
||||
|
||||
- Code Completion, which suggests completions the current line you are typing. These suggestions are usually low latency.
|
||||
- Code Generation, which generates code based on a natural language code comment block. Generating code can exceed multiple seconds.
|
||||
|
||||
## Start using Code Suggestions
|
||||
|
||||
GitLab Duo Code Suggestions are available:
|
||||
|
||||
- On [self-managed](self_managed.md) and [SaaS](saas.md).
|
||||
- On [self-managed](self_managed.md) and [SaaS](saas.md). View these pages to get started.
|
||||
- In VS Code, Microsoft Visual Studio, JetBrains IDEs, and Neovim. You must have the corresponding GitLab extension installed.
|
||||
- In the GitLab WebIDE.
|
||||
- In the GitLab Web IDE.
|
||||
|
||||
<div class="video-fallback">
|
||||
<a href="https://youtu.be/wAYiy05fjF0">View how to setup and use GitLab Duo Code Suggestions</a>.
|
||||
|
|
@ -37,36 +39,6 @@ GitLab Duo Code Suggestions are available:
|
|||
During Beta, usage of Code Suggestions is governed by the [GitLab Testing Agreement](https://about.gitlab.com/handbook/legal/testing-agreement/).
|
||||
Learn about [data usage when using Code Suggestions](#code-suggestions-data-usage). As Code Suggestions matures to General Availability it will be governed by our [AI Functionality Terms](https://about.gitlab.com/handbook/legal/ai-functionality-terms/).
|
||||
|
||||
## Use Code Suggestions
|
||||
|
||||
Prerequisites:
|
||||
|
||||
- You must have installed and configured a [supported IDE editor extension](index.md#supported-editor-extensions).
|
||||
- If you are a **SaaS** user, you must enable Code Suggestions for:
|
||||
- [The top-level group](../../../group/manage.md#enable-code-suggestions) (you must have the Owner role for that group).
|
||||
- [Your own account](../../../profile/preferences.md#enable-code-suggestions).
|
||||
- If you are a **self-managed** user, you must enable Code Suggestions [for your instance](self_managed.md#enable-code-suggestions-on-self-managed-gitlab). How you enable Code Suggestions differs depending on your version of GitLab.
|
||||
|
||||
To use Code Suggestions:
|
||||
|
||||
1. Author your code. As you type, suggestions are displayed. Code Suggestions, depending on the cursor position, either provides code snippets or completes the current line.
|
||||
1. Describe the requirements in natural language. Be concise and specific. Code Suggestions generates functions and code snippets as appropriate.
|
||||
1. To accept a suggestion, press <kbd>Tab</kbd>.
|
||||
1. To ignore a suggestion, keep typing as you usually would.
|
||||
1. To explicitly reject a suggestion, press <kbd>esc</kbd>.
|
||||
|
||||
Things to remember:
|
||||
|
||||
- AI is non-deterministic, so you may not get the same suggestion every time with the same input.
|
||||
- Just like product requirements, writing clear, descriptive, and specific tasks results in quality generated code.
|
||||
|
||||
### Progressive enhancement
|
||||
|
||||
This feature is designed as a progressive enhancement to developer's IDEs.
|
||||
Code Suggestions offer a completion if a suitable recommendation is provided to the user in a timely matter.
|
||||
In the event of a connection issue or model inference failure, the feature gracefully degrades.
|
||||
Code Suggestions do not prevent you from writing code in your IDE.
|
||||
|
||||
## Supported languages
|
||||
|
||||
Code Suggestions support is a function of the:
|
||||
|
|
@ -170,6 +142,13 @@ However, Code Suggestions may generate suggestions that are:
|
|||
- Insecure code
|
||||
- Offensive or insensitive
|
||||
|
||||
## Progressive enhancement
|
||||
|
||||
This feature is designed as a progressive enhancement to developer's IDEs.
|
||||
Code Suggestions offer a completion if a suitable recommendation is provided to the user in a timely matter.
|
||||
In the event of a connection issue or model inference failure, the feature gracefully degrades.
|
||||
Code Suggestions do not prevent you from writing code in your IDE.
|
||||
|
||||
## Feedback
|
||||
|
||||
Report issues in the [feedback issue](https://gitlab.com/gitlab-org/gitlab/-/issues/405152).
|
||||
|
|
|
|||
|
|
@ -34,7 +34,21 @@ If you are having issues enabling Code Suggestions, view the
|
|||
|
||||
Prerequisites:
|
||||
|
||||
- Ensure Code Suggestions is enabled for your user and group.
|
||||
- You must have installed and configured a [supported IDE editor extension](index.md#supported-editor-extensions).
|
||||
- You must have a [supported IDE editor extension](index.md#supported-editor-extensions).
|
||||
- Code Suggestions must be enabled for:
|
||||
- [The top-level group](../../../group/manage.md#enable-code-suggestions).
|
||||
- [Your own account](../../../profile/preferences.md#enable-code-suggestions).
|
||||
|
||||
[Use Code Suggestions](index.md#use-code-suggestions).
|
||||
To use Code Suggestions:
|
||||
|
||||
1. Author your code. As you type, suggestions are displayed.
|
||||
Code Suggestions provide code snippets or complete the current line, depending on the cursor position.
|
||||
1. Describe the requirements in natural language. Be concise and specific. Code Suggestions generates functions and code snippets as appropriate.
|
||||
1. To accept a suggestion, press <kbd>Tab</kbd>.
|
||||
1. To ignore a suggestion, keep typing as you usually would.
|
||||
1. To explicitly reject a suggestion, press <kbd>Esc</kbd>.
|
||||
|
||||
Things to remember:
|
||||
|
||||
- AI is non-deterministic, so you may not get the same suggestion every time with the same input.
|
||||
- Just like product requirements, writing clear, descriptive, and specific tasks results in quality generated code.
|
||||
|
|
|
|||
|
|
@ -151,10 +151,22 @@ Without the manual synchronization, it might take up to 24 hours to active Code
|
|||
|
||||
Prerequisites:
|
||||
|
||||
- Code Suggestions must be enabled [for the instance](#enable-code-suggestions-on-self-managed-gitlab).
|
||||
- You must have installed and configured a [supported IDE editor extension](index.md#supported-editor-extensions).
|
||||
- You must have a [supported IDE editor extension](index.md#supported-editor-extensions).
|
||||
- Code Suggestions must be enabled [for your instance](self_managed.md#enable-code-suggestions-on-self-managed-gitlab).
|
||||
|
||||
[Use Code Suggestions](index.md#use-code-suggestions).
|
||||
To use Code Suggestions:
|
||||
|
||||
1. Author your code. As you type, suggestions are displayed.
|
||||
Code Suggestions provide code snippets or complete the current line, depending on the cursor position.
|
||||
1. Describe the requirements in natural language. Be concise and specific. Code Suggestions generates functions and code snippets as appropriate.
|
||||
1. To accept a suggestion, press <kbd>Tab</kbd>.
|
||||
1. To ignore a suggestion, keep typing as you usually would.
|
||||
1. To explicitly reject a suggestion, press <kbd>Esc</kbd>.
|
||||
|
||||
Things to remember:
|
||||
|
||||
- AI is non-deterministic, so you may not get the same suggestion every time with the same input.
|
||||
- Just like product requirements, writing clear, descriptive, and specific tasks results in quality generated code.
|
||||
|
||||
### Data privacy
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ module API
|
|||
end
|
||||
|
||||
def run_id
|
||||
""
|
||||
object.candidate.eid
|
||||
end
|
||||
|
||||
def status
|
||||
|
|
|
|||
|
|
@ -5,6 +5,8 @@ module API
|
|||
module Ml
|
||||
module Mlflow
|
||||
class RunInfo < Grape::Entity
|
||||
include ::API::Helpers::RelatedResourcesHelpers
|
||||
|
||||
expose :run_id
|
||||
expose :run_id, as: :run_uuid
|
||||
expose(:experiment_id) { |candidate| candidate.experiment.iid.to_s }
|
||||
|
|
@ -12,7 +14,7 @@ module API
|
|||
expose :end_time, expose_nil: false
|
||||
expose :name, as: :run_name, expose_nil: false
|
||||
expose(:status) { |candidate| candidate.status.to_s.upcase }
|
||||
expose(:artifact_uri) { |candidate, options| "#{options[:packages_url]}#{candidate.artifact_root}" }
|
||||
expose :artifact_uri
|
||||
expose(:lifecycle_stage) { |candidate| 'active' }
|
||||
expose(:user_id) { |candidate| candidate.user_id.to_s }
|
||||
|
||||
|
|
@ -21,6 +23,34 @@ module API
|
|||
def run_id
|
||||
object.eid.to_s
|
||||
end
|
||||
|
||||
def artifact_uri
|
||||
expose_url(model_version_uri || generic_package_uri)
|
||||
end
|
||||
|
||||
# Example: http://127.0.0.1:3000/api/v4/projects/20/packages/ml_models/my-model-name-4/3.0.0
|
||||
def model_version_uri
|
||||
return unless object.model_version_id
|
||||
|
||||
model_version = object.model_version
|
||||
|
||||
path = api_v4_projects_packages_ml_models_model_version_path(
|
||||
id: object.project.id, model_name: model_version.model.name, model_version: '', file_name: ''
|
||||
)
|
||||
|
||||
path.sub('/model_version', "/#{model_version.version}")
|
||||
end
|
||||
|
||||
# Example: http://127.0.0.1:3000/api/v4/projects/20/packages/generic/ml_experiment_1/1/
|
||||
# Note: legacy format
|
||||
def generic_package_uri
|
||||
path = api_v4_projects_packages_generic_package_version_path(
|
||||
id: object.project.id, package_name: '', file_name: ''
|
||||
)
|
||||
path = path.delete_suffix('/package_version')
|
||||
|
||||
[path, object.artifact_root].join('')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -132,15 +132,6 @@ module API
|
|||
def model
|
||||
@model ||= find_model(user_project, params[:name])
|
||||
end
|
||||
|
||||
def packages_url
|
||||
path = api_v4_projects_packages_generic_package_version_path(
|
||||
id: user_project.id, package_name: '', file_name: ''
|
||||
)
|
||||
path = path.delete_suffix('/package_version')
|
||||
|
||||
expose_url(path)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ module API
|
|||
end
|
||||
post 'create', urgency: :low do
|
||||
present candidate_repository.create!(experiment, params[:start_time], params[:tags], params[:run_name]),
|
||||
with: Entities::Ml::Mlflow::GetRun, packages_url: packages_url
|
||||
with: Entities::Ml::Mlflow::GetRun
|
||||
end
|
||||
|
||||
desc 'Gets an MLFlow Run, which maps to GitLab Candidates' do
|
||||
|
|
@ -43,7 +43,7 @@ module API
|
|||
optional :run_uuid, type: String, desc: 'This parameter is ignored'
|
||||
end
|
||||
get 'get', urgency: :low do
|
||||
present candidate, with: Entities::Ml::Mlflow::GetRun, packages_url: packages_url
|
||||
present candidate, with: Entities::Ml::Mlflow::GetRun
|
||||
end
|
||||
|
||||
desc 'Searches runs/candidates within a project' do
|
||||
|
|
@ -83,7 +83,7 @@ module API
|
|||
next_page_token: paginator.cursor_for_next_page
|
||||
}
|
||||
|
||||
present result, with: Entities::Ml::Mlflow::SearchRuns, packages_url: packages_url
|
||||
present result, with: Entities::Ml::Mlflow::SearchRuns
|
||||
end
|
||||
|
||||
desc 'Updates a Run.' do
|
||||
|
|
@ -101,7 +101,7 @@ module API
|
|||
post 'update', urgency: :low do
|
||||
candidate_repository.update(candidate, params[:status], params[:end_time])
|
||||
|
||||
present candidate, with: Entities::Ml::Mlflow::UpdateRun, packages_url: packages_url
|
||||
present candidate, with: Entities::Ml::Mlflow::UpdateRun
|
||||
end
|
||||
|
||||
desc 'Logs a metric to a run.' do
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ module ExtractsRef
|
|||
|
||||
class << self
|
||||
def ref_type(type)
|
||||
return unless REF_TYPES.include?(type&.downcase)
|
||||
return unless REF_TYPES.include?(type.to_s.downcase)
|
||||
|
||||
type.downcase
|
||||
end
|
||||
|
|
|
|||
|
|
@ -32845,6 +32845,9 @@ msgstr ""
|
|||
msgid "Number of files touched"
|
||||
msgstr ""
|
||||
|
||||
msgid "Number of references exceeds the limit. Please provide no more than %{refs_limit} references at the same time."
|
||||
msgstr ""
|
||||
|
||||
msgid "Number of replicas"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -6,7 +6,10 @@ module RuboCop
|
|||
class IDType < RuboCop::Cop::Base
|
||||
MSG = 'Do not use GraphQL::Types::ID, use a specific GlobalIDType instead'
|
||||
|
||||
ALLOWLISTED_ARGUMENTS = %i[iid full_path project_path group_path target_project_path namespace_path].freeze
|
||||
ALLOWLISTED_ARGUMENTS = %i[
|
||||
iid full_path project_path group_path target_project_path namespace_path
|
||||
context_namespace_path
|
||||
].freeze
|
||||
|
||||
def_node_search :graphql_id_type?, <<~PATTERN
|
||||
(send nil? :argument (_ #does_not_match?) (const (const (const nil? :GraphQL) :Types) :ID) ...)
|
||||
|
|
|
|||
|
|
@ -25,8 +25,6 @@ RSpec.describe Ci::JobsHelper, feature_category: :continuous_integration do
|
|||
"artifact_help_url" => "/help/user/gitlab_com/index.md#gitlab-cicd",
|
||||
"deployment_help_url" => "/help/user/project/clusters/deploy_to_cluster.md#troubleshooting",
|
||||
"runner_settings_url" => "/#{project.full_path}/-/runners#js-runners-settings",
|
||||
"build_status" => "pending",
|
||||
"build_stage" => "test",
|
||||
"retry_outdated_job_docs_url" => "/help/ci/pipelines/settings#retry-outdated-jobs",
|
||||
"test_report_summary_url" => "/#{project.full_path}/-/jobs/#{job.id}/test_report_summary.json",
|
||||
"pipeline_test_report_url" => "/#{project.full_path}/-/pipelines/#{job.pipeline.id}/test_report"
|
||||
|
|
|
|||
|
|
@ -3,9 +3,9 @@
|
|||
require 'spec_helper'
|
||||
|
||||
RSpec.describe API::Entities::Ml::Mlflow::RunInfo, feature_category: :mlops do
|
||||
let_it_be(:candidate) { build(:ml_candidates) }
|
||||
let_it_be(:candidate) { build_stubbed(:ml_candidates, internal_id: 1) }
|
||||
|
||||
subject { described_class.new(candidate, packages_url: 'http://example.com').as_json }
|
||||
subject { described_class.new(candidate).as_json }
|
||||
|
||||
context 'when start_time is nil' do
|
||||
it { expect(subject[:start_time]).to eq(0) }
|
||||
|
|
@ -66,8 +66,19 @@ RSpec.describe API::Entities::Ml::Mlflow::RunInfo, feature_category: :mlops do
|
|||
end
|
||||
|
||||
describe 'artifact_uri' do
|
||||
it 'is not implemented' do
|
||||
expect(subject[:artifact_uri]).to eq("http://example.com#{candidate.artifact_root}")
|
||||
context 'when candidate does not belong to a model version' do
|
||||
it 'returns the generic package (legacy) format of the artifact_uri' do
|
||||
expect(subject[:artifact_uri]).to eq("http://localhost/api/v4/projects/#{candidate.project_id}/packages/generic#{candidate.artifact_root}")
|
||||
end
|
||||
end
|
||||
|
||||
context 'when candidate belongs to a model version' do
|
||||
let!(:version) { create(:ml_model_versions, :with_package) }
|
||||
let!(:candidate) { version.candidate }
|
||||
|
||||
it 'returns the model version format of the artifact_uri' do
|
||||
expect(subject[:artifact_uri]).to eq("http://localhost/api/v4/projects/#{candidate.project_id}/packages/ml_models/#{version.model.name}/#{version.version}")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -5,39 +5,6 @@ require 'spec_helper'
|
|||
RSpec.describe API::Ml::Mlflow::ApiHelpers, feature_category: :mlops do
|
||||
include described_class
|
||||
|
||||
describe '#packages_url' do
|
||||
subject { packages_url }
|
||||
|
||||
let_it_be(:user_project) { build_stubbed(:project) }
|
||||
|
||||
context 'with an empty relative URL root' do
|
||||
before do
|
||||
allow(Gitlab::Application.routes).to receive(:default_url_options)
|
||||
.and_return(protocol: 'http', host: 'localhost', script_name: '')
|
||||
end
|
||||
|
||||
it { is_expected.to eql("http://localhost/api/v4/projects/#{user_project.id}/packages/generic") }
|
||||
end
|
||||
|
||||
context 'with a forward slash relative URL root' do
|
||||
before do
|
||||
allow(Gitlab::Application.routes).to receive(:default_url_options)
|
||||
.and_return(protocol: 'http', host: 'localhost', script_name: '/')
|
||||
end
|
||||
|
||||
it { is_expected.to eql("http://localhost/api/v4/projects/#{user_project.id}/packages/generic") }
|
||||
end
|
||||
|
||||
context 'with a relative URL root' do
|
||||
before do
|
||||
allow(Gitlab::Application.routes).to receive(:default_url_options)
|
||||
.and_return(protocol: 'http', host: 'localhost', script_name: '/gitlab/root')
|
||||
end
|
||||
|
||||
it { is_expected.to eql("http://localhost/gitlab/root/api/v4/projects/#{user_project.id}/packages/generic") }
|
||||
end
|
||||
end
|
||||
|
||||
describe '#candidates_order_params' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe ExtractsRef do
|
||||
RSpec.describe ExtractsRef, feature_category: :source_code_management do
|
||||
include described_class
|
||||
include RepoHelpers
|
||||
|
||||
|
|
@ -98,6 +98,12 @@ RSpec.describe ExtractsRef do
|
|||
|
||||
it { is_expected.to eq(nil) }
|
||||
end
|
||||
|
||||
context 'when ref_type is a hash' do
|
||||
let(:ref_type) { { 'just' => 'hash' } }
|
||||
|
||||
it { is_expected.to eq(nil) }
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'extracts refs'
|
||||
|
|
|
|||
|
|
@ -0,0 +1,130 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe 'find work items by reference', feature_category: :portfolio_management do
|
||||
include GraphqlHelpers
|
||||
|
||||
let_it_be(:current_user) { create(:user) }
|
||||
let_it_be(:project) { create(:project, :repository, :public) }
|
||||
let_it_be(:group2) { create(:group, :public) }
|
||||
let_it_be(:project2) { create(:project, :repository, :public, group: group2) }
|
||||
let_it_be(:private_project2) { create(:project, :repository, :private, group: group2) }
|
||||
let_it_be(:work_item) { create(:work_item, :task, project: project2) }
|
||||
let_it_be(:private_work_item) { create(:work_item, :task, project: private_project2) }
|
||||
|
||||
let(:references) { [work_item.to_reference(full: true), private_work_item.to_reference(full: true)] }
|
||||
|
||||
shared_examples 'response with matching work items' do
|
||||
it 'returns accessible work item' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expected_items = items.map { |item| a_graphql_entity_for(item) }
|
||||
expect(graphql_data_at('workItemsByReference', 'nodes')).to match(expected_items)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has access only to public work items' do
|
||||
it_behaves_like 'a working graphql query that returns data' do
|
||||
before do
|
||||
post_graphql(query, current_user: current_user)
|
||||
end
|
||||
end
|
||||
|
||||
it_behaves_like 'response with matching work items' do
|
||||
let(:items) { [work_item] }
|
||||
end
|
||||
|
||||
it 'avoids N+1 queries', :use_sql_query_cache do
|
||||
post_graphql(query, current_user: current_user) # warm up
|
||||
|
||||
control_count = ActiveRecord::QueryRecorder.new(skip_cached: false) do
|
||||
post_graphql(query, current_user: current_user)
|
||||
end
|
||||
expect(graphql_data_at('workItemsByReference', 'nodes').size).to eq(1)
|
||||
|
||||
extra_work_items = create_list(:work_item, 2, :task, project: project2)
|
||||
refs = references + extra_work_items.map { |item| item.to_reference(full: true) }
|
||||
|
||||
expect do
|
||||
post_graphql(query(refs: refs), current_user: current_user)
|
||||
end.not_to exceed_all_query_limit(control_count)
|
||||
expect(graphql_data_at('workItemsByReference', 'nodes').size).to eq(3)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user has access to work items in private project' do
|
||||
before_all do
|
||||
private_project2.add_guest(current_user)
|
||||
end
|
||||
|
||||
it_behaves_like 'response with matching work items' do
|
||||
let(:items) { [private_work_item, work_item] }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when refs includes links' do
|
||||
let_it_be(:work_item_with_url) { create(:work_item, :task, project: project2) }
|
||||
let(:references) { [work_item.to_reference(full: true), Gitlab::UrlBuilder.build(work_item_with_url)] }
|
||||
|
||||
it_behaves_like 'response with matching work items' do
|
||||
let(:items) { [work_item_with_url, work_item] }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when refs includes a short reference present in the context project' do
|
||||
let_it_be(:same_project_work_item) { create(:work_item, :task, project: project) }
|
||||
let(:references) { ["##{same_project_work_item.iid}"] }
|
||||
|
||||
it_behaves_like 'response with matching work items' do
|
||||
let(:items) { [same_project_work_item] }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when user cannot access context namespace' do
|
||||
it 'returns error' do
|
||||
post_graphql(query(namespace_path: private_project2.full_path), current_user: current_user)
|
||||
|
||||
expect(graphql_data_at('workItemsByReference')).to be_nil
|
||||
expect(graphql_errors).to contain_exactly(a_hash_including(
|
||||
'message' => a_string_including("you don't have permission to perform this action"),
|
||||
'path' => %w[workItemsByReference]
|
||||
))
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the context is a group' do
|
||||
it 'returns empty result' do
|
||||
group2.add_guest(current_user)
|
||||
post_graphql(query(namespace_path: group2.full_path), current_user: current_user)
|
||||
|
||||
expect_graphql_errors_to_be_empty
|
||||
expect(graphql_data_at('workItemsByReference', 'nodes')).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'when there are more than the max allowed references' do
|
||||
let(:references_limit) { ::Resolvers::WorkItemReferencesResolver::REFERENCES_LIMIT }
|
||||
let(:references) { (0..references_limit).map { |n| "##{n}" } }
|
||||
let(:error_msg) do
|
||||
"Number of references exceeds the limit. " \
|
||||
"Please provide no more than #{references_limit} references at the same time."
|
||||
end
|
||||
|
||||
it 'returns an error message' do
|
||||
post_graphql(query, current_user: current_user)
|
||||
|
||||
expect_graphql_errors_to_include(error_msg)
|
||||
end
|
||||
end
|
||||
|
||||
def query(namespace_path: project.full_path, refs: references)
|
||||
fields = <<~GRAPHQL
|
||||
nodes {
|
||||
#{all_graphql_fields_for('WorkItem', max_depth: 2)}
|
||||
}
|
||||
GRAPHQL
|
||||
|
||||
graphql_query_for('workItemsByReference', { contextNamespacePath: namespace_path, refs: refs }, fields)
|
||||
end
|
||||
end
|
||||
|
|
@ -30,7 +30,8 @@ module Support
|
|||
duration = time_now - @start_time
|
||||
elapsed_time = time_now - @rspec_test_suite_start_time
|
||||
|
||||
output.puts "\n# Example group #{notification.group.description} took #{readable_duration(duration)}."
|
||||
output.puts "\n# Example group #{notification.group.description} " \
|
||||
"(#{notification.group.metadata[:file_path]}) took #{readable_duration(duration)}."
|
||||
output.puts "# RSpec elapsed time: #{readable_duration(elapsed_time)}.\n\n"
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -43,6 +43,7 @@ RSpec.shared_context 'with FOSS query type fields' do
|
|||
:user,
|
||||
:users,
|
||||
:work_item,
|
||||
:work_items_by_reference,
|
||||
:audit_event_definitions,
|
||||
:abuse_report,
|
||||
:abuse_report_labels
|
||||
|
|
|
|||
|
|
@ -96,18 +96,6 @@ RSpec.shared_examples 'an update storage move worker' do
|
|||
expect(repository_storage_move.reload).to be_failed
|
||||
end
|
||||
end
|
||||
|
||||
context 'when feature flag "use_lock_for_update_repository_storage" is disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_lock_for_update_repository_storage: false)
|
||||
end
|
||||
|
||||
it 'ignores lock and calls the update repository storage service' do
|
||||
expect(service).to receive(:execute)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -172,18 +160,6 @@ RSpec.shared_examples 'an update storage move worker' do
|
|||
expect(repository_storage_move.reload).to be_failed
|
||||
end
|
||||
end
|
||||
|
||||
context 'when feature flag "use_lock_for_update_repository_storage" is disabled' do
|
||||
before do
|
||||
stub_feature_flags(use_lock_for_update_repository_storage: false)
|
||||
end
|
||||
|
||||
it 'ignores lock and calls the update repository storage service' do
|
||||
expect(service).to receive(:execute)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -148,6 +148,12 @@ RSpec.describe Tooling::ParallelRSpecRunner, feature_category: :tooling do # rub
|
|||
Parsing expected rspec suite duration...
|
||||
03_spec.rb not found in master report
|
||||
RSpec suite is expected to take 1 minute 5 seconds.
|
||||
Expected duration for tests:
|
||||
|
||||
{
|
||||
"01_spec.rb": 65
|
||||
}
|
||||
|
||||
Running command: bundle exec rspec -- 01_spec.rb 03_spec.rb
|
||||
|
||||
MARKDOWN
|
||||
|
|
|
|||
|
|
@ -90,6 +90,9 @@ module Tooling
|
|||
knapsack_dir = File.dirname(ENV['KNAPSACK_RSPEC_SUITE_REPORT_PATH'])
|
||||
FileUtils.mkdir_p(knapsack_dir)
|
||||
File.write(File.join(knapsack_dir, 'node_specs_expected_duration.json'), JSON.dump(expected_duration_report))
|
||||
|
||||
Knapsack.logger.info "Expected duration for tests:\n\n"
|
||||
Knapsack.logger.info "#{JSON.pretty_generate(expected_duration_report)}\n\n"
|
||||
end
|
||||
|
||||
if node_tests.empty?
|
||||
|
|
|
|||
Loading…
Reference in New Issue