Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2025-06-14 00:11:58 +00:00
parent 29a7132039
commit eca6018a19
28 changed files with 398 additions and 74 deletions

View File

@ -1,15 +1,30 @@
<script>
import MergeRequestsWidget from './merge_requests_widget.vue';
import ActivityWidget from './activity_widget.vue';
import TodosWidget from './todos_widget.vue';
export default {
components: { ActivityWidget, TodosWidget },
components: { MergeRequestsWidget, ActivityWidget, TodosWidget },
props: {
reviewRequestedPath: {
type: String,
required: true,
},
assignedToYouPath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div>
<h1>{{ __("Today's highlights") }}</h1>
<merge-requests-widget
:review-requested-path="reviewRequestedPath"
:assigned-to-you-path="assignedToYouPath"
/>
<todos-widget />
<activity-widget />
</div>

View File

@ -0,0 +1,37 @@
<script>
import { GlIcon, GlLink } from '@gitlab/ui';
export default {
name: 'MergeRequestsWidget',
components: {
GlIcon,
GlLink,
},
props: {
reviewRequestedPath: {
type: String,
required: true,
},
assignedToYouPath: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="gl-border gl-rounded-lg gl-px-4 gl-py-1">
<h4 class="gl-flex gl-items-center gl-gap-2">
<gl-icon name="merge-request" :size="16" />{{ __('Merge requests') }}
</h4>
<ul class="gl-list-none gl-p-0">
<li>
<gl-link :href="reviewRequestedPath">{{ __('Review requested') }}</gl-link>
</li>
<li>
<gl-link :href="assignedToYouPath">{{ __('Assigned to you') }}</gl-link>
</li>
</ul>
</div>
</template>

View File

@ -12,13 +12,20 @@ export default () => {
return false;
}
const { reviewRequestedPath, assignedToYouPath } = el.dataset;
return new Vue({
el,
apolloProvider: new VueApollo({
defaultClient: createDefaultClient(),
}),
render(createElement) {
return createElement(HomepageApp);
return createElement(HomepageApp, {
props: {
reviewRequestedPath,
assignedToYouPath,
},
});
},
});
};

View File

@ -1,5 +1,6 @@
import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import { groupsProvideData } from 'ee_else_ce/invite_members/utils';
import InviteGroupsModal from '~/invite_members/components/invite_groups_modal.vue';
import { parseBoolean } from '~/lib/utils/common_utils';
@ -28,12 +29,7 @@ export default function initInviteGroupsModal() {
return new Vue({
el,
provide: {
freeUsersLimit: parseInt(el.dataset.freeUsersLimit, 10),
overageMembersModalAvailable: parseBoolean(el.dataset.overageMembersModalAvailable),
hasGitlabSubscription: parseBoolean(el.dataset.hasGitlabSubscription),
inviteWithCustomRoleEnabled: parseBoolean(el.dataset.inviteWithCustomRoleEnabled),
},
provide: groupsProvideData(el),
render: (createElement) =>
createElement(InviteGroupsModal, {
props: {

View File

@ -1,5 +1,6 @@
import { GlToast } from '@gitlab/ui';
import Vue from 'vue';
import { membersProvideData } from 'ee_else_ce/invite_members/utils';
import InviteMembersModal from '~/invite_members/components/invite_members_modal.vue';
import { parseBoolean, convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
@ -23,14 +24,7 @@ export default (function initInviteMembersModal() {
inviteMembersModal = new Vue({
el,
name: 'InviteMembersModalRoot',
provide: {
name: el.dataset.name,
overageMembersModalAvailable: parseBoolean(el.dataset.overageMembersModalAvailable),
hasGitlabSubscription: parseBoolean(el.dataset.hasGitlabSubscription),
addSeatsHref: el.dataset.addSeatsHref,
hasBsoEnabled: parseBoolean(el.dataset.hasBsoFeatureEnabled),
searchUrl: el.dataset.searchUrl,
},
provide: membersProvideData(el),
render: (createElement) =>
createElement(InviteMembersModal, {
props: {

View File

@ -0,0 +1,45 @@
import { parseBoolean } from '~/lib/utils/common_utils';
export function membersProvideData(el) {
if (!el) {
return false;
}
const {
name,
overageMembersModalAvailable,
hasGitlabSubscription,
addSeatsHref,
hasBsoFeatureEnabled,
searchUrl,
} = el.dataset;
return {
name,
overageMembersModalAvailable: parseBoolean(overageMembersModalAvailable),
hasGitlabSubscription: parseBoolean(hasGitlabSubscription),
addSeatsHref,
hasBsoEnabled: parseBoolean(hasBsoFeatureEnabled),
searchUrl,
};
}
export function groupsProvideData(el) {
if (!el) {
return false;
}
const {
freeUsersLimit,
overageMembersModalAvailable,
hasGitlabSubscription,
inviteWithCustomRoleEnabled,
} = el.dataset;
return {
freeUsersLimit: parseInt(freeUsersLimit, 10),
overageMembersModalAvailable: parseBoolean(overageMembersModalAvailable),
hasGitlabSubscription: parseBoolean(hasGitlabSubscription),
inviteWithCustomRoleEnabled: parseBoolean(inviteWithCustomRoleEnabled),
};
}

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
module HomepageData
extend ActiveSupport::Concern
private
def homepage_app_data(user)
{
review_requested_path: merge_requests_dashboard_path(reviewer_username: user.username),
assigned_to_you_path: merge_requests_dashboard_path(assignee_username: user.username)
}
end
end

View File

@ -9,6 +9,8 @@
# For users who haven't customized the setting, we simply delegate to
# `DashboardController#show`, which is the default.
class RootController < Dashboard::ProjectsController
include HomepageData
skip_before_action :authenticate_user!, only: [:index]
before_action :redirect_unlogged_user, if: -> { current_user.nil? }
@ -21,6 +23,7 @@ class RootController < Dashboard::ProjectsController
CACHE_CONTROL_HEADER = 'no-store'
def index
@homepage_app_data = @current_user.nil? ? {} : homepage_app_data(@current_user)
render('root/index') && return if Feature.enabled?(:personal_homepage, current_user)
super

View File

@ -1562,8 +1562,10 @@ class Project < ApplicationRecord
end
def merge_base_commit(first_commit_id, second_commit_id)
sha = repository.merge_base(first_commit_id, second_commit_id)
commit_by(oid: sha) if sha
strong_memoize(:"merge_base_commit_#{first_commit_id}_#{second_commit_id}") do
sha = repository.merge_base(first_commit_id, second_commit_id)
commit_by(oid: sha) if sha
end
end
def saved?

View File

@ -1,3 +1,3 @@
- page_title _("Home")
#js-homepage-app
#js-homepage-app{ data: @homepage_app_data }

View File

@ -142,6 +142,7 @@ To impersonate a user:
1. On the left sidebar, select **Overview > Users**.
1. From the list of users, select a user.
1. On the top right, select **Impersonate**.
1. To stop impersonating, on the left sidebar at the top, select **Stop impersonating** ({{< icon name="incognito">}}).
- With the API, using [impersonation tokens](../api/rest/authentication.md#impersonation-tokens).
All impersonation activities are [captured with audit events](compliance/audit_event_reports.md#user-impersonation).

View File

@ -349,7 +349,7 @@ use `%{created_at}` in Ruby but `%{createdAt}` in JavaScript. Make sure to
...
computed: {
userWelcome() {
sprintf(__('Hello %{username}'), { username: this.user.name });
return sprintf(__('Hello %{username}'), { username: this.user.name });
}
}
...

View File

@ -18,11 +18,11 @@ module Gitlab
GLAB_WARNING_MESSAGE = "Warning: release-cli will not be supported after 19.0. Please use glab version >= #{GLAB_REQUIRED_VERSION}. Troubleshooting: #{TROUBLESHOOTING_URL}".freeze
GLAB_ENV_SET_UNIX = 'export GITLAB_HOST=$CI_SERVER_URL'
GLAB_ENV_SET_WINDOWS = '$env:GITLAB_HOST = $env:CI_SERVER_URL'
GLAB_ENV_SET_WINDOWS = '$$env:GITLAB_HOST = $$env:CI_SERVER_URL'
GLAB_LOGIN_UNIX = 'glab auth login --job-token $CI_JOB_TOKEN --hostname "$CI_SERVER_FQDN" --api-protocol $CI_SERVER_PROTOCOL'
GLAB_LOGIN_WINDOWS = 'glab auth login --job-token $env:CI_JOB_TOKEN --hostname "$env:CI_SERVER_FQDN" --api-protocol $env:CI_SERVER_PROTOCOL'
GLAB_LOGIN_WINDOWS = 'glab auth login --job-token $$env:CI_JOB_TOKEN --hostname "$$env:CI_SERVER_FQDN" --api-protocol $$env:CI_SERVER_PROTOCOL'
GLAB_CREATE_UNIX = 'glab release create -R $CI_PROJECT_PATH'
GLAB_CREATE_WINDOWS = 'glab release create -R $env:CI_PROJECT_PATH'
GLAB_CREATE_WINDOWS = 'glab release create -R $$env:CI_PROJECT_PATH'
GLAB_PUBLISH_TO_CATALOG_FLAG = '--publish-to-catalog' # enables publishing to the catalog after creating the release
GLAB_NO_UPDATE_FLAG = '--no-update' # disables updating the release if it already exists
GLAB_NO_CLOSE_MILESTONE_FLAG = '--no-close-milestone' # disables closing the milestone after creating the release
@ -42,11 +42,11 @@ module Gitlab
fi
BASH
GLAB_CA_CERT_CONFIG_WINDOWS = <<~POWERSHELL.chomp.freeze
if ($env:ADDITIONAL_CA_CERT_BUNDLE) {
Write-Output "Setting CA certificate for $env:CI_SERVER_FQDN"
if ($$env:ADDITIONAL_CA_CERT_BUNDLE) {
Write-Output "Setting CA certificate for $$env:CI_SERVER_FQDN"
"$env:ADDITIONAL_CA_CERT_BUNDLE" > "#{GLAB_CA_CERT_FILENAME}"
glab config set ca_cert "#{GLAB_CA_CERT_FILENAME}" --host "$env:CI_SERVER_FQDN"
"$$env:ADDITIONAL_CA_CERT_BUNDLE" > "#{GLAB_CA_CERT_FILENAME}"
glab config set ca_cert "#{GLAB_CA_CERT_FILENAME}" --host "$$env:CI_SERVER_FQDN"
}
POWERSHELL
GLAB_CA_CERT_CLEANUP_WINDOWS = <<~POWERSHELL.chomp.freeze
@ -92,10 +92,10 @@ module Gitlab
def glab_windows_script
<<~POWERSHELL
if (Get-Command glab -ErrorAction SilentlyContinue) {
$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string]
$$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string]
if ($glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') {
if ([version]$matches[1] -ge [version]"#{GLAB_REQUIRED_VERSION}") {
if ($$glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') {
if ([version]$$matches[1] -ge [version]"#{GLAB_REQUIRED_VERSION}") {
#{GLAB_ENV_SET_WINDOWS}
#{GLAB_CA_CERT_CONFIG_WINDOWS}
#{GLAB_LOGIN_WINDOWS}
@ -159,8 +159,8 @@ module Gitlab
command = GLAB_CREATE_WINDOWS.dup
# More information: https://gitlab.com/groups/gitlab-org/-/epics/15437#note_2432564707
tag_name = config[:tag_name].presence || '$env:CI_COMMIT_TAG'
ref = config[:ref].presence || '$env:CI_COMMIT_SHA'
tag_name = config[:tag_name].presence || '$$env:CI_COMMIT_TAG'
ref = config[:ref].presence || '$$env:CI_COMMIT_SHA'
else
command = GLAB_CREATE_UNIX.dup

View File

@ -7,6 +7,22 @@ module Gitlab
Gitlab::Routing.url_helpers.help_page_path('ci/variables/_index.md', anchor: 'define-a-cicd-variable-in-the-ui')
end
def self.vulnerability_checks_documentation_link
Gitlab::Routing.url_helpers.help_page_path('user/application_security/dast/browser/checks/_index.md')
end
def self.secure_log_level_documentation_link
Gitlab::Routing.url_helpers.help_page_path('user/application_security/dast/browser/troubleshooting.md',
anchor: 'secure_log_level')
end
def self.authentication_actions_documentation_link
Gitlab::Routing.url_helpers.help_page_path(
'user/application_security/dast/browser/configuration/authentication.md',
anchor: 'taking-additional-actions-after-submitting-the-login-form'
)
end
# rubocop: disable Metrics/AbcSize -- Generate dynamic translation as per
# https://docs.gitlab.com/ee/development/i18n/externalization.html#keep-translations-dynamic
def self.data
@ -35,11 +51,11 @@ module Gitlab
type: "string",
example: "select(option=id:accept-yes),click(on=css:.continue)",
name: s_("DastProfiles|After-login actions"),
description: s_(
description: format(s_(
"DastProfiles|A comma-separated list of actions to take after login but before login verification. " \
"Supports `click` and `select` actions. " \
"See [Taking additional actions after submitting the login form]" \
"(authentication.md#taking-additional-actions-after-submitting-the-login-form)."
"See [Taking additional actions after submitting the login form](%{documentation_link})."),
documentation_link: authentication_actions_documentation_link
)
},
DAST_AUTH_BEFORE_LOGIN_ACTIONS: {
@ -519,6 +535,7 @@ module Gitlab
},
scanner: {
DAST_AUTH_REPORT: {
additional: true,
auth: true,
type: "boolean",
example: true,
@ -531,24 +548,29 @@ module Gitlab
)
},
DAST_CHECKS_TO_EXCLUDE: {
additional: true,
type: "string",
example: "552.2,78.1",
name: s_("DastProfiles|Excluded checks"),
description: s_(
description: format(s_(
"DastProfiles|Comma-separated list of check identifiers to exclude from the scan. " \
"For identifiers, see [vulnerability checks](../checks/_index.md)."
"For identifiers, see [vulnerability checks](%{documentation_link})."),
documentation_link: vulnerability_checks_documentation_link
)
},
DAST_CHECKS_TO_RUN: {
additional: true,
type: "List of strings",
example: "16.1,16.2,16.3",
name: s_("DastProfiles|Included checks"),
description: s_(
description: format(s_(
"DastProfiles|Comma-separated list of check identifiers to use for the scan. " \
"For identifiers, see [vulnerability checks](../checks/_index.md)."
"For identifiers, see [vulnerability checks](%{documentation_link})."),
documentation_link: vulnerability_checks_documentation_link
)
},
DAST_CRAWL_GRAPH: {
additional: true,
type: "boolean",
example: true,
name: s_("DastProfiles|Generate graph"),
@ -559,18 +581,21 @@ module Gitlab
)
},
DAST_FULL_SCAN: {
additional: true,
type: "boolean",
example: true,
name: s_("DastProfiles|Full scan"),
description: s_("DastProfiles|Set to `true` to run both passive and active checks. Default is `false`.")
},
DAST_LOG_BROWSER_OUTPUT: {
additional: true,
type: "boolean",
example: true,
name: s_("DastProfiles|Log browser output"),
description: s_("DastProfiles|Set to `true` to log Chromium `STDOUT` and `STDERR`.")
},
DAST_LOG_CONFIG: {
additional: true,
type: "List of strings",
example: "brows:debug,auth:debug",
name: s_("DastProfiles|Log levels"),
@ -578,12 +603,14 @@ module Gitlab
"DastProfiles|A list of modules and their intended logging level for use in the console log.")
},
DAST_LOG_DEVTOOLS_CONFIG: {
additional: true,
type: "string",
example: "Default:messageAndBody,truncate:2000",
name: s_("DastProfiles|Log messages"),
description: s_("DastProfiles|Set to log protocol messages between DAST and the Chromium browser.")
},
DAST_LOG_FILE_CONFIG: {
additional: true,
type: "List of strings",
example: "brows:debug,auth:debug",
name: s_("DastProfiles|Log file levels"),
@ -591,24 +618,28 @@ module Gitlab
"DastProfiles|A list of modules and their intended logging level for use in the file log.")
},
DAST_LOG_FILE_PATH: {
additional: true,
type: "string",
example: "/output/browserker.log",
name: s_("DastProfiles|Log file path"),
description: s_("DastProfiles|Set to the path of the file log. Default is `gl-dast-scan.log`.")
},
SECURE_ANALYZERS_PREFIX: {
additional: true,
type: "URL",
example: "registry.organization.com",
name: s_("DastProfiles|Docker registry"),
description: s_("DastProfiles|Set the Docker registry base address from which to download the analyzer.")
},
SECURE_LOG_LEVEL: {
additional: true,
type: "string",
example: "debug",
name: s_("DastProfiles|Default log level"),
description: s_(
description: format(s_(
"DastProfiles|Set the default level for the file log. " \
"See [SECURE_LOG_LEVEL](../troubleshooting.md#secure_log_level)." \
"See [SECURE_LOG_LEVEL](%{documentation_link})."),
documentation_link: secure_log_level_documentation_link
)
}
}
@ -617,7 +648,7 @@ module Gitlab
# rubocop: enable Metrics/AbcSize
def self.additional_site_variables
data[:site].filter { |_, variable| variable[:additional] }
data[:site].merge(data[:scanner]).filter { |_, variable| variable[:additional] }
end
def self.auth_variables

View File

@ -136,6 +136,9 @@ module Gitlab
end
def emitter_class
# Use test emitter in test environment to prevent HTTP requests
return SnowplowTestEmitter if Rails.env.test?
# snowplow_enabled? is true for gitlab.com and customers that configured their own Snowplow collector
# In both bases we do not want to log the events being sent as the instance is controlled by the same company
# controlling the Snowplow collector.

View File

@ -0,0 +1,16 @@
# frozen_string_literal: true
module Gitlab
module Tracking
class SnowplowTestEmitter < SnowplowTracker::Emitter
extend ::Gitlab::Utils::Override
# Override send_requests to prevent HTTP requests in test environment
# This allows event tracking to work normally without making actual HTTP calls
override :send_requests
def send_requests(events)
events.size
end
end
end
end

View File

@ -19978,7 +19978,7 @@ msgstr ""
msgid "DastProfiles|A URL that is compared to the URL in the browser to determine if authentication has succeeded after the login form is submitted."
msgstr ""
msgid "DastProfiles|A comma-separated list of actions to take after login but before login verification. Supports `click` and `select` actions. See [Taking additional actions after submitting the login form](authentication.md#taking-additional-actions-after-submitting-the-login-form)."
msgid "DastProfiles|A comma-separated list of actions to take after login but before login verification. Supports `click` and `select` actions. See [Taking additional actions after submitting the login form](%{documentation_link})."
msgstr ""
msgid "DastProfiles|A comma-separated list of selectors representing elements to click on prior to entering the DAST_AUTH_USERNAME and DAST_AUTH_PASSWORD into the login form."
@ -20086,10 +20086,10 @@ msgstr ""
msgid "DastProfiles|Clear input fields"
msgstr ""
msgid "DastProfiles|Comma-separated list of check identifiers to exclude from the scan. For identifiers, see [vulnerability checks](../checks/_index.md)."
msgid "DastProfiles|Comma-separated list of check identifiers to exclude from the scan. For identifiers, see [vulnerability checks](%{documentation_link})."
msgstr ""
msgid "DastProfiles|Comma-separated list of check identifiers to use for the scan. For identifiers, see [vulnerability checks](../checks/_index.md)."
msgid "DastProfiles|Comma-separated list of check identifiers to use for the scan. For identifiers, see [vulnerability checks](%{documentation_link})."
msgstr ""
msgid "DastProfiles|Comma-separated list of selectors that are ignored when scanning."
@ -20434,7 +20434,7 @@ msgstr ""
msgid "DastProfiles|Set the Docker registry base address from which to download the analyzer."
msgstr ""
msgid "DastProfiles|Set the default level for the file log. See [SECURE_LOG_LEVEL](../troubleshooting.md#secure_log_level)."
msgid "DastProfiles|Set the default level for the file log. See [SECURE_LOG_LEVEL](%{documentation_link})."
msgstr ""
msgid "DastProfiles|Set to `false` to disable caching. Default: `true`. **Note**: Disabling cache can cause OOM events or DAST job timeouts."
@ -23325,6 +23325,27 @@ msgstr ""
msgid "Duo Workflow|Something went wrong saving Duo Workflow settings"
msgstr ""
msgid "DuoAgentsPlatform|Agents"
msgstr ""
msgid "DuoAgentsPlatform|Failed to fetch workflows"
msgstr ""
msgid "DuoAgentsPlatform|Last updated"
msgstr ""
msgid "DuoAgentsPlatform|New Agent runs will appear here."
msgstr ""
msgid "DuoAgentsPlatform|No Agent runs yet"
msgstr ""
msgid "DuoAgentsPlatform|Prompt"
msgstr ""
msgid "DuoAgentsPlatform|Status"
msgstr ""
msgid "DuoChat|%{linkStart}Learn how%{linkEnd} to set up Code Suggestions and Chat in your IDE. You can also use Chat in GitLab. Ask questions about:"
msgstr ""

View File

@ -0,0 +1,32 @@
import { shallowMount } from '@vue/test-utils';
import HomepageApp from '~/homepage/components/homepage_app.vue';
import MergeRequestsWidget from '~/homepage/components/merge_requests_widget.vue';
describe('HomepageApp', () => {
const MOCK_REVIEW_REQUESTED_PATH = '/review/requested/path';
const MOCK_ASSIGNED_TO_YOU_PATH = '/assigned/to/you/path';
let wrapper;
const findMergeRequestsWidget = () => wrapper.findComponent(MergeRequestsWidget);
function createWrapper() {
wrapper = shallowMount(HomepageApp, {
propsData: {
reviewRequestedPath: MOCK_REVIEW_REQUESTED_PATH,
assignedToYouPath: MOCK_ASSIGNED_TO_YOU_PATH,
},
});
}
beforeEach(() => {
createWrapper();
});
it('passes the correct props to the `MergeRequestsWidget` component', () => {
expect(findMergeRequestsWidget().props()).toEqual({
reviewRequestedPath: MOCK_REVIEW_REQUESTED_PATH,
assignedToYouPath: MOCK_ASSIGNED_TO_YOU_PATH,
});
});
});

View File

@ -0,0 +1,33 @@
import { shallowMount } from '@vue/test-utils';
import { GlLink } from '@gitlab/ui';
import MergeRequestsWidget from '~/homepage/components/merge_requests_widget.vue';
describe('MergeRequestsWidget', () => {
const MOCK_REVIEW_REQUESTED_PATH = '/review/requested/path';
const MOCK_ASSIGNED_TO_YOU_PATH = '/assigned/to/you/path';
let wrapper;
const findGlLinks = () => wrapper.findAllComponents(GlLink);
function createWrapper() {
wrapper = shallowMount(MergeRequestsWidget, {
propsData: {
reviewRequestedPath: MOCK_REVIEW_REQUESTED_PATH,
assignedToYouPath: MOCK_ASSIGNED_TO_YOU_PATH,
},
});
}
beforeEach(() => {
createWrapper();
});
it('renders the "Review requested" link', () => {
expect(findGlLinks().at(0).props('href')).toBe(MOCK_REVIEW_REQUESTED_PATH);
});
it('renders the "Assigned to you" link', () => {
expect(findGlLinks().at(1).props('href')).toBe(MOCK_ASSIGNED_TO_YOU_PATH);
});
});

View File

@ -22,7 +22,7 @@ RSpec.describe InviteMembersHelper do
help_link: help_page_url('user/permissions.md'),
is_project: 'true',
access_levels: ProjectMember.access_level_roles.to_json,
full_path: project.full_path
full_path: Gitlab.ee? ? project.root_ancestor.full_path : project.full_path
}
expect(helper.common_invite_group_modal_data(project, ProjectMember)).to include(attributes)
@ -60,7 +60,7 @@ RSpec.describe InviteMembersHelper do
root_id: project.root_ancestor.id,
name: project.name,
default_access_level: Gitlab::Access::GUEST,
full_path: project.full_path
full_path: Gitlab.ee? ? project.root_ancestor.full_path : project.full_path
}
expect(helper.common_invite_modal_dataset(project)).to include(attributes)

View File

@ -40,7 +40,7 @@ RSpec.describe Gitlab::Ci::Build::Releaser, feature_category: :continuous_integr
result_for_release_cli_without_catalog_publish = "#{release_cli_command} #{release_cli_assets_links}"
glab_create_unix = 'glab release create -R $CI_PROJECT_PATH'
glab_create_windows = 'glab release create -R $env:CI_PROJECT_PATH'
glab_create_windows = 'glab release create -R $$env:CI_PROJECT_PATH'
glab_command = "\"release-$CI_COMMIT_SHA\" #{glab_assets_links} --milestone \"m1,m2,m3\" --name \"Release $CI_COMMIT_SHA\" --experimental-notes-text-or-file \"Created using the release-cli $EXTRA_DESCRIPTION\" --ref \"$CI_COMMIT_SHA\" --tag-message \"Annotated tag message\" --released-at \"2020-07-15T08:00:00Z\" --no-update --no-close-milestone"
warning_message = "Warning: release-cli will not be supported after 19.0. Please use glab version >= #{described_class::GLAB_REQUIRED_VERSION}. Troubleshooting: http://localhost/help/user/project/releases/_index.md#gitlab-cli-version-requirement"
@ -66,10 +66,10 @@ RSpec.describe Gitlab::Ci::Build::Releaser, feature_category: :continuous_integr
BASH
windows_result_for_glab_or_release_cli_without_catalog_publish = <<~POWERSHELL
if (Get-Command glab -ErrorAction SilentlyContinue) {
$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string]
$$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string]
if ($glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') {
if ([version]$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") {
if ($$glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') {
if ([version]$$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") {
#{described_class::GLAB_ENV_SET_WINDOWS}
#{described_class::GLAB_CA_CERT_CONFIG_WINDOWS}
#{described_class::GLAB_LOGIN_WINDOWS}
@ -145,10 +145,10 @@ RSpec.describe Gitlab::Ci::Build::Releaser, feature_category: :continuous_integr
BASH
windows_result_for_glab_or_release_cli_with_catalog_publish = <<~POWERSHELL
if (Get-Command glab -ErrorAction SilentlyContinue) {
$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string]
$$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string]
if ($glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') {
if ([version]$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") {
if ($$glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') {
if ([version]$$matches[1] -ge [version]"#{described_class::GLAB_REQUIRED_VERSION}") {
#{described_class::GLAB_ENV_SET_WINDOWS}
#{described_class::GLAB_CA_CERT_CONFIG_WINDOWS}
#{described_class::GLAB_LOGIN_WINDOWS}

View File

@ -6,9 +6,15 @@ RSpec.describe ::Gitlab::Security::DastVariables, feature_category: :dynamic_app
let(:dast_variables) { described_class }
describe '#additional_site_variables' do
it 'contains only additional variables' do
described_class.additional_site_variables.each_value do |variable|
expect(variable[:additional]).to be(true)
[:site, :scanner].each do |type|
it "contains additional #{type} variables" do
described_class.data[type].each do |key, variable|
if variable[:additional]
expect(described_class.additional_site_variables[key]).not_to be_nil
else
expect(described_class.additional_site_variables[key]).to be_nil
end
end
end
end
end

View File

@ -106,7 +106,11 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b
end
end
context "when in development or test environment" do
context "when in development environment" do
before do
allow(Rails.env).to receive_messages(test?: false, development?: true)
end
it "initializes POST emitter with buffer_size 1" do
allow(SnowplowTracker::Tracker).to receive(:new).and_return(tracker)
allow(tracker).to receive(:track_struct_event).and_call_original
@ -174,7 +178,7 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b
let(:payload) { { "event" => "page_view", "user_id" => "123" } }
before do
allow(SnowplowTracker::AsyncEmitter).to receive(:new).and_return(emitter)
allow(Gitlab::Tracking::SnowplowTestEmitter).to receive(:new).and_return(emitter)
end
it "forwards the payload to the emitter" do
@ -333,6 +337,7 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b
context 'when snowplow is enabled' do
before do
stub_application_setting(snowplow_enabled?: true)
allow(Rails.env).to receive(:test?).and_return(false)
end
it 'uses AsyncEmitter' do
@ -346,6 +351,7 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b
context 'when snowplow is disabled' do
before do
stub_application_setting(snowplow_enabled?: false)
allow(Rails.env).to receive(:test?).and_return(false)
end
context 'when GITLAB_DISABLE_PRODUCT_USAGE_EVENT_LOGGING env variable is true' do
@ -379,5 +385,15 @@ RSpec.describe Gitlab::Tracking::Destinations::Snowplow, :do_not_stub_snowplow_b
end
end
end
context 'in test environment' do
it 'uses SnowplowTestEmitter to prevent HTTP requests' do
# In test environment, we expect SnowplowTestEmitter to prevent HTTP requests
expect(Gitlab::Tracking::SnowplowTestEmitter).to receive(:new)
expect(SnowplowTracker::AsyncEmitter).not_to receive(:new)
expect(Gitlab::Tracking::SnowplowLoggingEmitter).not_to receive(:new)
subject.send(:emitter)
end
end
end
end

View File

@ -0,0 +1,14 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe Gitlab::Tracking::SnowplowTestEmitter, feature_category: :service_ping do
describe '#send_requests' do
it 'returns the number of events' do
emitter = described_class.new(endpoint: 'test')
events = [{}, {}]
expect(emitter.send_requests(events)).to eq(2)
end
end
end

View File

@ -10241,4 +10241,16 @@ RSpec.describe Project, factory_default: :keep, feature_category: :groups_and_pr
expect(project.valid_lfs_oids(oids)).to eq([lfs_object.oid])
end
end
describe '#merge_base_commit' do
let_it_be(:project) { create(:project, :repository) }
let(:commit1) { project.repository.commit }
let(:commit2) { project.repository.commit('feature') }
it 'memoizes the result' do
expect(project.repository).to receive(:merge_base).once.and_call_original
2.times { project.merge_base_commit(commit1.id, commit2.id) }
end
end
end

View File

@ -2,17 +2,9 @@
module StubSnowplow
def stub_snowplow
# Using a high buffer size to not cause early flushes
buffer_size = 100
# WebMock is set up to allow requests to `localhost`
host = 'localhost'
# rubocop:disable RSpec/AnyInstanceOf
allow_any_instance_of(Gitlab::Tracking::Destinations::Snowplow)
.to receive(:emitter)
.and_return(SnowplowTracker::Emitter.new(endpoint: host, options: { buffer_size: buffer_size }))
# rubocop:enable RSpec/AnyInstanceOf
stub_application_setting(snowplow_enabled: true, snowplow_collector_hostname: host)
allow(SnowplowTracker::SelfDescribingJson).to receive(:new).and_call_original

View File

@ -0,0 +1,21 @@
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'root/index.html.haml', feature_category: :onboarding do
let_it_be(:mock_review_requested_path) { "review_requested_path" }
let_it_be(:mock_assigned_to_you_path) { "assigned_to_you_path" }
before do
@homepage_app_data = {
review_requested_path: mock_review_requested_path,
assigned_to_you_path: mock_assigned_to_you_path
}
render
end
it 'renders the app root element with the correct data attributes' do
expect(rendered).to have_css("[data-review-requested-path='#{mock_review_requested_path}']")
expect(rendered).to have_css("[data-assigned-to-you-path='#{mock_assigned_to_you_path}']")
end
end

View File

@ -44,12 +44,25 @@ module Tooling
end
def render_description(description)
# replace help_page_path-generated documentation link
# with relative path to documentation file
description.sub(
Gitlab::Security::DastVariables.ci_variables_documentation_link,
'../../../../../ci/variables/_index.md#define-a-cicd-variable-in-the-ui'
)
# replace help_page_path-generated documentation links
# with relative paths to documentation files
description
.sub(
Gitlab::Security::DastVariables.ci_variables_documentation_link,
'../../../../../ci/variables/_index.md#define-a-cicd-variable-in-the-ui'
)
.sub(
Gitlab::Security::DastVariables.vulnerability_checks_documentation_link,
'../checks/_index.md'
)
.sub(
Gitlab::Security::DastVariables.secure_log_level_documentation_link,
'../troubleshooting.md#secure_log_level'
)
.sub(
Gitlab::Security::DastVariables.authentication_actions_documentation_link,
'authentication.md#taking-additional-actions-after-submitting-the-login-form'
)
end
def render_row(*values)