Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
1db959cb59
commit
22989942a8
|
|
@ -744,7 +744,6 @@ RSpec/ContextWording:
|
|||
- 'ee/spec/support/shared_examples/services/merge_merge_requests_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/services/scoped_label_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/services/search_notes_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/services/search_service_shared_examples.rb'
|
||||
- 'ee/spec/support/shared_examples/services/update_issuable_health_status_shared_examples.rb'
|
||||
- 'ee/spec/tasks/gitlab/license_rake_spec.rb'
|
||||
- 'ee/spec/views/groups/edit.html.haml_spec.rb'
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<script>
|
||||
import { GlModal } from '@gitlab/ui';
|
||||
import { uniqueId } from 'lodash';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { refreshCurrentPage, visitUrl } from '~/lib/utils/url_utility';
|
||||
import { __ } from '~/locale';
|
||||
import { INTERVAL_SESSION_MODAL } from '../constants';
|
||||
|
||||
|
|
@ -20,7 +20,8 @@ export default {
|
|||
},
|
||||
signInUrl: {
|
||||
type: String,
|
||||
required: true,
|
||||
default: null,
|
||||
required: false,
|
||||
},
|
||||
title: {
|
||||
type: String,
|
||||
|
|
@ -34,6 +35,12 @@ export default {
|
|||
showModal: false,
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
reload() {
|
||||
const text = this.signInUrl ? __('Sign in') : __('Reload page');
|
||||
return { text };
|
||||
},
|
||||
},
|
||||
async created() {
|
||||
this.intervalId = setInterval(this.checkStatus, INTERVAL_SESSION_MODAL);
|
||||
document.addEventListener('visibilitychange', this.onDocumentVisible);
|
||||
|
|
@ -61,10 +68,13 @@ export default {
|
|||
}
|
||||
},
|
||||
goTo() {
|
||||
visitUrl(this.signInUrl);
|
||||
if (this.signInUrl) {
|
||||
visitUrl(this.signInUrl);
|
||||
} else {
|
||||
refreshCurrentPage();
|
||||
}
|
||||
},
|
||||
},
|
||||
reload: { text: __('Sign in') },
|
||||
cancel: { text: __('Cancel') },
|
||||
};
|
||||
</script>
|
||||
|
|
@ -74,7 +84,7 @@ export default {
|
|||
v-model="showModal"
|
||||
:modal-id="modalId"
|
||||
:title="title"
|
||||
:action-primary="$options.reload"
|
||||
:action-primary="reload"
|
||||
:action-cancel="$options.cancel"
|
||||
aria-live="assertive"
|
||||
@primary="goTo"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,9 @@ export const initExpireSessionModal = () => {
|
|||
if (!el) return null;
|
||||
|
||||
const { sessionTimeout, signInUrl } = el.dataset;
|
||||
const message = s__('SessionExpire|Your session has expired. Please, sign in again.');
|
||||
const message = s__(
|
||||
'SessionExpire|Please, sign in again. To avoid data loss, if you have unsaved edits, dismiss the modal and copy the unsaved text before sign in again.',
|
||||
);
|
||||
const title = s__('SessionExpire|Your session has expired');
|
||||
return new Vue({
|
||||
el,
|
||||
|
|
|
|||
|
|
@ -125,7 +125,9 @@ export default {
|
|||
{{ $options.i18n.noForks }}<br />
|
||||
<gl-sprintf :message="$options.i18n.forkTheProject">
|
||||
<template #link="{ content }">
|
||||
<a :href="newForkPath" target="_blank" class="help-link">{{ content }}</a>
|
||||
<gl-link :href="newForkPath">
|
||||
{{ content }}
|
||||
</gl-link>
|
||||
</template>
|
||||
</gl-sprintf>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ export default {
|
|||
data() {
|
||||
return {
|
||||
hasMergeRequestsMetadataError: false,
|
||||
hasWorkItemsMetadataError: false,
|
||||
};
|
||||
},
|
||||
};
|
||||
|
|
@ -57,15 +58,40 @@ export default {
|
|||
)
|
||||
}}</gl-alert
|
||||
>
|
||||
<gl-alert
|
||||
v-if="hasWorkItemsMetadataError"
|
||||
variant="warning"
|
||||
data-testid="work-items-fetch-metadata-desktop-error"
|
||||
class="gl-hidden md:gl-block"
|
||||
@dismiss="hasWorkItemsMetadataError = false"
|
||||
>{{
|
||||
s__(
|
||||
'Homepage|The number of issues is not available. Please refresh the page to try again.',
|
||||
)
|
||||
}}</gl-alert
|
||||
>
|
||||
<div class="gl-grid gl-grid-cols-1 gl-gap-5 lg:gl-grid-cols-2">
|
||||
<merge-requests-widget
|
||||
:review-requested-path="reviewRequestedPath"
|
||||
:assigned-to-you-path="assignedMergeRequestsPath"
|
||||
@fetch-metadata-error="hasMergeRequestsMetadataError = true"
|
||||
/>
|
||||
<gl-alert
|
||||
v-if="hasWorkItemsMetadataError"
|
||||
variant="warning"
|
||||
data-testid="work-items-fetch-metadata-mobile-error"
|
||||
class="gl-block md:gl-hidden"
|
||||
@dismiss="hasWorkItemsMetadataError = false"
|
||||
>{{
|
||||
s__(
|
||||
'Homepage|The number of issues is not available. Please refresh the page to try again.',
|
||||
)
|
||||
}}</gl-alert
|
||||
>
|
||||
<work-items-widget
|
||||
:assigned-to-you-path="assignedWorkItemsPath"
|
||||
:authored-by-you-path="authoredWorkItemsPath"
|
||||
@fetch-metadata-error="hasWorkItemsMetadataError = true"
|
||||
/>
|
||||
</div>
|
||||
<todos-widget />
|
||||
|
|
|
|||
|
|
@ -48,9 +48,6 @@ export default {
|
|||
},
|
||||
},
|
||||
computed: {
|
||||
isLoadingMetadata() {
|
||||
return this.$apollo.queries.metadata.loading;
|
||||
},
|
||||
reviewRequestedCount() {
|
||||
return this.metadata.reviewRequestedMergeRequests?.count ?? '-';
|
||||
},
|
||||
|
|
@ -86,14 +83,12 @@ export default {
|
|||
>
|
||||
{{ __('Review requested') }}
|
||||
<gl-badge data-testid="review-requested-count">{{ reviewRequestedCount }}</gl-badge>
|
||||
<template v-if="!isLoadingMetadata">
|
||||
<span
|
||||
v-if="reviewRequestedLastUpdatedAt"
|
||||
data-testid="review-requested-last-updated-at"
|
||||
class="gl-ml-auto gl-text-sm gl-text-subtle"
|
||||
>{{ timeFormatted(reviewRequestedLastUpdatedAt) }}</span
|
||||
>
|
||||
</template>
|
||||
<span
|
||||
v-if="reviewRequestedLastUpdatedAt"
|
||||
data-testid="review-requested-last-updated-at"
|
||||
class="gl-ml-auto gl-text-sm gl-text-subtle"
|
||||
>{{ timeFormatted(reviewRequestedLastUpdatedAt) }}</span
|
||||
>
|
||||
</gl-link>
|
||||
</li>
|
||||
<li>
|
||||
|
|
@ -104,14 +99,12 @@ export default {
|
|||
>
|
||||
{{ __('Assigned to you') }}
|
||||
<gl-badge data-testid="assigned-count">{{ assignedCount }}</gl-badge>
|
||||
<template v-if="!isLoadingMetadata">
|
||||
<span
|
||||
v-if="assignedLastUpdatedAt"
|
||||
data-testid="assigned-last-updated-at"
|
||||
class="gl-ml-auto gl-text-sm gl-text-subtle"
|
||||
>{{ timeFormatted(assignedLastUpdatedAt) }}</span
|
||||
>
|
||||
</template>
|
||||
<span
|
||||
v-if="assignedLastUpdatedAt"
|
||||
data-testid="assigned-last-updated-at"
|
||||
class="gl-ml-auto gl-text-sm gl-text-subtle"
|
||||
>{{ timeFormatted(assignedLastUpdatedAt) }}</span
|
||||
>
|
||||
</gl-link>
|
||||
</li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
<script>
|
||||
import { GlIcon, GlLink, GlBadge } from '@gitlab/ui';
|
||||
import timeagoMixin from '~/vue_shared/mixins/timeago';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import workItemsWidgetMetadataQuery from '../graphql/queries/work_items_widget_metadata.query.graphql';
|
||||
import VisibilityChangeDetector from './visibility_change_detector.vue';
|
||||
|
||||
|
|
@ -37,20 +38,21 @@ export default {
|
|||
update({ currentUser }) {
|
||||
return currentUser;
|
||||
},
|
||||
error(error) {
|
||||
this.$emit('fetch-metadata-error');
|
||||
Sentry.captureException(error);
|
||||
},
|
||||
},
|
||||
},
|
||||
computed: {
|
||||
isLoadingMetadata() {
|
||||
return this.$apollo.queries.metadata.loading;
|
||||
},
|
||||
assignedCount() {
|
||||
return this.metadata?.assigned?.count ?? 0;
|
||||
return this.metadata?.assigned?.count ?? '-';
|
||||
},
|
||||
assignedLastUpdatedAt() {
|
||||
return this.metadata?.assigned?.nodes?.[0]?.updatedAt ?? null;
|
||||
},
|
||||
authoredCount() {
|
||||
return this.metadata?.authored?.count ?? 0;
|
||||
return this.metadata?.authored?.count ?? '-';
|
||||
},
|
||||
authoredLastUpdatedAt() {
|
||||
return this.metadata?.authored?.nodes?.[0]?.updatedAt ?? null;
|
||||
|
|
@ -70,15 +72,13 @@ export default {
|
|||
<gl-icon name="issues" :size="16" />{{ __('Issues') }}
|
||||
</h4>
|
||||
<ul class="gl-list-none gl-p-0">
|
||||
<li class="gl-flex gl-items-center gl-gap-3">
|
||||
<li>
|
||||
<gl-link
|
||||
class="gl-flex gl-items-center gl-gap-3 gl-rounded-small gl-px-1 gl-py-1 !gl-no-underline hover:gl-bg-gray-10 dark:hover:gl-bg-alpha-light-8"
|
||||
variant="meta"
|
||||
:href="assignedToYouPath"
|
||||
>
|
||||
{{ s__('HomePageWorkItemsWidget|Assigned to you') }}
|
||||
</gl-link>
|
||||
<template v-if="!isLoadingMetadata">
|
||||
<gl-badge data-testid="assigned-count">{{ assignedCount }}</gl-badge>
|
||||
<span
|
||||
v-if="assignedLastUpdatedAt"
|
||||
|
|
@ -86,17 +86,15 @@ export default {
|
|||
class="gl-ml-auto gl-text-sm gl-text-subtle"
|
||||
>{{ timeFormatted(assignedLastUpdatedAt) }}</span
|
||||
>
|
||||
</template>
|
||||
</gl-link>
|
||||
</li>
|
||||
<li class="gl-flex gl-items-center gl-gap-3">
|
||||
<li>
|
||||
<gl-link
|
||||
class="gl-flex gl-items-center gl-gap-3 gl-rounded-small gl-px-1 gl-py-1 !gl-no-underline hover:gl-bg-gray-10 dark:hover:gl-bg-alpha-light-8"
|
||||
variant="meta"
|
||||
:href="authoredByYouPath"
|
||||
>
|
||||
{{ s__('HomePageWorkItemsWidget|Authored by you') }}
|
||||
</gl-link>
|
||||
<template v-if="!isLoadingMetadata">
|
||||
<gl-badge data-testid="authored-count">{{ authoredCount }}</gl-badge>
|
||||
<span
|
||||
v-if="authoredLastUpdatedAt"
|
||||
|
|
@ -104,7 +102,7 @@ export default {
|
|||
class="gl-ml-auto gl-text-sm gl-text-subtle"
|
||||
>{{ timeFormatted(authoredLastUpdatedAt) }}</span
|
||||
>
|
||||
</template>
|
||||
</gl-link>
|
||||
</li>
|
||||
</ul>
|
||||
</visibility-change-detector>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,9 @@
|
|||
<template>
|
||||
<div class="nothing-here-block">
|
||||
{{ __("File suppressed by a .gitattributes entry or the file's encoding is unsupported.") }}
|
||||
{{
|
||||
__(
|
||||
"File suppressed by a .gitattributes entry, the file's encoding is unsupported, or the file size exceeds the limit.",
|
||||
)
|
||||
}}
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -182,7 +182,7 @@ class IssuableFinder
|
|||
|
||||
state_counts = finder
|
||||
.execute
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
.group(:state_id)
|
||||
.count
|
||||
|
||||
|
|
@ -385,11 +385,9 @@ class IssuableFinder
|
|||
items.pg_full_text_search(search, matched_columns: params[:in].to_s.split(','))
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def by_iids(items)
|
||||
params[:iids].present? ? items.where(iid: params[:iids]) : items
|
||||
params[:iids].present? ? items.iid_in(params[:iids]) : items
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def by_negated_iids(items)
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ module Issuables
|
|||
|
||||
Label
|
||||
.from_union([group_labels, project_labels], remove_duplicates: false)
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
.pluck(:title, :id)
|
||||
.group_by(&:first)
|
||||
.values
|
||||
|
|
|
|||
|
|
@ -140,7 +140,6 @@ class LabelsFinder < UnionFinder
|
|||
@project
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def projects
|
||||
return @projects if defined?(@projects)
|
||||
|
||||
|
|
@ -158,12 +157,11 @@ class LabelsFinder < UnionFinder
|
|||
end
|
||||
end
|
||||
|
||||
@projects = @projects.where(id: params[:project_ids]) if projects?
|
||||
@projects = @projects.reorder(nil)
|
||||
@projects = @projects.id_in(params[:project_ids]) if projects?
|
||||
@projects = @projects.without_order
|
||||
|
||||
@projects
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def read_permission
|
||||
:read_label
|
||||
|
|
|
|||
|
|
@ -7,12 +7,10 @@ module Types
|
|||
description: 'Total count of collection.'
|
||||
|
||||
def count
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
relation = object.items
|
||||
|
||||
# sometimes relation is an Array
|
||||
relation = relation.reorder(nil) if relation.respond_to?(:reorder)
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
relation = relation.without_order if relation.respond_to?(:reorder)
|
||||
|
||||
if relation.try(:group_values).present?
|
||||
relation.size.keys.size
|
||||
|
|
|
|||
|
|
@ -8,10 +8,8 @@ module Types
|
|||
null: true,
|
||||
description: 'Total sum of time to merge, in seconds, for the collection of merge requests.'
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def total_time_to_merge
|
||||
object.items.reorder(nil).total_time_to_merge
|
||||
object.items.without_order.total_time_to_merge
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -10,12 +10,10 @@ module Types
|
|||
description: 'Total time spent in seconds.'
|
||||
|
||||
def total_spent_time
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
relation = object.items
|
||||
|
||||
# sometimes relation is an Array
|
||||
relation = relation.reorder(nil) if relation.respond_to?(:reorder)
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
relation = relation.without_order if relation.respond_to?(:reorder)
|
||||
|
||||
relation.sum(:time_spent)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -49,7 +49,7 @@ module Types
|
|||
links_for_parents = ::WorkItems::ParentLink.for_parents(ids)
|
||||
.select(:work_item_parent_id)
|
||||
.group(:work_item_parent_id)
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
|
||||
links_for_parents.each { |link| loader.call(link.work_item_parent_id, true) }
|
||||
end
|
||||
|
|
|
|||
|
|
@ -1180,6 +1180,25 @@ module Ci
|
|||
builds_in_self_and_project_descendants.with_artifacts(reports_scope)
|
||||
end
|
||||
|
||||
# Expired artifacts are still valid if
|
||||
# "Keep artifacts from most recent successful jobs" is enabled
|
||||
def downloadable_artifacts_in_self_and_project_descendants
|
||||
hierarchy_builds = builds_in_self_and_project_descendants
|
||||
|
||||
artifacts = Ci::JobArtifact
|
||||
.with_job
|
||||
.where(job_id: hierarchy_builds.select(:id))
|
||||
.downloadable
|
||||
.in_partition(self)
|
||||
|
||||
non_expired = artifacts.not_expired
|
||||
|
||||
locked_pipeline_ids = self_and_project_descendants.artifacts_locked.select(:id)
|
||||
from_locked_pipelines = artifacts.joins(:job).where(p_ci_builds: { commit_id: locked_pipeline_ids })
|
||||
|
||||
non_expired.or(from_locked_pipelines).distinct
|
||||
end
|
||||
|
||||
def builds_with_coverage
|
||||
builds.latest.with_coverage
|
||||
end
|
||||
|
|
|
|||
|
|
@ -850,21 +850,21 @@ class Group < Namespace
|
|||
def members_with_descendants
|
||||
GroupMember
|
||||
.active_without_invites_and_requests
|
||||
.where(source_id: self_and_descendants.reorder(nil).select(:id))
|
||||
.where(source_id: self_and_descendants.without_order.select(:id))
|
||||
end
|
||||
|
||||
# Returns all members that are part of the group, it's subgroups, and ancestor groups
|
||||
def hierarchy_members
|
||||
GroupMember
|
||||
.active_without_invites_and_requests
|
||||
.where(source_id: self_and_hierarchy.reorder(nil).select(:id))
|
||||
.where(source_id: self_and_hierarchy.without_order.select(:id))
|
||||
end
|
||||
|
||||
def hierarchy_members_with_inactive
|
||||
GroupMember
|
||||
.non_request
|
||||
.non_invite
|
||||
.where(source_id: self_and_hierarchy.reorder(nil).select(:id))
|
||||
.where(source_id: self_and_hierarchy.without_order.select(:id))
|
||||
end
|
||||
|
||||
def descendant_project_members_with_inactive
|
||||
|
|
@ -876,8 +876,8 @@ class Group < Namespace
|
|||
|
||||
def users_with_descendants
|
||||
User
|
||||
.where(id: members_with_descendants.select(:user_id))
|
||||
.reorder(nil)
|
||||
.id_in(members_with_descendants.select(:user_id))
|
||||
.without_order
|
||||
end
|
||||
|
||||
def users_count
|
||||
|
|
|
|||
|
|
@ -53,7 +53,7 @@ module Members
|
|||
# Avoids an unnecessary SELECT when the group has no parents
|
||||
@source_ids ||=
|
||||
if group.has_parent?
|
||||
group.self_and_ancestors.reorder(nil).select(:id)
|
||||
group.self_and_ancestors.without_order.select(:id)
|
||||
else
|
||||
group.id
|
||||
end
|
||||
|
|
|
|||
|
|
@ -2121,7 +2121,12 @@ class MergeRequest < ApplicationRecord
|
|||
end
|
||||
|
||||
def has_sast_reports?
|
||||
!!diff_head_pipeline&.complete_or_manual_and_has_reports?(::Ci::JobArtifact.of_report_type(:sast))
|
||||
if Feature.enabled?(:show_child_reports_in_mr_page, project)
|
||||
!!diff_head_pipeline&.complete_or_manual? &&
|
||||
!!diff_head_pipeline&.latest_report_builds_in_self_and_project_descendants(Ci::JobArtifact.of_report_type(:sast))&.exists?
|
||||
else
|
||||
!!diff_head_pipeline&.complete_or_manual_and_has_reports?(::Ci::JobArtifact.of_report_type(:sast))
|
||||
end
|
||||
end
|
||||
|
||||
def has_secret_detection_reports?
|
||||
|
|
@ -2657,6 +2662,8 @@ class MergeRequest < ApplicationRecord
|
|||
def report_type_enabled?(report_type)
|
||||
if report_type == :license_scanning
|
||||
::Gitlab::LicenseScanning.scanner_for_pipeline(project, diff_head_pipeline).has_data?
|
||||
elsif report_type == :sast && Feature.enabled?(:show_child_reports_in_mr_page, project)
|
||||
!!diff_head_pipeline&.latest_report_builds_in_self_and_project_descendants(::Ci::JobArtifact.of_report_type(report_type))&.exists?
|
||||
else
|
||||
!!diff_head_pipeline&.batch_lookup_report_artifact_for_file_type(report_type)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ class Namespace
|
|||
Gitlab::ObjectHierarchy
|
||||
.new(Namespace.where(id: namespace))
|
||||
.base_and_ancestors
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
.find_top_level
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ module Namespaces
|
|||
roots = Gitlab::ObjectHierarchy
|
||||
.new(Namespace.id_in(parent_ids))
|
||||
.base_and_ancestors
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
.top_level
|
||||
|
||||
Namespace.lock('FOR NO KEY UPDATE').select(:id).id_in(roots).order(id: :asc).load
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ module Namespaces
|
|||
def root_ancestor
|
||||
if persisted? && !parent_id.nil?
|
||||
strong_memoize(:root_ancestor) do
|
||||
recursive_ancestors.reorder(nil).find_top_level
|
||||
recursive_ancestors.without_order.find_top_level
|
||||
end
|
||||
elsif parent.nil?
|
||||
self
|
||||
|
|
|
|||
|
|
@ -30,9 +30,14 @@ class MergeRequests::PipelineEntity < Grape::Entity
|
|||
end
|
||||
|
||||
expose :artifacts do |pipeline, options|
|
||||
rel = pipeline.downloadable_artifacts
|
||||
project = pipeline.project
|
||||
|
||||
rel = if Feature.enabled?(:show_child_reports_in_mr_page, project)
|
||||
pipeline.downloadable_artifacts_in_self_and_project_descendants
|
||||
else
|
||||
pipeline.downloadable_artifacts
|
||||
end
|
||||
|
||||
allowed_to_read_artifacts = rel.select { |artifact| can?(request.current_user, :read_job_artifacts, artifact) }
|
||||
|
||||
BuildArtifactEntity.represent(allowed_to_read_artifacts, options.merge(project: project))
|
||||
|
|
|
|||
|
|
@ -53,13 +53,11 @@ module Boards
|
|||
end
|
||||
|
||||
# We memoize the query here since the finder methods we use are quite complex. This does not memoize the result of the query.
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def init_collection
|
||||
strong_memoize(:init_collection) do
|
||||
filter(finder.execute).reorder(nil)
|
||||
filter(finder.execute).without_order
|
||||
end
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def filter(items)
|
||||
# when grouping board issues by epics (used in board swimlanes)
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ module Branches
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def merge_request_branch_names
|
||||
# reorder(nil) is necessary for SELECT DISTINCT because default scope adds an ORDER BY
|
||||
source_names = project.origin_merge_requests.opened.reorder(nil).distinct.pluck(:source_branch)
|
||||
target_names = project.merge_requests.opened.reorder(nil).distinct.pluck(:target_branch)
|
||||
# without_order is necessary for SELECT DISTINCT because default scope adds an ORDER BY
|
||||
source_names = project.origin_merge_requests.opened.without_order.distinct.pluck(:source_branch)
|
||||
target_names = project.merge_requests.opened.without_order.distinct.pluck(:target_branch)
|
||||
(source_names + target_names).uniq
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ module Issues
|
|||
|
||||
def initialize(projects)
|
||||
@projects_collection = (projects.is_a?(Array) ? Project.id_in(projects) : projects).select(:id).projects_order_id_asc
|
||||
@root_namespace = @projects_collection.select(:namespace_id).reorder(nil).take.root_namespace # rubocop:disable CodeReuse/ActiveRecord
|
||||
@root_namespace = @projects_collection.select(:namespace_id).without_order.take.root_namespace # rubocop:disable CodeReuse/ActiveRecord
|
||||
@caching = ::Gitlab::Issues::Rebalancing::State.new(@root_namespace, @projects_collection)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ module Labels
|
|||
group_labels_applied_to_issues,
|
||||
group_labels_applied_to_merge_requests
|
||||
])
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
.distinct
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
@ -50,7 +50,7 @@ module Labels
|
|||
def group_labels_applied_to_issues
|
||||
@labels_applied_to_issues ||= Label.joins(:issues)
|
||||
.joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'")
|
||||
.where(issues: { project_id: project.id }).reorder(nil)
|
||||
.where(issues: { project_id: project.id }).without_order
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
@ -58,7 +58,7 @@ module Labels
|
|||
def group_labels_applied_to_merge_requests
|
||||
@labels_applied_to_mrs ||= Label.joins(:merge_requests)
|
||||
.joins("INNER JOIN namespaces on namespaces.id = labels.group_id AND namespaces.type = 'Group'")
|
||||
.where(merge_requests: { target_project_id: project.id }).reorder(nil)
|
||||
.where(merge_requests: { target_project_id: project.id }).without_order
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ module Milestones
|
|||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def milestones_to_transfer
|
||||
Milestone.from_union([group_milestones_applied_to_issues, group_milestones_applied_to_merge_requests])
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
.distinct
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ module Snippets
|
|||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def snippet_counts
|
||||
@snippets_finder.execute
|
||||
.reorder(nil)
|
||||
.without_order
|
||||
.select(<<~SQL)
|
||||
count(case when snippets.visibility_level=#{Snippet::PUBLIC}
|
||||
and snippets.secret is FALSE then 1 else null end) as are_public,
|
||||
|
|
|
|||
|
|
@ -1,2 +1,2 @@
|
|||
.nothing-here-block
|
||||
= _("File suppressed by a .gitattributes entry or the file's encoding is unsupported.")
|
||||
= _("File suppressed by a .gitattributes entry, the file's encoding is unsupported, or the file size exceeds the limit.")
|
||||
|
|
|
|||
|
|
@ -70,7 +70,7 @@ class StuckMergeJobsWorker # rubocop:disable Scalability/IdempotentWorker
|
|||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def stuck_merge_requests
|
||||
MergeRequest.select('id, merge_jid').with_state(:locked).where.not(merge_jid: nil).reorder(nil)
|
||||
MergeRequest.select('id, merge_jid').with_state(:locked).where.not(merge_jid: nil).without_order
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
end
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
---
|
||||
name: secret_detection_enable_spp_for_public_projects
|
||||
description:
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/546115
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/194244
|
||||
rollout_issue_url:
|
||||
milestone: '18.1'
|
||||
group: group::secret detection
|
||||
type: development
|
||||
default_enabled: false
|
||||
|
|
@ -60,7 +60,8 @@ if Gitlab.ee?
|
|||
Ai::ActiveContext::Code::Repository,
|
||||
Ai::KnowledgeGraph::EnabledNamespace,
|
||||
Ai::KnowledgeGraph::Replica,
|
||||
Ai::KnowledgeGraph::Task
|
||||
Ai::KnowledgeGraph::Task,
|
||||
Ai::DuoWorkflows::Checkpoint
|
||||
])
|
||||
else
|
||||
Gitlab::Database::Partitioning.register_tables(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
modified_or_deleted_patches = helper.modified_files.select { |file| file.start_with?('patches/') } +
|
||||
helper.deleted_files.select { |file| file.start_with?('patches/') }
|
||||
|
||||
return if modified_or_deleted_patches.empty?
|
||||
|
||||
message = "This merge request modifies or deletes an existing patch in the `patches` " \
|
||||
"directory. Please ping `@gitlab-build` in a comment so that the cache with " \
|
||||
"existing patch can be invalidated for various build pipelines once this MR is " \
|
||||
"merged."
|
||||
|
||||
warn message
|
||||
|
|
@ -4,8 +4,8 @@ classes:
|
|||
- Ai::DuoWorkflows::Checkpoint
|
||||
feature_categories:
|
||||
- duo_workflow
|
||||
description:
|
||||
introduced_by_url:
|
||||
description:
|
||||
introduced_by_url:
|
||||
milestone: '17.2'
|
||||
gitlab_schema: gitlab_main_cell
|
||||
sharding_key:
|
||||
|
|
|
|||
|
|
@ -540,6 +540,7 @@ The newly-created vulnerability's detail page is opened.
|
|||
- Ingestion of vulnerability data into advanced search [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/536299) in GitLab 18.1 [with a flag](../../../administration/feature_flags/_index.md) named `vulnerability_es_ingestion`. Available in GitLab.com and GitLab Dedicated. Disabled by default.
|
||||
- Filters for OWASP 2021 grouping and identifiers in advanced search [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/537673) in GitLab 18.1 with the feature flag `advanced_vulnerability_management`. Available in GitLab.com and GitLab Dedicated. Disabled by default.
|
||||
- Ingestion of vulnerability data into advanced search is [generally available](https://gitlab.com/gitlab-org/gitlab/-/issues/536299) on GitLab.com and GitLab Dedicated in GitLab 18.2. Feature flag `vulnerability_es_ingestion` removed.
|
||||
- Filters for OWASP 2021 grouping and identifiers in advanced search [introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/537673) in GitLab 18.2 with the feature flag `advanced_vulnerability_management`. Available in GitLab.com and GitLab Dedicated. Enabled by default.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,191 +7,32 @@ title: GitLab Duo Agent Platform
|
|||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
- Status: Private beta
|
||||
- LLM: Anthropic [Claude Sonnet 4](https://www.anthropic.com/claude/sonnet)
|
||||
- Tier: Premium, Ultimate
|
||||
- Add-on: GitLab Duo Core, Pro, or Enterprise
|
||||
- Offering: GitLab.com, GitLab Self-Managed
|
||||
- Status: Experiment
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/14153) in GitLab 17.4 [with a flag](../../administration/feature_flags/_index.md) named `duo_workflow`. Enabled for GitLab team members only. This feature is a [private beta](../../policy/development_stages_support.md).
|
||||
- [Name changed](https://gitlab.com/gitlab-org/gitlab/-/issues/551382) from `Workflow` to `Agent Platform` in GitLab 18.2.
|
||||
- Introduced as [an experiment](../../policy/development_stages_support.md) in GitLab 18.2.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
This feature is available for internal GitLab team members for testing, but not ready for production use.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
{{< alert type="warning" >}}
|
||||
|
||||
This feature is [a private beta](../../policy/development_stages_support.md) and is not intended for customer usage outside of initial design partners. We expect major changes to this feature.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
{{< alert type="disclaimer" />}}
|
||||
|
||||
With the GitLab Duo Agent Platform, multiple AI agents can work in parallel, helping you create code,
|
||||
research results, and perform tasks simultaneously.
|
||||
The agents have full context across your entire software development lifecycle.
|
||||
|
||||
Use the Agent Platform to work on large problems, like understanding a codebase or
|
||||
generating an implementation plan. For more focused pieces of work, like generating
|
||||
or understanding specific code, use [GitLab Duo Agentic Chat](../gitlab_duo_chat/agentic_chat.md) instead.
|
||||
|
||||
For more details, [view this blog post](https://about.gitlab.com/blog/gitlab-duo-agent-platform-what-is-next-for-intelligent-devsecops/).
|
||||
|
||||
The Agent Platform is currently available in the VS Code IDE.
|
||||
Currently the Agent Platform is available in the VS Code IDE only,
|
||||
but other improvements are planned.
|
||||
|
||||
- It runs in your IDE so that you do not have to switch contexts or tools.
|
||||
- It creates and works through a plan, in response to your prompt.
|
||||
- It stages proposed changes in your project's repository.
|
||||
You control when to accept, modify, or reject the suggestions.
|
||||
- Understands the context of your project structure, codebase, and history.
|
||||
You can also add your own context, such as relevant GitLab issues or merge requests.
|
||||
In the meantime, choose which agent works best for the job you want to accomplish:
|
||||
|
||||
For a click-through demo, see [GitLab Duo Agent Platform](https://gitlab.navattic.com/duo-workflow).
|
||||
<!-- Demo published on 2025-03-18 -->
|
||||
|
||||
For an overview, watch <i class="fa fa-youtube-play youtube" aria-hidden="true"></i> [Enhancing your quality assurance with GitLab Duo Agent Platform](https://youtu.be/Tuj7TgqY81Q?si=IbxaKv7IhAHYnHkN). <!-- Video published on 2025-03-20-->
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you can use the Agent Platform in VS Code, you must:
|
||||
|
||||
- [Install Visual Studio Code](https://code.visualstudio.com/download) (VS Code).
|
||||
- [Set up the GitLab Workflow extension for VS Code](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#setup). Minimum version 5.16.0.
|
||||
- Have an account on GitLab.com.
|
||||
- Have a project that meets the following requirements:
|
||||
- The project is on GitLab.com.
|
||||
- You have at least the Developer role.
|
||||
- The project belongs to a [group namespace](../namespace/_index.md) with an Ultimate subscription.
|
||||
- [Beta and experimental features must be turned on](../gitlab_duo/turn_on_off.md#turn-on-beta-and-experimental-features).
|
||||
- [GitLab Duo must be turned on](../gitlab_duo/turn_on_off.md).
|
||||
- [Successfully connect to your repository](#connect-to-your-repository).
|
||||
- [Ensure an HTTP/2 connection to the backend service is possible](troubleshooting.md#network-issues).
|
||||
|
||||
{{< alert type="note" >}}
|
||||
|
||||
Though not recommended, you can [set up the Agent Platform in a Docker container](docker_set_up.md).
|
||||
You do not need to use Docker to run the Agent Platform.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
## Connect to your repository
|
||||
|
||||
To use the Agent Platform in VS Code, ensure your repository is properly connected.
|
||||
|
||||
1. In VS Code, on the top menu, select **Terminal > New Terminal**.
|
||||
1. Clone your repository: `git clone <repository>`.
|
||||
1. Change to the directory where your repository was cloned and check out your branch: `git checkout <branch_name>`.
|
||||
1. Ensure your project is selected:
|
||||
1. On the left sidebar, select **GitLab Workflow** ({{< icon name="tanuki" >}}).
|
||||
1. Select the project name. If you have multiple projects, select the one you want to work with.
|
||||
1. In the terminal, ensure your repository is configured with a remote: `git remote -v`. The results should look similar to:
|
||||
|
||||
```plaintext
|
||||
origin git@gitlab.com:gitlab-org/gitlab.git (fetch)
|
||||
origin git@gitlab.com:gitlab-org/gitlab.git (push)
|
||||
```
|
||||
|
||||
If no remote is defined, or you have multiple remotes:
|
||||
|
||||
1. On the left sidebar, select **Source Control** ({{< icon name="branch" >}}).
|
||||
1. On the **Source Control** label, right-click and select **Repositories**.
|
||||
1. Next to your repository, select the ellipsis ({{< icon name=ellipsis_h >}}), then **Remote > Add Remote**.
|
||||
1. Select **Add remote from GitLab**.
|
||||
1. Choose a remote.
|
||||
|
||||
Now you can use the Agent Platform to help solve your coding tasks.
|
||||
|
||||
## Use the Agent Platform in VS Code
|
||||
|
||||
The software development flow is one of many possible flows in the Agent Platform.
|
||||
|
||||
To use the software development flow:
|
||||
|
||||
1. On the left sidebar, select **GitLab Duo Workflow** ({{< icon name="pencil" >}}).
|
||||
1. In the text box, specify a code task in detail.
|
||||
- For assistance writing your prompt, see [use case examples](use_cases.md) and [best practices](best_practices.md).
|
||||
- The Agent Platform is aware of all files available to Git in the project branch.
|
||||
- You can also give the Agent Platform [additional context](#the-context-the-agent-platform-is-aware-of).
|
||||
- The Agent Platform cannot access external sources or the web.
|
||||
1. Select **Start**.
|
||||
|
||||
After you describe your task, a plan is generated and executed.
|
||||
You can pause or ask it to adjust the plan.
|
||||
|
||||
For more information about how to interact with the Agent Platform, see [best practices](best_practices.md).
|
||||
|
||||
## The context the Agent Platform is aware of
|
||||
|
||||
When you ask for help with a task in the Agent Platform, it will refer to files available to Git in the current branch of the project in your VS Code workspace.
|
||||
|
||||
You can ask about other projects, but they must meet the [prerequisites](#prerequisites).
|
||||
|
||||
You can also provide it with additional context.
|
||||
|
||||
| Area | Enter | Examples |
|
||||
|-------------------------|------------------------|----------|
|
||||
| Local files | The file with path. |• Summarize the file `src/main.js`<br>• Review the code in `app/models/`<br>• List all JavaScript files in the project |
|
||||
| Epics | Either:<br>• The URL of the group or epic. <br>• The epic ID and the name of the group the epic is in. | Examples:<br>• List all epics in `https://gitlab.com/groups/namespace/group`<br>• Summarize the epic: `https://gitlab.com/groups/namespace/group/-/epics/42`<br>• `Summarize epic 42 in group namespace/group` |
|
||||
| Issues | Either:<br>• The URL of the project or issue. <br>• The issue ID in the current or another project. | Examples:<br>• List all issues in the project at `https://gitlab.com/namespace/project`<br>• Summarize the issue at `https://gitlab.com/namespace/project/-/issues/103`<br>• Review the comment with ID `42` in `https://gitlab.com/namespace/project/-/issues/103`<br>• List all comments on the issue at `https://gitlab.com/namespace/project/-/issues/103`<br>• Summarize issue `103` in this project |
|
||||
| Merge requests | Either:<br>• The URL of the merge request. <br>• The merge request ID in the current or another project. |• Summarize `https://gitlab.com/namespace/project/-/merge_requests/103`<br>• Review the diffs in `https://gitlab.com/namespace/project/-/merge_requests/103`<br>• Summarize the comments on `https://gitlab.com/namespace/project/-/merge_requests/103`<br>• Summarize merge request `103` in this project |
|
||||
| Merge request pipelines | The merge request ID in the current or another project. |• Review the failures in merge request `12345`<br>• Can you identify the cause of the error in the merge request `54321` in project `gitlab-org/gitlab-qa` <br>• Suggest a solution to the pipeline failure in `https://gitlab.com/namespace/project/-/merge_requests/54321` |
|
||||
|
||||
The Agent Platform also has access to the GitLab [Search API](../../api/search.md) to find related issues or merge requests.
|
||||
|
||||
## Supported languages
|
||||
|
||||
The Agent Platform officially supports the following languages:
|
||||
|
||||
- CSS
|
||||
- Go
|
||||
- HTML
|
||||
- Java
|
||||
- JavaScript
|
||||
- Markdown
|
||||
- Python
|
||||
- Ruby
|
||||
- TypeScript
|
||||
|
||||
## APIs that the Agent Platform has access to
|
||||
|
||||
To create solutions and understand the context of the problem,
|
||||
the Agent Platform accesses several GitLab APIs.
|
||||
|
||||
Specifically, an OAuth token with the `ai_workflows` scope has access
|
||||
to the following APIs:
|
||||
|
||||
- [Projects API](../../api/projects.md)
|
||||
- [Search API](../../api/search.md)
|
||||
- [CI Pipelines API](../../api/pipelines.md)
|
||||
- [CI Jobs API](../../api/jobs.md)
|
||||
- [Merge Requests API](../../api/merge_requests.md)
|
||||
- [Epics API](../../api/epics.md)
|
||||
- [Issues API](../../api/issues.md)
|
||||
- [Notes API](../../api/notes.md)
|
||||
- [Usage Data API](../../api/usage_data.md)
|
||||
|
||||
## Audit log
|
||||
|
||||
An audit event is created for each API request done by the Agent Platform.
|
||||
On your GitLab Self-Managed instance, you can view these events on the
|
||||
[instance audit events](../../administration/compliance/audit_event_reports.md#instance-audit-events) page.
|
||||
|
||||
## Give feedback
|
||||
|
||||
The Agent Platform is a private beta and your feedback is crucial to improve it for you and others.
|
||||
To report issues or suggest improvements,
|
||||
[complete this survey](https://gitlab.fra1.qualtrics.com/jfe/form/SV_9GmCPTV7oH9KNuu).
|
||||
|
||||
## Related topics
|
||||
|
||||
- [Use GitLab Duo Agent Platform to improve application quality assurance](https://about.gitlab.com/blog/2025/04/10/use-gitlab-duo-workflow-to-improve-application-quality-assurance/)
|
||||
- Use [GitLab Duo Agentic Chat](../gitlab_duo_chat/agentic_chat.md)
|
||||
for focused pieces of work, like generating or understanding specific code.
|
||||
- Use [the software development flow](software_development_flow.md)
|
||||
to work on larger problems, like understanding a codebase or
|
||||
generating an implementation plan.
|
||||
|
|
|
|||
|
|
@ -1,106 +0,0 @@
|
|||
---
|
||||
stage: AI-powered
|
||||
group: Duo Workflow
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
title: Best practices for GitLab Duo Agent Platform
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
- Status: Private beta
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Name changed](https://gitlab.com/gitlab-org/gitlab/-/issues/551382) from `Workflow` to `Agent Platform` in GitLab 18.2.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="warning" >}}
|
||||
|
||||
This feature is [a private beta](../../policy/development_stages_support.md) and is not intended for customer usage outside of initial design partners. We expect major changes to this feature.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
When you use the GitLab Duo Agent Platform in the IDE, follow these best practices to get the most value from the software development flow.
|
||||
|
||||
## Create focused prompts
|
||||
|
||||
A prompt is the text input that you give to the Agent Platform. To create an effective prompt:
|
||||
|
||||
- Define a clear goal with measurable outcomes.
|
||||
- Provide clear context by including relevant files, merge requests, or issues.
|
||||
For information about the types of context the Agent Platform understands, see
|
||||
[context](_index.md#the-context-the-agent-platform-is-aware-of).
|
||||
- Provide examples of expected changes.
|
||||
- Include or link to any technical requirements or rules.
|
||||
|
||||
Example prompt:
|
||||
|
||||
```plaintext
|
||||
Scan all Vue.js components in the 'src/components' directory. Add appropriate ARIA attributes
|
||||
to improve accessibility. Focus on buttons, forms, and navigation elements.
|
||||
Ensure changes maintain existing functionality.
|
||||
```
|
||||
|
||||
## Review the plan
|
||||
|
||||
After you enter your prompt, the Agent Platform generates a plan containing tasks. You can pause and restart while it creates and works through its plan.
|
||||
|
||||
During this process:
|
||||
|
||||
- Confirm all target files are correctly identified.
|
||||
- Verify proposed changes align with requirements.
|
||||
- Check for any missing dependencies or integration points.
|
||||
- Pause the workflow and adjust if needed.
|
||||
|
||||
## Check proposed changes
|
||||
|
||||
As the Agent Platform works through its plan, it stages corresponding changes to the files in your project. The changes might include new or modified files.
|
||||
|
||||
Before committing the changes:
|
||||
|
||||
1. Check that the Agent Platform:
|
||||
|
||||
- Targeted the correct files.
|
||||
- Made appropriate changes.
|
||||
- Followed the requirements and rules from your prompt.
|
||||
|
||||
1. Look for patterns in what it's missing or misinterpreting. Use that data to refine your prompt. Common errors include:
|
||||
|
||||
- The incorrect solution. We are continuing to work on the accuracy of overall generated content. However, suggestions might be:
|
||||
- Irrelevant.
|
||||
- Incomplete.
|
||||
- Results in failed pipelines.
|
||||
- Potentially insecure.
|
||||
- Offensive or insensitive.
|
||||
- Adds code in the wrong location.
|
||||
- Includes code changes that can't be used by other parts of the system.
|
||||
|
||||
## Iterate and improve
|
||||
|
||||
When the Agent Platform does not produce the expected results:
|
||||
|
||||
- Document the specific areas that need improvement.
|
||||
- Break complex goals into smaller workflows.
|
||||
- Add examples of correct and incorrect implementations.
|
||||
- Refine prompts to address gaps.
|
||||
|
||||
For example, refine your prompts from the general to the specific:
|
||||
|
||||
General:
|
||||
|
||||
```plaintext
|
||||
Add ARIA attributes to improve accessibility.
|
||||
```
|
||||
|
||||
Specific:
|
||||
|
||||
```plaintext
|
||||
Add aria-label attributes to buttons without text content.
|
||||
Use the button's function for the label value.
|
||||
Required format: aria-label="Action description"
|
||||
```
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
---
|
||||
stage: AI-powered
|
||||
group: Duo Workflow
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
title: Set up Docker for GitLab Duo Agent Platform (optional)
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
- Status: Private beta
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Name changed](https://gitlab.com/gitlab-org/gitlab/-/issues/551382) from `Workflow` to `Agent Platform` in GitLab 18.2.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="warning" >}}
|
||||
|
||||
This feature is [a private beta](../../policy/development_stages_support.md) and is not intended for customer usage outside of initial design partners. We expect major changes to this feature.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
Use the following guide to set up GitLab Duo Agent Platform locally with Docker.
|
||||
|
||||
This is not the preferred method to run the Agent Platform.
|
||||
If you have VS Code and at least version 5.16.0 of the GitLab Workflow extension for VS Code,
|
||||
you can use the Agent Platform. For more information, see [the prerequisites](_index.md#prerequisites).
|
||||
|
||||
## Install Docker and set the socket file path
|
||||
|
||||
The Agent Platform needs an execution platform like Docker where it can execute arbitrary code,
|
||||
read and write files, and make API calls to GitLab.
|
||||
|
||||
If you are on macOS or Linux, you can either:
|
||||
|
||||
- Use the [automated setup script](#automated-setup). Recommended.
|
||||
- Follow the [manual setup](#manual-setup).
|
||||
|
||||
If you are not on macOS or Linux, follow the [manual setup](#manual-setup).
|
||||
|
||||
### Automated setup
|
||||
|
||||
The automated setup script:
|
||||
|
||||
- Installs [Docker](https://formulae.brew.sh/formula/docker) and [Colima](https://github.com/abiosoft/colima).
|
||||
- Sets Docker socket path in VS Code settings.
|
||||
|
||||
You can run the script with the `--dry-run` flag to check the dependencies
|
||||
that get installed with the script.
|
||||
|
||||
1. Download the [setup script](https://gitlab.com/gitlab-org/duo-workflow/duo-workflow-executor/-/blob/main/scripts/install-runtime).
|
||||
|
||||
```shell
|
||||
wget https://gitlab.com/gitlab-org/duo-workflow/duo-workflow-executor/-/raw/main/scripts/install-runtime
|
||||
```
|
||||
|
||||
1. Run the script.
|
||||
|
||||
```shell
|
||||
chmod +x install-runtime
|
||||
./install-runtime
|
||||
```
|
||||
|
||||
### Manual setup
|
||||
|
||||
1. Install a Docker container engine, such as [Rancher Desktop](https://docs.rancherdesktop.io/getting-started/installation/).
|
||||
1. Set the Docker socket path and Docker settings in VS Code:
|
||||
1. Open VS Code, then open the [Command Palette](https://code.visualstudio.com/docs/getstarted/userinterface#_command-palette):
|
||||
- On macOS: <kbd>Cmd</kbd> + <kbd>,</kbd>
|
||||
- On Windows and Linux: <kbd>Ctrl</kbd> + <kbd>,</kbd>
|
||||
1. In the open Command Palette search for `settings.json`.
|
||||
1. Add a line to `settings.json` that defines the Docker socket path setting `gitlab.duoWorkflow.dockerSocket`,
|
||||
according to your container manager, and save your settings file. Some examples for common container
|
||||
managers on macOS, where you would replace `<your_user>` with your user's home folder:
|
||||
|
||||
- Rancher Desktop:
|
||||
|
||||
```json
|
||||
"gitlab.duoWorkflow.dockerSocket": "/Users/<your_user>/.rd/docker.sock",
|
||||
"gitlab.duoWorkflow.useDocker": true,
|
||||
```
|
||||
|
||||
- Colima:
|
||||
|
||||
```json
|
||||
"gitlab.duoWorkflow.dockerSocket": "/Users/<your_user>/.colima/default/docker.sock",
|
||||
"gitlab.duoWorkflow.useDocker": true,
|
||||
```
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
---
|
||||
stage: AI-powered
|
||||
group: Duo Workflow
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
title: Risks in GitLab Duo Agent Platform
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
- Status: Private beta
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Name changed](https://gitlab.com/gitlab-org/gitlab/-/issues/551382) from `Workflow` to `Agent Platform` in GitLab 18.2.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="warning" >}}
|
||||
|
||||
This feature is [a private beta](../../policy/development_stages_support.md) and is not intended for customer usage outside of initial design partners. We expect major changes to this feature.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
The Agent Platform is a beta product and users should consider their
|
||||
circumstances before using this tool. It is subject to [the GitLab Testing Agreement](https://handbook.gitlab.com/handbook/legal/testing-agreement/).
|
||||
The Agent Platform is an AI Agent that is given some ability to perform actions on the user's behalf. AI tools based on LLMs are
|
||||
inherently unpredictable and you should take appropriate precautions.
|
||||
|
||||
The Agent Platform in VS Code runs workflows on your local workstation or in a Docker container.
|
||||
Running inside of a Docker container is not a security measure but a
|
||||
convenience to reduce the amount of disruption to your usual development
|
||||
environment. All the documented risks should be considered before using this
|
||||
product. The following risks are important to understand:
|
||||
|
||||
1. The Agent Platform has access to the local file system of the
|
||||
project where you started running it. The Agent Platform respects your local `.gitignore` file,
|
||||
but it can still access files that are not committed to the project and not called out in `.gitignore`.
|
||||
Such files can contain credentials (for example, `.env` files).
|
||||
1. The Agent Platform also gets access to a time-limited `ai_workflows` scoped GitLab
|
||||
OAuth token with your user's identity. This token can be used to access
|
||||
GitLab APIs on your behalf. This token is limited to the duration of
|
||||
the workflow and only has access to certain APIs in GitLab.
|
||||
Without user approval, the Agent Platform will only perform read operations but the token can still,
|
||||
by design, perform write operations on the users behalf. You should consider
|
||||
the access your user has in GitLab before running the Agent Platform.
|
||||
1. You should not give the Agent Platform any additional credentials or secrets, in
|
||||
goals or messages, as there is a chance it might end up using those in code
|
||||
or other API calls.
|
||||
|
||||
Risks specifically when using Docker to isolate the Agent Platform:
|
||||
|
||||
1. Our supported Docker servers are running in a VM. We do not support Docker
|
||||
Engine running on the host as this offers less isolation. Because Docker
|
||||
Engine is the most common way to run Docker on Linux we will likely not
|
||||
support many Linux setups by default, but instead we'll require them to
|
||||
install an additional Docker runtime to use the Agent Platform.
|
||||
1. This VM running on your local workstation likely has access to your local
|
||||
network, unless you have created additional firewall rules to prevent it.
|
||||
Local network access may be an issue if you are running local development
|
||||
servers on your host that you would not want reachable by the workflow
|
||||
commands. Local network access may also be risky in a corporate intranet
|
||||
environment where you have internal resources that you do not want
|
||||
accessible by the Agent Platform.
|
||||
1. The VM may be able to consume a lot of CPU, RAM and storage based on the
|
||||
limits configured with your Docker VM installation.
|
||||
1. Depending on the configuration of the VM in your Docker installation it may
|
||||
also have access to other hardware on your host.
|
||||
1. Unpatched installations of Docker may contain vulnerabilities that could
|
||||
eventually lead to code execution escaping the VM to the host or accessing
|
||||
resources on the host that you didn't intend.
|
||||
1. Each version of Docker has different ways of mounting directories into the
|
||||
containers. The Agent Platform only mounts the directory for the project you have
|
||||
open in VS Code but depending on how your Docker installation works and
|
||||
whether or not you are running other containers there may still be some
|
||||
risks it could access other parts of your file system.
|
||||
1. All your Docker containers usually run in a single VM. So this
|
||||
may mean that the containers are running in the same VM as other
|
||||
non-Agent Platform containers. While the containers are isolated to some
|
||||
degree this isolation is not as strict as VM level isolation.
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
---
|
||||
stage: AI-powered
|
||||
group: Duo Workflow
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
title: Agent flows
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Premium, Ultimate
|
||||
- Add-on: GitLab Duo Core, Pro, or Enterprise
|
||||
- Offering: GitLab.com, GitLab Self-Managed
|
||||
- Status: Experiment
|
||||
- LLM: Anthropic [Claude Sonnet 4](https://www.anthropic.com/claude/sonnet)
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Introduced](https://gitlab.com/groups/gitlab-org/-/epics/14153) in GitLab 17.4 [with a flag](../../administration/feature_flags/_index.md) named `duo_workflow`. Enabled for GitLab team members only. This feature is a [private beta](../../policy/development_stages_support.md).
|
||||
- [Changed name](https://gitlab.com/gitlab-org/gitlab/-/issues/551382) and `duo_workflow` [flag enabled](../../administration/feature_flags/_index.md) in GitLab 18.2.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag.
|
||||
For more information, see the history.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
The software development flow is the first flow that's available in the VS Code IDE.
|
||||
Formerly known as GitLab Duo Workflow, the software development flow:
|
||||
|
||||
- Runs in your IDE so that you do not have to switch contexts or tools.
|
||||
- Creates and works through a plan, in response to your prompt.
|
||||
- Stages proposed changes in your project's repository.
|
||||
You control when to accept, modify, or reject the suggestions.
|
||||
- Understands the context of your project structure, codebase, and history.
|
||||
You can also add your own context, such as relevant GitLab issues or merge requests.
|
||||
|
||||
## Prerequisites
|
||||
|
||||
Before you can use the software development flow in Visual Studio Code (VS Code), you must:
|
||||
|
||||
- [Install VS Code](https://code.visualstudio.com/download).
|
||||
- [Set up the GitLab Workflow extension for VS Code](https://marketplace.visualstudio.com/items?itemName=GitLab.gitlab-workflow#setup). Minimum version 5.16.0.
|
||||
- Have an account on GitLab.com.
|
||||
- Have a project that meets the following requirements:
|
||||
- The project is on GitLab.com.
|
||||
- You have at least the Developer role.
|
||||
- The project belongs to a [group namespace](../namespace/_index.md) with an Ultimate subscription.
|
||||
- [Beta and experimental features must be turned on](../gitlab_duo/turn_on_off.md#turn-on-beta-and-experimental-features).
|
||||
- [GitLab Duo must be turned on](../gitlab_duo/turn_on_off.md).
|
||||
- [Successfully connect to your repository](#connect-to-your-repository).
|
||||
- [Ensure an HTTP/2 connection to the backend service is possible](troubleshooting.md#network-issues).
|
||||
|
||||
## Connect to your repository
|
||||
|
||||
To use the software development flow in VS Code, ensure your repository is properly connected.
|
||||
|
||||
1. In VS Code, on the top menu, select **Terminal > New Terminal**.
|
||||
1. Clone your repository: `git clone <repository>`.
|
||||
1. Change to the directory where your repository was cloned and check out your branch: `git checkout <branch_name>`.
|
||||
1. Ensure your project is selected:
|
||||
1. On the left sidebar, select **GitLab Workflow** ({{< icon name="tanuki" >}}).
|
||||
1. Select the project name. If you have multiple projects, select the one you want to work with.
|
||||
1. In the terminal, ensure your repository is configured with a remote: `git remote -v`. The results should look similar to:
|
||||
|
||||
```plaintext
|
||||
origin git@gitlab.com:gitlab-org/gitlab.git (fetch)
|
||||
origin git@gitlab.com:gitlab-org/gitlab.git (push)
|
||||
```
|
||||
|
||||
If no remote is defined, or you have multiple remotes:
|
||||
|
||||
1. On the left sidebar, select **Source Control** ({{< icon name="branch" >}}).
|
||||
1. On the **Source Control** label, right-click and select **Repositories**.
|
||||
1. Next to your repository, select the ellipsis ({{< icon name=ellipsis_h >}}), then **Remote > Add Remote**.
|
||||
1. Select **Add remote from GitLab**.
|
||||
1. Choose a remote.
|
||||
|
||||
Now you can use the software development flow to help solve your coding tasks.
|
||||
|
||||
## Use the software development flow in VS Code
|
||||
|
||||
The software development flow is one flow in the Agent Platform.
|
||||
|
||||
To use the software development flow:
|
||||
|
||||
1. On the left sidebar, select **GitLab Duo Agent Platform**.
|
||||
1. In the text box, specify a code task in detail.
|
||||
- The software development flow is aware of all files available to Git in the project branch.
|
||||
You can also give [additional context](#the-context-the-software-development-flow-is-aware-of).
|
||||
- The software development flow cannot access external sources or the web.
|
||||
1. Select **Start**.
|
||||
|
||||
After you describe your task, a plan is generated and executed.
|
||||
You can pause or ask it to adjust the plan.
|
||||
|
||||
## The context the software development flow is aware of
|
||||
|
||||
When you ask for help with a task, the software development flow refers to
|
||||
files available to Git in the current branch of the project in your VS Code workspace.
|
||||
|
||||
You can also provide it with additional context.
|
||||
|
||||
| Area | Enter | Examples |
|
||||
|-------------------------|------------------------|----------|
|
||||
| Local files | The file with path. |• Summarize the file `src/main.js`<br>• Review the code in `app/models/`<br>• List all JavaScript files in the project |
|
||||
| Epics | Either:<br>• The URL of the group or epic. <br>• The epic ID and the name of the group the epic is in. | Examples:<br>• List all epics in `https://gitlab.com/groups/namespace/group`<br>• Summarize the epic: `https://gitlab.com/groups/namespace/group/-/epics/42`<br>• `Summarize epic 42 in group namespace/group` |
|
||||
| Issues | Either:<br>• The URL of the project or issue. <br>• The issue ID in the current or another project. | Examples:<br>• List all issues in the project at `https://gitlab.com/namespace/project`<br>• Summarize the issue at `https://gitlab.com/namespace/project/-/issues/103`<br>• Review the comment with ID `42` in `https://gitlab.com/namespace/project/-/issues/103`<br>• List all comments on the issue at `https://gitlab.com/namespace/project/-/issues/103`<br>• Summarize issue `103` in this project |
|
||||
| Merge requests | Either:<br>• The URL of the merge request. <br>• The merge request ID in the current or another project. |• Summarize `https://gitlab.com/namespace/project/-/merge_requests/103`<br>• Review the diffs in `https://gitlab.com/namespace/project/-/merge_requests/103`<br>• Summarize the comments on `https://gitlab.com/namespace/project/-/merge_requests/103`<br>• Summarize merge request `103` in this project |
|
||||
| Merge request pipelines | The merge request ID in the current or another project. |• Review the failures in merge request `12345`<br>• Can you identify the cause of the error in the merge request `54321` in project `gitlab-org/gitlab-qa` <br>• Suggest a solution to the pipeline failure in `https://gitlab.com/namespace/project/-/merge_requests/54321` |
|
||||
|
||||
The software development flow also has access to the GitLab [Search API](../../api/search.md) to find related issues or merge requests.
|
||||
|
||||
## Supported languages
|
||||
|
||||
The software development flow officially supports the following languages:
|
||||
|
||||
- CSS
|
||||
- Go
|
||||
- HTML
|
||||
- Java
|
||||
- JavaScript
|
||||
- Markdown
|
||||
- Python
|
||||
- Ruby
|
||||
- TypeScript
|
||||
|
||||
## APIs that the software development flow has access to
|
||||
|
||||
To create solutions and understand the context of the problem,
|
||||
the software development flow accesses several GitLab APIs.
|
||||
|
||||
Specifically, an OAuth token with the `ai_workflows` scope has access
|
||||
to the following APIs:
|
||||
|
||||
- [Projects API](../../api/projects.md)
|
||||
- [Search API](../../api/search.md)
|
||||
- [CI Pipelines API](../../api/pipelines.md)
|
||||
- [CI Jobs API](../../api/jobs.md)
|
||||
- [Merge Requests API](../../api/merge_requests.md)
|
||||
- [Epics API](../../api/epics.md)
|
||||
- [Issues API](../../api/issues.md)
|
||||
- [Notes API](../../api/notes.md)
|
||||
- [Usage Data API](../../api/usage_data.md)
|
||||
|
||||
## Audit log
|
||||
|
||||
An audit event is created for each API request done by the software development flow.
|
||||
On your GitLab Self-Managed instance, you can view these events on the
|
||||
[instance audit events](../../administration/compliance/audit_event_reports.md#instance-audit-events) page.
|
||||
|
||||
## Risks
|
||||
|
||||
The software development flow is an experimental product and users should consider their
|
||||
circumstances before using this tool. It is subject to [the GitLab Testing Agreement](https://handbook.gitlab.com/handbook/legal/testing-agreement/).
|
||||
The software development flow is an AI agent that is given some ability to perform actions on the user's behalf. AI tools based on LLMs are
|
||||
inherently unpredictable and you should take appropriate precautions.
|
||||
|
||||
The software development flow in VS Code runs workflows on your local workstation.
|
||||
All the documented risks should be considered before using this
|
||||
product. The following risks are important to understand:
|
||||
|
||||
1. The software development flow has access to the local file system of the
|
||||
project where you started running it. The software development flow respects your local `.gitignore` file,
|
||||
but it can still access files that are not committed to the project and not called out in `.gitignore`.
|
||||
Such files can contain credentials (for example, `.env` files).
|
||||
1. The software development flow also gets access to a time-limited `ai_workflows` scoped GitLab
|
||||
OAuth token with your user's identity. This token can be used to access
|
||||
GitLab APIs on your behalf. This token is limited to the duration of
|
||||
the workflow and only has access to certain APIs in GitLab.
|
||||
Without user approval, the software development flow will only perform read operations but the token can still,
|
||||
by design, perform write operations on the users behalf. You should consider
|
||||
the access your user has in GitLab before running the software development flow.
|
||||
1. You should not give the software development flow any additional credentials or secrets, in
|
||||
goals or messages, as there is a chance it might end up using those in code
|
||||
or other API calls.
|
||||
|
||||
## Give feedback
|
||||
|
||||
The software development flow is an experiment and your feedback is crucial to improve it for you and others.
|
||||
To report issues or suggest improvements,
|
||||
[complete this survey](https://gitlab.fra1.qualtrics.com/jfe/form/SV_9GmCPTV7oH9KNuu).
|
||||
|
|
@ -2,40 +2,29 @@
|
|||
stage: AI-powered
|
||||
group: Duo Workflow
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
title: Troubleshooting GitLab Duo Agent Platform
|
||||
title: Troubleshooting the software development flow
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
- Status: Private beta
|
||||
- Tier: Premium, Ultimate
|
||||
- Add-on: GitLab Duo Core, Pro, or Enterprise
|
||||
- Offering: GitLab.com, GitLab Self-Managed
|
||||
- Status: Experiment
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Name changed](https://gitlab.com/gitlab-org/gitlab/-/issues/551382) from `Workflow` to `Agent Platform` in GitLab 18.2.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="warning" >}}
|
||||
|
||||
This feature is [a private beta](../../policy/development_stages_support.md) and is not intended for customer usage outside of initial design partners. We expect major changes to this feature.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
## General guidance
|
||||
|
||||
If you encounter issues, ensure that you have:
|
||||
|
||||
1. The latest version of the GitLab Workflow extension for VS Code.
|
||||
1. A project that meets the [prerequisites](_index.md#prerequisites).
|
||||
1. A project that meets the [prerequisites](software_development_flow.md#prerequisites).
|
||||
1. The repository open in VS Code.
|
||||
1. The branch checked out.
|
||||
|
||||
For details on these steps, see [the prerequisites](_index.md#prerequisites) and
|
||||
[how to connect to your repository](_index.md#connect-to-your-repository).
|
||||
For details on these steps, see [the prerequisites](software_development_flow.md#prerequisites) and
|
||||
[how to connect to your repository](software_development_flow.md#connect-to-your-repository).
|
||||
|
||||
## View debugging logs
|
||||
|
||||
|
|
@ -71,26 +60,6 @@ If the request fails or does not show the HTTP/2 protocol:
|
|||
To correct this issue, ask your network administrator to put `https://duo-workflow-svc.runway.gitlab.net/DuoWorkflow/ExecuteWorkflow`
|
||||
on the correct allowlist, or to exempt it from traffic inspection.
|
||||
|
||||
## Docker setup
|
||||
|
||||
If you encounter issues with your Docker setup, try the following steps.
|
||||
|
||||
1. [Install Docker and set the socket file path](docker_set_up.md#install-docker-and-set-the-socket-file-path).
|
||||
1. Restart your container manager. For example, if you use Colima, `colima restart`.
|
||||
1. Pull the base Docker image:
|
||||
|
||||
```shell
|
||||
docker pull registry.gitlab.com/gitlab-org/duo-workflow/default-docker-image/workflow-generic-image:v0.0.4
|
||||
```
|
||||
|
||||
1. For permission issues, ensure your operating system user has the necessary Docker permissions.
|
||||
1. Verify that Docker has internet connectivity by executing the command `docker image pull redhat/ubi8`.
|
||||
If this does not work, the DNS configuration of Colima might be at fault.
|
||||
Edit the DNS setting in `~/.colima/default/colima.yaml` to `dns: [1.1.1.1]` and then restart Colima with `colima restart`.
|
||||
1. Check the executor logs:
|
||||
- Use `docker ps -a | grep duo-workflow` to get the list of containers and their ids.
|
||||
- Use `docker logs <container_id>` to view the logs for the specific container.
|
||||
|
||||
## IDE configuration
|
||||
|
||||
You can try several things to ensure your repository is properly configured and connected.
|
||||
|
|
|
|||
|
|
@ -1,262 +0,0 @@
|
|||
---
|
||||
stage: AI-powered
|
||||
group: Duo Workflow
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://handbook.gitlab.com/handbook/product/ux/technical-writing/#assignments
|
||||
title: GitLab Duo Agent Platform use cases
|
||||
---
|
||||
|
||||
{{< details >}}
|
||||
|
||||
- Tier: Ultimate
|
||||
- Offering: GitLab.com
|
||||
- Status: Private beta
|
||||
|
||||
{{< /details >}}
|
||||
|
||||
{{< history >}}
|
||||
|
||||
- [Name changed](https://gitlab.com/gitlab-org/gitlab/-/issues/551382) from `Workflow` to `Agent Platform` in GitLab 18.2.
|
||||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="warning" >}}
|
||||
|
||||
This feature is [a private beta](../../policy/development_stages_support.md) and is not intended for customer usage outside of initial design partners. We expect major changes to this feature.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
The following use case examples demonstrate some of the ways you might use GitLab Duo Agent Platform.
|
||||
|
||||
## Refactor existing code
|
||||
|
||||
Use this approach when you need to improve performance, readability, or maintainability of existing code.
|
||||
|
||||
### Analyze
|
||||
|
||||
Ask GitLab Duo to analyze the current implementation.
|
||||
|
||||
- Request identification of complexity issues, performance bottlenecks, and readability concerns.
|
||||
- Have the Agent Platform suggest applicable design patterns.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Analyze the UserPermissions class in app/models/user_permissions.rb. Focus on:
|
||||
|
||||
1. Current methods and their complexity
|
||||
2. Performance bottlenecks
|
||||
3. Areas where readability can be improved
|
||||
4. Potential design patterns that could be applied
|
||||
|
||||
Provide a summary of your findings and suggestions for refactoring.
|
||||
Reference any similar refactoring in our codebase if applicable (link existing files if any).
|
||||
Document your analysis process.
|
||||
```
|
||||
|
||||
### Plan
|
||||
|
||||
Then, request a structured refactoring proposal.
|
||||
|
||||
- Ask for clear documentation of proposed changes.
|
||||
- Have the Agent Platform outline potential risks and estimated effort.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Based on the analysis of UserPermissions, create a refactoring proposal:
|
||||
|
||||
1. Outline the new structure for UserPermissions
|
||||
2. Suggest new method names and their purposes
|
||||
3. Propose any new classes or modules if needed
|
||||
4. Explain how this refactoring will improve performance and readability
|
||||
|
||||
Format the proposal as a GitLab issue template, including:
|
||||
|
||||
- Problem statement
|
||||
- Proposed solution
|
||||
- Potential risks
|
||||
- Estimated effort
|
||||
```
|
||||
|
||||
### Implement
|
||||
|
||||
Now, ask GitLab Duo to create implementation files that follow your coding standards.
|
||||
|
||||
- Request detailed comments explaining the changes.
|
||||
- Ask for test coverage of the new implementation.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Implement the refactoring of UserPermissions as proposed:
|
||||
|
||||
1. Create a new file app/models/user_permissions_refactored.rb
|
||||
2. Implement the new UserPermissions class structure
|
||||
3. Include detailed comments explaining the changes
|
||||
4. Update one existing method in app/controllers/users_controller.rb to use the new UserPermissions class
|
||||
5. Write RSpec tests for the new UserPermissions class in spec/models/user_permissions_spec.rb
|
||||
|
||||
Follow our Ruby style guide and best practices for testing.
|
||||
Document any decisions made during implementation.
|
||||
```
|
||||
|
||||
### Evaluate results
|
||||
|
||||
Finally, verify the changes work as expected through testing.
|
||||
|
||||
- If issues arise, provide specific feedback to guide improvement.
|
||||
- Document performance gains or other improvements.
|
||||
|
||||
## Bootstrap a new project
|
||||
|
||||
Use this approach when you start a new application or service from scratch.
|
||||
|
||||
### Initialize the project
|
||||
|
||||
Request a project structure that follow best practices for your tech stack.
|
||||
|
||||
- Ask for recommended dependencies and configurations.
|
||||
- Have GitLab Duo generate initial documentation.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Initialize a new Ruby on Rails project for a team collaboration tool:
|
||||
|
||||
1. Generate a project structure following our best practices
|
||||
2. Include recommended gems for development, testing, and production
|
||||
3. Set up a basic CI/CD configuration
|
||||
4. Create an initial README.md with project overview and setup instructions
|
||||
|
||||
Use our existing Rails projects as reference. Document your decisions and reasoning.
|
||||
```
|
||||
|
||||
### Plan the feature
|
||||
|
||||
Now, ask GitLab Duo to create feature definitions and user stories.
|
||||
|
||||
- Request technical approaches for each core feature.
|
||||
- Have the Agent Platform identify potential challenges.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Create an issue template for the core features of our team collaboration tool:
|
||||
|
||||
1. User authentication and authorization
|
||||
2. Team creation and management
|
||||
3. Task tracking and assignment
|
||||
4. Real-time chat functionality
|
||||
5. File sharing and version control
|
||||
|
||||
For each feature:
|
||||
|
||||
- Provide a brief description
|
||||
- List key user stories
|
||||
- Suggest potential technical approaches
|
||||
- Identify any potential challenges or considerations
|
||||
|
||||
Format this as an epic with individual issues for each core feature.
|
||||
```
|
||||
|
||||
### Set up a foundation
|
||||
|
||||
Now, ask GitLab Duo to design initial data models and schemas.
|
||||
|
||||
- Request setup of testing frameworks and CI/CD configurations.
|
||||
- Ask for implementation of authentication and core APIs.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Design an initial database schema for our team collaboration tool:
|
||||
|
||||
1. Create migrations for core models (User, Team, Task, Message, File)
|
||||
2. Define associations between models
|
||||
3. Include necessary indexes for performance
|
||||
4. Add comments explaining design decisions
|
||||
|
||||
Use our database best practices and naming conventions.
|
||||
Generate the migrations in db/migrate/ directory.
|
||||
Provide a visual representation of the schema (for example, using Mermaid diagram syntax).
|
||||
```
|
||||
|
||||
### Track progress
|
||||
|
||||
Finally, request a summary of implemented features.
|
||||
|
||||
- Ask for a prioritized list of remaining tasks.
|
||||
- Have GitLab Duo identify risks or challenges.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Create a progress report and next steps plan:
|
||||
|
||||
1. Summarize implemented features and their current status
|
||||
2. Identify any deviations from the initial plan and explain reasons
|
||||
3. List remaining tasks from the core features epic
|
||||
4. Suggest a prioritized roadmap for the next development sprint
|
||||
5. Identify any potential risks or challenges for upcoming work
|
||||
|
||||
Format this as an issue with appropriate labels and mentions.
|
||||
Include relevant metrics (like test coverage and security scan results).
|
||||
```
|
||||
|
||||
## Add a new feature
|
||||
|
||||
Use this approach to extend functionality in existing projects.
|
||||
|
||||
### Provision the context
|
||||
|
||||
First, specify the technology stack and relevant files.
|
||||
|
||||
- Clearly define the desired behavior and requirements.
|
||||
- Point to similar implementations that can serve as reference.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
In this project, let's add a new page for users to submit feedback.
|
||||
The current implementation is in Vue and routes are served from a fastify HTTP server,
|
||||
located at path/to/fastify/server.ts. The new route should be `/feedback` and serve
|
||||
a new vue component called `feedback.vue`.
|
||||
|
||||
The feedback vue component should have 3 fields:
|
||||
|
||||
- User email as an input field
|
||||
- A dropdown with 5 values to ask how they heard about us
|
||||
- One textarea for the actual feedback
|
||||
|
||||
The dropdown field is optional. There should also be a submit button.
|
||||
When the button is clicked, show a banner to tell users their feedback was sent.
|
||||
```
|
||||
|
||||
### Request implementation
|
||||
|
||||
Now, ask for all necessary component parts (UI, logic, data models).
|
||||
|
||||
- Request test files for the new functionality.
|
||||
- Specify expected output formats and integration points.
|
||||
|
||||
Sample prompt:
|
||||
|
||||
```plaintext
|
||||
Please implement:
|
||||
|
||||
1. The new Vue component at src/components/feedback.vue
|
||||
2. The route handling in the fastify server at path/to/fastify/server.ts
|
||||
3. Any necessary backend API endpoints to handle the form submission
|
||||
4. Unit tests for the Vue component and API endpoints
|
||||
|
||||
The implementation should follow our existing patterns for
|
||||
form validation and API responses. Reference the contact form at
|
||||
src/components/contact.vue for styling and error handling approaches.
|
||||
```
|
||||
|
||||
### Review and refine
|
||||
|
||||
Finally, verify the implementation meets requirements.
|
||||
|
||||
- Check for adherence to code standards.
|
||||
- Test the feature thoroughly.
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../duo_agent_platform/best_practices.md'
|
||||
redirect_to: '../duo_agent_platform/software_development_flow.md'
|
||||
remove_date: '2025-09-29'
|
||||
---
|
||||
|
||||
<!-- markdownlint-disable -->
|
||||
|
||||
This document was moved to [another location](../duo_agent_platform/best_practices.md).
|
||||
This document was moved to [another location](../duo_agent_platform/software_development_flow.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2025-09-29>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../duo_agent_platform/docker_set_up.md'
|
||||
redirect_to: '../duo_agent_platform/software_development_flow.md'
|
||||
remove_date: '2025-09-29'
|
||||
---
|
||||
|
||||
<!-- markdownlint-disable -->
|
||||
|
||||
This document was moved to [another location](../duo_agent_platform/docker_set_up.md).
|
||||
This document was moved to [another location](../duo_agent_platform/software_development_flow.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2025-09-29>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../duo_agent_platform/risks.md'
|
||||
redirect_to: '../duo_agent_platform/software_development_flow.md'
|
||||
remove_date: '2025-09-29'
|
||||
---
|
||||
|
||||
<!-- markdownlint-disable -->
|
||||
|
||||
This document was moved to [another location](../duo_agent_platform/risks.md).
|
||||
This document was moved to [another location](../duo_agent_platform/software_development_flow.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2025-09-29>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../duo_agent_platform/docker_set_up.md'
|
||||
redirect_to: '../duo_agent_platform/software_development_flow.md'
|
||||
remove_date: '2025-06-05'
|
||||
---
|
||||
|
||||
<!-- markdownlint-disable -->
|
||||
|
||||
This document was moved to [another location](../duo_agent_platform/docker_set_up.md).
|
||||
This document was moved to [another location](../duo_agent_platform/software_development_flow.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2025-06-05>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
---
|
||||
redirect_to: '../duo_agent_platform/use_cases.md'
|
||||
redirect_to: '../duo_agent_platform/software_development_flow.md'
|
||||
remove_date: '2025-06-05'
|
||||
---
|
||||
|
||||
<!-- markdownlint-disable -->
|
||||
|
||||
This document was moved to [another location](../duo_agent_platform/use_cases.md).
|
||||
This document was moved to [another location](../duo_agent_platform/software_development_flow.md).
|
||||
|
||||
<!-- This redirect file can be deleted after <2025-06-05>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ The following features are generally available on GitLab.com, GitLab Self-Manage
|
|||
They require a Premium or Ultimate subscription and one of the available add-ons.
|
||||
|
||||
The GitLab Duo with Amazon Q features are available as a separate add-on, and
|
||||
are available on GitLab.com and GitLab Self-Managed only.
|
||||
are available on GitLab Self-Managed only.
|
||||
|
||||
| Feature | GitLab Duo Core | GitLab Duo Pro | GitLab Duo Enterprise | GitLab Duo with Amazon Q |
|
||||
|---------|----------|---------|----------------|--------------------------|
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ files for you.
|
|||
- Can create and change local files.
|
||||
|
||||
For larger problems, like understanding a codebase or generating an implementation
|
||||
plan, use the [GitLab Duo Agent Platform](../duo_agent_platform/_index.md).
|
||||
plan, use the [software development flow of the GitLab Duo Agent Platform](../duo_agent_platform/_index.md).
|
||||
|
||||
<i class="fa fa-youtube-play youtube" aria-hidden="true"></i>
|
||||
For an overview, see [GitLab Duo Agentic Chat](https://youtu.be/uG9-QLAJrrg?si=c25SR7DoRAep7jvQ).
|
||||
|
|
@ -91,7 +91,7 @@ To use Agentic Chat:
|
|||
1. Under **Gitlab › Duo Agentic Chat: Enabled**, select the
|
||||
**Enable GitLab Duo Agentic Chat** checkbox.
|
||||
1. On the left sidebar, select **GitLab Duo Agentic Chat** ({{< icon name="duo-agentic-chat" >}}).
|
||||
1. Optional. Select **Refresh page**, if prompted.
|
||||
1. Select **Refresh page** if prompted.
|
||||
1. In the message box, enter your question and press **Enter** or select **Send**.
|
||||
<!-- markdownlint-enable MD044 -->
|
||||
Conversations in Agentic Chat do not expire and are stored permanently. You cannot delete these conversations.
|
||||
|
|
@ -134,16 +134,16 @@ Conversations that existed before you created any custom rules do not follow tho
|
|||
|
||||
Agentic Chat extends Chat capabilities with the following features:
|
||||
|
||||
- **Project Search**: Can search through your projects to find relevant
|
||||
- **Project search**: Can search through your projects to find relevant
|
||||
issues, merge requests, and other artifacts using keyword-based search. Agentic
|
||||
Chat does not have semantic search capability.
|
||||
- **File Access**: Can read and list files in your local project without you
|
||||
- **File access**: Can read and list files in your local project without you
|
||||
needing to manually specify file paths.
|
||||
- **Create and Edit Files**: Can create files and edit multiple files in multiple locations.
|
||||
- **Create and edit files**: Can create files and edit multiple files in multiple locations.
|
||||
This affects the local files.
|
||||
- **Resource Retrieval**: Can automatically retrieve detailed information about
|
||||
- **Resource retrieval**: Can automatically retrieve detailed information about
|
||||
issues, merge requests, and pipeline logs of your current project.
|
||||
- **Multi-source Analysis**: Can combine information from multiple sources to
|
||||
- **Multi-source analysis**: Can combine information from multiple sources to
|
||||
provide more complete answers to complex questions. You can use [Model Context Protocol](../gitlab_duo/model_context_protocol/_index.md) to connect Agentic Chat to
|
||||
external data sources and tools.
|
||||
- **Custom rules**: Conversations can follow any customised rules that you specify.
|
||||
|
|
|
|||
|
|
@ -499,11 +499,9 @@ module API
|
|||
permitted_attrs.to_h
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def filter_by_iid(items, iid)
|
||||
items.where(iid: iid)
|
||||
items.iid_in(iid)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def filter_by_title(items, title)
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module Banzai
|
|||
def parent_records(parent, ids)
|
||||
return AlertManagement::Alert.none unless parent.is_a?(Project)
|
||||
|
||||
parent.alert_management_alerts.where(iid: ids.to_a)
|
||||
parent.alert_management_alerts.iid_in(ids.to_a)
|
||||
end
|
||||
|
||||
def url_for_object(alert, project)
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ module Banzai
|
|||
return DesignManagement::Design.none unless parent.design_management_enabled?
|
||||
|
||||
iids = identifiers.map(&:issue_iid).to_set
|
||||
issues = parent.issues.where(iid: iids).includes(:project, :namespace)
|
||||
issues = parent.issues.iid_in(iids).includes(:project, :namespace)
|
||||
id_for_iid = issues.index_by(&:iid).transform_values(&:id)
|
||||
issue_by_id = issues.index_by(&:id)
|
||||
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ module Banzai
|
|||
def parent_records(parent, ids)
|
||||
return Operations::FeatureFlag.none unless parent.is_a?(Project)
|
||||
|
||||
parent.operations_feature_flags.where(iid: ids.to_a)
|
||||
parent.operations_feature_flags.iid_in(ids.to_a)
|
||||
end
|
||||
|
||||
def url_for_object(feature_flag, project)
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ module Banzai
|
|||
# by the WorkItemReferenceFilter
|
||||
return Issue.none if parent.is_a?(Group)
|
||||
|
||||
parent.issues.where(iid: ids.to_a)
|
||||
parent.issues.iid_in(ids.to_a)
|
||||
.includes(:project, :namespace, :work_item_type)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -44,7 +44,7 @@ module Banzai
|
|||
return MergeRequest.none unless parent.is_a?(Project)
|
||||
|
||||
parent.merge_requests
|
||||
.where(iid: ids.to_a)
|
||||
.iid_in(ids.to_a)
|
||||
.includes(target_project: :namespace)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ module Banzai
|
|||
milestone_iids = fitered_ids&.pluck(:milestone_iid)&.compact
|
||||
|
||||
if milestone_iids.present?
|
||||
relation << find_milestones(parent, true, absolute_path: absolute_path).where(iid: milestone_iids)
|
||||
relation << find_milestones(parent, true, absolute_path: absolute_path).iid_in(milestone_iids)
|
||||
end
|
||||
|
||||
milestone_names = fitered_ids&.pluck(:milestone_name)&.compact
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ module Banzai
|
|||
self.object_class = WorkItem
|
||||
|
||||
def parent_records(parent, ids)
|
||||
parent.work_items.where(iid: ids.to_a)
|
||||
parent.work_items.iid_in(ids.to_a)
|
||||
.includes(:project, :namespace, :work_item_type)
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -155,11 +155,9 @@ module Gitlab
|
|||
project.repository.commit(key) if Commit.valid_hash?(key)
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def project_ids_relation
|
||||
Project.where(id: project).select(:id).reorder(nil)
|
||||
Project.id_in(project).select(:id).without_order
|
||||
end
|
||||
# rubocop: enabled CodeReuse/ActiveRecord
|
||||
|
||||
def filter_milestones_by_project(milestones)
|
||||
return Milestone.none unless Ability.allowed?(@current_user, :read_milestone, @project)
|
||||
|
|
|
|||
|
|
@ -259,11 +259,9 @@ module Gitlab
|
|||
milestones.of_projects(authorized_project_ids_relation)
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def project_ids_relation
|
||||
limit_projects.select(:id).reorder(nil)
|
||||
limit_projects.select(:id).without_order
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
def issuable_params
|
||||
{}.tap do |params|
|
||||
|
|
@ -295,11 +293,9 @@ module Gitlab
|
|||
.pluck_primary_key
|
||||
end
|
||||
|
||||
# rubocop: disable CodeReuse/ActiveRecord
|
||||
def limited_count(relation)
|
||||
relation.reorder(nil).limit(count_limit).size
|
||||
relation.without_order.limit(count_limit).size
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -15614,6 +15614,27 @@ msgstr ""
|
|||
msgid "Compliance frameworks"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance report|Actions"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance report|Edit framework"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance report|Framework name"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance report|Policies"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance report|Projects"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance report|Requirements"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance report|Requirements without controls"
|
||||
msgstr ""
|
||||
|
||||
msgid "Compliance requirement control successfully deleted"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -27161,7 +27182,7 @@ msgstr ""
|
|||
msgid "File size exceeds preview limit."
|
||||
msgstr ""
|
||||
|
||||
msgid "File suppressed by a .gitattributes entry or the file's encoding is unsupported."
|
||||
msgid "File suppressed by a .gitattributes entry, the file's encoding is unsupported, or the file size exceeds the limit."
|
||||
msgstr ""
|
||||
|
||||
msgid "File too large. Secure files must be less than %{limit} MB."
|
||||
|
|
@ -31761,6 +31782,9 @@ msgstr ""
|
|||
msgid "Homepage|Start creating merge requests, pushing code, commenting in issues, and doing other work to view a feed of your activity here."
|
||||
msgstr ""
|
||||
|
||||
msgid "Homepage|The number of issues is not available. Please refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
msgid "Homepage|The number of merge requests is not available. Please refresh the page to try again."
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -54141,6 +54165,9 @@ msgstr ""
|
|||
msgid "SAML single sign-on for %{group_name}"
|
||||
msgstr ""
|
||||
|
||||
msgid "SAML|Please, reload the page and sign in again, if necessary. To avoid data loss, if you have unsaved edits, dismiss the modal and copy the unsaved text before refreshing the page."
|
||||
msgstr ""
|
||||
|
||||
msgid "SAML|Sign in to %{groupName}"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -54162,9 +54189,6 @@ msgstr ""
|
|||
msgid "SAML|Your SAML session has expired"
|
||||
msgstr ""
|
||||
|
||||
msgid "SAML|Your SAML session has expired. Please, reload the page and sign in again, if necessary."
|
||||
msgstr ""
|
||||
|
||||
msgid "SAML|Your organization's SSO has been connected to your GitLab account"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -58883,10 +58907,10 @@ msgstr ""
|
|||
msgid "Session ID"
|
||||
msgstr ""
|
||||
|
||||
msgid "SessionExpire|Your session has expired"
|
||||
msgid "SessionExpire|Please, sign in again. To avoid data loss, if you have unsaved edits, dismiss the modal and copy the unsaved text before sign in again."
|
||||
msgstr ""
|
||||
|
||||
msgid "SessionExpire|Your session has expired. Please, sign in again."
|
||||
msgid "SessionExpire|Your session has expired"
|
||||
msgstr ""
|
||||
|
||||
msgid "Session|There was a error loading the user verification challenge. Refresh to try again."
|
||||
|
|
|
|||
|
|
@ -254,7 +254,7 @@
|
|||
"devDependencies": {
|
||||
"@eslint/eslintrc": "^3.2.0",
|
||||
"@eslint/js": "^9.15.0",
|
||||
"@gitlab/eslint-plugin": "21.1.0",
|
||||
"@gitlab/eslint-plugin": "21.2.0",
|
||||
"@gitlab/noop": "^1.0.1",
|
||||
"@gitlab/stylelint-config": "6.2.2",
|
||||
"@graphql-eslint/eslint-plugin": "4.4.0",
|
||||
|
|
|
|||
|
|
@ -128,19 +128,21 @@ class PreMergeChecks
|
|||
end
|
||||
|
||||
def check_pipeline_identifier!(pipeline)
|
||||
if pipeline.name.match?(TIER_IDENTIFIER_REGEX)
|
||||
fail_check! <<~MSG unless pipeline.name.include?(REQUIRED_TIER_IDENTIFIER)
|
||||
if pipeline.name.match?(TIER_IDENTIFIER_REGEX) && !pipeline.name.include?(REQUIRED_TIER_IDENTIFIER) # rubocop:disable Rails/NegateInclude -- Not executed in Rails context
|
||||
fail_check! <<~MSG
|
||||
Expected latest pipeline (#{pipeline.web_url}) to be a tier-3 pipeline! Pipeline name was "#{pipeline.name}".
|
||||
|
||||
Please ensure the MR has all the required approvals, start a new pipeline and put the MR back on the Merge Train.
|
||||
MSG
|
||||
elsif pipeline.name.include?(PREDICTIVE_PIPELINE_IDENTIFIER)
|
||||
fail_check! <<~MSG
|
||||
Expected latest pipeline (#{pipeline.web_url}) not to be a predictive pipeline! Pipeline name was "#{pipeline.name}".
|
||||
|
||||
Please ensure the MR has all the required approvals, start a new pipeline and put the MR back on the Merge Train.
|
||||
MSG
|
||||
end
|
||||
|
||||
return unless pipeline.name.include?(PREDICTIVE_PIPELINE_IDENTIFIER)
|
||||
|
||||
fail_check! <<~MSG
|
||||
Expected latest pipeline (#{pipeline.web_url}) not to be a predictive pipeline! Pipeline name was "#{pipeline.name}".
|
||||
|
||||
Please ensure the MR has all the required approvals, start a new pipeline and put the MR back on the Merge Train.
|
||||
MSG
|
||||
end
|
||||
|
||||
def target_branch_is_stable_branch?
|
||||
|
|
|
|||
|
|
@ -266,7 +266,9 @@ RSpec.describe 'Expand and collapse diffs', :js, feature_category: :source_code_
|
|||
click_link('Expand all')
|
||||
|
||||
# Wait for elements to appear to ensure full page reload
|
||||
expect(page).to have_content("File suppressed by a .gitattributes entry or the file's encoding is unsupported.")
|
||||
expect(page).to have_content(
|
||||
"File suppressed by a .gitattributes entry, the file's encoding is unsupported, " \
|
||||
"or the file size exceeds the limit.")
|
||||
expect(page).to have_content('Source diff could not be displayed: it is too large.')
|
||||
expect(page).to have_content('too_large_image.jpg')
|
||||
find('.note-textarea')
|
||||
|
|
|
|||
|
|
@ -181,7 +181,7 @@ RSpec.describe 'Diff file viewer', :js, :with_clean_rails_cache, feature_categor
|
|||
end
|
||||
|
||||
it 'shows it is not diffable' do
|
||||
expect(page).to have_content("File suppressed by a .gitattributes entry or the file's encoding is unsupported.")
|
||||
expect(page).to have_content("File suppressed by a .gitattributes entry, the file's encoding is unsupported, or the file size exceeds the limit.")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { shallowMount } from '@vue/test-utils';
|
|||
import { nextTick } from 'vue';
|
||||
import SessionExpireModal from '~/authentication/sessions/components/session_expire_modal.vue';
|
||||
import { INTERVAL_SESSION_MODAL } from '~/authentication/sessions/constants';
|
||||
import { visitUrl } from '~/lib/utils/url_utility';
|
||||
import { refreshCurrentPage, visitUrl } from '~/lib/utils/url_utility';
|
||||
|
||||
jest.useFakeTimers();
|
||||
jest.mock('~/lib/utils/url_utility');
|
||||
|
|
@ -94,11 +94,22 @@ describe('SessionExpireModal', () => {
|
|||
expect(findModal().text()).toBe(message);
|
||||
});
|
||||
|
||||
it('triggers a refresh of the current page', () => {
|
||||
it('navigates to the singInUrl', () => {
|
||||
createComponent();
|
||||
expect(findModal().props('actionPrimary')).toMatchObject({ text: 'Sign in' });
|
||||
|
||||
findModal().vm.$emit('primary');
|
||||
expect(visitUrl).toHaveBeenCalledWith(signInUrl);
|
||||
});
|
||||
|
||||
describe('when no signInUrl prop', () => {
|
||||
it('triggers a refresh of the current page', () => {
|
||||
createComponent({ signInUrl: null });
|
||||
expect(findModal().props('actionPrimary')).toMatchObject({ text: 'Reload page' });
|
||||
|
||||
findModal().vm.$emit('primary');
|
||||
expect(refreshCurrentPage).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,13 +14,11 @@ exports[`Confidential merge request project form group component renders empty s
|
|||
No forks are available to you.
|
||||
<br />
|
||||
To protect this issue's confidentiality,
|
||||
<a
|
||||
class="help-link"
|
||||
<gl-link-stub
|
||||
href="https://test.com"
|
||||
target="_blank"
|
||||
>
|
||||
fork this project
|
||||
</a>
|
||||
</gl-link-stub>
|
||||
and set the fork's visibility to private.
|
||||
<gl-link-stub
|
||||
class="gl-bg-transparent gl-inline-block gl-p-0 gl-w-auto"
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ describe('HiddenFilesWarning', () => {
|
|||
|
||||
it('does not render buttons when links are not provided', () => {
|
||||
createComponent({ plainDiffPath: undefined, emailPatchPath: undefined });
|
||||
expect(wrapper.findAllComponents(GlButton).length).toBe(0);
|
||||
expect(wrapper.findAllComponents(GlButton)).toHaveLength(0);
|
||||
});
|
||||
|
||||
it('has a correct visible/total files text', () => {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,10 @@ describe('HomepageApp', () => {
|
|||
const findWorkItemsWidget = () => wrapper.findComponent(WorkItemsWidget);
|
||||
const findMergeRequestsFetchMetadataError = () =>
|
||||
wrapper.findByTestId('merge-requests-fetch-metadata-error');
|
||||
const findWorkItemsFetchMetadataDesktopError = () =>
|
||||
wrapper.findByTestId('work-items-fetch-metadata-desktop-error');
|
||||
const findWorkItemsFetchMetadataMobileError = () =>
|
||||
wrapper.findByTestId('work-items-fetch-metadata-mobile-error');
|
||||
|
||||
function createWrapper() {
|
||||
wrapper = shallowMountExtended(HomepageApp, {
|
||||
|
|
@ -40,7 +44,7 @@ describe('HomepageApp', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('shows an alert of if `MergeRequestsWidget` fails to fetch the metadata', async () => {
|
||||
it('shows an alert if `MergeRequestsWidget` fails to fetch the metadata', async () => {
|
||||
expect(findMergeRequestsFetchMetadataError().exists()).toBe(false);
|
||||
|
||||
findMergeRequestsWidget().vm.$emit('fetch-metadata-error');
|
||||
|
|
@ -61,10 +65,40 @@ describe('HomepageApp', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('passes the correct props to the `WorkItemsWidget` component', () => {
|
||||
expect(findWorkItemsWidget().props()).toEqual({
|
||||
assignedToYouPath: MOCK_ASSIGNED_WORK_ITEMS_PATH,
|
||||
authoredByYouPath: MOCK_AUTHORED_WORK_ITEMS_PATH,
|
||||
describe('WorkItemsWidget', () => {
|
||||
it('passes the correct props to the `WorkItemsWidget` component', () => {
|
||||
expect(findWorkItemsWidget().props()).toEqual({
|
||||
assignedToYouPath: MOCK_ASSIGNED_WORK_ITEMS_PATH,
|
||||
authoredByYouPath: MOCK_AUTHORED_WORK_ITEMS_PATH,
|
||||
});
|
||||
});
|
||||
|
||||
it('shows an alert if `WorkItemsWidget` fails to fetch the metadata', async () => {
|
||||
expect(findWorkItemsFetchMetadataDesktopError().exists()).toBe(false);
|
||||
expect(findWorkItemsFetchMetadataMobileError().exists()).toBe(false);
|
||||
|
||||
findWorkItemsWidget().vm.$emit('fetch-metadata-error');
|
||||
await nextTick();
|
||||
|
||||
expect(findWorkItemsFetchMetadataDesktopError().text()).toBe(
|
||||
'The number of issues is not available. Please refresh the page to try again.',
|
||||
);
|
||||
expect(findWorkItemsFetchMetadataMobileError().text()).toBe(
|
||||
'The number of issues is not available. Please refresh the page to try again.',
|
||||
);
|
||||
});
|
||||
|
||||
it.each([findWorkItemsFetchMetadataDesktopError, findWorkItemsFetchMetadataMobileError])(
|
||||
'hides the alert on dismiss',
|
||||
async (alertFinder) => {
|
||||
findWorkItemsWidget().vm.$emit('fetch-metadata-error');
|
||||
await nextTick();
|
||||
alertFinder().vm.$emit('dismiss');
|
||||
await nextTick();
|
||||
|
||||
expect(findWorkItemsFetchMetadataDesktopError().exists()).toBe(false);
|
||||
expect(findWorkItemsFetchMetadataMobileError().exists()).toBe(false);
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,7 +11,6 @@ import mergeRequestsWidgetMetadataQuery from '~/homepage/graphql/queries/merge_r
|
|||
import VisibilityChangeDetector from '~/homepage/components/visibility_change_detector.vue';
|
||||
import { withItems, withoutItems } from './mocks/merge_requests_widget_metadata_query_mocks';
|
||||
|
||||
jest.mock('~/alert');
|
||||
jest.mock('~/sentry/sentry_browser_wrapper');
|
||||
|
||||
describe('MergeRequestsWidget', () => {
|
||||
|
|
|
|||
|
|
@ -6,10 +6,13 @@ import waitForPromises from 'helpers/wait_for_promises';
|
|||
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||
import { useFakeDate } from 'helpers/fake_date';
|
||||
import WorkItemsWidget from '~/homepage/components/work_items_widget.vue';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import workItemsWidgetMetadataQuery from '~/homepage/graphql/queries/work_items_widget_metadata.query.graphql';
|
||||
import VisibilityChangeDetector from '~/homepage/components/visibility_change_detector.vue';
|
||||
import { withItems, withoutItems } from './mocks/work_items_widget_metadata_query_mocks';
|
||||
|
||||
jest.mock('~/sentry/sentry_browser_wrapper');
|
||||
|
||||
describe('WorkItemsWidget', () => {
|
||||
Vue.use(VueApollo);
|
||||
|
||||
|
|
@ -19,7 +22,7 @@ describe('WorkItemsWidget', () => {
|
|||
|
||||
useFakeDate(MOCK_CURRENT_TIME);
|
||||
|
||||
const workItemsWidgetMetadataQueryHandler = (data) => jest.fn().mockResolvedValue(data);
|
||||
const workItemsWidgetMetadataQuerySuccessHandler = (data) => jest.fn().mockResolvedValue(data);
|
||||
|
||||
let wrapper;
|
||||
|
||||
|
|
@ -30,12 +33,11 @@ describe('WorkItemsWidget', () => {
|
|||
const findAuthoredLastUpdatedAt = () => wrapper.findByTestId('authored-last-updated-at');
|
||||
const findDetector = () => wrapper.findComponent(VisibilityChangeDetector);
|
||||
|
||||
function createWrapper({ workItemsWidgetMetadataQueryMock = withItems } = {}) {
|
||||
function createWrapper({
|
||||
workItemsWidgetMetadataQueryHandler = workItemsWidgetMetadataQuerySuccessHandler(withItems),
|
||||
} = {}) {
|
||||
const mockApollo = createMockApollo([
|
||||
[
|
||||
workItemsWidgetMetadataQuery,
|
||||
workItemsWidgetMetadataQueryHandler(workItemsWidgetMetadataQueryMock),
|
||||
],
|
||||
[workItemsWidgetMetadataQuery, workItemsWidgetMetadataQueryHandler],
|
||||
]);
|
||||
wrapper = shallowMountExtended(WorkItemsWidget, {
|
||||
apolloProvider: mockApollo,
|
||||
|
|
@ -55,25 +57,26 @@ describe('WorkItemsWidget', () => {
|
|||
const link = findGlLinks().at(0);
|
||||
|
||||
expect(link.props('href')).toBe(MOCK_ASSIGNED_TO_YOU_PATH);
|
||||
expect(link.text()).toBe('Assigned to you');
|
||||
expect(link.text()).toMatch('Assigned to you');
|
||||
});
|
||||
|
||||
it('renders the "Authored by you" link', () => {
|
||||
const link = findGlLinks().at(1);
|
||||
|
||||
expect(link.props('href')).toBe(MOCK_AUTHORED_BY_YOU_PATH);
|
||||
expect(link.text()).toBe('Authored by you');
|
||||
expect(link.text()).toMatch('Authored by you');
|
||||
});
|
||||
});
|
||||
|
||||
describe('metadata', () => {
|
||||
it('does not show any metadata until the query has resolved', () => {
|
||||
it("shows the counts' loading state and no timestamp until the query has resolved", () => {
|
||||
createWrapper();
|
||||
|
||||
expect(findAssignedCount().exists()).toBe(false);
|
||||
expect(findAssignedLastUpdatedAt().exists()).toBe(false);
|
||||
expect(findAuthoredCount().exists()).toBe(false);
|
||||
expect(findAuthoredLastUpdatedAt().exists()).toBe(false);
|
||||
|
||||
expect(findAssignedCount().text()).toBe('-');
|
||||
expect(findAuthoredCount().text()).toBe('-');
|
||||
});
|
||||
|
||||
it('shows the metadata once the query has resolved', async () => {
|
||||
|
|
@ -87,7 +90,10 @@ describe('WorkItemsWidget', () => {
|
|||
});
|
||||
|
||||
it('shows partial metadata when the user has no relevant items', async () => {
|
||||
createWrapper({ workItemsWidgetMetadataQueryMock: withoutItems });
|
||||
createWrapper({
|
||||
workItemsWidgetMetadataQueryHandler:
|
||||
workItemsWidgetMetadataQuerySuccessHandler(withoutItems),
|
||||
});
|
||||
await waitForPromises();
|
||||
|
||||
expect(findAssignedLastUpdatedAt().exists()).toBe(false);
|
||||
|
|
@ -96,6 +102,24 @@ describe('WorkItemsWidget', () => {
|
|||
expect(findAssignedCount().text()).toBe('0');
|
||||
expect(findAuthoredCount().text()).toBe('0');
|
||||
});
|
||||
|
||||
it('emits the `fetch-metadata-error` event if the query errors out', async () => {
|
||||
createWrapper({
|
||||
workItemsWidgetMetadataQueryHandler: () => jest.fn().mockRejectedValue(),
|
||||
});
|
||||
|
||||
expect(wrapper.emitted('fetch-metadata-error')).toBeUndefined();
|
||||
|
||||
await waitForPromises();
|
||||
|
||||
expect(wrapper.emitted('fetch-metadata-error')).toHaveLength(1);
|
||||
expect(Sentry.captureException).toHaveBeenCalled();
|
||||
expect(findAssignedLastUpdatedAt().exists()).toBe(false);
|
||||
expect(findAuthoredLastUpdatedAt().exists()).toBe(false);
|
||||
|
||||
expect(findAssignedCount().text()).toBe('-');
|
||||
expect(findAuthoredCount().text()).toBe('-');
|
||||
});
|
||||
});
|
||||
|
||||
describe('refresh functionality', () => {
|
||||
|
|
|
|||
|
|
@ -4738,6 +4738,51 @@ RSpec.describe Ci::Pipeline, :mailer, factory_default: :keep, feature_category:
|
|||
end
|
||||
end
|
||||
|
||||
describe '#downloadable_artifacts_in_self_and_project_descendants' do
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, :unlocked, project: project) }
|
||||
let_it_be(:child_pipeline) { create(:ci_pipeline, :unlocked, child_of: pipeline) }
|
||||
let_it_be(:grandchild_pipeline) { create(:ci_pipeline, :unlocked, child_of: child_pipeline) }
|
||||
|
||||
let_it_be(:parent_build) { create(:ci_build, :test_reports, pipeline: pipeline) }
|
||||
let_it_be(:parent_build_not_downloadable) { create(:ci_build, :trace_artifact, pipeline: pipeline) }
|
||||
let_it_be(:child_build) { create(:ci_build, :coverage_reports, pipeline: child_pipeline) }
|
||||
let_it_be(:child_build_not_downloadable) { create(:ci_build, :trace_artifact, pipeline: child_pipeline) }
|
||||
let_it_be(:grandchild_build) { create(:ci_build, :codequality_reports, pipeline: grandchild_pipeline) }
|
||||
|
||||
let_it_be(:unrelated_pipeline) { create(:ci_pipeline, project: create(:project)) }
|
||||
let_it_be(:unrelated_build) { create(:ci_build, :test_reports, pipeline: unrelated_pipeline) }
|
||||
|
||||
let(:parent_artifact) { parent_build.job_artifacts.first }
|
||||
let(:child_artifact) { child_build.job_artifacts.first }
|
||||
let(:grandchild_artifact) { grandchild_build.job_artifacts.first }
|
||||
|
||||
subject { pipeline.downloadable_artifacts_in_self_and_project_descendants }
|
||||
|
||||
it 'returns downloadable parent artifact as well as downstream artifacts' do
|
||||
expect(subject).to contain_exactly(parent_artifact, child_artifact, grandchild_artifact)
|
||||
end
|
||||
|
||||
context 'when there are expired artifacts' do
|
||||
before do
|
||||
grandchild_artifact.update!(expire_at: 1.week.ago)
|
||||
end
|
||||
|
||||
it 'does not return expired artifacts' do
|
||||
expect(subject).to contain_exactly(parent_artifact, child_artifact)
|
||||
end
|
||||
|
||||
context 'when the expired artifact belongs to a locked pipeline' do
|
||||
before do
|
||||
grandchild_pipeline.update!(locked: described_class.lockeds[:artifacts_locked])
|
||||
end
|
||||
|
||||
it 'returns expired artifact' do
|
||||
expect(subject).to contain_exactly(parent_artifact, child_artifact, grandchild_artifact)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_reports?' do
|
||||
subject { pipeline.has_reports?(Ci::JobArtifact.of_report_type(:test)) }
|
||||
|
||||
|
|
|
|||
|
|
@ -3214,14 +3214,14 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
describe '#has_sast_reports?' do
|
||||
subject { merge_request.has_sast_reports? }
|
||||
|
||||
let(:project) { create(:project, :repository) }
|
||||
let_it_be(:project) { create(:project, :repository) }
|
||||
|
||||
before do
|
||||
stub_licensed_features(sast: true)
|
||||
end
|
||||
|
||||
context 'when head pipeline has sast reports' do
|
||||
let(:merge_request) { create(:merge_request, :with_sast_reports, source_project: project) }
|
||||
let_it_be(:merge_request) { create(:merge_request, :with_sast_reports, source_project: project) }
|
||||
|
||||
it { is_expected.to be_truthy }
|
||||
|
||||
|
|
@ -3235,10 +3235,39 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
end
|
||||
|
||||
context 'when head pipeline does not have sast reports' do
|
||||
let(:merge_request) { create(:merge_request, source_project: project) }
|
||||
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
||||
it { is_expected.to be_falsey }
|
||||
end
|
||||
|
||||
context 'when the child pipeline has sast reports' do
|
||||
let_it_be(:merge_request) { create(:merge_request, source_project: project) }
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, :success, sha: merge_request.diff_head_sha, merge_requests_as_head_pipeline: [merge_request]) }
|
||||
let_it_be(:child_pipeline) { create(:ci_pipeline, :success, child_of: pipeline) }
|
||||
let_it_be(:child_build) { create(:ci_build, :sast_report, pipeline: child_pipeline) }
|
||||
|
||||
context 'when the pipeline is still running' do
|
||||
let_it_be(:pipeline) { create(:ci_pipeline, :running, sha: merge_request.diff_head_sha, merge_requests_as_head_pipeline: [merge_request]) }
|
||||
|
||||
it 'returns false if head pipeline is running' do
|
||||
expect(subject).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
it 'returns true if head pipeline is finished' do
|
||||
expect(subject).to eq(true)
|
||||
end
|
||||
|
||||
context 'when FF show_child_reports_in_mr_page is disabled' do
|
||||
before do
|
||||
stub_feature_flags(show_child_reports_in_mr_page: false)
|
||||
end
|
||||
|
||||
it 'returns false regardless of child pipeline reports' do
|
||||
expect(subject).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#has_secret_detection_reports?' do
|
||||
|
|
@ -6453,9 +6482,9 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
describe '#enabled_reports' do
|
||||
let(:project) { create(:project, :repository) }
|
||||
|
||||
where(:report_type, :with_reports, :feature) do
|
||||
:sast | :with_sast_reports | :sast
|
||||
:secret_detection | :with_secret_detection_reports | :secret_detection
|
||||
where(:report_type, :with_reports, :feature, :artifact_report) do
|
||||
:sast | :with_sast_reports | :sast | :sast_report
|
||||
:secret_detection | :with_secret_detection_reports | :secret_detection | :secret_detection_report
|
||||
end
|
||||
|
||||
with_them do
|
||||
|
|
@ -6475,6 +6504,28 @@ RSpec.describe MergeRequest, factory_default: :keep, feature_category: :code_rev
|
|||
let(:merge_request) { create(:merge_request, source_project: project) }
|
||||
|
||||
it { is_expected.to be_falsy }
|
||||
|
||||
context "but the child pipeline has reports" do
|
||||
let(:pipeline) { create(:ci_pipeline, :success, sha: merge_request.diff_head_sha, merge_requests_as_head_pipeline: [merge_request]) }
|
||||
let(:child_pipeline) { create(:ci_pipeline, :success, child_of: pipeline) }
|
||||
let!(:child_build) { create(:ci_build, artifact_report, pipeline: child_pipeline) }
|
||||
|
||||
it 'returns true for sast reports' do
|
||||
if feature == :sast
|
||||
is_expected.to be_truthy
|
||||
else
|
||||
is_expected.to be_falsy
|
||||
end
|
||||
end
|
||||
|
||||
context 'with FF show_child_reports_in_mr_page disabled' do
|
||||
before do
|
||||
stub_feature_flags(show_child_reports_in_mr_page: false)
|
||||
end
|
||||
|
||||
it { is_expected.to be_falsy }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -257,6 +257,19 @@ RSpec.describe PreMergeChecks, time_travel_to: Time.parse('2024-05-29T10:00:00 U
|
|||
)
|
||||
expect(instance.execute.message).to include("Pipeline name was \"#{latest_mr_pipeline_name}\".")
|
||||
end
|
||||
|
||||
context 'when also matching the required tier identifier' do
|
||||
let(:latest_mr_pipeline_name) { "Ruby 3.2 MR [predictive,tier:3]" }
|
||||
|
||||
it 'returns a failed PreMergeChecksStatus' do
|
||||
expect(instance.execute).to be_a(described_class::PreMergeChecksStatus)
|
||||
expect(instance.execute).not_to be_success
|
||||
expect(instance.execute.message).to include(
|
||||
"Expected latest pipeline (#{latest_mr_pipeline_web_url}) not to be a predictive pipeline!"
|
||||
)
|
||||
expect(instance.execute.message).to include("Pipeline name was \"#{latest_mr_pipeline_name}\".")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'and it is not a tier-3 pipeline' do
|
||||
|
|
|
|||
|
|
@ -50,5 +50,33 @@ RSpec.describe MergeRequests::PipelineEntity do
|
|||
|
||||
expect(entity.as_json).not_to include(:coverage)
|
||||
end
|
||||
|
||||
describe 'artifacts' do
|
||||
let_it_be(:build_with_artifact) { create(:ci_build, :codequality_report, pipeline: pipeline) }
|
||||
let_it_be(:child_pipeline) { create(:ci_pipeline, child_of: pipeline) }
|
||||
let_it_be(:child_build_with_artifact) { create(:ci_build, :test_reports, pipeline: child_pipeline) }
|
||||
|
||||
context 'when show_child_reports_in_mr_page feature is disabled' do
|
||||
before do
|
||||
stub_feature_flags(show_child_reports_in_mr_page: false)
|
||||
end
|
||||
|
||||
it 'gets artifacts from itself' do
|
||||
expect(entity.as_json[:details][:artifacts].pluck(:name)).to match_array(["test:codequality"])
|
||||
end
|
||||
end
|
||||
|
||||
it 'gets artifacts from itself and child pipelines' do
|
||||
expect(entity.as_json[:details][:artifacts].pluck(:name)).to match_array(["test:codequality", "test:junit"])
|
||||
end
|
||||
|
||||
context 'when the user does not have permission to view artifact' do
|
||||
let_it_be(:build_with_private_artifact) { create(:ci_build, :private_artifacts, pipeline: pipeline) }
|
||||
|
||||
it 'does not return unauthorized artifacts' do
|
||||
expect(entity.as_json[:details][:artifacts].pluck(:name)).to match_array(["test:codequality", "test:junit"])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
15
yarn.lock
15
yarn.lock
|
|
@ -1414,10 +1414,10 @@
|
|||
vue-resizable "1.3.4"
|
||||
vue-runtime-helpers "^1.1.2"
|
||||
|
||||
"@gitlab/eslint-plugin@21.1.0":
|
||||
version "21.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-21.1.0.tgz#4cbf2db8b424a93a68dd32be7116e8869e7c55d1"
|
||||
integrity sha512-Va3LlxesMFSnENH6jkxUR6J4TXAdMsn+BmF1UWsr7mvUjkgZSkd4nUlkYxVYYuqRDcpZVcpFHKHa+TsTF4LCQQ==
|
||||
"@gitlab/eslint-plugin@21.2.0":
|
||||
version "21.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/eslint-plugin/-/eslint-plugin-21.2.0.tgz#0b9b4c0c1e012f5262d172aeafdfe72a31c6fadf"
|
||||
integrity sha512-m5mK6mMojp0Jclr0i6ipjv3YM76pJIw+Tsimbn5DNR+lVXSIz4i7gOP3RW4oMgu0ThSVA3klta8TKfdigKoh1g==
|
||||
dependencies:
|
||||
"@typescript-eslint/eslint-plugin" "^7.14.1"
|
||||
confusing-browser-globals "^1.0.11"
|
||||
|
|
@ -1440,7 +1440,7 @@
|
|||
resolved "https://registry.yarnpkg.com/@gitlab/fonts/-/fonts-1.3.0.tgz#df89c1bb6714e4a8a5d3272568aa4de7fb337267"
|
||||
integrity sha512-DoMUIN3DqjEn7wvcxBg/b7Ite5fTdF5EmuOZoBRo2j0UBGweDXmNBi+9HrTZs4cBU660dOxcf1hATFcG3npbPg==
|
||||
|
||||
"@gitlab/noop@^1.0.1", jackspeak@^3.1.2, "jackspeak@npm:@gitlab/noop@1.0.1":
|
||||
"@gitlab/noop@^1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/noop/-/noop-1.0.1.tgz#71a831146ee02732b4a61d2d3c11204564753454"
|
||||
integrity sha512-s++4wjMYeDvBp9IO59DBrWjy8SE/gFkjTDO5ck2W0S6Vv7OlqgErwL7pHngAnrSmTJAzyUG8wHGqo0ViS4jn5Q==
|
||||
|
|
@ -9509,6 +9509,11 @@ istanbul-reports@^3.1.3:
|
|||
html-escaper "^2.0.0"
|
||||
istanbul-lib-report "^3.0.0"
|
||||
|
||||
jackspeak@^3.1.2, "jackspeak@npm:@gitlab/noop@1.0.1":
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@gitlab/noop/-/noop-1.0.1.tgz#71a831146ee02732b4a61d2d3c11204564753454"
|
||||
integrity sha512-s++4wjMYeDvBp9IO59DBrWjy8SE/gFkjTDO5ck2W0S6Vv7OlqgErwL7pHngAnrSmTJAzyUG8wHGqo0ViS4jn5Q==
|
||||
|
||||
jed@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/jed/-/jed-1.1.1.tgz#7a549bbd9ffe1585b0cd0a191e203055bee574b4"
|
||||
|
|
|
|||
Loading…
Reference in New Issue