Add latest changes from gitlab-org/gitlab@master

This commit is contained in:
GitLab Bot 2023-01-10 12:09:05 +00:00
parent 14b71b2795
commit fbf183eebe
179 changed files with 81280 additions and 28165 deletions

View File

@ -1438,11 +1438,11 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab
/**/javascripts/pipelines/ @gitlab-org/ci-cd/verify/frontend
/app/assets/javascripts/ci/ @gitlab-org/ci-cd/verify/frontend
/app/assets/javascripts/pipeline_new/ @gitlab-org/ci-cd/verify/frontend
/app/assets/javascripts/ci_variable_list/ @gitlab-org/ci-cd/verify/frontend
/app/assets/javascripts/ci/pipeline_schedules/ @gitlab-org/ci-cd/verify/frontend
/ee/app/assets/javascripts/ci/ @gitlab-org/ci-cd/verify/frontend
/app/assets/javascripts/token_access/ @gitlab-org/ci-cd/verify/frontend
/app/assets/javascripts/admin/application_settings/runner_token_expiration/ @gitlab-org/ci-cd/verify/frontend
/ee/app/assets/javascripts/usage_quotas/pipelines/ @gitlab-org/ci-cd/verify/frontend @fulfillment-group/utilization-group/fe
[Manage::Workspace]
lib/api/entities/basic_project_details.rb @gitlab-org/manage/manage-workspace/backend-approvers
@ -1517,3 +1517,8 @@ ee/lib/ee/api/entities/project.rb @gitlab-org/manage/manage-workspace/backend-ap
/ee/lib/ee/gitlab/audit/ @gitlab-org/govern/compliance
/lib/gitlab/audit/auditor.rb @gitlab-org/govern/compliance
/lib/gitlab/audit_json_logger.rb @gitlab-org/govern/compliance
[Fulfillment::Utilization]
/ee/app/assets/javascripts/usage_quotas/components/ @fulfillment-group/utilization-group/fe
/ee/app/assets/javascripts/usage_quotas/seats/ @fulfillment-group/utilization-group/fe
/ee/app/assets/javascripts/usage_quotas/storage/ @fulfillment-group/utilization-group/fe

View File

@ -60,8 +60,7 @@ include:
- !reference [.base-script, script]
- rspec_paralellized_job "--tag ~quarantine --tag ~level:migration"
allow_failure:
# the exit code listed here must match the one defined for the variable SUCCESSFULLY_RETRIED_TEST_EXIT_CODE
exit_codes: 137
exit_codes: !reference [.rspec-base, variables, SUCCESSFULLY_RETRIED_TEST_EXIT_CODE]
.base-artifacts:
artifacts:

View File

@ -1 +1 @@
7144bcd52a6b8c745bf90af812a78426384ac535
522c0d9283f757583fcfd43e66b4d5b323503bc0

View File

@ -358,7 +358,7 @@ gem 'prometheus-client-mmap', '~> 0.17', require: 'prometheus/client'
gem 'warning', '~> 1.3.0'
group :development do
gem 'lefthook', '~> 1.2.6', require: false
gem 'lefthook', '~> 1.2.7', require: false
gem 'rubocop'
gem 'solargraph', '~> 0.47.2', require: false

View File

@ -310,7 +310,7 @@
{"name":"kramdown","version":"2.3.2","platform":"ruby","checksum":"cb4530c2e9d16481591df2c9336723683c354e5416a5dd3e447fa48215a6a71c"},
{"name":"kramdown-parser-gfm","version":"1.1.0","platform":"ruby","checksum":"fb39745516427d2988543bf01fc4cf0ab1149476382393e0e9c48592f6581729"},
{"name":"launchy","version":"2.5.0","platform":"ruby","checksum":"954243c4255920982ce682f89a42e76372dba94770bf09c23a523e204bdebef5"},
{"name":"lefthook","version":"1.2.6","platform":"ruby","checksum":"8d8ab03a559d1f5d40b4416072edf5ebb22eddfc74b75479458edd5318a3de63"},
{"name":"lefthook","version":"1.2.7","platform":"ruby","checksum":"82736715006361aac32b9ae36086288691c024ff471a9df056d09535e5546ca3"},
{"name":"letter_opener","version":"1.7.0","platform":"ruby","checksum":"095bc0d58e006e5b43ea7d219e64ecf2de8d1f7d9dafc432040a845cf59b4725"},
{"name":"letter_opener_web","version":"2.0.0","platform":"ruby","checksum":"33860ad41e1785d75456500e8ca8bba8ed71ee6eaf08a98d06bbab67c5577b6f"},
{"name":"libyajl2","version":"1.2.0","platform":"ruby","checksum":"1117cd1e48db013b626e36269bbf1cef210538ca6d2e62d3fa3db9ded005b258"},

View File

