Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-09-07 18:09:15 +00:00
parent 06c9acad67
commit 1869c23b11
67 changed files with 568 additions and 319 deletions

View File

@ -345,7 +345,6 @@ Layout/LineLength:
- 'app/models/integrations/base_chat_notification.rb'
- 'app/models/integrations/base_issue_tracker.rb'
- 'app/models/integrations/bugzilla.rb'
- 'app/models/integrations/campfire.rb'
- 'app/models/integrations/chat_message/deployment_message.rb'
- 'app/models/integrations/chat_message/merge_message.rb'
- 'app/models/integrations/chat_message/note_message.rb'

View File

@ -80,7 +80,6 @@ Style/FormatString:
- 'app/models/integrations/asana.rb'
- 'app/models/integrations/bamboo.rb'
- 'app/models/integrations/bugzilla.rb'
- 'app/models/integrations/campfire.rb'
- 'app/models/integrations/chat_message/pipeline_message.rb'
- 'app/models/integrations/confluence.rb'
- 'app/models/integrations/custom_issue_tracker.rb'

View File

@ -24,7 +24,6 @@ Style/RedundantFreeze:
- 'app/models/error_tracking/project_error_tracking_setting.rb'
- 'app/models/hooks/web_hook.rb'
- 'app/models/integrations/apple_app_store.rb'
- 'app/models/integrations/campfire.rb'
- 'app/models/integrations/chat_message/base_message.rb'
- 'app/models/integrations/confluence.rb'
- 'app/models/integrations/datadog.rb'

View File

@ -87,7 +87,6 @@ Style/RedundantSelf:
- 'app/models/integrations/base_ci.rb'
- 'app/models/integrations/base_issue_tracker.rb'
- 'app/models/integrations/base_slash_commands.rb'
- 'app/models/integrations/campfire.rb'
- 'app/models/integrations/emails_on_push.rb'
- 'app/models/integrations/jira.rb'
- 'app/models/integrations/pipelines_email.rb'

View File

@ -6,7 +6,6 @@ Style/StringLiteralsInInterpolation:
- 'app/helpers/colors_helper.rb'
- 'app/models/application_setting_implementation.rb'
- 'app/models/ci/namespace_mirror.rb'
- 'app/models/integrations/campfire.rb'
- 'app/models/integrations/jira.rb'
- 'app/services/draft_notes/publish_service.rb'
- 'app/services/projects/create_service.rb'

View File

