Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-07-10 21:07:54 +00:00
parent 1db959cb59
commit 22989942a8
76 changed files with 691 additions and 933 deletions

View File

@ -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'

View File

@ -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"

View File

@ -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,

View File

@ -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>

View File

@ -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 />

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -115,7 +115,7 @@ class Namespace
Gitlab::ObjectHierarchy
.new(Namespace.where(id: namespace))
.base_and_ancestors
.reorder(nil)
.without_order
.find_top_level
end

View File

@ -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

View File

@ -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

View File

@ -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))

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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.")

View File

@ -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

View File

@ -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

View File

@ -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(

13
danger/build/Dangerfile Normal file
View File

@ -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

View File

@ -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:

View File

@ -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 >}}

View File

@ -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.

View File

@ -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"
```

View File

@ -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,
```

View File

@ -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.

View File

@ -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).

View File

@ -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.

View File

@ -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.

View File

@ -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. -->

View File

@ -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. -->

View File

@ -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. -->

View File

@ -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. -->

View File

@ -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. -->

View File

@ -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 |
|---------|----------|---------|----------------|--------------------------|

View File

@ -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.

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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."

View File

@ -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",

View File

@ -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?

View File

@ -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')

View File

@ -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

View File

@ -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);
});
});
});
});

View File

@ -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"

View File

@ -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', () => {

View File

@ -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);
},
);
});
});

View File

@ -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', () => {

View File

@ -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', () => {

View File

@ -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)) }

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"