Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
06c9acad67
commit
1869c23b11
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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'
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -24,9 +24,6 @@ module Ci
|
|||
request_tag_list!
|
||||
|
||||
@runners
|
||||
|
||||
rescue Gitlab::Access::AccessDeniedError
|
||||
Ci::Runner.none
|
||||
end
|
||||
|
||||
def sort_key
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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: {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -0,0 +1 @@
|
|||
70e07f9790b7a9011fce37cc1376d61d84c98ef677fcce534dd97a78f892af86
|
||||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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) |
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
|
|
|||
|
|
@ -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)** |
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
---
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -21256,6 +21256,9 @@ msgstr ""
|
|||
msgid "Get a support subscription"
|
||||
msgstr ""
|
||||
|
||||
msgid "Get more information about troubleshooting pipelines"
|
||||
msgstr ""
|
||||
|
||||
msgid "Get started"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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', () => {
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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('
|
||||
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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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')
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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) }
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in New Issue