@ -108,7 +108,6 @@ export default {
<gl-form-group
id="commit-group"
:label="$options.i18n.commitMessage"
label-cols-sm="2"
label-for="commit-message"
>
<gl-form-textarea
@ -122,7 +121,6 @@ export default {
<gl-form-group
id="source-branch-group"
:label="$options.i18n.sourceBranch"
label-cols-sm="2"
label-for="source-branch-field"
>
<gl-form-input

View File

@ -52,7 +52,7 @@ export default {
};
</script>
<template>
<div class="gl-mb-4 gl-display-flex gl-flex-wrap gl-gap-3">
<div class="gl-display-flex gl-flex-wrap gl-gap-3">
<gl-button
v-if="showFileTreeToggle"
id="file-tree-toggle"

View File

@ -1,30 +1,11 @@
<script>
import { GlCard } from '@gitlab/ui';
import PipelineStatus from './pipeline_status.vue';
import ValidationSegment from './validation_segment.vue';
const baseClasses = ['gl-p-5', 'gl-bg-gray-10', 'gl-border-solid', 'gl-border-gray-100'];
const pipelineStatusClasses = [
...baseClasses,
'gl-border-1',
'gl-border-b-0!',
'gl-rounded-top-base',
];
const validationSegmentClasses = [...baseClasses, 'gl-border-1', 'gl-rounded-base'];
const validationSegmentWithPipelineStatusClasses = [
...baseClasses,
'gl-border-1',
'gl-rounded-bottom-left-base',
'gl-rounded-bottom-right-base',
];
export default {
pipelineStatusClasses,
validationSegmentClasses,
validationSegmentWithPipelineStatusClasses,
components: {
GlCard,
PipelineStatus,
ValidationSegment,
},
@ -47,24 +28,19 @@ export default {
showPipelineStatus() {
return !this.isNewCiConfigFile;
},
// make sure corners are rounded correctly depending on if
// pipeline status is rendered
validationStyling() {
return this.showPipelineStatus
? this.$options.validationSegmentWithPipelineStatusClasses
: this.$options.validationSegmentClasses;
},
},
};
</script>
<template>
<div class="gl-mb-5">
<pipeline-status
v-if="showPipelineStatus"
:commit-sha="commitSha"
:class="$options.pipelineStatusClasses"
v-on="$listeners"
/>
<validation-segment :class="validationStyling" :ci-config="ciConfigData" />
</div>
<gl-card
class="gl-new-card gl-mb-3"
header-class="gl-new-card-header"
body-class="gl-new-card-body gl-py-4 gl-px-5"
>
<template v-if="showPipelineStatus" #header>
<pipeline-status :commit-sha="commitSha" v-on="$listeners" />
</template>
<validation-segment :ci-config="ciConfigData" />
</gl-card>
</template>

View File

@ -138,7 +138,9 @@ export default {
</script>
<template>
<div class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-wrap">
<div
class="gl-display-flex gl-justify-content-space-between gl-align-items-center gl-flex-wrap gl-w-full"
>
<template v-if="showLoadingState">
<div>
<gl-loading-icon class="gl-mr-auto gl-display-inline-block" size="sm" />
@ -146,13 +148,15 @@ export default {
</div>
</template>
<template v-else-if="hasError">
<gl-icon class="gl-mr-auto" name="warning-solid" />
<span data-testid="pipeline-error-msg">{{ $options.i18n.fetchError }}</span>
<div>
<gl-icon class="gl-mr-auto" name="warning-solid" />
<span data-testid="pipeline-error-msg">{{ $options.i18n.fetchError }}</span>
</div>
</template>
<template v-else>
<div class="gl-text-truncate gl-md-max-w-50p gl-mr-1">
<a :href="status.detailsPath" class="gl-mr-auto">
<ci-icon :status="status" :size="16" data-testid="pipeline-status-icon" />
<ci-icon :status="status" :size="16" data-testid="pipeline-status-icon" class="gl-mr-2" />
</a>
<span class="gl-font-weight-bold">
<gl-sprintf :message="$options.i18n.pipelineInfo">
@ -182,9 +186,8 @@ export default {
/>
<pipeline-editor-mini-graph v-else :pipeline="pipeline" v-on="$listeners" />
<gl-button
class="gl-ml-3"
category="secondary"
variant="confirm"
class="gl-ml-3 gl-align-self-center"
size="small"
:href="status.detailsPath"
data-testid="pipeline-view-btn"
>

View File

@ -113,7 +113,7 @@ export default {
</template>
<span v-else data-testid="validation-segment">
<span class="gl-max-w-full">
<gl-icon :name="icon" />
<gl-icon :name="icon" class="gl-mr-2" />
<gl-sprintf :message="message">
<template v-if="hasLink" #link="{ content }">
<gl-link :href="helpPath">{{ content }}</gl-link>

View File

@ -579,10 +579,12 @@ export default class MergeRequestTabs {
expandViewContainer() {
this.contentWrapper.classList.remove('container-limited');
this.contentWrapper.classList.add('diffs-container-limited');
}
resetViewContainer() {
this.contentWrapper.classList.toggle('container-limited', this.isFixedLayoutPreferred);
this.contentWrapper.classList.remove('diffs-container-limited');
}
// Expand the issuable sidebar unless the user explicitly collapsed it

View File

@ -183,7 +183,7 @@ export default {
v-gl-tooltip
:href="ciTroubleshootingDocsPath"
target="_blank"
:title="__('About this feature')"
:title="__('Get more information about troubleshooting pipelines')"
class="gl-display-flex gl-align-items-center gl-ml-2"
>
<gl-icon

View File

@ -985,6 +985,14 @@ $tabs-holder-z-index: 250;
}
}
.container-fluid.diffs-container-limited {
.flash-container {
@include gl-mx-auto;
@include gl-max-w-container-xl;
@include gl-px-5;
}
}
.submit-review-dropdown {
&.show .dropdown-menu {
width: calc(100vw - 20px);

View File

@ -42,6 +42,8 @@ class Groups::RunnersController < Groups::ApplicationController
@runner ||= Ci::RunnersFinder.new(current_user: current_user, params: group_params).execute
.except(:limit, :offset)
.find(params[:id])
rescue Gitlab::Access::AccessDeniedError
nil
end
def runner_params

View File

@ -24,9 +24,6 @@ module Ci
request_tag_list!
@runners
rescue Gitlab::Access::AccessDeniedError
Ci::Runner.none
end
def sort_key

View File

@ -46,10 +46,16 @@ module Resolvers
::Ci::RunnersFinder
.new(current_user: current_user, params: runners_finder_params(args))
.execute)
rescue Gitlab::Access::AccessDeniedError
handle_access_denied_error!
end
protected
def handle_access_denied_error!
raise_resource_not_available_error!
end
def runners_finder_params(params)
# Give preference to paused argument over the deprecated 'active' argument
paused = params.fetch(:paused, params[:active] ? !params[:active] : nil)

View File

@ -128,7 +128,8 @@ module Types
field :runners, Types::Ci::RunnerType.connection_type,
null: true,
resolver: Resolvers::Ci::RunnersResolver,
description: "Find runners visible to the current user."
description: "Get all runners in the GitLab instance (project and shared). " \
"Access is restricted to users with administrator access."
field :snippets,
Types::SnippetType.connection_type,
null: true,

View File

@ -4,6 +4,7 @@ module Emails
module ServiceDesk
extend ActiveSupport::Concern
include MarkupHelper
include ::ServiceDesk::CustomEmails::Logger
EMAIL_ATTACHMENTS_SIZE_LIMIT = 10.megabytes.freeze
@ -61,6 +62,7 @@ module Emails
def service_desk_custom_email_verification_email(service_desk_setting)
@service_desk_setting = service_desk_setting
@project = @service_desk_setting.project
email_sender = sender(
Users::Internal.support_bot.id,
@ -73,7 +75,7 @@ module Emails
subject = format(s_("Notify|Verify custom email address %{email} for %{project_name}"),
email: @service_desk_setting.custom_email,
project_name: @service_desk_setting.project.name
project_name: @project.name
)
options = {
@ -142,6 +144,8 @@ module Emails
# Only set custom email reply address if it's enabled, not when we force it.
inject_service_desk_custom_email_reply_address unless force
log_info(project: @project)
mail.delivery_method(::Mail::SMTP, @service_desk_setting.custom_email_credential.delivery_options)
end

View File

@ -2,7 +2,7 @@
module Integrations
class Campfire < Integration
SUBDOMAIN_REGEXP = %r{\A[a-z](?:[a-z0-9-]*[a-z0-9])?\z}i.freeze
SUBDOMAIN_REGEXP = %r{\A[a-z](?:[a-z0-9-]*[a-z0-9])?\z}i
validates :token, presence: true, if: :activated?
validates :room,
@ -26,12 +26,9 @@ module Integrations
placeholder: '',
exposes_secrets: true,
help: -> do
ERB::Util.html_escape(
format(ERB::Util.html_escape(
s_('CampfireService|The %{code_open}.campfirenow.com%{code_close} subdomain.')
) % {
code_open: '<code>'.html_safe,
code_close: '</code>'.html_safe
}
), code_open: '<code>'.html_safe, code_close: '</code>'.html_safe)
end
field :room,
@ -48,13 +45,16 @@ module Integrations
end
def help
docs_link = ActionController::Base.helpers.link_to _('Learn more.'), Rails.application.routes.url_helpers.help_page_url('api/services', anchor: 'campfire'), target: '_blank', rel: 'noopener noreferrer'
docs_link = ActionController::Base.helpers.link_to(
_('Learn more.'),
Rails.application.routes.url_helpers.help_page_url('api/integrations', anchor: 'campfire'),
target: '_blank',
rel: 'noopener noreferrer'
)
ERB::Util.html_escape(
format(ERB::Util.html_escape(
s_('CampfireService|Send notifications about push events to Campfire chat rooms. %{docs_link}')
) % {
docs_link: docs_link.html_safe
}
), docs_link: docs_link.html_safe)
end
def self.to_param
@ -69,7 +69,7 @@ module Integrations
return unless supported_events.include?(data[:object_kind])
message = create_message(data)
speak(self.room, message, auth)
speak(room, message, auth)
end
private
@ -96,7 +96,7 @@ module Integrations
room = rooms(auth).find { |r| r["name"] == room_name }
return unless room
path = "/room/#{room["id"]}/speak.json"
path = "/room/#{room['id']}/speak.json"
body = {
body: {
message: {

View File

@ -11,17 +11,17 @@ module ServiceDesk
end
end
def log_info(error_message: nil)
with_context do
def log_info(error_message: nil, project: nil)
with_context(project: project) do
Gitlab::AppLogger.info(build_log_message(error_message: error_message))
end
end
def with_context(&block)
def with_context(project: nil, &block)
Gitlab::ApplicationContext.with_context(
related_class: self.class.to_s,
user: current_user,
project: project,
project: project || self.project,
&block
)
end

View File

@ -45,10 +45,12 @@ else
/Merging .* no longer maintain both conditions, and will be replaced by the latter in Rails 7\.0/,
# https://gitlab.com/gitlab-org/gitlab/-/issues/415890
/(Date|Time|TimeWithZone)#to_s.+ is deprecated/,
# https://gitlab.com/gitlab-org/gitlab/-/merge_requests/129686
/Sum of non-numeric elements requires an initial argument/
]
view_component_3_warnings = [
# https://gitlab.com/gitlab-org/gitlab/-/issues/408988
/Setting a slot with `#\w+` is deprecated and will be removed from ViewComponent 3.0.0/
]
ActiveSupport::Deprecation.disallowed_warnings = rails7_deprecation_warnings + view_component_3_warnings

View File

@ -0,0 +1,18 @@
# frozen_string_literal: true
class ReplaceSbomOccurrencesComponentIdIndex < Gitlab::Database::Migration[2.1]
REMOVED_INDEX_NAME = "index_sbom_occurrences_on_component_id"
ADDED_INDEX_NAME = "index_sbom_occurrences_on_component_id_and_id"
disable_ddl_transaction!
def up
add_concurrent_index :sbom_occurrences, %i[component_id id], name: ADDED_INDEX_NAME
remove_concurrent_index_by_name :sbom_occurrences, name: REMOVED_INDEX_NAME
end
def down
add_concurrent_index :sbom_occurrences, :component_id, name: REMOVED_INDEX_NAME
remove_concurrent_index_by_name :sbom_occurrences, name: ADDED_INDEX_NAME
end
end

View File

@ -0,0 +1 @@
70e07f9790b7a9011fce37cc1376d61d84c98ef677fcce534dd97a78f892af86

View File

@ -33459,7 +33459,7 @@ CREATE UNIQUE INDEX index_sbom_components_on_component_type_name_and_purl_type O
CREATE INDEX index_sbom_occurrences_for_input_file_path_search ON sbom_occurrences USING btree (project_id, component_id, input_file_path);
CREATE INDEX index_sbom_occurrences_on_component_id ON sbom_occurrences USING btree (component_id);
CREATE INDEX index_sbom_occurrences_on_component_id_and_id ON sbom_occurrences USING btree (component_id, id);
CREATE INDEX index_sbom_occurrences_on_component_version_id ON sbom_occurrences USING btree (component_version_id);

View File

@ -156,7 +156,7 @@ The following API resources are available outside of project and group contexts
| [Avatar](avatar.md) | `/avatar` |
| [Broadcast messages](broadcast_messages.md) | `/broadcast_messages` |
| [Code snippets](snippets.md) | `/snippets` |
| [Code suggestions](code_suggestions.md) | `/code_suggestions` |
| [Code Suggestions](code_suggestions.md) | `/code_suggestions` |
| [Custom attributes](custom_attributes.md) | `/users/:id/custom_attributes` (also available for groups and projects) |
| [Deploy keys](deploy_keys.md) | `/deploy_keys` (also available for projects) |
| [Deploy tokens](deploy_tokens.md) | `/deploy_tokens` (also available for projects and groups) |

View File

@ -1,6 +1,6 @@
---
stage: Manage
group: AI assisted
stage: Create
group: Code Creation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---

View File

@ -649,7 +649,7 @@ Returns [`RunnerSetup`](#runnersetup).
### `Query.runners`
Find runners visible to the current user.
Get all runners in the GitLab instance (project and shared). Access is restricted to users with administrator access.
Returns [`CiRunnerConnection`](#cirunnerconnection).

View File

@ -519,7 +519,7 @@ POST /projects/:id/members
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `user_id` | integer/string | yes | The user ID of the new member or multiple IDs separated by commas |
| `access_level` | integer | yes | A valid access level |
| `access_level` | integer | yes | [A valid access level](access_requests.md#valid-access-levels) |
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY` |
| `invite_source` | string | no | The source of the invitation that starts the member creation process. GitLab team members can view more information in this confidential issue: `https://gitlab.com/gitlab-org/gitlab/-/issues/327120>`. |
| `tasks_to_be_done` | array of strings | no | Tasks the inviter wants the member to focus on. The tasks are added as issues to a specified project. The possible values are: `ci`, `code` and `issues`. If specified, requires `tasks_project_id`. [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/69299) in GitLab 14.5 [with a flag](../administration/feature_flags.md) named `invite_members_for_task`. Disabled by default. |
@ -571,7 +571,7 @@ PUT /projects/:id/members/:user_id
| --------- | ---- | -------- | ----------- |
| `id` | integer/string | yes | The ID or [URL-encoded path of the project or group](rest/index.md#namespaced-path-encoding) owned by the authenticated user |
| `user_id` | integer | yes | The user ID of the member |
| `access_level` | integer | yes | A valid access level |
| `access_level` | integer | yes | A [valid access level](access_requests.md#valid-access-levels) |
| `expires_at` | string | no | A date string in the format `YEAR-MONTH-DAY` |
| `member_role_id` | integer | no | The ID of a member role **(ULTIMATE ALL)** |

View File

@ -46,7 +46,7 @@ connect to 3rd party providers.
## Language: Python
The AI-Gateway was originally started as the "model-gateway" that
handled requests from IDEs to provide code suggestions. It was written
handled requests from IDEs to provide Code Suggestions. It was written
in Python.
Python is an object oriented language that is familiar enough for
@ -96,7 +96,7 @@ GitLab instances, they differ on these items:
| + Strict protocol definition that is easier to evolve versionless | - No strict schema, so the implementation needs to take good care of supporting multiple versions |
| + A new Ruby-gRPC server for vscode: likely faster because we can limit dependencies to load ([modular monolith](https://gitlab.com/gitlab-org/gitlab/-/issues/365293)) | - Existing Grape API for vscode: meaning slow boot time and unneeded resources loaded |
| + Bi-directional streaming | - Straight forward way to stream requests and responses (could still be added) |
| - A new Python-gRPC server: we don't have experience running gRPC-Python servers | + Existing Python fastapi server, already running for code suggestions to extend |
| - A new Python-gRPC server: we don't have experience running gRPC-Python servers | + Existing Python fastapi server, already running for Code Suggestions to extend |
| - Hard to pass on unknown messages from vscode through GitLab to ai-gateway | + Easier support for newer vscode + newer ai-gatway, through old GitLab instance |
| - Unknown support for gRPC in other clients (vscode, jetbrains, other editors) | + Support in all external clients |
| - Possible protocol mismatch (VSCode --REST--> Rails --gRPC--> AI gateway) | + Same protocol across the stack |
@ -116,7 +116,7 @@ with a stable API over the [provider API we expose](#exposing-ai-providers)
as a direct proxy.
Some features will have specific endpoints, while others can share
endpoints. For example, code suggestions or chat could have their own
endpoints. For example, Code Suggestions or chat could have their own
endpoint, while several features that summarize issues or merge
requests could use the same endpoint but make the distinction on what
information is provided in the payload.
@ -215,9 +215,9 @@ what is in the payload.
To document and validate the content of `payload` we can specify their
format using [JSON-schema](https://json-schema.org/).
#### Example feature: code suggestions
#### Example feature: Code Suggestions
For example, a rough code suggestions service could look like this:
For example, a rough Code Suggestions service could look like this:
```plaintext
POST /internal/code-suggestions/completions
@ -281,7 +281,7 @@ The `metadata` field contains information that could be used in a
telemetry endpoint on the AI-gateway where we could count
suggestion-acceptance rates among other things.
The way we will receive telemetry for code suggestions is being
The way we will receive telemetry for Code Suggestions is being
discussed in [#415745](https://gitlab.com/gitlab-org/gitlab/-/issues/415745).
We will try to come up with an architecture for all AI-related features.

View File

@ -38,7 +38,7 @@ Prerequisites:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Select the environment to be associated with the Kubernetes.
1. Select the environment to be associated with the agent for Kubernetes.
1. Select **Edit**.
1. Select a GitLab agent for Kubernetes.
1. Optional. From the **Kubernetes namespace** dropdown list, select a namespace.
@ -62,7 +62,7 @@ To view a configured dashboard:
1. On the left sidebar, select **Search or go to** and find your project.
1. Select **Operate > Environments**.
1. Expand the environment associated with GitLab agent for Kubernetes.
1. Expand the environment associated with the agent for Kubernetes.
1. Expand **Kubernetes overview**.
### Flux sync status

View File

@ -98,7 +98,7 @@ The following table documents functionality that Code Suggestions offers today,
#### Code Suggestions Latency
Code Suggestions acceptance rates are _highly_ sensitive to latency. While writing code with an AI assistant, a user will pause only for a short duration before continuing on with manually typing out a block of code. As soon as the user has pressed a subsequent keypress, the existing suggestion will be invalidated and a new request will need to be issued to the code suggestions endpoint. In turn, this request will also be highly sensitive to latency.
Code Suggestions acceptance rates are _highly_ sensitive to latency. While writing code with an AI assistant, a user will pause only for a short duration before continuing on with manually typing out a block of code. As soon as the user has pressed a subsequent keypress, the existing suggestion will be invalidated and a new request will need to be issued to the Code Suggestions endpoint. In turn, this request will also be highly sensitive to latency.
In a worst case with sufficient latency, the IDE could be issuing a string of requests, each of which is then ignored as the user proceeds without waiting for the response. This adds no value for the user, while still putting load on our services.

View File

@ -127,3 +127,13 @@ REAL_AI_REQUEST=1 rspec ee/spec/lib/gitlab/llm/chain/agents/zero_shot/executor_s
When you need to update the test questions that require documentation embeddings,
make sure a new fixture is generated and committed together with the change.
## GraphQL Subscription
The GraphQL Subscription for chat behaves slightly different because it's user-centric. A user could have the chat open on multiple browser tabs, or also on their IDE.
We therefore need to broadcast messages to multiple clients to keep them in sync. The `aiAction` mutation with the `chat` action behaves the following:
1. All complete chat messages (including messages from the user) are broadcasted with the `userId` and the `resourceId` from the mutation as identifier, ignoring the `clientSubscriptionId`.
1. Chunks from streamed chat messages are broadcasted with the `userId`, `resourceId`, and `clientSubscriptionId` as identifier.
To truly sync messages between all clients of a user, we need to remove the `resourceId` as well, which will be fixed by [this issue](https://gitlab.com/gitlab-org/gitlab/-/issues/420296).

View File

@ -230,20 +230,41 @@ Remember that other clients are available and you should not use OpenAI.
#### How to receive a response
As the OpenAI API requests are handled in a background job, we do not keep the request alive and
the response is sent through the `aiCompletionResponse` subscription:
The API requests to AI providers are handled in a background job. We therefore do not keep the request alive and the Frontend needs to match the request to the response from the subscription.
```mutation
subscription aiCompletionResponse($userId: UserID, $resourceId: AiModelID!) {
aiCompletionResponse(userId: $userId, resourceId: $resourceId) {
WARNING:
Determining the right response to a request can cause problems when only `userId` and `resourceId` are used. For example, when two AI features use the same `userId` and `resourceId` both subscriptions will receive the response from each other. To prevent this intereference, we introduced the `clientSubscriptionId`.
To match a response on the `aiCompletionResponse` subscription, you can provide a `clientSubscriptionId` to the `aiAction` mutation.
- The `clientSubscriptionId` should be unique per feature and within a page to not interfere with other AI features. We recommend to use a `UUID`.
- Only when the `clientSubscriptionId` is provided as part of the `aiAction` mutation, it will be used for broadcasting the `aiCompletionResponse`.
- If the `clientSubscriptionId` is not provided, only `userId` and `resourceId` are used for the `aiCompletionResponse`.
As an example mutation for summarizing comments, we provide a `randomId` as part of the mutation:
```graphql
mutation {
aiAction(input: {summarizeComments: {resourceId: "gid://gitlab/Issue/52"}, clientSubscriptionId: "randomId"}) {
clientMutationId
}
}
```
In our component, we then listen on the `aiCompletionResponse` using the `userId`, `resourceId` and `clientSubscriptionId` (`"randomId"`):
```graphql
subscription aiCompletionResponse($userId: UserID, $resourceId: AiModelID, $clientSubscriptionId: String) {
aiCompletionResponse(userId: $userId, resourceId: $resourceId, clientSubscriptionId: $clientSubscriptionId) {
responseBody
errors
}
}
```
WARNING:
You should only subscribe to the subscription once the mutation is sent. If multiple subscriptions are active on the same page, they currently all receive updates as our identifier is the user and the resource. To mitigate this, you should only subscribe when the mutation is sent. You can use [`skip()`](You can use [`skip()`](https://apollo.vuejs.org/guide/apollo/subscriptions.html#skipping-the-subscription)) for this case. To prevent this problem in the future, we implement a [request identifier](https://gitlab.com/gitlab-org/gitlab/-/issues/408196).
Note that the [subscription for chat](duo_chat.md#graphql-subscription) behaves differently.
To not have many concurrent subscriptions, you should also only subscribe to the subscription once the mutation is sent by using [`skip()`](https://apollo.vuejs.org/guide/apollo/subscriptions.html#skipping-the-subscription).
#### Current abstraction layer flow

View File

@ -4,11 +4,11 @@ group: Code Creation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
---
# Code suggestions development guidelines
# Code Suggestions development guidelines
## Code suggestions development setup
## Code Suggestions development setup
The recommended setup for locally developing and debugging code suggestions is to have all 3 different components running:
The recommended setup for locally developing and debugging Code Suggestions is to have all 3 different components running:
- IDE Extension (e.g. VSCode Extension)
- Main application configured correctly
@ -19,7 +19,7 @@ This should enable everyone to see locally any change in an IDE being sent to th
### Setup instructions
1. Install and run locally the [VSCode Extension](https://gitlab.com/gitlab-org/gitlab-vscode-extension/-/blob/main/CONTRIBUTING.md#configuring-development-environment)
1. Add the ```"gitlab.debug": true,``` info to the code suggestions development config
1. Add the ```"gitlab.debug": true,``` info to the Code Suggestions development config
1. In VSCode navigate to the Extensions page and find "GitLab Workflow" in the list
1. Open the extension settings by clicking a small cog icon and select "Extension Settings" option
1. Check a "GitLab: Debug" checkbox.

View File

@ -822,7 +822,7 @@ Example response:
## Subscription add-on purchases (excluding storage and compute packs)
The subscription add-on purchase endpoint is used by [CustomersDot](https://gitlab.com/gitlab-org/customers-gitlab-com) (`customers.gitlab.com`) to apply subscription add-on purchases like code suggestions for personal namespaces, or top-level groups within GitLab.com. It is not used to apply storage and compute pack purchases.
The subscription add-on purchase endpoint is used by [CustomersDot](https://gitlab.com/gitlab-org/customers-gitlab-com) (`customers.gitlab.com`) to apply subscription add-on purchases like Code Suggestions for personal namespaces, or top-level groups within GitLab.com. It is not used to apply storage and compute pack purchases.
### Create a subscription add-on purchase
@ -834,9 +834,9 @@ POST /namespaces/:id/subscription_add_on_purchase/:add_on_name
| Attribute | Type | Required | Description |
|:------------|:--------|:---------|:------------|
| `quantity` | integer | yes | Amount of units in the subscription add-on purchase (Example: Number of seats for a code suggestions add-on) |
| `quantity` | integer | yes | Amount of units in the subscription add-on purchase (Example: Number of seats for a Code Suggestions add-on) |
| `expires_on` | date | yes | Expiration date of the subscription add-on purchase |
| `purchase_xid` | string | yes | Identifier for the subscription add-on purchase (Example: Subscription name for a code suggestions add-on) |
| `purchase_xid` | string | yes | Identifier for the subscription add-on purchase (Example: Subscription name for a Code Suggestions add-on) |
Example request:
@ -867,9 +867,9 @@ PUT /namespaces/:id/subscription_add_on_purchase/:add_on_name
| Attribute | Type | Required | Description |
|:------------|:--------|:---------|:------------|
| `quantity` | integer | no | Amount of units in the subscription add-on purchase (Example: Number of seats for a code suggestions add-on) |
| `quantity` | integer | no | Amount of units in the subscription add-on purchase (Example: Number of seats for a Code Suggestions add-on) |
| `expires_on` | date | yes | Expiration date of the subscription add-on purchase |
| `purchase_xid` | string | no | Identifier for the subscription add-on purchase (Example: Subscription name for a code suggestions add-on) |
| `purchase_xid` | string | no | Identifier for the subscription add-on purchase (Example: Subscription name for a Code Suggestions add-on) |
Example request:

View File

@ -36,6 +36,44 @@ For more information about upgrading GitLab Helm Chart, see [the release notes f
server-side custom hooks.
1. Remove the `[gitlab-shell] dir` configuration.
- You might encounter the following error while upgrading to GitLab 16.4 or later:
```plaintext
main: == 20230830084959 ValidatePushRulesConstraints: migrating =====================
main: -- execute("SET statement_timeout TO 0")
main: -> 0.0002s
main: -- execute("ALTER TABLE push_rules VALIDATE CONSTRAINT force_push_regex_size_constraint;")
main: -> 0.0004s
main: -- execute("RESET statement_timeout")
main: -> 0.0003s
main: -- execute("ALTER TABLE push_rules VALIDATE CONSTRAINT delete_branch_regex_size_constraint;")
rails aborted!
StandardError: An error has occurred, all later migrations canceled:
PG::CheckViolation: ERROR: check constraint "delete_branch_regex_size_constraint" of relation "push_rules" is violated by some row
```
These constraints might return an error:
- `author_email_regex_size_constraint`
- `branch_name_regex_size_constraint`
- `commit_message_negative_regex_size_constraint`
- `commit_message_regex_size_constraint`
- `delete_branch_regex_size_constraint`
- `file_name_regex_size_constraint`
- `force_push_regex_size_constraint`
To fix the error, find the records in the `push_rules` table that exceed the 511
character limit.
```sql
;; replace `delete_branch_regex` with a name of the field used in constraint
SELECT id FROM push_rules WHERE LENGTH(delete_branch_regex) > 511;
```
Reduce the value length of the regex field for affected push rules records, then
retry the migration.
## 16.3.0
- For Go applications, [`crypto/tls`: verifying certificate chains containing large RSA keys is slow (CVE-2023-29409)](https://github.com/golang/go/issues/61460)

View File

@ -13,7 +13,7 @@ type: reference, howto
> - Paginated merge request discussions [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/370075) in GitLab 15.8. Feature flag `paginated_mr_discussions` removed.
GitLab encourages communication through comments, threads, and
[code suggestions](../project/merge_requests/reviews/suggestions.md).
[Code Suggestions](../project/merge_requests/reviews/suggestions.md).
Two types of comments are available:

View File

@ -39,7 +39,7 @@ Packages can be pulled from your project, group, or instance.
| [Maven (with `mvn`)](../maven_repository/index.md) | Y | Y | Y |
| [Maven (with `gradle`)](../maven_repository/index.md) | Y | Y | Y |
| [Maven (with `sbt`)](../maven_repository/index.md) | Y | Y | Y |
| [npm](../npm_registry/index.md) | Y | N | Y |
| [npm](../npm_registry/index.md) | Y | Y | Y |
| [NuGet](../nuget_repository/index.md) | Y | Y | N |
| [PyPI](../pypi_repository/index.md) | Y | Y | N |
| [Generic packages](../generic_packages/index.md) | Y | N | N |
@ -72,7 +72,7 @@ Requests for packages not found in your GitLab project are forwarded to the publ
| [Go](../go_proxy/index.md) | N |
| [Ruby gems](../rubygems_registry/index.md) | N |
### Deleting packages
## Deleting packages
When package requests are forwarded to a public registry, deleting packages can
be a [dependency confusion vulnerability](https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610).
@ -89,6 +89,27 @@ To reduce the associated security risks, before deleting a package you can:
- Instance administrators can disable forwarding in the [**Continuous Integration** section](../../../administration/settings/continuous_integration.md#package-registry-configuration) of the Admin Area.
- Group owners can disable forwarding in the **Packages and Registries** section of the group settings.
## Importing packages from other repositories
You can use GitLab pipelines to import packages from other repositories, such as Maven Central or Artifactory with the [package importer tool](https://gitlab.com/gitlab-org/ci-cd/package-stage/pkgs_importer).
| Package type | Importer available? |
|-------------------------------------------------------|---------------------|
| [Maven (with `mvn`)](../maven_repository/index.md) | Y |
| [Maven (with `gradle`)](../maven_repository/index.md) | Y |
| [Maven (with `sbt`)](../maven_repository/index.md) | Y |
| [npm](../npm_registry/index.md) | Y |
| [NuGet](../nuget_repository/index.md) | Y |
| [PyPI](../pypi_repository/index.md) | Y |
| [Generic packages](../generic_packages/index.md) | N |
| [Terraform](../terraform_module_registry/index.md) | N |
| [Composer](../composer_repository/index.md) | N |
| [Conan](../conan_repository/index.md) | N |
| [Helm](../helm_repository/index.md) | N |
| [Debian](../debian_repository/index.md) | N |
| [Go](../go_proxy/index.md) | N |
| [Ruby gems](../rubygems_registry/index.md) | N |
## Allow or prevent duplicates **(FREE ALL)**
By default, the GitLab package registry either allows or prevents duplicates based on the default of that specific package manager format.

View File

@ -261,12 +261,9 @@ For more information, see [Coverage check approval rule](../../../../ci/testing/
## Security Approvals **(ULTIMATE ALL)**
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357021) in GitLab 15.0.
> - Security approvals moved to merge request approvals settings [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/357021) in GitLab 15.0.
> - Bot comment for approvals [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/411656) in GitLab 16.2 [with a flag](../../../../administration/feature_flags.md) named `security_policy_approval_notification`. Enabled by default.
FLAG:
On self-managed GitLab, by default the bot comment for approvals is available. To hide the feature, an administrator can [disable the feature flag](../../../../administration/feature_flags.md) named `security_policy_approval_notification`.
On GitLab.com, the bot comment for approvals is available.
> - Bot comment for approvals [generally available](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/130827) in GitLab 16.3. Feature flag `security_policy_approval_notification` removed.
You can use [scan result policies](../../../application_security/policies/scan-result-policies.md#scan-result-policy-editor) to define security approvals based on the status of vulnerabilities in the merge request and the default branch.
Details for each security policy is shown in the Security Approvals section of your Merge Request configuration.

View File

@ -10,7 +10,7 @@ type: index, reference
[Merge requests](../index.md) are the primary method of making changes to files in a
GitLab project. [Create and submit a merge request](../creating_merge_requests.md)
to propose changes. Your team leaves [comments](../../../discussions/index.md) on
your merge request, and makes [code suggestions](suggestions.md) you can accept
your merge request, and makes [Code Suggestions](suggestions.md) you can accept
from the user interface. When your work is reviewed, your team members can choose
to accept or reject it.

View File

@ -6,119 +6,97 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Push options **(FREE ALL)**
GitLab supports using client-side [Git push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt)
to perform various actions at the same time as pushing changes. Additionally, [Push Rules](repository/push_rules.md) offer server-side control and enforcement options.
When you push changes to a branch, you can use client-side
[Git push options](https://git-scm.com/docs/git-push#Documentation/git-push.txt--oltoptiongt).
In Git 2.10 and later, use Git push options to:
Currently, there are push options available for:
- [Skip CI jobs](#push-options-for-gitlab-cicd)
- [Push to merge requests](#push-options-for-merge-requests)
- [Skipping CI jobs](#push-options-for-gitlab-cicd)
- [Merge requests](#push-options-for-merge-requests)
NOTE:
Git push options are only available with Git 2.10 or newer.
For Git versions 2.10 to 2.17 use `--push-option`:
```shell
git push --push-option=<push_option>
```
For version 2.18 and later, you can use the above format, or the shorter `-o`:
In Git 2.18 and later, you can use either the long format (`--push-option`) or the shorter `-o`:
```shell
git push -o <push_option>
```
In Git 2.10 to 2.17, you must use the long format:
```shell
git push --push-option=<push_option>
```
For server-side controls and enforcement of best practices, see
[push rules](repository/push_rules.md) and [server hooks](../../administration/server_hooks.md).
## Push options for GitLab CI/CD
You can use push options to skip a CI/CD pipeline, or pass CI/CD variables.
| Push option | Description | Introduced in version |
| ------------------------------ | ------------------------------------------------------------------------------------------- |---------------------- |
| `ci.skip` | Do not create a CI pipeline for the latest push. Only skips branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). This does not skip pipelines for CI integrations, such as Jenkins. | [11.7](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/15643) |
| `ci.variable="<name>=<value>"` | Provide [CI/CD variables](../../ci/variables/index.md) to be used in a CI pipeline, if one is created due to the push. Only passes variables to branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). | [12.6](https://gitlab.com/gitlab-org/gitlab/-/issues/27983) |
| `integrations.skip_ci` | Skip push events for CI integrations, such as Atlassian Bamboo, Buildkite, Drone, Jenkins, and JetBrains TeamCity. | [16.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123837) |
An example of using `ci.skip`:
```shell
git push -o ci.skip
```
An example of passing some CI/CD variables for a pipeline:
```shell
git push -o ci.variable="MAX_RETRIES=10" -o ci.variable="MAX_TIME=600"
```
An example of using `integrations.skip_ci`:
```shell
git push -o integrations.skip_ci
```
| Push option | Description | Example |
|--------------------------------|-------------|---------|
| `ci.skip` | Do not create a CI/CD pipeline for the latest push. Skips only branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). This does not skip pipelines for CI/CD integrations, such as Jenkins. | `git push -o ci.skip` |
| `ci.variable="<name>=<value>"` | Provide [CI/CD variables](../../ci/variables/index.md) to the CI/CD pipeline, if one is created due to the push. Passes variables only to branch pipelines and not [merge request pipelines](../../ci/pipelines/merge_request_pipelines.md). | `git push -o ci.variable="MAX_RETRIES=10" -o ci.variable="MAX_TIME=600"` |
| `integrations.skip_ci` | Skip push events for CI/CD integrations, such as Atlassian Bamboo, Buildkite, Drone, Jenkins, and JetBrains TeamCity. Introduced in [GitLab 16.2](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/123837). | `git push -o integrations.skip_ci` |
## Push options for merge requests
You can use Git push options to perform certain actions for merge requests at the same
time as pushing changes:
Git push options can perform actions for merge requests while pushing changes:
| Push option | Description | Introduced in version |
| -------------------------------------------- | --------------------------------------------------------------------------------------------------------------- | --------------------- |
| `merge_request.create` | Create a new merge request for the pushed branch. | [11.10](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26752) |
| `merge_request.target=<branch_name>` | Set the target of the merge request to a particular branch or upstream project, such as: `git push -o merge_request.target=project_path/branch` | [11.10](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26752) |
| `merge_request.merge_when_pipeline_succeeds` | Set the merge request to [merge when its pipeline succeeds](merge_requests/merge_when_pipeline_succeeds.md). | [11.10](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/26752) |
| `merge_request.remove_source_branch` | Set the merge request to remove the source branch when it's merged. | [12.2](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/64320) |
| `merge_request.title="<title>"` | Set the title of the merge request. For example: `git push -o merge_request.title="The title I want"`. | [12.2](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/64320) |
| `merge_request.description="<description>"` | Set the description of the merge request. For example: `git push -o merge_request.description="The description I want"`. | [12.2](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/64320) |
| `merge_request.draft` | Mark the merge request as a draft. For example: `git push -o merge_request.draft`. | [15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/296673) |
| `merge_request.milestone="<milestone>"` | Set the milestone of the merge request. For example: `git push -o merge_request.milestone="3.0"`. | [14.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63960) |
| `merge_request.label="<label>"` | Add labels to the merge request. If the label does not exist, it is created. For example, for two labels: `git push -o merge_request.label="label1" -o merge_request.label="label2"`. | [12.3](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31831) |
| `merge_request.unlabel="<label>"` | Remove labels from the merge request. For example, for two labels: `git push -o merge_request.unlabel="label1" -o merge_request.unlabel="label2"`. | [12.3](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/31831) |
| `merge_request.assign="<user>"` | Assign users to the merge request. Accepts username or user ID. For example, for two users: `git push -o merge_request.assign="user1" -o merge_request.assign="user2"`. | [13.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25904), support for usernames added in [15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276) |
| `merge_request.unassign="<user>"` | Remove assigned users from the merge request. Accepts username or user ID.For example, for two users: `git push -o merge_request.unassign="user1" -o merge_request.unassign="user2"`. | [13.10](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25904), support for usernames added in [15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276) |
| Push option | Description |
|----------------------------------------------|-------------|
| `merge_request.create` | Create a new merge request for the pushed branch. |
| `merge_request.target=<branch_name>` | Set the target of the merge request to a particular branch or upstream project, such as: `git push -o merge_request.target=project_path/branch`. |
| `merge_request.merge_when_pipeline_succeeds` | Set the merge request to [merge when its pipeline succeeds](merge_requests/merge_when_pipeline_succeeds.md). |
| `merge_request.remove_source_branch` | Set the merge request to remove the source branch when it's merged. |
| `merge_request.title="<title>"` | Set the title of the merge request. For example: `git push -o merge_request.title="The title I want"`. |
| `merge_request.description="<description>"` | Set the description of the merge request. For example: `git push -o merge_request.description="The description I want"`. |
| `merge_request.draft` | Mark the merge request as a draft. For example: `git push -o merge_request.draft`. Introduced in [GitLab 15.0](https://gitlab.com/gitlab-org/gitlab/-/issues/296673). |
| `merge_request.milestone="<milestone>"` | Set the milestone of the merge request. For example: `git push -o merge_request.milestone="3.0"`. Introduced in [GitLab 14.1](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/63960). |
| `merge_request.label="<label>"` | Add labels to the merge request. If the label does not exist, it is created. For example, for two labels: `git push -o merge_request.label="label1" -o merge_request.label="label2"`. |
| `merge_request.unlabel="<label>"` | Remove labels from the merge request. For example, for two labels: `git push -o merge_request.unlabel="label1" -o merge_request.unlabel="label2"`. |
| `merge_request.assign="<user>"` | Assign users to the merge request. Accepts username or user ID. For example, for two users: `git push -o merge_request.assign="user1" -o merge_request.assign="user2"`. Support for usernames added in [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276). |
| `merge_request.unassign="<user>"` | Remove assigned users from the merge request. Accepts username or user ID. For example, for two users: `git push -o merge_request.unassign="user1" -o merge_request.unassign="user2"`. Support for usernames added in [GitLab 15.5](https://gitlab.com/gitlab-org/gitlab/-/issues/344276). |
If you use a push option that requires text with spaces in it, you need to enclose it
in quotes (`"`). You can omit the quotes if there are no spaces. Some examples:
## Formats for push options
If your push option requires text containing spaces, enclose the text in
double quotes (`"`). You can omit the quotes if there are no spaces. Some examples:
```shell
git push -o merge_request.label="Label with spaces"
git push -o merge_request.label=Label-with-no-spaces
```
You can combine push options to accomplish multiple tasks at once, by using
multiple `-o` (or `--push-option`) flags. For example, if you want to create a new
merge request, and target a branch named `my-target-branch`:
```shell
git push -o merge_request.create -o merge_request.target=my-target-branch
```
Additionally if you want the merge request to merge as soon as the pipeline succeeds you can do:
To combine push options to accomplish multiple tasks at once, use
multiple `-o` (or `--push-option`) flags. This command creates a
new merge request, targets a branch (`my-target-branch`), and sets auto-merge:
```shell
git push -o merge_request.create -o merge_request.target=my-target-branch -o merge_request.merge_when_pipeline_succeeds
```
## Useful Git aliases
## Create Git aliases for common commands
As shown above, Git push options can cause Git commands to grow very long. If
you use the same push options frequently, it's useful to create
[Git aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases). Git aliases
are command line shortcuts for Git which can significantly simplify the use of
long Git commands.
Adding push options to Git commands can create very long commands. If
you use the same push options frequently, create Git aliases for them.
Git aliases are command-line shortcuts for longer Git commands.
### Merge when pipeline succeeds alias
To set up a Git alias for the
To create and use a Git alias for the
[merge when pipeline succeeds Git push option](#push-options-for-merge-requests):
```shell
git config --global alias.mwps "push -o merge_request.create -o merge_request.target=master -o merge_request.merge_when_pipeline_succeeds"
```
1. In your terminal window, run this command:
Then to quickly push a local branch that targets the default branch and merges when the
pipeline succeeds:
```shell
git config --global alias.mwps "push -o merge_request.create -o merge_request.target=main -o merge_request.merge_when_pipeline_succeeds"
```
```shell
git mwps origin <local-branch-name>
```
1. To use the alias to push a local branch that targets the default branch (`main`)
and auto-merges, run this command:
```shell
git mwps origin <local-branch-name>
```
## Related topics
- [Git aliases](https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases) in the Git documentation

View File

@ -1,6 +1,6 @@
---
stage: AI-powered
group: AI Model Validation
stage: Create
group: Code Creation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: index, reference
---
@ -135,7 +135,7 @@ Learn more about Google Vertex AI [`code-gecko`](https://cloud.google.com/vertex
### Training data
Code suggestions are routed through Google Vertex AI Codey APIs. Learn more about Google Vertex AI Codey APIs [Data Governance](https://cloud.google.com/vertex-ai/docs/generative-ai/data-governance) and [Responsible AI](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/responsible-ai).
Code Suggestions are routed through Google Vertex AI Codey APIs. Learn more about Google Vertex AI Codey APIs [Data Governance](https://cloud.google.com/vertex-ai/docs/generative-ai/data-governance) and [Responsible AI](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/responsible-ai).
Google Vertex AI Codey APIs are not trained on private non-public GitLab customer or user data.
@ -167,7 +167,7 @@ We strongly encourage all beta users to leverage GitLab native
[Security Scanning](../../../application_security/index.md) capabilities.
GitLab currently does not retrain Google Vertex AI Codey APIs. GitLab makes no claims
to the accuracy or quality of code suggestions generated by Google Vertex AI Codey API.
to the accuracy or quality of Code Suggestions generated by Google Vertex AI Codey API.
Read more about [Google Vertex AI foundation model capabilities](https://cloud.google.com/vertex-ai/docs/generative-ai/learn/models).
## Known limitations

View File

@ -1,6 +1,6 @@
---
stage: AI-powered
group: AI Model Validation
stage: Create
group: Code Creation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: index, reference
---

View File

@ -1,6 +1,6 @@
---
stage: AI-powered
group: AI Model Validation
stage: Create
group: Code Creation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: index, reference
---
@ -56,7 +56,7 @@ To enable Code Suggestions for your self-managed GitLab instance:
This setting is visible only in self-managed GitLab instances.
WARNING:
In GitLab 16.2 and earlier, if you clear the **Turn on code suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
In GitLab 16.2 and earlier, if you clear the **Turn on Code Suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
To make sure Code Suggestions works immediately, you must [manually synchronize your subscription](#manually-synchronize-your-subscription).
@ -101,7 +101,7 @@ To enable Code Suggestions for your self-managed GitLab instance:
This setting is visible only in self-managed GitLab instances.
WARNING:
If you clear the **Turn on code suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
If you clear the **Turn on Code Suggestions for this instance** checkbox, the users in your instance can still use Code Suggestions for up to one hour, until the issued JSON web token (JWT) expires.
#### Request access to Code Suggestions

View File

@ -1,6 +1,6 @@
---
stage: AI-powered
group: AI Model Validation
stage: Create
group: Code Creation
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments
type: index, reference
---
@ -66,4 +66,4 @@ specifically the token system. To resolve the issue:
1. Remove the existing personal access token from your GitLab account settings.
1. Reauthorize your GitLab account in VS Code using OAuth.
1. Test the code suggestions feature with different file extensions to verify if the issue is resolved.
1. Test the Code Suggestions feature with different file extensions to verify if the issue is resolved.

View File

@ -37,7 +37,7 @@ When commits include changes to Jupyter Notebook files, GitLab:
- Enables switching between raw and rendered diffs on the Commit and Compare pages. (Not available on merge request pages.)
- Renders images on the diffs.
Code suggestions are not available on diffs and merge requests for `.ipynb` files.
Code Suggestions are not available on diffs and merge requests for `.ipynb` files.
Cleaner notebook diffs are not generated when the notebook is too large.

View File

@ -12,11 +12,13 @@ module Gitlab
FILENAME_SIZE_LIMIT = 255 # chars before the extension
DEFAULT_FILE_SIZE_LIMIT = 25.megabytes
TMP_DIR = File.join(Dir.tmpdir, 'github_attachments').freeze
GITHUB_ASSETS_URL_REGEX = %r{#{Regexp.escape(::Gitlab::GithubImport::MarkdownText.github_url)}/.*/assets/}
attr_reader :file_url, :filename, :file_size_limit
attr_reader :file_url, :filename, :file_size_limit, :options
def initialize(file_url, file_size_limit: DEFAULT_FILE_SIZE_LIMIT)
def initialize(file_url, options: {}, file_size_limit: DEFAULT_FILE_SIZE_LIMIT)
@file_url = file_url
@options = options
@file_size_limit = file_size_limit
filename = URI(file_url).path.split('/').last
@ -27,7 +29,9 @@ module Gitlab
validate_content_length
validate_filepath
file = download
redirection_url = get_download_redirection_url
file = download_from(redirection_url)
validate_symlink
file
end
@ -47,9 +51,23 @@ module Gitlab
Gitlab::HTTP.perform_request(Net::HTTP::Head, file_url, {}).headers
end
def download
# Github /assets redirection link will redirect to aws which has its own authorization.
# Keeping our bearer token will cause request rejection
# eg. Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter,
# Signature query string parameter or the Authorization header should be specified.
def get_download_redirection_url
return file_url unless file_url.starts_with?(GITHUB_ASSETS_URL_REGEX)
options[:follow_redirects] = false
response = Gitlab::HTTP.perform_request(Net::HTTP::Get, file_url, options)
raise_error("expected a redirect response, got #{response.code}") unless response.redirection?
response.headers[:location]
end
def download_from(url)
file = File.open(filepath, 'wb')
Gitlab::HTTP.perform_request(Net::HTTP::Get, file_url, stream_body: true) { |batch| file.write(batch) }
Gitlab::HTTP.perform_request(Net::HTTP::Get, url, stream_body: true) { |batch| file.write(batch) }
file
end

View File

@ -4,14 +4,15 @@ module Gitlab
module GithubImport
module Importer
class NoteAttachmentsImporter
attr_reader :note_text, :project
attr_reader :note_text, :project, :client
# note_text - An instance of `Gitlab::GithubImport::Representation::NoteText`.
# project - An instance of `Project`.
# client - An instance of `Gitlab::GithubImport::Client`.
def initialize(note_text, project, _client = nil)
def initialize(note_text, project, client)
@note_text = note_text
@project = project
@client = client
end
def execute
@ -33,7 +34,7 @@ module Gitlab
if attachment.part_of_project_blob?(project_import_source)
convert_project_content_link(attachment.url, project_import_source)
elsif attachment.media? || attachment.doc_belongs_to_project?(project_import_source)
elsif attachment.media?(project_import_source) || attachment.doc_belongs_to_project?(project_import_source)
download_attachment(attachment)
else # url to other GitHub project
attachment.url
@ -53,7 +54,7 @@ module Gitlab
# in: an instance of Gitlab::GithubImport::Markdown::Attachment
# out: gitlab attachment markdown url
def download_attachment(attachment)
downloader = ::Gitlab::GithubImport::AttachmentsDownloader.new(attachment.url)
downloader = ::Gitlab::GithubImport::AttachmentsDownloader.new(attachment.url, options: options)
file = downloader.perform
uploader = UploadService.new(project, file, FileUploader).execute
uploader.to_h[:url]
@ -61,6 +62,14 @@ module Gitlab
downloader&.delete
end
def options
{
headers: {
'Authorization' => "Bearer #{client.octokit.access_token}"
}
}
end
def update_note_record(text)
case note_text.record_type
when ::Release.name

View File

@ -57,7 +57,8 @@ module Gitlab
def github_url?(url, docs: false, media: false)
if media
url.start_with?(::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN)
url.start_with?(::Gitlab::GithubImport::MarkdownText.github_url,
::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN)
elsif docs
url.start_with?(::Gitlab::GithubImport::MarkdownText.github_url)
end
@ -65,6 +66,9 @@ module Gitlab
def whitelisted_type?(url, docs: false, media: false)
if media
# We do not know the file extension type from the /assets markdown
return true if url.start_with?(::Gitlab::GithubImport::MarkdownText.github_url)
MEDIA_TYPES.any? { |type| url.end_with?(type) }
elsif docs
DOC_TYPES.any? { |type| url.end_with?(type) }
@ -91,8 +95,11 @@ module Gitlab
)
end
def media?
url.start_with?(::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN)
def media?(import_source)
url.start_with?(
"#{::Gitlab::GithubImport::MarkdownText.github_url}/#{import_source}/assets",
::Gitlab::GithubImport::MarkdownText::GITHUB_MEDIA_CDN
)
end
def inspect

View File

@ -21256,6 +21256,9 @@ msgstr ""
msgid "Get a support subscription"
msgstr ""
msgid "Get more information about troubleshooting pipelines"
msgstr ""
msgid "Get started"
msgstr ""

View File

@ -3,8 +3,9 @@
require 'spec_helper'
RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group) }
let_it_be(:user) { create(:user) }
let_it_be(:namespace_settings) { create(:namespace_settings, runner_registration_enabled: true) }
let_it_be(:group) { create(:group, namespace_settings: namespace_settings) }
let_it_be(:project) { create(:project, group: group) }
let_it_be(:runner) { create(:ci_runner, :group, groups: [group]) }
@ -226,6 +227,12 @@ RSpec.describe Groups::RunnersController, feature_category: :runner_fleet do
expect(response).to render_template(:edit)
end
it 'renders 404 for non-existing runner' do
get :edit, params: { group_id: group, id: non_existing_record_id }
expect(response).to have_gitlab_http_status(:not_found)
end
it 'renders 404 for instance runner' do
get :edit, params: { group_id: group, id: instance_runner }

View File

@ -222,12 +222,14 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
end
shared_examples 'executes as normal user' do
it 'returns no runners' do
it 'raises Gitlab::Access::AccessDeniedError' do
user = create :user
create :ci_runner, active: true
create :ci_runner, active: false
expect(described_class.new(current_user: user, params: {}).execute).to be_empty
expect do
described_class.new(current_user: user, params: {}).execute
end.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
@ -250,12 +252,14 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
end
context 'when user is nil' do
it 'returns no runners' do
it 'raises Gitlab::Access::AccessDeniedError' do
user = nil
create :ci_runner, active: true
create :ci_runner, active: false
expect(described_class.new(current_user: user, params: {}).execute).to be_empty
expect do
described_class.new(current_user: user, params: {}).execute
end.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
@ -306,10 +310,11 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
shared_examples 'membership equal to :descendants' do
it 'returns all descendant runners' do
expect(subject).to eq([runner_project_7, runner_project_6, runner_project_5,
runner_project_4, runner_project_3, runner_project_2,
runner_project_1, runner_sub_group_4, runner_sub_group_3,
runner_sub_group_2, runner_sub_group_1, runner_group])
is_expected.to contain_exactly(
runner_project_7, runner_project_6, runner_project_5,
runner_project_4, runner_project_3, runner_project_2,
runner_project_1, runner_sub_group_4, runner_sub_group_3,
runner_sub_group_2, runner_sub_group_1, runner_group)
end
end
@ -340,7 +345,7 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let(:membership) { :direct }
it 'returns runners belonging to group' do
expect(subject).to eq([runner_group])
is_expected.to contain_exactly(runner_group)
end
end
@ -348,10 +353,11 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let(:membership) { :all_available }
it 'returns runners available to group' do
expect(subject).to match_array([runner_project_7, runner_project_6, runner_project_5,
runner_project_4, runner_project_3, runner_project_2,
runner_project_1, runner_sub_group_4, runner_sub_group_3,
runner_sub_group_2, runner_sub_group_1, runner_group, runner_instance])
is_expected.to contain_exactly(
runner_project_7, runner_project_6, runner_project_5,
runner_project_4, runner_project_3, runner_project_2,
runner_project_1, runner_sub_group_4, runner_sub_group_3,
runner_sub_group_2, runner_sub_group_1, runner_group, runner_instance)
end
end
@ -366,9 +372,9 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
context 'with nil group' do
let(:target_group) { nil }
it 'returns no runners' do
# Query should run against all runners, however since user is not admin, query returns no results
expect(subject).to eq([])
it 'raises Gitlab::Access::AccessDeniedError' do
# Query should run against all runners, however since user is not admin, we raise an error
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
@ -443,23 +449,23 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
context 'with :sub_group_1 as target group' do
let(:target_group) { sub_group_1 }
it 'returns no runners' do
is_expected.to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'with :group as target group' do
let(:target_group) { group }
it 'returns no runners' do
is_expected.to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
context 'with :all_available membership' do
let(:membership) { :all_available }
it 'returns no runners' do
expect(subject).to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
@ -467,35 +473,31 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
end
context 'when user has no access' do
it 'returns no runners' do
expect(subject).to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'when user is nil' do
let_it_be(:user) { nil }
let(:user) { nil }
it 'returns no runners' do
expect(subject).to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end
describe '#sort_key' do
subject { described_class.new(current_user: user, params: params.merge(group: group)).sort_key }
subject(:sort_key) { described_class.new(current_user: user, params: params.merge(group: group)).sort_key }
context 'without params' do
it 'returns created_at_desc' do
expect(subject).to eq('created_at_desc')
end
it { is_expected.to eq('created_at_desc') }
end
context 'with params' do
let(:extra_params) { { sort: 'contacted_asc' } }
it 'returns contacted_asc' do
expect(subject).to eq('contacted_asc')
end
it { is_expected.to eq('contacted_asc') }
end
end
end
@ -510,7 +512,7 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let(:params) { { project: project }.merge(extra_params).reject { |_, v| v.nil? } }
describe '#execute' do
subject { described_class.new(current_user: user, params: params).execute }
subject(:execute) { described_class.new(current_user: user, params: params).execute }
context 'with user as project admin' do
before do
@ -521,7 +523,7 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let_it_be(:runner_project) { create(:ci_runner, :project, contacted_at: 7.minutes.ago, projects: [project]) }
it 'returns runners available to project' do
expect(subject).to match_array([runner_project])
is_expected.to match_array([runner_project])
end
end
@ -530,7 +532,7 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
let_it_be(:runner_group) { create(:ci_runner, :group, contacted_at: 12.minutes.ago, groups: [group]) }
it 'returns runners available to project' do
expect(subject).to match_array([runner_instance, runner_group])
is_expected.to match_array([runner_instance, runner_group])
end
end
@ -616,24 +618,24 @@ RSpec.describe Ci::RunnersFinder, feature_category: :runner_fleet do
project.add_developer(user)
end
it 'returns no runners' do
expect(subject).to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'when user is nil' do
let_it_be(:user) { nil }
it 'returns no runners' do
expect(subject).to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
context 'with nil project_full_path' do
let(:project_full_path) { nil }
it 'returns no runners' do
expect(subject).to be_empty
it 'raises Gitlab::Access::AccessDeniedError' do
expect { execute }.to raise_error(Gitlab::Access::AccessDeniedError)
end
end
end

View File

@ -1,4 +1,5 @@
import { shallowMount } from '@vue/test-utils';
import { GlCard } from '@gitlab/ui';
import PipelineEditorHeader from '~/ci/pipeline_editor/components/header/pipeline_editor_header.vue';
import PipelineStatus from '~/ci/pipeline_editor/components/header/pipeline_status.vue';
import ValidationSegment from '~/ci/pipeline_editor/components/header/validation_segment.vue';
@ -20,6 +21,9 @@ describe('Pipeline editor header', () => {
isNewCiConfigFile: false,
...props,
},
stubs: {
GlCard,
},
});
};

View File

@ -281,6 +281,14 @@ describe('MergeRequestTabs', () => {
testContext.class.expandViewContainer();
expect($('.content-wrapper .container-limited')).toHaveLength(0);
});
it('adds the diff-specific width-limiter', () => {
testContext.class.expandViewContainer();
expect(testContext.class.contentWrapper.classList.contains('diffs-container-limited')).toBe(
true,
);
});
});
describe('resetViewContainer', () => {
@ -302,6 +310,14 @@ describe('MergeRequestTabs', () => {
expect($('.content-wrapper .container-limited')).toHaveLength(1);
});
it('removes the diff-specific width-limiter', () => {
testContext.class.resetViewContainer();
expect(testContext.class.contentWrapper.classList.contains('diffs-container-limited')).toBe(
false,
);
});
});
describe('tabShown', () => {

View File

@ -6,7 +6,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
include GraphqlHelpers
describe '#resolve' do
subject do
subject(:resolve_scope) do
resolve(described_class, obj: obj, ctx: { current_user: user }, args: args,
arg_style: :internal)
end
@ -18,8 +18,10 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
# First, we can do a couple of basic real tests to verify common cases. That ensures that the code works.
context 'when user cannot see runners' do
it 'returns no runners' do
expect(subject.items.to_a).to eq([])
it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
resolve_scope
end
end
end
@ -29,14 +31,16 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
end
it 'returns all the runners' do
expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner)
expect(resolve_scope.items.to_a).to contain_exactly(
inactive_project_runner, offline_project_runner, group_runner, subgroup_runner
)
end
context 'with membership direct' do
let(:args) { { membership: :direct } }
it 'returns only direct runners' do
expect(subject.items.to_a).to contain_exactly(group_runner)
expect(resolve_scope.items.to_a).to contain_exactly(group_runner)
end
end
end
@ -46,7 +50,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
let(:obj) { nil }
it 'raises an error' do
expect { subject }.to raise_error('Expected group missing')
expect { resolve_scope }.to raise_error('Expected group missing')
end
end
@ -54,7 +58,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
let(:obj) { build(:project) }
it 'raises an error' do
expect { subject }.to raise_error('Expected group missing')
expect { resolve_scope }.to raise_error('Expected group missing')
end
end
@ -90,7 +94,7 @@ RSpec.describe Resolvers::Ci::GroupRunnersResolver, feature_category: :runner_fl
allow(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
expect(subject.items.to_a).to eq([:execute_return_value])
expect(resolve_scope.items.to_a).to eq([:execute_return_value])
end
end
end

View File

@ -6,7 +6,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
include GraphqlHelpers
describe '#resolve' do
subject do
subject(:resolve_scope) do
resolve(described_class, obj: obj, ctx: { current_user: user }, args: args,
arg_style: :internal)
end
@ -17,8 +17,10 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:args) { {} }
context 'when user cannot see runners' do
it 'returns no runners' do
expect(subject.items.to_a).to eq([])
it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
resolve_scope
end
end
end
@ -30,7 +32,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:available_runners) { [inactive_project_runner, offline_project_runner, group_runner, instance_runner] }
it 'returns all runners available to the project' do
expect(subject.items.to_a).to match_array(available_runners)
expect(resolve_scope.items.to_a).to match_array(available_runners)
end
end
@ -38,7 +40,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:obj) { nil }
it 'raises an error' do
expect { subject }.to raise_error('Expected project missing')
expect { resolve_scope }.to raise_error('Expected project missing')
end
end
@ -46,7 +48,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
let(:obj) { build(:group) }
it 'raises an error' do
expect { subject }.to raise_error('Expected project missing')
expect { resolve_scope }.to raise_error('Expected project missing')
end
end
@ -79,7 +81,7 @@ RSpec.describe Resolvers::Ci::ProjectRunnersResolver, feature_category: :runner_
params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
expect(subject.items.to_a).to eq([:execute_return_value])
expect(resolve_scope.items.to_a).to contain_exactly(:execute_return_value)
end
end
end

View File

@ -20,8 +20,10 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
context 'when user cannot see runners' do
let(:user) { build(:user) }
it 'returns no runners' do
expect(subject.items.to_a).to eq([])
it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
resolve_scope
end
end
end
@ -30,20 +32,26 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
context 'when admin mode setting is disabled', :do_not_mock_admin_mode_setting do
it 'returns all the runners' do
expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner)
expect(resolve_scope.items.to_a).to contain_exactly(
inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner
)
end
end
context 'when admin mode setting is enabled' do
context 'when in admin mode', :enable_admin_mode do
it 'returns all the runners' do
expect(subject.items.to_a).to contain_exactly(inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner)
expect(resolve_scope.items.to_a).to contain_exactly(
inactive_project_runner, offline_project_runner, group_runner, subgroup_runner, instance_runner
)
end
end
context 'when not in admin mode' do
it 'returns no runners' do
expect(subject.items.to_a).to eq([])
it 'returns Gitlab::Graphql::Errors::ResourceNotAvailable' do
expect_graphql_error_to_be_created(Gitlab::Graphql::Errors::ResourceNotAvailable) do
resolve_scope
end
end
end
end
@ -54,7 +62,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
let(:obj) { build(:project) }
it 'raises an error' do
expect { subject }.to raise_error(a_string_including('Unexpected parent type'))
expect { resolve_scope }.to raise_error(a_string_including('Unexpected parent type'))
end
end
@ -93,7 +101,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
expect(subject.items.to_a).to eq([:execute_return_value])
expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
@ -116,7 +124,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
expect(subject.items.to_a).to eq([:execute_return_value])
expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
@ -136,7 +144,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
expect(subject.items.to_a).to eq([:execute_return_value])
expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
@ -153,7 +161,7 @@ RSpec.describe Resolvers::Ci::RunnersResolver, feature_category: :runner_fleet d
expect(::Ci::RunnersFinder).to receive(:new).with(current_user: user, params: expected_params).once.and_return(finder)
allow(finder).to receive(:execute).once.and_return([:execute_return_value])
expect(subject.items.to_a).to eq([:execute_return_value])
expect(resolve_scope.items.to_a).to contain_exactly :execute_return_value
end
end
end

View File

@ -93,6 +93,43 @@ RSpec.describe Gitlab::GithubImport::AttachmentsDownloader, feature_category: :i
expect(File.basename(file)).to eq('av.png')
end
end
context 'when attachment is behind a redirect' do
let_it_be(:file_url) { "https://github.com/test/project/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
let(:redirect_url) { "https://https://github-production-user-asset-6210df.s3.amazonaws.com/142635249/740edb05293e.jpg" }
let(:sample_response) do
instance_double(HTTParty::Response, redirection?: true, headers: { location: redirect_url })
end
it 'gets redirection url' do
expect(Gitlab::HTTP).to receive(:perform_request)
.with(Net::HTTP::Get, file_url, { follow_redirects: false })
.and_return sample_response
expect(Gitlab::HTTP).to receive(:perform_request)
.with(Net::HTTP::Get, redirect_url, stream_body: true).and_yield(chunk_double)
file = downloader.perform
expect(File.exist?(file.path)).to eq(true)
end
context 'when url is not a redirection' do
let(:sample_response) do
instance_double(HTTParty::Response, code: 200, redirection?: false)
end
before do
allow(Gitlab::HTTP).to receive(:perform_request)
.with(Net::HTTP::Get, file_url, { follow_redirects: false })
.and_return sample_response
end
it 'raises upon unsuccessful redirection' do
expect { downloader.perform }.to raise_error("expected a redirect response, got #{sample_response.code}")
end
end
end
end
describe '#delete' do

View File

@ -53,6 +53,19 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter, feature_
record.reload
expect(record.description).to include("[link to other project blob file](#{other_project_blob_url})")
end
context 'with new github image format' do
let(:image_url) { 'https://github.com/nickname/public-test-repo/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11' }
let(:image_tag_url) { 'https://github.com/nickname/public-test-repo/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11' }
it 'changes image attachment links' do
importer.execute
record.reload
expect(record.description).to include('![image.jpeg](/uploads/')
expect(record.description).to include('<img width="248" alt="tag-image" src="/uploads')
end
end
end
describe '#execute' do
@ -60,16 +73,19 @@ RSpec.describe Gitlab::GithubImport::Importer::NoteAttachmentsImporter, feature_
let(:tmp_stub_doc) { Tempfile.create('attachment_download_test.txt') }
let(:tmp_stub_image) { Tempfile.create('image.jpeg') }
let(:tmp_stub_image_tag) { Tempfile.create('image-tag.jpeg') }
let(:access_token) { 'exampleGitHubToken' }
let(:options) { { headers: { 'Authorization' => "Bearer #{access_token}" } } }
before do
allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(doc_url)
allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(doc_url, options: options)
.and_return(downloader_stub)
allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_url)
allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_url, options: options)
.and_return(downloader_stub)
allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_tag_url)
allow(Gitlab::GithubImport::AttachmentsDownloader).to receive(:new).with(image_tag_url, options: options)
.and_return(downloader_stub)
allow(downloader_stub).to receive(:perform).and_return(tmp_stub_doc, tmp_stub_image, tmp_stub_image_tag)
allow(downloader_stub).to receive(:delete).exactly(3).times
allow(client).to receive_message_chain(:octokit, :access_token).and_return(access_token)
end
context 'when importing release attachments' do

View File

@ -5,6 +5,7 @@ require 'spec_helper'
RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :importers do
let(:name) { FFaker::Lorem.word }
let(:url) { FFaker::Internet.uri('https') }
let(:import_source) { 'nickname/public-test-repo' }
describe '.from_markdown' do
context "when it's a doc attachment" do
@ -75,6 +76,17 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
it { expect(described_class.from_markdown(markdown_node)).to eq nil }
end
context 'when image attachment is in the new format' do
let(:url) { "https://github.com/#{import_source}/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
it 'returns instance with attachment info' do
attachment = described_class.from_markdown(markdown_node)
expect(attachment.name).to eq name
expect(attachment.url).to eq url
end
end
end
context "when it's an inline html node" do
@ -103,7 +115,6 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
describe '#part_of_project_blob?' do
let(:attachment) { described_class.new('test', url) }
let(:import_source) { 'nickname/public-test-repo' }
context 'when url is a part of project blob' do
let(:url) { "https://github.com/#{import_source}/blob/main/example.md" }
@ -120,7 +131,6 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
describe '#doc_belongs_to_project?' do
let(:attachment) { described_class.new('test', url) }
let(:import_source) { 'nickname/public-test-repo' }
context 'when url relates to this project' do
let(:url) { "https://github.com/#{import_source}/files/9020437/git-cheat-sheet.txt" }
@ -147,13 +157,19 @@ RSpec.describe Gitlab::GithubImport::Markdown::Attachment, feature_category: :im
context 'when it is a media link' do
let(:url) { 'https://user-images.githubusercontent.com/6833842/0cf366b61ef2.jpeg' }
it { expect(attachment.media?).to eq true }
it { expect(attachment.media?(import_source)).to eq true }
context 'when it is a new media link' do
let(:url) { "https://github.com/#{import_source}/assets/142635249/4b9f9c90-f060-4845-97cf-b24c558bcb11" }
it { expect(attachment.media?(import_source)).to eq true }
end
end
context 'when it is not a media link' do
let(:url) { 'https://github.com/nickname/public-test-repo/files/9020437/git-cheat-sheet.txt' }
it { expect(attachment.media?).to eq false }
it { expect(attachment.media?(import_source)).to eq false }
end
end

View File

@ -172,10 +172,14 @@ RSpec.describe Emails::ServiceDesk, feature_category: :service_desk do
project.reset
service_desk_setting.update!(custom_email_enabled: true) unless service_desk_setting.custom_email_enabled?
allow(Gitlab::AppLogger).to receive(:info)
end
it 'uses SMTP delivery method and custom email settings' do
expect_service_desk_custom_email_delivery_options(service_desk_setting)
expect(Gitlab::AppLogger).to have_received(:info).with({ category: 'custom_email' })
end
it 'generates Reply-To address from custom email' do

View File

@ -25,16 +25,22 @@ RSpec.describe 'RunnerWebUrlEdge', feature_category: :runner_fleet do
GQL
end
before do
subject(:request) do
post_graphql(query, current_user: user, variables: { path: group.full_path })
end
context 'with an authorized user' do
let(:user) { create_default(:user, :admin) }
it_behaves_like 'a working graphql query'
it_behaves_like 'a working graphql query' do
before do
request
end
end
it 'returns correct URLs' do
request
expect(edges_graphql_data).to match_array [
{
'editUrl' => Gitlab::Routing.url_helpers.edit_group_runner_url(group, group_runner),
@ -47,10 +53,14 @@ RSpec.describe 'RunnerWebUrlEdge', feature_category: :runner_fleet do
context 'with an unauthorized user' do
let(:user) { create(:user) }
it_behaves_like 'a working graphql query'
it 'returns nil runners and an error' do
request
it 'returns no edges' do
expect(edges_graphql_data).to be_empty
expect(graphql_data.dig('group', 'runners')).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[group runners]
))
end
end
end

View File

@ -17,7 +17,7 @@ RSpec.describe 'getting group information', :with_license, feature_category: :gr
# similar to the API "GET /groups/:id"
describe "Query group(fullPath)" do
def group_query(group)
fields = all_graphql_fields_for('Group')
fields = all_graphql_fields_for('Group', excluded: %w[runners])
# TODO: Set required timelogs args elsewhere https://gitlab.com/gitlab-org/gitlab/-/issues/325499
fields.selection['timelogs(startDate: "2021-03-01" endDate: "2021-03-30")'] = fields.selection.delete('timelogs')

View File

@ -12,7 +12,7 @@ RSpec.describe 'searching groups', :with_license, feature_category: :groups_and_
let(:fields) do
<<~FIELDS
nodes {
#{all_graphql_fields_for('Group')}
#{all_graphql_fields_for('Group', excluded: %w[runners])}
}
FIELDS
end

View File

@ -16,7 +16,7 @@ RSpec.describe 'package details', feature_category: :package_registry do
end
let(:depth) { 3 }
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles] }
let(:excluded) { %w[metadata apiFuzzingCiConfiguration pipeline packageFiles runners] }
let(:metadata) { query_graphql_fragment('ComposerMetadata') }
let(:package_files) { all_graphql_fields_for('PackageFile') }
let(:package_global_id) { global_id_of(composer_package) }

View File

@ -21,9 +21,11 @@ RSpec.describe 'getting merge request information nested in a project', feature_
end
it_behaves_like 'a working graphql query' do
# we exclude Project.pipeline because it needs arguments
# and codequalityReportsComparer because no pipeline exist yet
let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: %w[jobs pipeline codequalityReportsComparer]) }
# we exclude Project.pipeline because it needs arguments,
# codequalityReportsComparer because no pipeline exist yet
# and runners because the user is not an admin and therefore has no access
let(:excluded) { %w[jobs pipeline runners codequalityReportsComparer] }
let(:mr_fields) { all_graphql_fields_for('MergeRequest', excluded: excluded) }
before do
post_graphql(query, current_user: current_user)

View File

@ -28,6 +28,8 @@ RSpec.describe 'Project.runners', feature_category: :runner do
)
end
subject(:request) { post_graphql(query, current_user: user) }
context 'when the user is a project admin' do
before do
project.add_maintainer(user)
@ -36,7 +38,7 @@ RSpec.describe 'Project.runners', feature_category: :runner do
let(:expected_ids) { [project_runner, group_runner, instance_runner].map { |g| g.to_global_id.to_s } }
it 'returns all runners available to project' do
post_graphql(query, current_user: user)
request
expect(graphql_data_at(:project, :runners, :nodes).pluck('id')).to match_array(expected_ids)
end
@ -47,10 +49,14 @@ RSpec.describe 'Project.runners', feature_category: :runner do
project.add_developer(user)
end
it 'returns no runners' do
post_graphql(query, current_user: user)
it 'returns nil runners and an error' do
request
expect(graphql_data_at(:project, :runners, :nodes)).to be_empty
expect(graphql_data_at(:project, :runners)).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[project runners]
))
end
end
end