Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
14b71b2795
commit
fbf183eebe
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
7144bcd52a6b8c745bf90af812a78426384ac535
|
||||
522c0d9283f757583fcfd43e66b4d5b323503bc0
|
||||
|
|
|
|||
2
Gemfile
2
Gemfile
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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"},
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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 {
|
||||
|
|
@ -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(
|
||||
|
|
@ -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(
|
||||
|
|
@ -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(
|
||||
|
|
@ -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(
|
||||
|
|
@ -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!
|
||||
|
|
@ -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!
|
||||
|
|
@ -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!) {
|
||||
|
|
@ -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!) {
|
||||
|
|
@ -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) {
|
||||
|
|
@ -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,
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
|
|
@ -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">
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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 }),
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
},
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -264,6 +264,7 @@ export default {
|
|||
:work-item-type="workItemType"
|
||||
:children="children"
|
||||
@removeChild="fetchChildren"
|
||||
@click="$emit('click', $event)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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?
|
||||
|
|
|
|||
|
|
@ -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 }
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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",
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
||||
|
|
|
|||
|
|
@ -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`
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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
1430
locale/bg/gitlab.po
1430
locale/bg/gitlab.po
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
1504
locale/de/gitlab.po
1504
locale/de/gitlab.po
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
1430
locale/eo/gitlab.po
1430
locale/eo/gitlab.po
File diff suppressed because it is too large
Load Diff
1448
locale/es/gitlab.po
1448
locale/es/gitlab.po
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
3788
locale/fr/gitlab.po
3788
locale/fr/gitlab.po
File diff suppressed because it is too large
Load Diff
|
|
@ -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
Loading…
Reference in New Issue