@ -835,7 +835,7 @@ GEM
kramdown (~> 2.0)
launchy (2.5.0)
addressable (~> 2.7)
lefthook (1.2.6)
lefthook (1.2.7)
letter_opener (1.7.0)
launchy (~> 2.2)
letter_opener_web (2.0.0)
@ -1720,7 +1720,7 @@ DEPENDENCIES
knapsack (~> 1.21.1)
kramdown (~> 2.3.1)
kubeclient (~> 4.9.3)!
lefthook (~> 1.2.6)
lefthook (~> 1.2.7)
letter_opener_web (~> 2.0.0)
license_finder (~> 7.0)
licensee (~> 9.15)

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation addAdminVariable($variable: CiVariable!, $endpoint: String!) {
ciVariableMutation: addAdminVariable(variable: $variable, endpoint: $endpoint) @client {

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation deleteAdminVariable($variable: CiVariable!, $endpoint: String!) {
ciVariableMutation: deleteAdminVariable(variable: $variable, endpoint: $endpoint) @client {

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation updateAdminVariable($variable: CiVariable!, $endpoint: String!) {
ciVariableMutation: updateAdminVariable(variable: $variable, endpoint: $endpoint) @client {

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation addGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
ciVariableMutation: addGroupVariable(

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation deleteGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
ciVariableMutation: deleteGroupVariable(

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation updateGroupVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
ciVariableMutation: updateGroupVariable(

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation addProjectVariable($variable: CiVariable!, $endpoint: String!, $fullPath: ID!, $id: ID!) {
ciVariableMutation: addProjectVariable(

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation deleteProjectVariable(
$variable: CiVariable!

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
mutation updateProjectVariable(
$variable: CiVariable!

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getGroupVariables($after: String, $first: Int = 100, $fullPath: ID!) {

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getProjectVariables($after: String, $first: Int = 100, $fullPath: ID!) {

View File

@ -1,4 +1,4 @@
#import "~/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/ci/ci_variable_list/graphql/fragments/ci_variable.fragment.graphql"
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
query getVariables($after: String, $first: Int = 100) {

View File

@ -2,8 +2,8 @@ import axios from 'axios';
import {
convertObjectPropsToCamelCase,
convertObjectPropsToSnakeCase,
} from '../../lib/utils/common_utils';
import { convertToGraphQLId, getIdFromGraphQLId } from '../../graphql_shared/utils';
} from '~/lib/utils/common_utils';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import {
GRAPHQL_GROUP_TYPE,
GRAPHQL_PROJECT_TYPE,

View File

@ -23,6 +23,8 @@ export default {
RunnerSingleStat,
RunnerUpgradeStatusStats: () =>
import('ee_component/ci/runner/components/stat/runner_upgrade_status_stats.vue'),
RunnerPerformanceStat: () =>
import('ee_component/ci/runner/components/stat/runner_performance_stat.vue'),
},
props: {
scope: {
@ -95,6 +97,8 @@ export default {
:scope="scope"
:variables="variables"
/>
<runner-performance-stat class="gl-px-5" />
</div>
</runner-count>
</template>

View File

@ -1,4 +1,4 @@
import initVariableList from '~/ci_variable_list';
import initVariableList from '~/ci/ci_variable_list';
import projectSelect from '~/project_select';
import initSearchSettings from '~/search_settings';
import selfMonitor from '~/self_monitor';

View File

@ -1,5 +1,5 @@
import initStaleRunnerCleanupSetting from 'ee_else_ce/group_settings/stale_runner_cleanup';
import initVariableList from '~/ci_variable_list';
import initVariableList from '~/ci/ci_variable_list';
import initSharedRunnersForm from '~/group_settings/mount_shared_runners';
import initSettingsPanels from '~/settings_panels';
import initDeployTokens from '~/deploy_tokens';

View File

@ -22,7 +22,7 @@ export default {
GlTooltip,
},
i18n: {
contactAdmin: s__('LearnGitlab|Contact your administrator to start a free Ultimate trial.'),
contactAdmin: s__('LearnGitlab|Contact your administrator to enable this action.'),
viewAdminList: s__('LearnGitlab|View administrator list'),
watchHow: __('Watch how'),
},
@ -50,6 +50,9 @@ export default {
openInNewTab() {
return ACTION_LABELS[this.action]?.openInNewTab === true || this.value.openInNewTab === true;
},
popoverText() {
return this.value.message || this.$options.i18n.contactAdmin;
},
},
methods: {
openModal() {
@ -101,7 +104,7 @@ export default {
category="tertiary"
icon="question-o"
class="ml-auto"
:aria-label="$options.i18n.contactAdmin"
:aria-label="popoverText"
size="small"
data-testid="contact-admin-popover-trigger"
/>
@ -111,7 +114,7 @@ export default {
triggers="hover focus"
data-testid="contact-admin-popover"
>
<p>{{ $options.i18n.contactAdmin }}</p>
<p>{{ popoverText }}</p>
<gl-link
:href="value.url"
class="font-size-inherit"

View File

@ -3,7 +3,7 @@ import Vue from 'vue';
import { __ } from '~/locale';
import RefSelector from '~/ref/components/ref_selector.vue';
import { REF_TYPE_BRANCHES, REF_TYPE_TAGS } from '~/ref/constants';
import setupNativeFormVariableList from '~/ci_variable_list/native_form_variable_list';
import setupNativeFormVariableList from '~/ci/ci_variable_list/native_form_variable_list';
import GlFieldErrors from '~/gl_field_errors';
import Translate from '~/vue_shared/translate';
import { initTimezoneDropdown } from '../../../profiles/init_timezone_dropdown';

View File

@ -1,7 +1,7 @@
import initArtifactsSettings from '~/artifacts_settings';
import SecretValues from '~/behaviors/secret_values';
import initSettingsPipelinesTriggers from '~/ci_settings_pipeline_triggers';
import initVariableList from '~/ci_variable_list';
import initVariableList from '~/ci/ci_variable_list';
import initDeployFreeze from '~/deploy_freeze';
import registrySettingsApp from '~/packages_and_registries/settings/project/registry_settings_bundle';
import { initRunnerAwsDeployments } from '~/pages/shared/mount_runner_aws_deployments';

View File

@ -56,6 +56,7 @@ export default {
},
update({ project: { branchRules } }) {
const branchRule = branchRules.nodes.find((rule) => rule.name === this.branch);
this.branchRule = branchRule;
this.branchProtection = branchRule?.branchProtection;
this.approvalRules = branchRule?.approvalRules;
this.statusChecks = branchRule?.externalStatusChecks?.nodes || [];
@ -69,6 +70,7 @@ export default {
branchProtection: {},
approvalRules: {},
statusChecks: [],
branchRule: {},
matchingBranchesCount: null,
};
},
@ -88,12 +90,12 @@ export default {
},
allowedToMergeHeader() {
return sprintf(this.$options.i18n.allowedToMergeHeader, {
total: this.mergeAccessLevels.total,
total: this.mergeAccessLevels?.total || 0,
});
},
allowedToPushHeader() {
return sprintf(this.$options.i18n.allowedToPushHeader, {
total: this.pushAccessLevels.total,
total: this.pushAccessLevels?.total || 0,
});
},
approvalsHeader() {
@ -141,7 +143,7 @@ export default {
<template>
<gl-loading-icon v-if="$apollo.loading" />
<div v-else-if="!branchProtection">{{ $options.i18n.noData }}</div>
<div v-else-if="!branchRule">{{ $options.i18n.noData }}</div>
<div v-else>
<strong data-testid="branch-title">{{ branchTitle }}</strong>
<p v-if="!allBranches" class="gl-mb-3 gl-text-gray-400">

View File

@ -5,6 +5,7 @@ import { getAccessLevels } from '../../../utils';
export const i18n = {
defaultLabel: s__('BranchRules|default'),
protectedLabel: s__('BranchRules|protected'),
detailsButtonLabel: s__('BranchRules|Details'),
allowForcePush: s__('BranchRules|Allowed to force push'),
codeOwnerApprovalRequired: s__('BranchRules|Requires CODEOWNERS approval'),
@ -62,6 +63,9 @@ export default {
isWildcard() {
return this.name.includes('*');
},
isProtected() {
return Boolean(this.branchProtection);
},
hasApprovalDetails() {
return this.approvalDetails.length;
},
@ -105,10 +109,10 @@ export default {
if (this.isWildcard) {
approvalDetails.push(this.matchingBranchesText);
}
if (this.branchProtection.allowForcePush) {
if (this.branchProtection?.allowForcePush) {
approvalDetails.push(this.$options.i18n.allowForcePush);
}
if (this.branchProtection.codeOwnerApprovalRequired) {
if (this.branchProtection?.codeOwnerApprovalRequired) {
approvalDetails.push(this.$options.i18n.codeOwnerApprovalRequired);
}
if (this.statusChecksTotal) {
@ -154,6 +158,10 @@ export default {
$options.i18n.defaultLabel
}}</gl-badge>
<gl-badge v-if="isProtected" variant="success" size="sm" class="gl-ml-2">{{
$options.i18n.protectedLabel
}}</gl-badge>
<ul v-if="hasApprovalDetails" class="gl-pl-6 gl-mt-2 gl-mb-0 gl-text-gray-500">
<li v-for="(detail, index) in approvalDetails" :key="index">{{ detail }}</li>
</ul>

View File

@ -6,7 +6,15 @@ export default {
};
},
updated() {
this.hasChildren = this.$scopedSlots.default?.()?.some((c) => c.tag);
this.hasChildren = this.checkSlots();
},
mounted() {
this.hasChildren = this.checkSlots();
},
methods: {
checkSlots() {
return this.$scopedSlots.default?.()?.some((c) => c.tag);
},
},
};
</script>

View File

@ -1,5 +1,11 @@
<script>
export default {
components: {
MrSecurityWidget: () =>
import(
'~/vue_merge_request_widget/extensions/security_reports/mr_widget_security_reports.vue'
),
},
props: {
mr: {
type: Object,
@ -8,7 +14,9 @@ export default {
},
computed: {
widgets() {
return [].filter((w) => w);
return [window.gon?.features?.refactorSecurityExtension && 'MrSecurityWidget'].filter(
(w) => w,
);
},
},
};

View File

@ -42,7 +42,8 @@ export default {
*/
value: {
type: Object,
required: true,
required: false,
default: () => ({}),
},
loadingText: {
type: String,
@ -56,7 +57,8 @@ export default {
},
fetchCollapsedData: {
type: Function,
required: true,
required: false,
default: undefined,
},
fetchExpandedData: {
type: Function,
@ -119,6 +121,12 @@ export default {
required: false,
default: null,
},
// When this is provided, the widget will display an error message in the summary section.
hasError: {
type: Boolean,
required: false,
default: false,
},
},
data() {
return {
@ -138,8 +146,17 @@ export default {
summaryStatusIcon() {
return this.summaryError ? this.$options.failedStatusIcon : this.statusIconName;
},
hasActionButtons() {
return this.actionButtons.length > 0 || Boolean(this.$scopedSlots['action-buttons']);
},
},
watch: {
hasError: {
handler(newValue) {
this.summaryError = newValue ? this.errorText : null;
},
immediate: true,
},
isLoading(newValue) {
this.$emit('is-loading', newValue);
},
@ -154,7 +171,9 @@ export default {
this.telemetryHub?.viewed();
try {
await this.fetch(this.fetchCollapsedData, FETCH_TYPE_COLLAPSED);
if (this.fetchCollapsedData) {
await this.fetch(this.fetchCollapsedData, FETCH_TYPE_COLLAPSED);
}
} catch {
this.summaryError = this.errorText;
}
@ -258,7 +277,7 @@ export default {
v-if="helpPopover"
icon="information-o"
:options="helpPopover.options"
:class="{ 'gl-mr-3': actionButtons.length > 0 }"
:class="{ 'gl-mr-3': hasActionButtons }"
>
<template v-if="helpPopover.content">
<p
@ -275,12 +294,14 @@ export default {
>
</template>
</help-popover>
<action-buttons
v-if="actionButtons.length > 0"
:widget="widgetName"
:tertiary-buttons="actionButtons"
@clickedAction="onActionClick"
/>
<slot name="action-buttons">
<action-buttons
v-if="actionButtons.length > 0"
:widget="widgetName"
:tertiary-buttons="actionButtons"
@clickedAction="onActionClick"
/>
</slot>
</div>
<div
v-if="isCollapsible"

View File

@ -1,4 +1,9 @@
import { n__, s__, sprintf } from '~/locale';
import { n__, s__, __, sprintf } from '~/locale';
export const codeQualityPrefixes = {
fixed: 'fixed',
new: 'new',
};
export const i18n = {
label: s__('ciReport|Code Quality'),
@ -7,25 +12,23 @@ export const i18n = {
noChanges: s__(`ciReport|Code Quality hasn't changed.`),
prependText: s__(`ciReport|in`),
fixed: s__(`ciReport|Fixed`),
pluralReport: (errors) =>
findings: (errors, prefix) =>
sprintf(
n__(
'%{strong_start}%{errors}%{strong_end} point',
'%{strong_start}%{errors}%{strong_end} points',
'%{strong_start}%{errors}%{strong_end} %{prefix} finding',
'%{strong_start}%{errors}%{strong_end} %{prefix} findings',
errors.length,
),
{
errors: errors.length,
prefix,
},
false,
),
singularReport: (errors) => n__('%d point', '%d points', errors.length),
improvementAndDegradationCopy: (improvement, degradation) =>
sprintf(
s__(`ciReport|Code Quality improved on ${improvement} and degraded on ${degradation}.`),
),
improvedCopy: (improvements) =>
sprintf(s__(`ciReport|Code Quality improved on ${improvements}.`)),
degradedCopy: (degradations) =>
sprintf(s__(`ciReport|Code Quality degraded on ${degradations}.`)),
sprintf(__('Code Quality scans found %{degradation} and fixed %{improvement}.'), {
improvement,
degradation,
}),
singularCopy: (findings) => sprintf(__('Code Quality scans found %{findings}.'), { findings }),
};

View File

@ -4,7 +4,7 @@ import { SEVERITY_ICONS_MR_WIDGET } from '~/ci/reports/codequality_report/consta
import { HTTP_STATUS_NO_CONTENT } from '~/lib/utils/http_status';
import { parseCodeclimateMetrics } from '~/ci/reports/codequality_report/store/utils/codequality_parser';
import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
import { i18n } from './constants';
import { i18n, codeQualityPrefixes } from './constants';
export default {
name: 'WidgetCodeQuality',
@ -25,13 +25,13 @@ export default {
return i18n.loading;
} else if (newErrors.length >= 1 && resolvedErrors.length >= 1) {
return i18n.improvementAndDegradationCopy(
i18n.pluralReport(resolvedErrors),
i18n.pluralReport(newErrors),
i18n.findings(resolvedErrors, codeQualityPrefixes.fixed),
i18n.findings(newErrors, codeQualityPrefixes.new),
);
} else if (resolvedErrors.length >= 1) {
return i18n.improvedCopy(i18n.singularReport(resolvedErrors));
return i18n.singularCopy(i18n.findings(resolvedErrors, codeQualityPrefixes.fixed));
} else if (newErrors.length >= 1) {
return i18n.degradedCopy(i18n.singularReport(newErrors));
return i18n.singularCopy(i18n.findings(newErrors, codeQualityPrefixes.new));
}
return i18n.noChanges;
},

View File

@ -0,0 +1,28 @@
query securityReportsDownloadPaths(
$projectPath: ID!
$iid: String!
$reportTypes: [SecurityReportTypeEnum!]
) {
project(fullPath: $projectPath) {
id
mergeRequest(iid: $iid) {
id
headPipeline {
id
jobs(securityReportTypes: $reportTypes) {
nodes {
id
name
artifacts {
# eslint-disable-next-line @graphql-eslint/require-id-when-available
nodes {
downloadPath
fileType
}
}
}
}
}
}
}
}

View File

@ -0,0 +1,134 @@
<script>
import { GlDropdown, GlDropdownItem, GlTooltipDirective as GlTooltip } from '@gitlab/ui';
import MrWidget from '~/vue_merge_request_widget/components/widget/widget.vue';
import { helpPagePath } from '~/helpers/help_page_helper';
import { s__, sprintf } from '~/locale';
import { EXTENSION_ICONS } from '~/vue_merge_request_widget/constants';
import securityReportMergeRequestDownloadPathsQuery from './graphql/security_report_merge_request_download_paths.query.graphql';
export default {
name: 'WidgetSecurityReportsCE',
components: {
MrWidget,
GlDropdown,
GlDropdownItem,
},
directives: {
GlTooltip,
},
i18n: {
apiError: s__(
'SecurityReports|Failed to get security report information. Please reload the page or try again later.',
),
scansHaveRun: s__('SecurityReports|Security scans have run'),
},
props: {
mr: {
type: Object,
required: true,
},
},
data() {
return {
hasError: false,
};
},
reportTypes: ['sast', 'secret_detection'],
apollo: {
reportArtifacts: {
query: securityReportMergeRequestDownloadPathsQuery,
variables() {
return {
projectPath: this.mr.targetProjectFullPath,
iid: String(this.mr.iid),
reportTypes: this.$options.reportTypes.map((r) => r.toUpperCase()),
};
},
update(data) {
const artifacts = [];
(data?.project?.mergeRequest?.headPipeline?.jobs?.nodes || []).forEach((reportType) => {
reportType.artifacts?.nodes.forEach((artifact) => {
if (artifact.fileType !== 'TRACE') {
artifacts.push({
name: reportType.name,
id: reportType.id,
path: artifact.downloadPath,
});
}
});
});
return artifacts;
},
error() {
this.hasError = true;
},
},
},
computed: {
artifacts() {
return this.reportArtifacts || [];
},
},
methods: {
handleIsLoading(value) {
this.isLoading = value;
},
artifactText({ name }) {
return sprintf(s__('SecurityReports|Download %{artifactName}'), {
artifactName: name,
});
},
},
widgetHelpPopover: {
options: { title: s__('ciReport|Security scan results') },
content: {
text: s__(
'ciReport|New vulnerabilities are vulnerabilities that the security scan detects in the merge request that are different to existing vulnerabilities in the default branch.',
),
learnMorePath: helpPagePath('user/application_security/index', {
anchor: 'view-security-scan-information-in-merge-requests',
}),
},
},
icons: EXTENSION_ICONS,
};
</script>
<template>
<mr-widget
:has-error="hasError"
:error-text="$options.i18n.apiError"
:status-icon-name="$options.icons.warning"
:widget-name="$options.name"
:is-collapsible="false"
:help-popover="$options.widgetHelpPopover"
:summary="$options.i18n.scansHaveRun"
@is-loading="handleIsLoading"
>
<template v-if="artifacts.length > 0" #action-buttons>
<div class="gl-ml-3">
<gl-dropdown
v-gl-tooltip
icon="download"
size="small"
category="tertiary"
variant="confirm"
right
>
<gl-dropdown-item
v-for="artifact in artifacts"
:key="artifact.path"
:href="artifact.path"
:data-testid="`download-${artifact.name}`"
download
>
{{ artifactText(artifact) }}
</gl-dropdown-item>
</gl-dropdown>
</div>
</template>
</mr-widget>
</template>

View File

@ -15,8 +15,11 @@ import noAccessSvg from '@gitlab/svgs/dist/illustrations/analytics/no-access.svg
import * as Sentry from '@sentry/browser';
import { s__ } from '~/locale';
import { parseBoolean } from '~/lib/utils/common_utils';
import { getParameterByName } from '~/lib/utils/url_utility';
import { getParameterByName, updateHistory, setUrlParams } from '~/lib/utils/url_utility';
import { isPositiveInteger } from '~/lib/utils/number_utils';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { convertToGraphQLId, getIdFromGraphQLId } from '~/graphql_shared/utils';
import { TYPE_WORK_ITEM } from '~/graphql_shared/constants';
import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue';
import {
sprintfWorkItem,
@ -54,6 +57,7 @@ import WorkItemAssignees from './work_item_assignees.vue';
import WorkItemLabels from './work_item_labels.vue';
import WorkItemMilestone from './work_item_milestone.vue';
import WorkItemNotes from './work_item_notes.vue';
import WorkItemDetailModal from './work_item_detail_modal.vue';
export default {
i18n,
@ -84,6 +88,7 @@ export default {
WorkItemMilestone,
WorkItemTree,
WorkItemNotes,
WorkItemDetailModal,
},
mixins: [glFeatureFlagMixin()],
inject: ['fullPath'],
@ -110,11 +115,16 @@ export default {
},
},
data() {
const workItemId = getParameterByName('work_item_id');
return {
error: undefined,
updateError: undefined,
workItem: {},
updateInProgress: false,
modalWorkItemId: isPositiveInteger(workItemId)
? convertToGraphQLId(TYPE_WORK_ITEM, workItemId)
: null,
};
},
apollo: {
@ -299,6 +309,11 @@ export default {
return widgetHierarchy.children.nodes;
},
},
mounted() {
if (this.modalWorkItemId) {
this.openInModal(undefined, { id: this.modalWorkItemId });
}
},
methods: {
isWidgetPresent(type) {
return this.workItem?.widgets?.find((widget) => widget.type === type);
@ -424,6 +439,26 @@ export default {
Sentry.captureException(error);
}
},
updateUrl(modalWorkItemId) {
updateHistory({
url: setUrlParams({ work_item_id: getIdFromGraphQLId(modalWorkItemId) }),
replace: true,
});
},
openInModal(event, modalWorkItem) {
if (event) {
event.preventDefault();
this.updateUrl(modalWorkItem.id);
}
if (this.isModal) {
this.$emit('update-modal', event, modalWorkItem.id);
return;
}
this.modalWorkItemId = modalWorkItem.id;
this.$refs.modal.show();
},
},
WORK_ITEM_TYPE_VALUE_OBJECTIVE,
};
@ -461,6 +496,7 @@ export default {
category="tertiary"
:href="parentUrl"
:title="parentWorkItem.title"
@click="openInModal($event, parentWorkItem)"
>{{ parentWorkItem.title }}</gl-button
>
<gl-icon name="chevron-right" :size="16" class="gl-flex-shrink-0" />
@ -632,6 +668,7 @@ export default {
:confidential="workItem.confidential"
@addWorkItemChild="addChild"
@removeChild="removeChild"
@show-modal="openInModal"
/>
<template v-if="workItemsMvcEnabled">
<work-item-notes
@ -652,5 +689,12 @@ export default {
:svg-path="noAccessSvgPath"
/>
</template>
<work-item-detail-modal
v-if="!isModal"
ref="modal"
:work-item-id="modalWorkItemId"
:show="true"
@close="updateUrl"
/>
</section>
</template>

View File

@ -3,7 +3,6 @@ import { GlAlert, GlModal } from '@gitlab/ui';
import { s__ } from '~/locale';
import deleteWorkItemFromTaskMutation from '../graphql/delete_task_from_work_item.mutation.graphql';
import deleteWorkItemMutation from '../graphql/delete_work_item.mutation.graphql';
import WorkItemDetail from './work_item_detail.vue';
export default {
i18n: {
@ -12,7 +11,7 @@ export default {
components: {
GlAlert,
GlModal,
WorkItemDetail,
WorkItemDetail: () => import('./work_item_detail.vue'),
},
props: {
workItemId: {
@ -46,12 +45,18 @@ export default {
default: null,
},
},
emits: ['workItemDeleted', 'close'],
emits: ['workItemDeleted', 'close', 'update-modal'],
data() {
return {
error: undefined,
updatedWorkItemId: null,
};
},
computed: {
displayedWorkItemId() {
return this.updatedWorkItemId || this.workItemId;
},
},
methods: {
deleteWorkItem() {
if (this.lockVersion != null && this.lineNumberStart && this.lineNumberEnd) {
@ -116,6 +121,7 @@ export default {
});
},
closeModal() {
this.updatedWorkItemId = null;
this.error = '';
this.$emit('close');
},
@ -128,6 +134,10 @@ export default {
show() {
this.$refs.modal.show();
},
updateModal($event, workItemId) {
this.updatedWorkItemId = workItemId;
this.$emit('update-modal', $event, workItemId);
},
},
};
</script>
@ -149,11 +159,12 @@ export default {
<work-item-detail
is-modal
:work-item-parent-id="issueGid"
:work-item-id="workItemId"
:work-item-id="displayedWorkItemId"
:work-item-iid="workItemIid"
class="gl-p-5 gl-mt-n3"
@close="hide"
@deleteWorkItem="deleteWorkItem"
@update-modal="updateModal"
/>
</gl-modal>
</template>

View File

@ -264,6 +264,7 @@ export default {
:work-item-type="workItemType"
:children="children"
@removeChild="fetchChildren"
@click="$emit('click', $event)"
/>
</div>
</template>

View File

@ -251,6 +251,7 @@ export default {
@mouseover="prefetchWorkItem(child)"
@mouseout="clearPrefetching"
@removeChild="$emit('removeChild', $event)"
@click="$emit('show-modal', $event, $event.childItem || child)"
/>
</div>
</div>

View File

@ -63,6 +63,7 @@ export default {
:child-item="child"
:work-item-type="workItemType"
@removeChild="updateWorkItem"
@click="$emit('click', Object.assign($event, { childItem: child }))"
/>
</div>
</template>

View File

@ -236,7 +236,7 @@ module ApplicationHelper
end
def instance_review_permitted?
::Gitlab::CurrentSettings.instance_review_permitted? && current_user&.admin?
::Gitlab::CurrentSettings.instance_review_permitted? && current_user&.can_read_all_resources?
end
def static_objects_external_storage_enabled?

View File

@ -62,7 +62,7 @@ module ImportHelper
def import_configure_github_admin_message
github_integration_link = link_to 'GitHub integration', help_page_path('integration/github')
if current_user.admin?
if current_user.can_admin_all_resources?
_('Note: As an administrator you may like to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token.').html_safe % { github_integration_link: github_integration_link }
else
_('Note: Consider asking your GitLab administrator to configure %{github_integration_link}, which will allow login via GitHub and allow importing repositories without generating a Personal Access Token.').html_safe % { github_integration_link: github_integration_link }

View File

@ -520,7 +520,7 @@ module ProjectsHelper
end
def configure_oauth_import_message(provider, help_url)
str = if current_user.admin?
str = if current_user.can_admin_all_resources?
'ImportProjects|To enable importing projects from %{provider}, as administrator you need to configure %{link_start}OAuth integration%{link_end}'
else
'ImportProjects|To enable importing projects from %{provider}, ask your GitLab administrator to configure %{link_start}OAuth integration%{link_end}'
@ -658,7 +658,7 @@ module ProjectsHelper
end
def restricted_levels
return [] if current_user.admin?
return [] if current_user.can_admin_all_resources?
Gitlab::CurrentSettings.restricted_visibility_levels || []
end

View File

@ -49,7 +49,7 @@ module SearchHelper
search_pattern = Regexp.new(Regexp.escape(term), "i")
generic_results = project_autocomplete + default_autocomplete + help_autocomplete
generic_results.concat(default_autocomplete_admin) if current_user.admin?
generic_results.concat(default_autocomplete_admin) if current_user.can_read_all_resources?
generic_results.select { |result| result[:label] =~ search_pattern }
end

View File

@ -49,7 +49,7 @@ module Users
def show_registration_enabled_user_callout?
!Gitlab.com? &&
current_user&.admin? &&
current_user&.can_admin_all_resources? &&
signup_enabled? &&
!user_dismissed?(REGISTRATION_ENABLED_CALLOUT) &&
REGISTRATION_ENABLED_CALLOUT_ALLOWED_CONTROLLER_PATHS.any? { |path| controller.controller_path.match?(path) }
@ -59,7 +59,7 @@ module Users
end
def show_security_newsletter_user_callout?
current_user&.admin? &&
current_user&.can_admin_all_resources? &&
!user_dismissed?(SECURITY_NEWSLETTER_CALLOUT)
end

View File

@ -93,7 +93,7 @@ module UsersHelper
def user_badges_in_admin_section(user)
[].tap do |badges|
badges << blocked_user_badge(user) if user.blocked?
badges << { text: s_('AdminUsers|Admin'), variant: 'success' } if user.admin?
badges << { text: s_('AdminUsers|Admin'), variant: 'success' } if user.admin? # rubocop:disable Cop/UserAdmin
badges << { text: s_('AdminUsers|Bot'), variant: 'muted' } if user.bot?
badges << { text: s_('AdminUsers|External'), variant: 'secondary' } if user.external?
badges << { text: s_("AdminUsers|It's you!"), variant: 'muted' } if current_user == user

View File

@ -39,7 +39,7 @@ module VisibilityLevelHelper
end
def restricted_visibility_levels(show_all = false)
return [] if current_user.admin? && !show_all
return [] if current_user.can_admin_all_resources? && !show_all
Gitlab::CurrentSettings.restricted_visibility_levels || []
end

View File

@ -118,6 +118,7 @@ the other way around.
sudo gitlab-ctl start postgresql
sudo -u gitlab-psql /opt/gitlab/embedded/bin/psql -h /var/opt/gitlab/postgresql -d template1 -c "CREATE DATABASE gitlabhq_production_ci OWNER gitlab;"
sudo gitlab-rake db:schema:load:ci
```
1. Lock writes for `ci` tables in `main` database, and the other way around:

View File

@ -217,7 +217,7 @@ GET /groups/:id/descendant_groups
{
"id": 2,
"name": "Bar Group",
"path": "foo/bar",
"path": "bar",
"description": "A subgroup of Foo Group",
"visibility": "public",
"share_with_group_lock": false,
@ -242,7 +242,7 @@ GET /groups/:id/descendant_groups
{
"id": 3,
"name": "Baz Group",
"path": "foo/bar/baz",
"path": "baz",
"description": "A subgroup of Bar Group",
"visibility": "public",
"share_with_group_lock": false,
@ -1025,7 +1025,7 @@ Example response:
"web_url": "http://gitlab.example.com/groups/h5bp",
"request_access_enabled": false,
"full_name": "Foobar Group",
"full_path": "foo-bar",
"full_path": "h5bp",
"file_template_project_id": 1,
"parent_id": null,
"created_at": "2020-01-15T12:36:29.590Z",

View File

@ -134,6 +134,24 @@ For best experience with any systems made of components it's fundamental that co
The version identifies the exact interface and behavior of the component.
- **Resolvable**: when a component depends on another component, this dependency must be explicit and trackable.
### Predictable components
Eventually, we want to make CI Catalog Components predictable. Including a
component by its path, using a fixed `@` version, should always return the same
configuration, regardless of a context from which it is getting included from.
The resulting configuration should be the same for a given component version
and the set of inputs passed using `with:` keyword, hence it should be
[deterministic](https://en.wikipedia.org/wiki/Deterministic_algorithm).
A component should not produce side effects by being included and should be
[referentially transparent](https://en.wikipedia.org/wiki/Referential_transparency).
Making components predictable is a process, and we may not be able to achieve
this without significantly redesigning CI templates, what could be disruptive
for users and customers right now. The predictability, determinism, referential
transparency and making CI components predictable is still important for us,
but we may be unable to achieve it early iterations.
## Structure of a component
A pipeline component is identified by the path to a repository or directory that defines it
@ -143,7 +161,8 @@ For example: `gitlab-org/dast@1.0`.
### The component path
A component path must contain at least the component YAML and optionally a related `README.md` documentation file.
A component path must contain at least the component YAML and optionally a
related `README.md` documentation file.
The component path can be:

View File

@ -216,9 +216,10 @@ The cost factors on self-managed instances are:
#### Cost factor for community contributions to GitLab projects
Community contributors can use up to 300,000 minutes on shared runners when
contributing to open source projects maintained by GitLab. The 300,000
minutes applies to all SaaS tiers, and the cost factor calculation is:
Community contributors can use up to 300,000 minutes on shared runners when contributing to open source projects
maintained by GitLab. The maximum of 300,000 minutes would only be possible if contributing exclusively to projects [part of the GitLab product](https://about.gitlab.com/handbook/engineering/metrics/#projects-that-are-part-of-the-product). The total number of minutes available on shared runners
is reduced by the CI/CD minutes used by pipelines from other projects.
The 300,000 minutes applies to all SaaS tiers, and the cost factor calculation is:
- `Monthly minute quota / 300,000 job duration minutes = Cost factor`

View File

@ -967,6 +967,23 @@ To determine which runners need to be upgraded:
1. Filter the list by status to view which individual runners need to be upgraded.
## View statistics for runner performance **(ULTIMATE)**
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/377963) in GitLab 15.8.
As an administrator, you can view runner statistics to learn about the runner fleet performance.
1. Select **Main menu > Admin** and on the left sidebar, select **CI/CD > Runners**.
1. Select **View metrics** under **Runners performance**.
The **Median job queued time** value is calculated by sampling the queue duration of the
most recent 100 jobs that were run by Instance runners. Jobs from only the latest 5000
runners are considered.
The median is a value that falls into the 50th percentile: half of the jobs
queued for longer than the median value, and half of the jobs queued for less than the
median value.
## Authentication token security
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/30942) in GitLab 15.3 [with a flag](../../administration/feature_flags.md) named `enforce_runner_token_expires_at`. Disabled by default.

View File

@ -6,7 +6,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Value Streams Dashboard **(PREMIUM)**
> Introduced in GitLab 15.8 as a [Closed Beta](https://about.gitlab.com/handbook/product/gitlab-the-product/#closed-beta) feature.
> Introduced in GitLab 15.8 as a Closed [Beta](../../policy/alpha-beta-support.md#beta-features) feature.
You can leave feedback on dashboard bugs or functionality in [issue 381787](https://gitlab.com/gitlab-org/gitlab/-/issues/381787).
@ -31,7 +31,7 @@ The Value Streams Dashboard allows you to:
- Aggregate data records from different APIs.
- Track software performance (DORA) and flow of value (VSA) across the organization.
## DevSecOps metrics comparison
## DevOps metrics comparison
The DevOps metrics comparison displays DORA4 and flow metrics for a group or project in the
month-to-date, last month, the month before, and the past 180 days.
@ -59,4 +59,3 @@ For example, the parameter `query=gitlab-org/gitlab-foss,gitlab-org/gitlab,gitla
- `gitlab-org` group
- `gitlab-ui` project
- `gitlab-org/plan-stage` subgroup
- Select which groups, subgroups, or projects to display on the page. Each of them has its own widget.

View File

@ -6,9 +6,16 @@ info: To determine the technical writer assigned to the Stage/Group associated w
# Free user limit **(FREE SAAS)**
A five-user limit applies to top-level [namespaces](namespace/index.md) with private visibility on GitLab SaaS. This limit is being rolled out gradually, and impacted users will be notified in GitLab.com at least 60 days before the limit is applied.
A five-user limit applies to newly created top-level namespaces with
private visibility on GitLab SaaS. For existing namespaces, this limit
is being rolled out gradually. Impacted users are notified in
GitLab.com at least 60 days before the limit is applied.
When the five-user limit is applied, top-level private namespaces exceeding the user limit are placed in a read-only state. These namespaces cannot write new data to repositories, Git Large File Storage (LFS), packages, or registries.
When the five-user limit is applied, top-level private namespaces
exceeding the user limit are placed in a read-only state. These
namespaces cannot write new data to repositories, Git Large File
Storage (LFS), packages, or registries. For the full list of restricted
actions, see [Read-only namespaces](read_only_namespaces.md).
## Manage members in your namespace

View File

@ -40,6 +40,9 @@ module API
end
def source_members(source)
return source.namespace_members if source.is_a?(Project) &&
Feature.enabled?(:project_members_index_by_project_namespace, source)
source.members
end
# rubocop: enable CodeReuse/ActiveRecord

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -358,11 +358,6 @@ msgid_plural "%d personal projects will be removed and cannot be restored."
msgstr[0] ""
msgstr[1] ""
msgid "%d point"
msgid_plural "%d points"
msgstr[0] ""
msgstr[1] ""
msgid "%d previously merged commit"
msgid_plural "%d previously merged commits"
msgstr[0] ""
@ -1094,8 +1089,8 @@ msgid_plural "%{strong_start}%{count} members%{strong_end} must approve to merge
msgstr[0] ""
msgstr[1] ""
msgid "%{strong_start}%{errors}%{strong_end} point"
msgid_plural "%{strong_start}%{errors}%{strong_end} points"
msgid "%{strong_start}%{errors}%{strong_end} %{prefix} finding"
msgid_plural "%{strong_start}%{errors}%{strong_end} %{prefix} findings"
msgstr[0] ""
msgstr[1] ""
@ -7110,6 +7105,9 @@ msgstr ""
msgid "BranchRules|default"
msgstr ""
msgid "BranchRules|protected"
msgstr ""
msgid "Branches"
msgstr ""
@ -9844,6 +9842,12 @@ msgstr ""
msgid "Code Quality"
msgstr ""
msgid "Code Quality scans found %{degradation} and fixed %{improvement}."
msgstr ""
msgid "Code Quality scans found %{findings}."
msgstr ""
msgid "Code Review"
msgstr ""
@ -24665,6 +24669,9 @@ msgstr ""
msgid "LearnGitlab|- Included in trial"
msgstr ""
msgid "LearnGitlab|Contact your administrator to enable this action."
msgstr ""
msgid "LearnGitlab|Contact your administrator to start a free Ultimate trial."
msgstr ""
@ -36041,6 +36048,11 @@ msgid_plural "Runners|%d selected runners deleted"
msgstr[0] ""
msgstr[1] ""
msgid "Runners|%{highlightStart}%{duration}%{highlightEnd} second"
msgid_plural "Runners|%{highlightStart}%{duration}%{highlightEnd} seconds"
msgstr[0] ""
msgstr[1] ""
msgid "Runners|%{link_start}These runners%{link_end} are available to all groups and projects."
msgstr ""
@ -36230,6 +36242,9 @@ msgstr ""
msgid "Runners|Instance"
msgstr ""
msgid "Runners|Instance: Median job queued time"
msgstr ""
msgid "Runners|Jobs"
msgstr ""
@ -36412,6 +36427,9 @@ msgstr ""
msgid "Runners|Runner is stale; last contact was %{timeAgo}"
msgstr ""
msgid "Runners|Runner performance insights"
msgstr ""
msgid "Runners|Runner registration"
msgstr ""
@ -36433,6 +36451,9 @@ msgstr ""
msgid "Runners|Runners are the agents that run your CI/CD jobs. To register new runners, please contact your administrator."
msgstr ""
msgid "Runners|Runners performance"
msgstr ""
msgid "Runners|Running"
msgstr ""
@ -36522,6 +36543,9 @@ msgstr ""
msgid "Runners|Token expiry"
msgstr ""
msgid "Runners|Understand how long it takes for runners to pick up a job. %{linkStart}How is this calculated?%{linkEnd}"
msgstr ""
msgid "Runners|Unselect all"
msgstr ""
@ -36564,6 +36588,9 @@ msgstr ""
msgid "Runners|View installation instructions"
msgstr ""
msgid "Runners|View metrics"
msgstr ""
msgid "Runners|Windows 2019 Shell with manual scaling and optional scheduling. %{percentage} spot."
msgstr ""

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More