Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
aafd8d0b36
commit
e503135bfe
|
|
@ -265,6 +265,14 @@
|
|||
- "GITALY_SERVER_VERSION"
|
||||
- "lib/gitlab/setup_helper.rb"
|
||||
|
||||
# versions of all these components can affect cloud native deployment
|
||||
.cng-dependency-patterns: &cng-dependency-patterns
|
||||
- GITLAB_WORKHORSE_VERSION
|
||||
- GITLAB_SHELL_VERSION
|
||||
- GITLAB_KAS_VERSION
|
||||
- GITLAB_PAGES_VERSION
|
||||
- GITALY_SERVER_VERSION
|
||||
|
||||
.workhorse-patterns: &workhorse-patterns
|
||||
- ".gitlab/ci/version.yml"
|
||||
- ".gitlab/ci/workhorse.gitlab-ci.yml"
|
||||
|
|
@ -1318,6 +1326,8 @@
|
|||
- <<: *if-merge-request-labels-run-review-app
|
||||
- <<: *if-merge-request
|
||||
changes: *qa-patterns
|
||||
- <<: *if-merge-request
|
||||
changes: *cng-dependency-patterns
|
||||
- <<: *if-merge-request-targeting-stable-branch
|
||||
changes: *setup-test-env-patterns
|
||||
- <<: *if-default-refs
|
||||
|
|
@ -1887,14 +1897,14 @@
|
|||
when: never
|
||||
- <<: *if-security-schedule
|
||||
when: never
|
||||
- <<: *if-merge-request
|
||||
changes: *cng-dependency-patterns
|
||||
- !reference [".qa:rules:e2e-blocking-base-before", rules]
|
||||
- !reference [".prevent-tier-2-and-below", rules]
|
||||
- !reference [".qa:rules:e2e-blocking-base-after", rules]
|
||||
- !reference [".qa:rules:e2e-schedule-nightly", rules]
|
||||
- <<: *if-dot-com-gitlab-org-schedule
|
||||
variables:
|
||||
<<: *qa-e2e-test-schedule-variables
|
||||
QA_RUN_IN_PARALLEL: "true"
|
||||
variables: *qa-e2e-test-schedule-variables
|
||||
|
||||
.qa:rules:test-on-omnibus-nightly:
|
||||
rules:
|
||||
|
|
|
|||
13
CHANGELOG.md
13
CHANGELOG.md
|
|
@ -1083,6 +1083,13 @@ entry.
|
|||
- [Quarantine a flaky test](https://gitlab.com/gitlab-org/gitlab/-/commit/c932e35efdc0e3c6f316a3c2d37045e115ce8cd5) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/176452))
|
||||
- [Finalize migration BackfillRemoteDevelopmentAgentConfigsProjectId](https://gitlab.com/gitlab-org/gitlab/-/commit/da4c63d7aab3685c3fbe9d1e48f68ba2162a0b5e) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/172769))
|
||||
|
||||
## 17.8.3 (2025-02-21)
|
||||
|
||||
### Fixed (2 changes)
|
||||
|
||||
- [Use primary DB when authenticating via job token in jobs API](https://gitlab.com/gitlab-org/gitlab/-/commit/6eee5c6811cac82981252280f1b08316ae8c1fd5) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181872))
|
||||
- [Revert stricter workhorse route regexes](https://gitlab.com/gitlab-org/gitlab/-/commit/aba07e94e0587dd378dccbdf18dfe839f09078bf) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181358))
|
||||
|
||||
## 17.8.2 (2025-02-11)
|
||||
|
||||
### Fixed (3 changes)
|
||||
|
|
@ -1567,6 +1574,12 @@ entry.
|
|||
- [Remove default on `group_saved_replies_flag feature flag](https://gitlab.com/gitlab-org/gitlab/-/commit/75d49fe13646e1e0d3b68233ac4a965c86853917) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175647))
|
||||
- [Remove use_actual_plan_in_license_check flag](https://gitlab.com/gitlab-org/gitlab/-/commit/b8c3fe16aedb69c82ff52d1c695d72e933c4b946) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/175649))
|
||||
|
||||
## 17.7.5 (2025-02-21)
|
||||
|
||||
### Fixed (1 change)
|
||||
|
||||
- [Revert stricter workhorse route regexes](https://gitlab.com/gitlab-org/gitlab/-/commit/9f1a05217022094de570ca4e4afd5b96b9b68c56) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181359))
|
||||
|
||||
## 17.7.4 (2025-02-11)
|
||||
|
||||
### Security (8 changes)
|
||||
|
|
|
|||
|
|
@ -330,10 +330,7 @@ export default {
|
|||
class="rca-bar-component gl-fixed gl-left-0 gl-flex gl-w-full gl-items-center"
|
||||
data-testid="rca-bar-component"
|
||||
>
|
||||
<div
|
||||
class="rca-bar-content gl-flex gl-w-full gl-justify-end"
|
||||
data-testid="rca-bar-content"
|
||||
>
|
||||
<div class="rca-bar-content gl-flex gl-w-full" data-testid="rca-bar-content">
|
||||
<root-cause-analysis-button
|
||||
:job-id="job.id"
|
||||
:job-status-group="job.status.group"
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ function createSuggestionPlugin({
|
|||
return Suggestion({
|
||||
editor,
|
||||
char,
|
||||
allowSpaces: true,
|
||||
pluginKey: new PluginKey(uniqueId('suggestions')),
|
||||
|
||||
command: ({ editor: tiptapEditor, range, props }) => {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
<script>
|
||||
import { GlEmptyState, GlButton } from '@gitlab/ui';
|
||||
import emptySvgUrl from '@gitlab/svgs/dist/illustrations/status/status-new-md.svg';
|
||||
import EMPTY_SVG_PATH from '@gitlab/svgs/dist/illustrations/status/status-new-md.svg';
|
||||
import * as Sentry from '~/sentry/sentry_browser_wrapper';
|
||||
import { s__, __, sprintf } from '~/locale';
|
||||
import { helpPagePath } from '~/helpers/help_page_helper';
|
||||
|
|
@ -87,7 +87,7 @@ export default {
|
|||
CANDIDATES_DOCS_PATH: helpPagePath('user/project/ml/experiment_tracking/mlflow_client.md', {
|
||||
anchor: 'logging-runs-to-a-model',
|
||||
}),
|
||||
EMPTY_SVG_PATH: emptySvgUrl,
|
||||
EMPTY_SVG_PATH,
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import $ from 'jquery';
|
||||
import BranchGraph from '~/network/branch_graph';
|
||||
|
||||
const vph = $(window).height() - 250;
|
||||
const vph = $(window).height() - $('.project-network-header').height();
|
||||
|
||||
export default class Network {
|
||||
constructor(opts) {
|
||||
|
|
@ -11,6 +11,8 @@ export default class Network {
|
|||
this.filter_ref.click(() => this.submit());
|
||||
this.branch_graph = new BranchGraph(this.network_graph, this.opts);
|
||||
this.network_graph.css({ height: `${vph}px` });
|
||||
$('body').css({ 'overflow-y': 'hidden' });
|
||||
$('.content-wrapper').css({ 'padding-bottom': 0 });
|
||||
}
|
||||
|
||||
submit() {
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ import {
|
|||
TODO_ACTION_TYPE_UNMERGEABLE,
|
||||
TODO_ACTION_TYPE_SSH_KEY_EXPIRED,
|
||||
TODO_ACTION_TYPE_SSH_KEY_EXPIRING_SOON,
|
||||
TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED,
|
||||
TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED,
|
||||
} from '../constants';
|
||||
|
||||
export default {
|
||||
|
|
@ -58,7 +60,15 @@ export default {
|
|||
this.todo.action !== TODO_ACTION_TYPE_MERGE_TRAIN_REMOVED &&
|
||||
this.todo.action !== TODO_ACTION_TYPE_UNMERGEABLE &&
|
||||
this.todo.action !== TODO_ACTION_TYPE_SSH_KEY_EXPIRED &&
|
||||
this.todo.action !== TODO_ACTION_TYPE_SSH_KEY_EXPIRING_SOON
|
||||
this.todo.action !== TODO_ACTION_TYPE_SSH_KEY_EXPIRING_SOON &&
|
||||
this.todo.action !== TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED &&
|
||||
this.todo.action !== TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED
|
||||
);
|
||||
},
|
||||
showAvatarOnNote() {
|
||||
return (
|
||||
this.todo.action !== TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED &&
|
||||
this.todo.action !== TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED
|
||||
);
|
||||
},
|
||||
author() {
|
||||
|
|
@ -152,6 +162,18 @@ export default {
|
|||
name = s__('Todos|Your SSH key is expiring soon');
|
||||
}
|
||||
|
||||
if (this.todo.action === TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED) {
|
||||
name = s__(
|
||||
'Todos|You now have access to AI-powered features. Boost your productivity with Code Suggestions and GitLab Duo Chat',
|
||||
);
|
||||
}
|
||||
|
||||
if (this.todo.action === TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED) {
|
||||
name = s__(
|
||||
'Todos|You now have access to AI-powered features. Boost your productivity with Code Suggestions, GitLab Duo Chat, Vulnerability Explanation, and more',
|
||||
);
|
||||
}
|
||||
|
||||
if (!name) {
|
||||
Sentry.captureException(
|
||||
new Error(`Encountered unknown TODO_ACTION_TYPE ${this.todo.action}`),
|
||||
|
|
@ -170,7 +192,7 @@ export default {
|
|||
|
||||
<template>
|
||||
<div class="gl-flex gl-items-start gl-px-2" data-testid="todo-item-container">
|
||||
<div class="gl-mr-3 gl-hidden sm:gl-inline-block">
|
||||
<div v-if="showAvatarOnNote" class="gl-mr-3 gl-hidden sm:gl-inline-block">
|
||||
<gl-avatar-link :href="author.webUrl" aria-hidden="true" tabindex="-1">
|
||||
<gl-avatar :size="24" :src="author.avatarUrl" role="none" />
|
||||
</gl-avatar-link>
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
import { GlIcon } from '@gitlab/ui';
|
||||
import StatusBadge from '~/issuable/components/status_badge.vue';
|
||||
import { STATUS_OPEN, TYPE_ALERT, TYPE_ISSUE, TYPE_MERGE_REQUEST } from '~/issues/constants';
|
||||
import { s__ } from '~/locale';
|
||||
import {
|
||||
TODO_ACTION_TYPE_MEMBER_ACCESS_REQUESTED,
|
||||
TODO_TARGET_TYPE_ALERT,
|
||||
|
|
@ -11,6 +12,8 @@ import {
|
|||
TODO_TARGET_TYPE_MERGE_REQUEST,
|
||||
TODO_TARGET_TYPE_PIPELINE,
|
||||
TODO_TARGET_TYPE_SSH_KEY,
|
||||
TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED,
|
||||
TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED,
|
||||
} from '../constants';
|
||||
|
||||
export default {
|
||||
|
|
@ -40,6 +43,12 @@ export default {
|
|||
isMemberAccessRequestAction() {
|
||||
return this.todo.action === TODO_ACTION_TYPE_MEMBER_ACCESS_REQUESTED;
|
||||
},
|
||||
isDuoActionType() {
|
||||
return (
|
||||
this.todo.action === TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED ||
|
||||
this.todo.action === TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED
|
||||
);
|
||||
},
|
||||
issuableType() {
|
||||
if (this.isMergeRequest) {
|
||||
return TYPE_MERGE_REQUEST;
|
||||
|
|
@ -79,6 +88,8 @@ export default {
|
|||
* Full title line of the todo title + full reference, joined by a middot
|
||||
*/
|
||||
todoTitle() {
|
||||
if (this.isDuoActionType) return s__('Todos|Getting started with GitLab Duo');
|
||||
|
||||
return [this.targetName, this.targetFullReference].filter(Boolean).join(' · ');
|
||||
},
|
||||
/**
|
||||
|
|
@ -130,6 +141,8 @@ export default {
|
|||
return '';
|
||||
},
|
||||
icon() {
|
||||
if (this.isDuoActionType) return 'book';
|
||||
|
||||
switch (this.todo.targetType) {
|
||||
case TODO_TARGET_TYPE_ISSUE:
|
||||
return 'issues';
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ export const TODO_ACTION_TYPE_OKR_CHECKIN_REQUESTED = 'okr_checkin_requested';
|
|||
export const TODO_ACTION_TYPE_ADDED_APPROVER = 'added_approver';
|
||||
export const TODO_ACTION_TYPE_SSH_KEY_EXPIRED = 'ssh_key_expired';
|
||||
export const TODO_ACTION_TYPE_SSH_KEY_EXPIRING_SOON = 'ssh_key_expiring_soon';
|
||||
export const TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED = 'duo_pro_access_granted';
|
||||
export const TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED = 'duo_enterprise_access_granted';
|
||||
|
||||
export const TODO_EMPTY_TITLE_POOL = [
|
||||
s__("Todos|Good job! Looks like you don't have anything left on your To-Do List"),
|
||||
|
|
|
|||
|
|
@ -24,4 +24,3 @@
|
|||
.top-app-header {
|
||||
top: $calc-application-header-height;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -257,8 +257,6 @@
|
|||
bottom: $calc-application-footer-height;
|
||||
z-index: $zindex-dropdown-menu;
|
||||
height: var(--rca-bar-height);
|
||||
padding-left: $super-sidebar-width;
|
||||
padding-right: $right-sidebar-collapsed-width;
|
||||
background: var(--gl-background-color-default);
|
||||
border-top: 1px solid var(--gl-border-color-default);
|
||||
@apply gl-transition-padding;
|
||||
|
|
@ -272,7 +270,12 @@
|
|||
.rca-bar-content {
|
||||
max-width: $limited-layout-width;
|
||||
padding: 0 $container-margin;
|
||||
margin: 0 auto;
|
||||
margin-left: $super-sidebar-width + 0.5rem;
|
||||
margin-right: auto;
|
||||
|
||||
@media (max-width: map-get($grid-breakpoints, sm)-1) {
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
.loader-animation {
|
||||
|
|
|
|||
|
|
@ -17,5 +17,7 @@ module Types
|
|||
value 'added_approver', value: 13, description: 'User was added as an approver.'
|
||||
value 'ssh_key_expired', value: 14, description: 'SSH key of the user has expired.'
|
||||
value 'ssh_key_expiring_soon', value: 15, description: 'SSH key of the user will expire soon.'
|
||||
value 'duo_pro_access_granted', value: 16, description: 'Access to Duo Pro has been granted to the user.'
|
||||
value 'duo_enterprise_access_granted', value: 17, description: 'Access to Duo Enterprise has been granted to the user.'
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -413,7 +413,11 @@ class Commit
|
|||
message_body = ["(cherry picked from commit #{sha})"]
|
||||
|
||||
if merged_merge_request?(user)
|
||||
commits_in_merge_request = merged_merge_request(user).commits
|
||||
commits_in_merge_request = if Feature.enabled?(:optimized_commit_storage, project)
|
||||
merged_merge_request(user).commits(load_from_gitaly: true)
|
||||
else
|
||||
merged_merge_request(user).commits
|
||||
end
|
||||
|
||||
if commits_in_merge_request.present?
|
||||
message_body << ""
|
||||
|
|
|
|||
|
|
@ -345,11 +345,19 @@ class MergeRequestDiff < ApplicationRecord
|
|||
end
|
||||
|
||||
def first_commit
|
||||
commits.last
|
||||
if Feature.enabled?(:optimized_commit_storage, project)
|
||||
commits(load_from_gitaly: true).last
|
||||
else
|
||||
commits.last
|
||||
end
|
||||
end
|
||||
|
||||
def last_commit
|
||||
commits.first
|
||||
if Feature.enabled?(:optimized_commit_storage, project)
|
||||
commits(load_from_gitaly: true).first
|
||||
else
|
||||
commits.first
|
||||
end
|
||||
end
|
||||
|
||||
def base_commit
|
||||
|
|
@ -847,7 +855,7 @@ class MergeRequestDiff < ApplicationRecord
|
|||
end
|
||||
|
||||
def save_commits
|
||||
MergeRequestDiffCommit.create_bulk(self.id, compare.commits.reverse)
|
||||
MergeRequestDiffCommit.create_bulk(self.id, compare.commits.reverse, skip_commit_data: Feature.enabled?(:optimized_commit_storage, project))
|
||||
self.class.uncached { merge_request_diff_commits.reset }
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ class MergeRequestDiffCommit < ApplicationRecord
|
|||
|
||||
# Deprecated; use `bulk_insert!` from `BulkInsertSafe` mixin instead.
|
||||
# cf. https://gitlab.com/gitlab-org/gitlab/issues/207989 for progress
|
||||
def self.create_bulk(merge_request_diff_id, commits)
|
||||
def self.create_bulk(merge_request_diff_id, commits, skip_commit_data: false)
|
||||
commit_hashes, user_tuples = prepare_commits_for_bulk_insert(commits)
|
||||
users = MergeRequest::DiffCommitUser.bulk_find_or_create(user_tuples)
|
||||
|
||||
|
|
@ -59,7 +59,7 @@ class MergeRequestDiffCommit < ApplicationRecord
|
|||
commit_hash = commit_hash
|
||||
.except(:author_name, :author_email, :committer_name, :committer_email, :extended_trailers)
|
||||
|
||||
commit_hash.merge(
|
||||
commit_hash = commit_hash.merge(
|
||||
commit_author_id: author.id,
|
||||
committer_id: committer.id,
|
||||
merge_request_diff_id: merge_request_diff_id,
|
||||
|
|
@ -69,6 +69,12 @@ class MergeRequestDiffCommit < ApplicationRecord
|
|||
committed_date: Gitlab::Database.sanitize_timestamp(commit_hash[:committed_date]),
|
||||
trailers: Gitlab::Json.dump(commit_hash.fetch(:trailers, {}))
|
||||
)
|
||||
|
||||
if skip_commit_data
|
||||
commit_hash.merge(message: '')
|
||||
else
|
||||
commit_hash
|
||||
end
|
||||
end
|
||||
|
||||
ApplicationRecord.legacy_bulk_insert(self.table_name, rows) # rubocop:disable Gitlab/BulkInsert
|
||||
|
|
|
|||
|
|
@ -26,6 +26,8 @@ class Todo < ApplicationRecord
|
|||
ADDED_APPROVER = 13 # This is an EE-only feature,
|
||||
SSH_KEY_EXPIRED = 14
|
||||
SSH_KEY_EXPIRING_SOON = 15
|
||||
DUO_PRO_ACCESS_GRANTED = 16 # This is an EE-only feature,
|
||||
DUO_ENTERPRISE_ACCESS_GRANTED = 17 # This is an EE-only feature,
|
||||
|
||||
ACTION_NAMES = {
|
||||
ASSIGNED => :assigned,
|
||||
|
|
@ -42,11 +44,20 @@ class Todo < ApplicationRecord
|
|||
OKR_CHECKIN_REQUESTED => :okr_checkin_requested,
|
||||
ADDED_APPROVER => :added_approver,
|
||||
SSH_KEY_EXPIRED => :ssh_key_expired,
|
||||
SSH_KEY_EXPIRING_SOON => :ssh_key_expiring_soon
|
||||
SSH_KEY_EXPIRING_SOON => :ssh_key_expiring_soon,
|
||||
DUO_PRO_ACCESS_GRANTED => :duo_pro_access_granted,
|
||||
DUO_ENTERPRISE_ACCESS_GRANTED => :duo_enterprise_access_granted
|
||||
}.freeze
|
||||
|
||||
ACTIONS_MULTIPLE_ALLOWED = [Todo::MENTIONED, Todo::DIRECTLY_ADDRESSED, Todo::MEMBER_ACCESS_REQUESTED].freeze
|
||||
|
||||
PARENTLESS_ACTION_TYPES = [
|
||||
DUO_PRO_ACCESS_GRANTED,
|
||||
DUO_ENTERPRISE_ACCESS_GRANTED,
|
||||
SSH_KEY_EXPIRED,
|
||||
SSH_KEY_EXPIRING_SOON
|
||||
].freeze
|
||||
|
||||
belongs_to :author, class_name: "User"
|
||||
belongs_to :note
|
||||
belongs_to :project
|
||||
|
|
@ -68,8 +79,8 @@ class Todo < ApplicationRecord
|
|||
validates :author, presence: true
|
||||
validates :target_id, presence: true, unless: :for_commit?
|
||||
validates :commit_id, presence: true, if: :for_commit?
|
||||
validates :project, presence: true, unless: -> { group_id || for_ssh_key? }
|
||||
validates :group, presence: true, unless: -> { project_id || for_ssh_key? }
|
||||
validates :project, presence: true, unless: -> { group_id || parentless_type? }
|
||||
validates :group, presence: true, unless: -> { project_id || parentless_type? }
|
||||
|
||||
scope :pending, -> { with_state(:pending) }
|
||||
scope :snoozed, -> { where(arel_table[:snoozed_until].gt(Time.current)) }
|
||||
|
|
@ -353,6 +364,14 @@ class Todo < ApplicationRecord
|
|||
target_type == Key.name
|
||||
end
|
||||
|
||||
def for_duo_access_granted?
|
||||
action == DUO_PRO_ACCESS_GRANTED || action == DUO_ENTERPRISE_ACCESS_GRANTED
|
||||
end
|
||||
|
||||
def parentless_type?
|
||||
PARENTLESS_ACTION_TYPES.include?(action)
|
||||
end
|
||||
|
||||
# override to return commits, which are not active record
|
||||
def target
|
||||
if for_commit?
|
||||
|
|
@ -379,6 +398,8 @@ class Todo < ApplicationRecord
|
|||
def target_url
|
||||
return if target.nil?
|
||||
|
||||
return build_duo_getting_started_url if for_duo_access_granted?
|
||||
|
||||
case target
|
||||
when WorkItem
|
||||
build_work_item_target_url
|
||||
|
|
@ -413,6 +434,10 @@ class Todo < ApplicationRecord
|
|||
|
||||
private
|
||||
|
||||
def build_duo_getting_started_url
|
||||
::Gitlab::Routing.url_helpers.help_page_path('user/get_started/getting_started_gitlab_duo.md')
|
||||
end
|
||||
|
||||
def build_work_item_target_url
|
||||
::Gitlab::UrlBuilder.build(
|
||||
target,
|
||||
|
|
|
|||
|
|
@ -387,20 +387,20 @@ class TodoService
|
|||
end
|
||||
|
||||
def create_assignment_todo(target, author, old_assignees = [])
|
||||
if target.assignees.any?
|
||||
project = target.project
|
||||
assignees = target.assignees - old_assignees
|
||||
attributes = attributes_for_todo(project, target, author, Todo::ASSIGNED)
|
||||
return unless target.assignees.any?
|
||||
|
||||
create_todos(assignees, attributes, target_namespace(target), project)
|
||||
end
|
||||
project = target.project
|
||||
assignees = target.assignees - old_assignees
|
||||
attributes = attributes_for_todo(project, target, author, ::Todo::ASSIGNED)
|
||||
|
||||
create_todos(assignees, attributes, target_namespace(target), project)
|
||||
end
|
||||
|
||||
def create_reviewer_todo(target, author, old_reviewers = [])
|
||||
if target.reviewers.any?
|
||||
reviewers = target.reviewers - old_reviewers
|
||||
create_request_review_todo(target, author, reviewers)
|
||||
end
|
||||
return unless target.reviewers.any?
|
||||
|
||||
reviewers = target.reviewers - old_reviewers
|
||||
create_request_review_todo(target, author, reviewers)
|
||||
end
|
||||
|
||||
def create_mention_todos(parent, target, author, note = nil, skip_users = [])
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
.row-content-block.second-block.content-component-block.gl-px-0.gl-py-3
|
||||
.gl-w-max.gl-max-w-full
|
||||
#js-graph-ref-switcher{ data: { project_id: @project.id, ref: @ref, network_path: project_network_path(@project, @ref, ref_type: @ref_type) } }
|
||||
|
||||
.oneline
|
||||
= _("You can move around the graph by using the arrow keys.")
|
||||
|
|
@ -1,18 +1,28 @@
|
|||
- breadcrumb_title _("Graph")
|
||||
- page_title _("Graph"), @ref
|
||||
- title = _("Repository graph")
|
||||
- breadcrumb_title title
|
||||
- page_title title, @ref
|
||||
- network_path = project_network_path(@project, @ref, ref_type: @ref_type)
|
||||
= render "head"
|
||||
.gl-mt-5
|
||||
.project-network.gl-border-1.gl-border-solid.gl-border-gray-300
|
||||
.controls.gl-bg-strong.gl-p-2.gl-text-base.gl-text-subtle.gl-border-b-1.gl-border-b-solid.gl-border-b-gray-300
|
||||
= form_tag network_path, method: :get, class: 'form-inline network-form' do |f|
|
||||
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: _("Git revision"), class: 'search-input form-control gl-form-input input-mx-250 search-sha gl-mr-2'
|
||||
= render Pajamas::ButtonComponent.new(type: :submit, variant: :confirm, icon: 'search', button_options: {'aria-label': _("Search"), 'title': _("Search")})
|
||||
.form-group{ class: 'gl-ml-5 !gl-mb-3' }
|
||||
|
||||
.project-network-header.gl-flex.gl-flex-col.gl-overflow-hidden
|
||||
= render ::Layouts::PageHeadingComponent.new(title) do |c|
|
||||
- c.with_description do
|
||||
= _("You can move around the graph by using the arrow keys.")
|
||||
|
||||
.project-network
|
||||
.gl-flex.gl-flex-wrap.gl-items-start.gl-gap-3.gl-p-5.gl-bg-subtle.gl-border-t.gl-border-b
|
||||
.gl-min-w-26
|
||||
#js-graph-ref-switcher{ data: { project_id: @project.id, ref: @ref, network_path: project_network_path(@project, @ref, ref_type: @ref_type) } }
|
||||
|
||||
= form_tag network_path, method: :get, class: 'gl-grow gl-flex gl-flex-wrap gl-gap-3 gl-items-center network-form' do |f|
|
||||
.gl-flex
|
||||
= text_field_tag :extended_sha1, @options[:extended_sha1], placeholder: _("Git revision"), class: 'search-input form-control gl-form-input search-sha !gl-rounded-r-none'
|
||||
= render Pajamas::ButtonComponent.new(type: :submit, icon: 'search', button_options: { class: '!gl-rounded-l-none -gl-ml-[1px]', 'aria-label': _("Search"), 'title': _("Search") })
|
||||
|
||||
.gl-mt-3
|
||||
= render Pajamas::CheckboxTagComponent.new(name: :filter_ref, checked: @options[:filter_ref]) do |c|
|
||||
- c.with_label do
|
||||
= _("Begin with the selected commit")
|
||||
|
||||
- if @commit
|
||||
.network-graph.gl-bg-white.gl-overflow-scroll.gl-overflow-x-hidden{ data: { url: @url, commit_url: @commit_url, ref: @ref, commit_id: @commit.id } }
|
||||
= gl_loading_icon(size: 'md', css_class: 'gl-mt-3')
|
||||
.network-graph.gl-overflow-scroll.gl-overflow-x-hidden{ data: { url: @url, commit_url: @commit_url, ref: @ref, commit_id: @commit.id } }
|
||||
= gl_loading_icon(size: 'md', css_class: 'gl-mt-5')
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: duo_seat_assignment_todo
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/507338
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/177019
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/514937
|
||||
milestone: '17.10'
|
||||
group: group::acquisition
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
name: optimized_commit_storage
|
||||
feature_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/517497
|
||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/181958
|
||||
rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/520259
|
||||
milestone: '17.10'
|
||||
group: group::source code
|
||||
type: gitlab_com_derisk
|
||||
default_enabled: false
|
||||
|
|
@ -6,7 +6,7 @@ class CreateAiDuoChatEvents < Gitlab::Database::Migration[2.2]
|
|||
|
||||
def up
|
||||
# rubocop:disable Migration/Datetime -- "timestamp" is a column name
|
||||
create_table :ai_duo_chat_events, # rubocop:disable Migration/EnsureFactoryForTable -- code_suggestion_event
|
||||
create_table :ai_duo_chat_events,
|
||||
options: 'PARTITION BY RANGE (timestamp)',
|
||||
primary_key: [:id, :timestamp] do |t|
|
||||
t.bigserial :id, null: false
|
||||
|
|
|
|||
|
|
@ -43326,6 +43326,8 @@ Values for sorting timelogs.
|
|||
| <a id="todoactionenumassigned"></a>`assigned` | User was assigned. |
|
||||
| <a id="todoactionenumbuild_failed"></a>`build_failed` | Build triggered by the user failed. |
|
||||
| <a id="todoactionenumdirectly_addressed"></a>`directly_addressed` | User was directly addressed. |
|
||||
| <a id="todoactionenumduo_enterprise_access_granted"></a>`duo_enterprise_access_granted` | Access to Duo Enterprise has been granted to the user. |
|
||||
| <a id="todoactionenumduo_pro_access_granted"></a>`duo_pro_access_granted` | Access to Duo Pro has been granted to the user. |
|
||||
| <a id="todoactionenummarked"></a>`marked` | User added a to-do item. |
|
||||
| <a id="todoactionenummember_access_requested"></a>`member_access_requested` | Group or project access requested from the user. |
|
||||
| <a id="todoactionenummentioned"></a>`mentioned` | User was mentioned. |
|
||||
|
|
|
|||
|
|
@ -103,15 +103,6 @@ updating the active and current stable releases only, with no backports. Factors
|
|||
the very low likelihood of exploitation, the low impact of the vulnerability, the complexity of security fixes and
|
||||
the eventual risk to stability. We always address high and critical security issues with a patch release.
|
||||
|
||||
In cases where a strategic user has a requirement to test a feature before it is
|
||||
officially released, we can offer to create a Release Candidate (RC) version that
|
||||
includes the specific feature. This should be needed only in extreme cases and can be requested for
|
||||
consideration by raising an issue in the [release/tasks](https://gitlab.com/gitlab-org/release/tasks/-/issues/new?issuable_template=Backporting-request) issue tracker.
|
||||
It is important to note that the Release Candidate contains other features and changes as
|
||||
it is not possible to easily isolate a specific feature (similar reasons as noted above). The
|
||||
Release Candidate is no different than any code that is deployed to GitLab.com or is publicly
|
||||
accessible.
|
||||
|
||||
### Backporting to older releases
|
||||
|
||||
Backporting to more than one stable release is usually reserved for [security fixes](#patch-releases).
|
||||
|
|
|
|||
|
|
@ -18,12 +18,6 @@ title: GitLab-managed Kubernetes resources
|
|||
|
||||
{{< /history >}}
|
||||
|
||||
{{< alert type="flag" >}}
|
||||
|
||||
The availability of this feature is controlled by a feature flag. For more information, see the history.
|
||||
|
||||
{{< /alert >}}
|
||||
|
||||
Use GitLab-managed Kubernetes resources to provision Kubernetes resources with environment templates. An environment template can:
|
||||
|
||||
- Create namespaces and service accounts automatically for new environments
|
||||
|
|
|
|||
|
|
@ -317,7 +317,7 @@ Here are possible causes and solutions:
|
|||
|
||||
| Cause | Solution |
|
||||
| ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
||||
| When a user account with the email address already exists in GitLab, but the user does not have the SAML identity tied to their account. | The user needs to [link their account](_index.md#user-access-and-management). |
|
||||
| If a GitLab user account exists with the same email address, but the account is not associated with a SAML identity. | On GitLab.com, the user needs to [link their account](_index.md#user-access-and-management). On GitLab Self-Managed, administrators can configure the instance to [automatically link the SAML identity with the GitLab user account](../../../integration/saml.md#link-saml-identity-for-an-existing-user) when they first sign in. |
|
||||
|
||||
User accounts are created in one of the following ways:
|
||||
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ module Gitlab
|
|||
ALLOWED_ROUTER_RULE_ACTIONS = %w[classify proxy].freeze
|
||||
# We do not expect a type for `proxy` rules
|
||||
ROUTER_RULE_ACTIONS_WITHOUT_TYPE = %w[proxy].freeze
|
||||
ALLOWED_ROUTER_RULE_TYPES = %w[FIRST_CELL SESSION_PREFIX].freeze
|
||||
ALLOWED_ROUTER_RULE_TYPES = %w[FIRST_CELL SESSION_PREFIX CELL_ID].freeze
|
||||
|
||||
private
|
||||
|
||||
|
|
|
|||
|
|
@ -60260,6 +60260,9 @@ msgstr ""
|
|||
msgid "Todos|For one hour"
|
||||
msgstr ""
|
||||
|
||||
msgid "Todos|Getting started with GitLab Duo"
|
||||
msgstr ""
|
||||
|
||||
msgid "Todos|Give yourself a pat on the back!"
|
||||
msgstr ""
|
||||
|
||||
|
|
@ -60471,6 +60474,12 @@ msgstr ""
|
|||
msgid "Todos|You"
|
||||
msgstr ""
|
||||
|
||||
msgid "Todos|You now have access to AI-powered features. Boost your productivity with Code Suggestions and GitLab Duo Chat"
|
||||
msgstr ""
|
||||
|
||||
msgid "Todos|You now have access to AI-powered features. Boost your productivity with Code Suggestions, GitLab Duo Chat, Vulnerability Explanation, and more"
|
||||
msgstr ""
|
||||
|
||||
msgid "Todos|Your SSH key has expired"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
|||
|
|
@ -86,7 +86,7 @@ RSpec.describe 'Project Network Graph', :js, feature_category: :groups_and_proje
|
|||
it 'filters select tag' do
|
||||
switch_ref_to('v1.0.0')
|
||||
|
||||
expect(page).to have_css 'title', text: 'Graph · v1.0.0', visible: false
|
||||
expect(page).to have_css 'title', text: 'Repository graph · v1.0.0', visible: false
|
||||
page.within '.network-graph' do
|
||||
expect(page).to have_content 'Change some files'
|
||||
end
|
||||
|
|
|
|||
|
|
@ -17,6 +17,8 @@ import {
|
|||
TODO_ACTION_TYPE_UNMERGEABLE,
|
||||
TODO_ACTION_TYPE_SSH_KEY_EXPIRED,
|
||||
TODO_ACTION_TYPE_SSH_KEY_EXPIRING_SOON,
|
||||
TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED,
|
||||
TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED,
|
||||
} from '~/todos/constants';
|
||||
import { SAML_HIDDEN_TODO } from '../mock_data';
|
||||
|
||||
|
|
@ -61,22 +63,24 @@ describe('TodoItemBody', () => {
|
|||
|
||||
describe('correct text for actionName', () => {
|
||||
it.each`
|
||||
actionName | text | showsAuthor
|
||||
${TODO_ACTION_TYPE_ADDED_APPROVER} | ${'set you as an approver.'} | ${true}
|
||||
${TODO_ACTION_TYPE_APPROVAL_REQUIRED} | ${'set you as an approver.'} | ${true}
|
||||
${TODO_ACTION_TYPE_ASSIGNED} | ${'assigned you.'} | ${true}
|
||||
${TODO_ACTION_TYPE_BUILD_FAILED} | ${'The pipeline failed.'} | ${false}
|
||||
${TODO_ACTION_TYPE_DIRECTLY_ADDRESSED} | ${'mentioned you.'} | ${true}
|
||||
${TODO_ACTION_TYPE_MARKED} | ${'added a to-do item'} | ${true}
|
||||
${TODO_ACTION_TYPE_MEMBER_ACCESS_REQUESTED} | ${'has requested access to group Foo'} | ${true}
|
||||
${TODO_ACTION_TYPE_MENTIONED} | ${'mentioned you.'} | ${true}
|
||||
${TODO_ACTION_TYPE_MERGE_TRAIN_REMOVED} | ${'Removed from Merge Train.'} | ${false}
|
||||
${TODO_ACTION_TYPE_OKR_CHECKIN_REQUESTED} | ${'requested an OKR update for Foo'} | ${true}
|
||||
${TODO_ACTION_TYPE_REVIEW_REQUESTED} | ${'requested a review.'} | ${true}
|
||||
${TODO_ACTION_TYPE_REVIEW_SUBMITTED} | ${'reviewed your merge request.'} | ${true}
|
||||
${TODO_ACTION_TYPE_UNMERGEABLE} | ${'Could not merge.'} | ${false}
|
||||
${TODO_ACTION_TYPE_SSH_KEY_EXPIRED} | ${'Your SSH key has expired.'} | ${false}
|
||||
${TODO_ACTION_TYPE_SSH_KEY_EXPIRING_SOON} | ${'Your SSH key is expiring soon.'} | ${false}
|
||||
actionName | text | showsAuthor
|
||||
${TODO_ACTION_TYPE_ADDED_APPROVER} | ${'set you as an approver.'} | ${true}
|
||||
${TODO_ACTION_TYPE_APPROVAL_REQUIRED} | ${'set you as an approver.'} | ${true}
|
||||
${TODO_ACTION_TYPE_ASSIGNED} | ${'assigned you.'} | ${true}
|
||||
${TODO_ACTION_TYPE_BUILD_FAILED} | ${'The pipeline failed.'} | ${false}
|
||||
${TODO_ACTION_TYPE_DIRECTLY_ADDRESSED} | ${'mentioned you.'} | ${true}
|
||||
${TODO_ACTION_TYPE_MARKED} | ${'added a to-do item'} | ${true}
|
||||
${TODO_ACTION_TYPE_MEMBER_ACCESS_REQUESTED} | ${'has requested access to group Foo'} | ${true}
|
||||
${TODO_ACTION_TYPE_MENTIONED} | ${'mentioned you.'} | ${true}
|
||||
${TODO_ACTION_TYPE_MERGE_TRAIN_REMOVED} | ${'Removed from Merge Train.'} | ${false}
|
||||
${TODO_ACTION_TYPE_OKR_CHECKIN_REQUESTED} | ${'requested an OKR update for Foo'} | ${true}
|
||||
${TODO_ACTION_TYPE_REVIEW_REQUESTED} | ${'requested a review.'} | ${true}
|
||||
${TODO_ACTION_TYPE_REVIEW_SUBMITTED} | ${'reviewed your merge request.'} | ${true}
|
||||
${TODO_ACTION_TYPE_UNMERGEABLE} | ${'Could not merge.'} | ${false}
|
||||
${TODO_ACTION_TYPE_SSH_KEY_EXPIRED} | ${'Your SSH key has expired.'} | ${false}
|
||||
${TODO_ACTION_TYPE_SSH_KEY_EXPIRING_SOON} | ${'Your SSH key is expiring soon.'} | ${false}
|
||||
${TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED} | ${'You now have access to AI-powered features. Boost your productivity with Code Suggestions and GitLab Duo Chat'} | ${false}
|
||||
${TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED} | ${'You now have access to AI-powered features. Boost your productivity with Code Suggestions, GitLab Duo Chat, Vulnerability Explanation, and more.'} | ${false}
|
||||
`('renders "$text" for the "$actionName" action', ({ actionName, text, showsAuthor }) => {
|
||||
createComponent({ action: actionName, memberAccessType: 'group' });
|
||||
expect(wrapper.text()).toContain(text);
|
||||
|
|
@ -98,6 +102,14 @@ describe('TodoItemBody', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it.each([
|
||||
TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED,
|
||||
TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED,
|
||||
])('when todo action is `%s`, avatar is not shown', (action) => {
|
||||
createComponent({ action });
|
||||
expect(wrapper.findComponent(GlAvatarLink).exists()).toBe(false);
|
||||
});
|
||||
|
||||
describe('when todo has a note', () => {
|
||||
it('renders note text', () => {
|
||||
createComponent({ note: { bodyFirstLineHtml: '<p>This is a note</p>' } });
|
||||
|
|
|
|||
|
|
@ -10,6 +10,8 @@ import {
|
|||
TODO_TARGET_TYPE_MERGE_REQUEST,
|
||||
TODO_TARGET_TYPE_PIPELINE,
|
||||
TODO_TARGET_TYPE_SSH_KEY,
|
||||
TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED,
|
||||
TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED,
|
||||
} from '~/todos/constants';
|
||||
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
|
||||
import { DESIGN_TODO, MR_BUILD_FAILED_TODO } from '../mock_data';
|
||||
|
|
@ -56,6 +58,11 @@ describe('TodoItemTitle', () => {
|
|||
'Important issue › Screenshot_2024-11-22_at_16.11.25.png · Flightjs / Flight #35',
|
||||
DESIGN_TODO,
|
||||
],
|
||||
[
|
||||
'to-do for duo pro access granted',
|
||||
'Getting started with GitLab Duo',
|
||||
{ ...mockToDo, action: TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED },
|
||||
],
|
||||
])(`renders %s as %s`, (_a, b, c) => {
|
||||
createComponent(c);
|
||||
expect(wrapper.findByTestId('todo-title').text()).toBe(b);
|
||||
|
|
@ -85,4 +92,21 @@ describe('TodoItemTitle', () => {
|
|||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('correct icon for action', () => {
|
||||
it.each`
|
||||
action | icon | showsIcon
|
||||
${TODO_ACTION_TYPE_DUO_PRO_ACCESS_GRANTED} | ${'book'} | ${true}
|
||||
${TODO_ACTION_TYPE_DUO_ENTERPRISE_ACCESS_GRANTED} | ${'book'} | ${true}
|
||||
`('renders "$icon" for the "$action" action', ({ action, icon, showsIcon }) => {
|
||||
createComponent({ ...mockToDo, action });
|
||||
|
||||
const glIcon = wrapper.findComponent(GlIcon);
|
||||
expect(glIcon.exists()).toBe(showsIcon);
|
||||
|
||||
if (showsIcon) {
|
||||
expect(glIcon.props('name')).toBe(icon);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -557,6 +557,14 @@ EOS
|
|||
let(:commit) { project.commit('video') }
|
||||
|
||||
it { expect(commit.cherry_pick_message(user)).to include("\n\n(cherry picked from commit 88790590ed1337ab189bccaa355f068481c90bec)") }
|
||||
|
||||
context 'when "optimized_commit_storage" feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(optimized_commit_storage: false)
|
||||
end
|
||||
|
||||
it { expect(commit.cherry_pick_message(user)).to include("\n\n(cherry picked from commit 88790590ed1337ab189bccaa355f068481c90bec)") }
|
||||
end
|
||||
end
|
||||
|
||||
context 'of a merge commit' do
|
||||
|
|
|
|||
|
|
@ -26,14 +26,17 @@ RSpec.describe MergeRequestDiffCommit, feature_category: :code_review_workflow d
|
|||
|
||||
it 'returns the same results as Commit#to_hash, except for parent_ids' do
|
||||
commit_from_repo = project.repository.commit(subject.sha)
|
||||
commit_from_repo_hash = commit_from_repo.to_hash.merge(parent_ids: [])
|
||||
commit_from_repo_hash = commit_from_repo.to_hash.merge(parent_ids: [], message: '')
|
||||
|
||||
expect(subject.to_hash).to eq(commit_from_repo_hash)
|
||||
end
|
||||
end
|
||||
|
||||
describe '.create_bulk' do
|
||||
subject { described_class.create_bulk(merge_request_diff_id, commits, skip_commit_data: skip_commit_data) }
|
||||
|
||||
let(:merge_request_diff_id) { merge_request.merge_request_diff.id }
|
||||
let(:skip_commit_data) { false }
|
||||
let(:commits) do
|
||||
[
|
||||
project.commit('5937ac0a7beb003549fc5fd26fc247adbce4a52e'),
|
||||
|
|
@ -68,8 +71,6 @@ RSpec.describe MergeRequestDiffCommit, feature_category: :code_review_workflow d
|
|||
]
|
||||
end
|
||||
|
||||
subject { described_class.create_bulk(merge_request_diff_id, commits) }
|
||||
|
||||
it 'inserts the commits into the database en masse' do
|
||||
expect(ApplicationRecord).to receive(:legacy_bulk_insert)
|
||||
.with(described_class.table_name, rows)
|
||||
|
|
@ -92,6 +93,19 @@ RSpec.describe MergeRequestDiffCommit, feature_category: :code_review_workflow d
|
|||
expect(commit_row.committer).to eq(commit_user_row)
|
||||
end
|
||||
|
||||
context 'when "skip_commit_data: true"' do
|
||||
let(:skip_commit_data) { true }
|
||||
|
||||
it 'inserts the commits into the database en masse' do
|
||||
rows_with_empty_messages = rows.map { |h| h.merge(message: '') }
|
||||
|
||||
expect(ApplicationRecord).to receive(:legacy_bulk_insert)
|
||||
.with(described_class.table_name, rows_with_empty_messages)
|
||||
|
||||
subject
|
||||
end
|
||||
end
|
||||
|
||||
context 'with dates larger than the DB limit' do
|
||||
let(:commits) do
|
||||
# This commit's date is "Sun Aug 17 07:12:55 292278994 +0000"
|
||||
|
|
|
|||
|
|
@ -57,6 +57,20 @@ RSpec.describe MergeRequestDiff, feature_category: :code_review_workflow do
|
|||
it { expect(subject.start_commit_sha).to eq('0b4bc9a49b562e85de7cc9e834518ea6828729b9') }
|
||||
it { expect(subject.patch_id_sha).to eq('f14ae956369247901117b8b7d237c9dc605898c5') }
|
||||
|
||||
it 'creates commits with empty messages' do
|
||||
expect(subject.commits).to all(have_attributes(message: ''))
|
||||
end
|
||||
|
||||
context 'when feature flag "optimized_commit_storage" is disabled' do
|
||||
before do
|
||||
stub_feature_flags(optimized_commit_storage: false)
|
||||
end
|
||||
|
||||
it 'creates commits with messages' do
|
||||
expect(subject.commits).to all(have_attributes(message: be_present))
|
||||
end
|
||||
end
|
||||
|
||||
it 'calls GraphqlTriggers.merge_request_diff_generated' do
|
||||
merge_request = create(:merge_request, :skip_diff_creation)
|
||||
|
||||
|
|
@ -1244,12 +1258,32 @@ RSpec.describe MergeRequestDiff, feature_category: :code_review_workflow do
|
|||
it 'returns first commit' do
|
||||
expect(diff_with_commits.first_commit.sha).to eq(diff_with_commits.merge_request_diff_commits.last.sha)
|
||||
end
|
||||
|
||||
context 'when "optimized_commit_storage" feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(optimized_commit_storage: false)
|
||||
end
|
||||
|
||||
it 'returns first commit' do
|
||||
expect(diff_with_commits.first_commit.sha).to eq(diff_with_commits.merge_request_diff_commits.last.sha)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#last_commit' do
|
||||
it 'returns last commit' do
|
||||
expect(diff_with_commits.last_commit.sha).to eq(diff_with_commits.merge_request_diff_commits.first.sha)
|
||||
end
|
||||
|
||||
context 'when "optimized_commit_storage" feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(optimized_commit_storage: false)
|
||||
end
|
||||
|
||||
it 'returns last commit' do
|
||||
expect(diff_with_commits.last_commit.sha).to eq(diff_with_commits.merge_request_diff_commits.first.sha)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#includes_any_commits?' do
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ require 'spec_helper'
|
|||
|
||||
RSpec.describe Todo, feature_category: :notifications do
|
||||
let(:issue) { create(:issue) }
|
||||
let_it_be(:user) { create(:user) }
|
||||
|
||||
describe 'relationships' do
|
||||
it { is_expected.to belong_to(:author).class_name("User") }
|
||||
|
|
@ -25,6 +26,41 @@ RSpec.describe Todo, feature_category: :notifications do
|
|||
it { is_expected.to validate_presence_of(:user) }
|
||||
it { is_expected.to validate_presence_of(:author) }
|
||||
|
||||
context "for project and/or group" do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let_it_be(:group) { create(:group) }
|
||||
let_it_be(:project) { create(:project) }
|
||||
|
||||
subject { described_class.new(project: project, group: group) }
|
||||
|
||||
where(:project?, :group?) do
|
||||
true | true
|
||||
true | false
|
||||
false | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
it "are valid" do
|
||||
subject.project = project? ? project : nil
|
||||
subject.group = group? ? group : nil
|
||||
subject.validate
|
||||
|
||||
expect(subject.errors[:project]).to be_empty
|
||||
expect(subject.errors[:group]).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
it "are both are missing" do
|
||||
subject.project = nil
|
||||
subject.group = nil
|
||||
subject.validate
|
||||
|
||||
expect(subject.errors.messages[:project].first).to eq("can't be blank")
|
||||
expect(subject.errors.messages[:group].first).to eq("can't be blank")
|
||||
end
|
||||
end
|
||||
|
||||
context 'for commits' do
|
||||
subject { described_class.new(target_type: 'Commit') }
|
||||
|
||||
|
|
@ -38,6 +74,24 @@ RSpec.describe Todo, feature_category: :notifications do
|
|||
it { is_expected.to validate_presence_of(:target_id) }
|
||||
it { is_expected.not_to validate_presence_of(:commit_id) }
|
||||
end
|
||||
|
||||
context 'for parentless types' do
|
||||
where(:action_type) do
|
||||
[
|
||||
[Todo::DUO_PRO_ACCESS_GRANTED],
|
||||
[Todo::SSH_KEY_EXPIRED]
|
||||
]
|
||||
end
|
||||
|
||||
with_them do
|
||||
context "for #{params[:action_type]} should not require a target" do
|
||||
subject { described_class.new(target: user, action: action_type) }
|
||||
|
||||
it { is_expected.not_to validate_presence_of(:project) }
|
||||
it { is_expected.not_to validate_presence_of(:group) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#body' do
|
||||
|
|
|
|||
|
|
@ -1808,7 +1808,7 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
|
|||
|
||||
it 'returns a 200 when merge request is valid' do
|
||||
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/commits", user)
|
||||
commit = merge_request.commits.first
|
||||
commit = merge_request.merge_request_diff.last_commit
|
||||
|
||||
expect_successful_response_with_paginated_array
|
||||
expect(json_response.size).to eq(merge_request.commits.size)
|
||||
|
|
@ -1817,14 +1817,15 @@ RSpec.describe API::MergeRequests, :aggregate_failures, feature_category: :sourc
|
|||
expect(json_response.first['parent_ids']).to be_present
|
||||
end
|
||||
|
||||
context 'when commits_from_gitaly feature flag is disabled' do
|
||||
context 'when commits_from_gitaly and optimized_commit_storage feature flags are disabled' do
|
||||
before do
|
||||
stub_feature_flags(commits_from_gitaly: false)
|
||||
stub_feature_flags(optimized_commit_storage: false)
|
||||
end
|
||||
|
||||
it 'returns a 200 without parent_ids' do
|
||||
get api("/projects/#{project.id}/merge_requests/#{merge_request.iid}/commits", user)
|
||||
commit = merge_request.commits.first
|
||||
commit = merge_request.merge_request_diff.last_commit
|
||||
|
||||
expect_successful_response_with_paginated_array
|
||||
expect(json_response.size).to eq(merge_request.commits.size)
|
||||
|
|
|
|||
|
|
@ -131,6 +131,36 @@ RSpec.describe ApplicationController, type: :request, feature_category: :shared
|
|||
end
|
||||
end
|
||||
|
||||
context 'for classify action by SESSION_PREFIX' do
|
||||
let(:headers) do
|
||||
{
|
||||
'X-Gitlab-Http-Router-Rule-Action' => 'classify',
|
||||
'X-Gitlab-Http-Router-Rule-Type' => 'SESSION_PREFIX'
|
||||
}
|
||||
end
|
||||
|
||||
it 'increments the counter with labels' do
|
||||
expect { perform_request }.to change {
|
||||
http_router_rule_counter.get(rule_action: 'classify', rule_type: 'SESSION_PREFIX')
|
||||
}.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for classify action by CELL_ID' do
|
||||
let(:headers) do
|
||||
{
|
||||
'X-Gitlab-Http-Router-Rule-Action' => 'classify',
|
||||
'X-Gitlab-Http-Router-Rule-Type' => 'CELL_ID'
|
||||
}
|
||||
end
|
||||
|
||||
it 'increments the counter with labels' do
|
||||
expect { perform_request }.to change {
|
||||
http_router_rule_counter.get(rule_action: 'classify', rule_type: 'CELL_ID')
|
||||
}.by(1)
|
||||
end
|
||||
end
|
||||
|
||||
context 'for proxy action' do
|
||||
let(:headers) do
|
||||
{
|
||||
|
|
|
|||
|
|
@ -890,10 +890,10 @@ RSpec.describe MergeRequests::RefreshService, feature_category: :code_review_wor
|
|||
target_project: @project
|
||||
)
|
||||
|
||||
commits = draft_merge_request.commits
|
||||
commits = draft_merge_request.commits(load_from_gitaly: true)
|
||||
oldrev = commits.last.id
|
||||
newrev = commits.first.id
|
||||
draft_commit = draft_merge_request.commits.find(&:draft?)
|
||||
draft_commit = commits.find(&:draft?)
|
||||
|
||||
refresh_service.execute(oldrev, newrev, 'refs/heads/wip')
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue