Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
e69d400913
commit
7564f3f38f
|
|
@ -15,7 +15,7 @@ include:
|
||||||
gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE"
|
gitlab_auth_token_variable_name: "PROJECT_TOKEN_FOR_CI_SCRIPTS_API_USAGE"
|
||||||
allure_job_name: "${QA_RUN_TYPE}"
|
allure_job_name: "${QA_RUN_TYPE}"
|
||||||
- project: gitlab-org/quality/pipeline-common
|
- project: gitlab-org/quality/pipeline-common
|
||||||
ref: 8.4.3
|
ref: 8.4.4
|
||||||
file:
|
file:
|
||||||
- /ci/base.gitlab-ci.yml
|
- /ci/base.gitlab-ci.yml
|
||||||
- /ci/knapsack-report.yml
|
- /ci/knapsack-report.yml
|
||||||
|
|
|
||||||
|
|
@ -4025,7 +4025,6 @@ RSpec/FeatureCategory:
|
||||||
- 'spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb'
|
- 'spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb'
|
||||||
- 'spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb'
|
- 'spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb'
|
||||||
- 'spec/lib/gitlab/usage_data_counters/search_counter_spec.rb'
|
- 'spec/lib/gitlab/usage_data_counters/search_counter_spec.rb'
|
||||||
- 'spec/lib/gitlab/usage_data_counters/service_usage_data_counter_spec.rb'
|
|
||||||
- 'spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb'
|
- 'spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb'
|
||||||
- 'spec/lib/gitlab/usage_data_counters/source_code_counter_spec.rb'
|
- 'spec/lib/gitlab/usage_data_counters/source_code_counter_spec.rb'
|
||||||
- 'spec/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter_spec.rb'
|
- 'spec/lib/gitlab/usage_data_counters/vscode_extension_activity_unique_counter_spec.rb'
|
||||||
|
|
|
||||||
|
|
@ -516,7 +516,6 @@ Style/ClassAndModuleChildren:
|
||||||
- 'lib/gitlab/usage_data_counters/designs_counter.rb'
|
- 'lib/gitlab/usage_data_counters/designs_counter.rb'
|
||||||
- 'lib/gitlab/usage_data_counters/note_counter.rb'
|
- 'lib/gitlab/usage_data_counters/note_counter.rb'
|
||||||
- 'lib/gitlab/usage_data_counters/productivity_analytics_counter.rb'
|
- 'lib/gitlab/usage_data_counters/productivity_analytics_counter.rb'
|
||||||
- 'lib/gitlab/usage_data_counters/service_usage_data_counter.rb'
|
|
||||||
- 'lib/gitlab/usage_data_counters/snippet_counter.rb'
|
- 'lib/gitlab/usage_data_counters/snippet_counter.rb'
|
||||||
- 'lib/gitlab/usage_data_counters/source_code_counter.rb'
|
- 'lib/gitlab/usage_data_counters/source_code_counter.rb'
|
||||||
- 'lib/gitlab/usage_data_counters/wiki_page_counter.rb'
|
- 'lib/gitlab/usage_data_counters/wiki_page_counter.rb'
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,92 @@
|
||||||
|
<script>
|
||||||
|
import { GlButton } from '@gitlab/ui';
|
||||||
|
import { __, s__ } from '~/locale';
|
||||||
|
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||||
|
import { DEFAULT_PER_PAGE } from '~/api';
|
||||||
|
import { createAlert } from '~/alert';
|
||||||
|
import organizationsQuery from '../graphql/queries/organizations.query.graphql';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
name: 'AdminOrganizationsIndexApp',
|
||||||
|
i18n: {
|
||||||
|
pageTitle: __('Organizations'),
|
||||||
|
newOrganization: s__('Organization|New organization'),
|
||||||
|
errorMessage: s__(
|
||||||
|
'Organization|An error occurred loading organizations. Please refresh the page to try again.',
|
||||||
|
),
|
||||||
|
},
|
||||||
|
components: { GlButton, OrganizationsView },
|
||||||
|
inject: ['newOrganizationUrl'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
organizations: {},
|
||||||
|
pagination: {
|
||||||
|
first: DEFAULT_PER_PAGE,
|
||||||
|
after: null,
|
||||||
|
last: null,
|
||||||
|
before: null,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
},
|
||||||
|
apollo: {
|
||||||
|
organizations: {
|
||||||
|
query: organizationsQuery,
|
||||||
|
variables() {
|
||||||
|
return this.pagination;
|
||||||
|
},
|
||||||
|
update(data) {
|
||||||
|
return data.organizations;
|
||||||
|
},
|
||||||
|
error(error) {
|
||||||
|
createAlert({ message: this.$options.i18n.errorMessage, error, captureError: true });
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showHeader() {
|
||||||
|
return this.loading || this.organizations.nodes?.length;
|
||||||
|
},
|
||||||
|
loading() {
|
||||||
|
return this.$apollo.queries.organizations.loading;
|
||||||
|
},
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
onNext(endCursor) {
|
||||||
|
this.pagination = {
|
||||||
|
first: DEFAULT_PER_PAGE,
|
||||||
|
after: endCursor,
|
||||||
|
last: null,
|
||||||
|
before: null,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
onPrev(startCursor) {
|
||||||
|
this.pagination = {
|
||||||
|
first: null,
|
||||||
|
after: null,
|
||||||
|
last: DEFAULT_PER_PAGE,
|
||||||
|
before: startCursor,
|
||||||
|
};
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="gl-py-6">
|
||||||
|
<div
|
||||||
|
v-if="showHeader"
|
||||||
|
class="gl-display-flex gl-align-items-center gl-justify-content-space-between gl-mb-5"
|
||||||
|
>
|
||||||
|
<h1 class="gl-m-0 gl-font-size-h-display">{{ $options.i18n.pageTitle }}</h1>
|
||||||
|
<gl-button :href="newOrganizationUrl" variant="confirm">{{
|
||||||
|
$options.i18n.newOrganization
|
||||||
|
}}</gl-button>
|
||||||
|
</div>
|
||||||
|
<organizations-view
|
||||||
|
:organizations="organizations"
|
||||||
|
:loading="loading"
|
||||||
|
@next="onNext"
|
||||||
|
@prev="onPrev"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
#import "~/graphql_shared/fragments/page_info.fragment.graphql"
|
||||||
|
#import "~/organizations/shared/graphql/fragments/organization.fragment.graphql"
|
||||||
|
|
||||||
|
query getOrganizations($first: Int, $last: Int, $before: String, $after: String) {
|
||||||
|
organizations(first: $first, last: $last, before: $before, after: $after) {
|
||||||
|
nodes {
|
||||||
|
...Organization
|
||||||
|
}
|
||||||
|
pageInfo {
|
||||||
|
...PageInfo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import Vue from 'vue';
|
||||||
|
import VueApollo from 'vue-apollo';
|
||||||
|
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
|
||||||
|
import createDefaultClient from '~/lib/graphql';
|
||||||
|
import App from './components/app.vue';
|
||||||
|
|
||||||
|
export const initAdminOrganizationsIndex = () => {
|
||||||
|
const el = document.getElementById('js-admin-organizations-index');
|
||||||
|
|
||||||
|
if (!el) return false;
|
||||||
|
|
||||||
|
const {
|
||||||
|
dataset: { appData },
|
||||||
|
} = el;
|
||||||
|
const { newOrganizationUrl, organizationsEmptyStateSvgPath } = convertObjectPropsToCamelCase(
|
||||||
|
JSON.parse(appData),
|
||||||
|
);
|
||||||
|
|
||||||
|
const apolloProvider = new VueApollo({
|
||||||
|
defaultClient: createDefaultClient(),
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Vue({
|
||||||
|
el,
|
||||||
|
name: 'AdminOrganizationIndexRoot',
|
||||||
|
apolloProvider,
|
||||||
|
provide: {
|
||||||
|
newOrganizationUrl,
|
||||||
|
organizationsEmptyStateSvgPath,
|
||||||
|
},
|
||||||
|
render(createElement) {
|
||||||
|
return createElement(App);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
@ -31,6 +31,16 @@ export default {
|
||||||
headingDescription: s__(
|
headingDescription: s__(
|
||||||
'Runners|After you complete the steps below, an autoscaling fleet of runners is available to execute your CI/CD jobs in Google Cloud. Based on demand, a runner manager automatically creates temporary runners.',
|
'Runners|After you complete the steps below, an autoscaling fleet of runners is available to execute your CI/CD jobs in Google Cloud. Based on demand, a runner manager automatically creates temporary runners.',
|
||||||
),
|
),
|
||||||
|
beforeHeading: s__('Runners|Before you begin'),
|
||||||
|
permissionsText: s__(
|
||||||
|
'Runners|Ensure you have the %{linkStart}Owner%{linkEnd} IAM role on your Google Cloud project.',
|
||||||
|
),
|
||||||
|
billingLinkText: s__(
|
||||||
|
'Runners|Ensure that %{linkStart}billing is enabled for your Google Cloud project%{linkEnd}.',
|
||||||
|
),
|
||||||
|
preInstallText: s__(
|
||||||
|
'Runners|To follow the setup instructions, %{gcloudLinkStart}install the Google Cloud CLI%{gcloudLinkEnd} and %{terraformLinkStart}install Terraform%{terraformLinkEnd}.',
|
||||||
|
),
|
||||||
stepOneHeading: s__('Runners|Step 1: Specify environment'),
|
stepOneHeading: s__('Runners|Step 1: Specify environment'),
|
||||||
stepOneDescription: s__(
|
stepOneDescription: s__(
|
||||||
'Runners|Environment in Google Cloud where runners execute CI/CD jobs. Runners are created in temporary virtual machines based on demand.',
|
'Runners|Environment in Google Cloud where runners execute CI/CD jobs. Runners are created in temporary virtual machines based on demand.',
|
||||||
|
|
@ -86,8 +96,14 @@ export default {
|
||||||
},
|
},
|
||||||
alertBody: s__('Runners|To view the setup instructions, complete the previous form'),
|
alertBody: s__('Runners|To view the setup instructions, complete the previous form'),
|
||||||
invalidFormButton: s__('Runners|Go to first invalid form field'),
|
invalidFormButton: s__('Runners|Go to first invalid form field'),
|
||||||
|
externalLink: __('(external link)'),
|
||||||
},
|
},
|
||||||
links: {
|
links: {
|
||||||
|
permissionsLink: 'https://cloud.google.com/iam/docs/understanding-roles#owner',
|
||||||
|
billingLink:
|
||||||
|
'https://cloud.google.com/billing/docs/how-to/verify-billing-enabled#confirm_billing_is_enabled_on_a_project',
|
||||||
|
gcloudLink: 'https://cloud.google.com/sdk/docs/install',
|
||||||
|
terraformLink: 'https://developer.hashicorp.com/terraform/install',
|
||||||
projectIdLink:
|
projectIdLink:
|
||||||
'https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects',
|
'https://cloud.google.com/resource-manager/docs/creating-managing-projects#identifying_projects',
|
||||||
regionAndZonesLink: 'https://cloud.google.com/compute/docs/regions-zones',
|
regionAndZonesLink: 'https://cloud.google.com/compute/docs/regions-zones',
|
||||||
|
|
@ -309,6 +325,51 @@ export default {
|
||||||
</div>
|
</div>
|
||||||
<hr />
|
<hr />
|
||||||
|
|
||||||
|
<!-- start: before you begin -->
|
||||||
|
<div>
|
||||||
|
<h2 class="gl-font-lg">{{ $options.i18n.beforeHeading }}</h2>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<gl-sprintf :message="$options.i18n.permissionsText">
|
||||||
|
<template #link="{ content }">
|
||||||
|
<gl-link :href="$options.links.permissionsLink" target="_blank">
|
||||||
|
{{ content }}
|
||||||
|
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||||
|
</gl-link>
|
||||||
|
</template>
|
||||||
|
</gl-sprintf>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<gl-sprintf :message="$options.i18n.billingLinkText">
|
||||||
|
<template #link="{ content }">
|
||||||
|
<gl-link :href="$options.links.billingLink" target="_blank">
|
||||||
|
{{ content }}
|
||||||
|
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||||
|
</gl-link>
|
||||||
|
</template>
|
||||||
|
</gl-sprintf>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<gl-sprintf :message="$options.i18n.preInstallText">
|
||||||
|
<template #gcloudLink="{ content }">
|
||||||
|
<gl-link :href="$options.links.gcloudLink" target="_blank">
|
||||||
|
{{ content }}
|
||||||
|
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||||
|
</gl-link>
|
||||||
|
</template>
|
||||||
|
<template #terraformLink="{ content }">
|
||||||
|
<gl-link :href="$options.links.terraformLink" target="_blank">
|
||||||
|
{{ content }}
|
||||||
|
<gl-icon name="external-link" :aria-label="$options.i18n.externalLink" />
|
||||||
|
</gl-link>
|
||||||
|
</template>
|
||||||
|
</gl-sprintf>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
<hr />
|
||||||
|
<!-- end: before you begin -->
|
||||||
|
|
||||||
<!-- start: step one -->
|
<!-- start: step one -->
|
||||||
<div class="gl-pb-4">
|
<div class="gl-pb-4">
|
||||||
<h2 class="gl-font-lg">{{ $options.i18n.stepOneHeading }}</h2>
|
<h2 class="gl-font-lg">{{ $options.i18n.stepOneHeading }}</h2>
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import { EditorContent as TiptapEditorContent } from '@tiptap/vue-2';
|
||||||
import { __ } from '~/locale';
|
import { __ } from '~/locale';
|
||||||
import { VARIANT_DANGER } from '~/alert';
|
import { VARIANT_DANGER } from '~/alert';
|
||||||
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
|
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
|
||||||
import { CONTENT_EDITOR_READY_EVENT } from '~/vue_shared/constants';
|
import { CONTENT_EDITOR_READY_EVENT, CONTENT_EDITOR_PASTE } from '~/vue_shared/constants';
|
||||||
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
|
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||||
import SidebarMediator from '~/sidebar/sidebar_mediator';
|
import SidebarMediator from '~/sidebar/sidebar_mediator';
|
||||||
import { createContentEditor } from '../services/create_content_editor';
|
import { createContentEditor } from '../services/create_content_editor';
|
||||||
|
|
@ -169,11 +169,16 @@ export default {
|
||||||
this.$emit('initialized');
|
this.$emit('initialized');
|
||||||
await this.setSerializedContent(this.markdown);
|
await this.setSerializedContent(this.markdown);
|
||||||
markdownEditorEventHub.$emit(CONTENT_EDITOR_READY_EVENT);
|
markdownEditorEventHub.$emit(CONTENT_EDITOR_READY_EVENT);
|
||||||
|
markdownEditorEventHub.$on(CONTENT_EDITOR_PASTE, this.pasteContent);
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
|
markdownEditorEventHub.$off(CONTENT_EDITOR_PASTE, this.pasteContent);
|
||||||
this.contentEditor.dispose();
|
this.contentEditor.dispose();
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
pasteContent(content) {
|
||||||
|
this.contentEditor.tiptapEditor.chain().focus().pasteContent(content).run();
|
||||||
|
},
|
||||||
async setSerializedContent(markdown) {
|
async setSerializedContent(markdown) {
|
||||||
this.notifyLoading();
|
this.notifyLoading();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ import { GlButton } from '@gitlab/ui';
|
||||||
import { __, s__ } from '~/locale';
|
import { __, s__ } from '~/locale';
|
||||||
import { createAlert } from '~/alert';
|
import { createAlert } from '~/alert';
|
||||||
import { DEFAULT_PER_PAGE } from '~/api';
|
import { DEFAULT_PER_PAGE } from '~/api';
|
||||||
|
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||||
import organizationsQuery from '../../shared/graphql/queries/organizations.query.graphql';
|
import organizationsQuery from '../../shared/graphql/queries/organizations.query.graphql';
|
||||||
import OrganizationsView from './organizations_view.vue';
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'OrganizationsIndexApp',
|
name: 'OrganizationsIndexApp',
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,16 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlAvatarLabeled, GlTruncateText } from '@gitlab/ui';
|
import { GlAvatarLabeled, GlTruncateText } from '@gitlab/ui';
|
||||||
|
import { __ } from '~/locale';
|
||||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||||
import SafeHtml from '~/vue_shared/directives/safe_html';
|
import SafeHtml from '~/vue_shared/directives/safe_html';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'OrganizationsListItem',
|
name: 'OrganizationsListItem',
|
||||||
|
i18n: {
|
||||||
|
showMore: __('Show more'),
|
||||||
|
showLess: __('Show less'),
|
||||||
|
},
|
||||||
|
truncateTextToggleButtonProps: { class: 'gl-font-sm!' },
|
||||||
components: {
|
components: {
|
||||||
GlAvatarLabeled,
|
GlAvatarLabeled,
|
||||||
GlTruncateText,
|
GlTruncateText,
|
||||||
|
|
@ -21,17 +27,20 @@ export default {
|
||||||
required: true,
|
required: true,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
avatarSize: { default: 32, md: 48 },
|
methods: {
|
||||||
getIdFromGraphQLId,
|
getIdFromGraphQLId,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<li class="organization-row gl-py-3 gl-border-b gl-display-flex gl-align-items-flex-start">
|
<li
|
||||||
|
class="organization-row gl-py-5 gl-px-5 gl-border-b gl-display-flex gl-align-items-flex-start"
|
||||||
|
>
|
||||||
<gl-avatar-labeled
|
<gl-avatar-labeled
|
||||||
:size="$options.avatarSize"
|
:size="48"
|
||||||
:src="organization.avatarUrl"
|
:src="organization.avatarUrl"
|
||||||
:entity-id="$options.getIdFromGraphQLId(organization.id)"
|
:entity-id="getIdFromGraphQLId(organization.id)"
|
||||||
:entity-name="organization.name"
|
:entity-name="organization.name"
|
||||||
:label="organization.name"
|
:label="organization.name"
|
||||||
:label-link="organization.webUrl"
|
:label-link="organization.webUrl"
|
||||||
|
|
@ -41,12 +50,15 @@ export default {
|
||||||
v-if="organization.descriptionHtml"
|
v-if="organization.descriptionHtml"
|
||||||
:lines="2"
|
:lines="2"
|
||||||
:mobile-lines="2"
|
:mobile-lines="2"
|
||||||
class="gl-mt-2"
|
:show-more-text="$options.i18n.showMore"
|
||||||
|
:show-less-text="$options.i18n.showLess"
|
||||||
|
:toggle-button-props="$options.truncateTextToggleButtonProps"
|
||||||
|
class="gl-mt-2 gl-max-w-88"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-safe-html:[$options.safeHtmlConfig]="organization.descriptionHtml"
|
v-safe-html:[$options.safeHtmlConfig]="organization.descriptionHtml"
|
||||||
data-testid="organization-description-html"
|
data-testid="organization-description-html"
|
||||||
class="organization-description gl-text-secondary gl-font-sm"
|
class="gl-text-secondary gl-font-sm md"
|
||||||
></div>
|
></div>
|
||||||
</gl-truncate-text>
|
</gl-truncate-text>
|
||||||
</gl-avatar-labeled>
|
</gl-avatar-labeled>
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script>
|
<script>
|
||||||
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
|
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
|
||||||
import { s__ } from '~/locale';
|
import { s__ } from '~/locale';
|
||||||
import OrganizationsList from './organizations_list.vue';
|
import OrganizationsList from './list/organizations_list.vue';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'OrganizationsView',
|
name: 'OrganizationsView',
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
import initUsageQuotas from '~/usage_quotas';
|
import initUsageQuotas from '~/usage_quotas';
|
||||||
|
import { GROUP_VIEW_TYPE } from '~/usage_quotas/constants';
|
||||||
|
|
||||||
initUsageQuotas();
|
initUsageQuotas(GROUP_VIEW_TYPE);
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ export default {
|
||||||
:key="tab.hash"
|
:key="tab.hash"
|
||||||
:title="tab.title"
|
:title="tab.title"
|
||||||
:active="isActive(tab.hash)"
|
:active="isActive(tab.hash)"
|
||||||
|
:data-testid="tab.hash"
|
||||||
@click="updateActiveTab(tab.hash)"
|
@click="updateActiveTab(tab.hash)"
|
||||||
>
|
>
|
||||||
<component :is="tab.component" :data-testid="`${tab.hash}-app`" />
|
<component :is="tab.component" :data-testid="`${tab.hash}-app`" />
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
export const GROUP_VIEW_TYPE = 'group_view';
|
export const GROUP_VIEW_TYPE = 'group_view';
|
||||||
export const PROJECT_VIEW_TYPE = 'project_view';
|
export const PROJECT_VIEW_TYPE = 'project_view';
|
||||||
|
export const PROFILE_VIEW_TYPE = 'profile_view';
|
||||||
|
|
||||||
export const STORAGE_TAB_METADATA_EL_SELECTOR = '#js-namespace-storage-app';
|
export const STORAGE_TAB_METADATA_EL_SELECTOR = '#js-namespace-storage-app';
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,3 @@
|
||||||
import { getStorageTabMetadata } from './storage/tab_metadata';
|
import { getStorageTabMetadata } from './storage/tab_metadata';
|
||||||
|
|
||||||
export const usageQuotasTabsMetadata = [getStorageTabMetadata()];
|
export const usageQuotasTabsMetadata = [getStorageTabMetadata()].filter(Boolean);
|
||||||
|
|
|
||||||
|
|
@ -1,26 +1,32 @@
|
||||||
import Vue from 'vue';
|
import Vue from 'vue';
|
||||||
import VueApollo from 'vue-apollo';
|
import { usageQuotasTabsMetadata as groupViewTabsMetadata } from 'ee_else_ce/usage_quotas/group_view_metadata';
|
||||||
import createDefaultClient from '~/lib/graphql';
|
import { usageQuotasTabsMetadata as profileViewTabsMetadata } from 'ee_else_ce/usage_quotas/profile_view_metadata';
|
||||||
import { usageQuotasTabsMetadata } from 'ee_else_ce/usage_quotas/group_view_metadata';
|
|
||||||
import UsageQuotasApp from './components/usage_quotas_app.vue';
|
import UsageQuotasApp from './components/usage_quotas_app.vue';
|
||||||
|
import { GROUP_VIEW_TYPE, PROFILE_VIEW_TYPE } from './constants';
|
||||||
|
|
||||||
Vue.use(VueApollo);
|
const getViewTabs = (viewType) => {
|
||||||
|
if (viewType === GROUP_VIEW_TYPE) {
|
||||||
|
return groupViewTabsMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
const apolloProvider = new VueApollo({
|
if (viewType === PROFILE_VIEW_TYPE) {
|
||||||
defaultClient: createDefaultClient(),
|
return profileViewTabsMetadata;
|
||||||
});
|
}
|
||||||
|
|
||||||
export default () => {
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
export default (viewType) => {
|
||||||
const el = document.querySelector('#js-usage-quotas-view');
|
const el = document.querySelector('#js-usage-quotas-view');
|
||||||
|
const tabs = getViewTabs(viewType);
|
||||||
|
|
||||||
if (!el) return false;
|
if (!el || !tabs) return false;
|
||||||
|
|
||||||
return new Vue({
|
return new Vue({
|
||||||
el,
|
el,
|
||||||
name: 'UsageQuotasView',
|
name: 'UsageQuotasView',
|
||||||
apolloProvider,
|
|
||||||
provide: {
|
provide: {
|
||||||
tabs: usageQuotasTabsMetadata.filter(Boolean),
|
tabs,
|
||||||
},
|
},
|
||||||
render(createElement) {
|
render(createElement) {
|
||||||
return createElement(UsageQuotasApp);
|
return createElement(UsageQuotasApp);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,2 @@
|
||||||
|
// To Be implemented in https://gitlab.com/gitlab-org/gitlab/-/issues/385653
|
||||||
|
export const usageQuotasTabsMetadata = [];
|
||||||
|
|
@ -100,4 +100,5 @@ export const EDITING_MODE_CONTENT_EDITOR = 'contentEditor';
|
||||||
|
|
||||||
export const CLEAR_AUTOSAVE_ENTRY_EVENT = 'markdown_clear_autosave_entry';
|
export const CLEAR_AUTOSAVE_ENTRY_EVENT = 'markdown_clear_autosave_entry';
|
||||||
export const CONTENT_EDITOR_READY_EVENT = 'content_editor_ready';
|
export const CONTENT_EDITOR_READY_EVENT = 'content_editor_ready';
|
||||||
|
export const CONTENT_EDITOR_PASTE = 'content_editor_paste';
|
||||||
export const MARKDOWN_EDITOR_READY_EVENT = 'markdown_editor_ready';
|
export const MARKDOWN_EDITOR_READY_EVENT = 'markdown_editor_ready';
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
@import 'mixins_and_variables_and_functions';
|
@import 'mixins_and_variables_and_functions';
|
||||||
|
|
||||||
// Modeled after projects.scss and groups.scss
|
|
||||||
.organization-row .organization-description p {
|
|
||||||
margin-bottom: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.organization-root-path {
|
.organization-root-path {
|
||||||
max-width: 40vw;
|
max-width: 40vw;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class Admin::ApplicationSettingsController < Admin::ApplicationController
|
||||||
end
|
end
|
||||||
|
|
||||||
format.json do
|
format.json do
|
||||||
Gitlab::UsageDataCounters::ServiceUsageDataCounter.count(:download_payload_click)
|
Gitlab::InternalEvents.track_event('usage_data_download_payload_clicked', user: current_user)
|
||||||
|
|
||||||
render json: Gitlab::Json.dump(prerecorded_service_ping_data)
|
render json: Gitlab::Json.dump(prerecorded_service_ping_data)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -34,10 +34,7 @@ module Organizations
|
||||||
end
|
end
|
||||||
|
|
||||||
def organization_index_app_data
|
def organization_index_app_data
|
||||||
{
|
shared_organization_index_app_data
|
||||||
new_organization_url: new_organization_path,
|
|
||||||
organizations_empty_state_svg_path: image_path('illustrations/empty-state/empty-organizations-md.svg')
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def organization_user_app_data(organization)
|
def organization_user_app_data(organization)
|
||||||
|
|
@ -66,6 +63,10 @@ module Organizations
|
||||||
}.to_json
|
}.to_json
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def admin_organizations_index_app_data
|
||||||
|
shared_organization_index_app_data.to_json
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def shared_groups_and_projects_app_data(organization)
|
def shared_groups_and_projects_app_data(organization)
|
||||||
|
|
@ -89,6 +90,13 @@ module Organizations
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def shared_organization_index_app_data
|
||||||
|
{
|
||||||
|
new_organization_url: new_organization_path,
|
||||||
|
organizations_empty_state_svg_path: image_path('illustrations/empty-state/empty-organizations-md.svg')
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
# See UsersHelper#admin_users_paths for inspiration to this method
|
# See UsersHelper#admin_users_paths for inspiration to this method
|
||||||
def organizations_users_paths
|
def organizations_users_paths
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
- page_title _('Organizations')
|
- page_title _('Organizations')
|
||||||
|
|
||||||
|
#js-admin-organizations-index{ data: { app_data: admin_organizations_index_app_data } }
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,13 @@
|
||||||
|
|
||||||
.row
|
.row
|
||||||
.col-sm-6{ data: { testid: 'group-usage-message' } }
|
.col-sm-6{ data: { testid: 'group-usage-message' } }
|
||||||
%p.text-secondary
|
%p.gl-text-secondary
|
||||||
= safe_format(s_('UsageQuota|Usage of group resources across the projects in the %{strong_start}%{group_name}%{strong_end} group'),
|
= safe_format(s_('UsageQuota|Usage of group resources across the projects in the %{strong_start}%{group_name}%{strong_end} group'),
|
||||||
{ group_name: @group.name },
|
{ group_name: @group.name },
|
||||||
tag_pair(tag.strong, :strong_start, :strong_end))
|
tag_pair(tag.strong, :strong_start, :strong_end))
|
||||||
|
|
||||||
#js-usage-quotas-view
|
#js-usage-quotas-view
|
||||||
.gl-font-lg.gl--flex-center
|
.gl-font-lg.gl--flex-center
|
||||||
%span.mr-1= s_('UsageQuota|Loading Usage Quotas tabs')
|
%span.gl-mr-1= s_('UsageQuota|Loading Usage Quotas tabs')
|
||||||
= render Pajamas::SpinnerComponent.new(inline: true, size: :md)
|
= render Pajamas::SpinnerComponent.new(inline: true, size: :md)
|
||||||
#js-namespace-storage-app{ data: storage_usage_app_data(@group) }
|
#js-namespace-storage-app{ data: storage_usage_app_data(@group) }
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,18 @@
|
||||||
|
---
|
||||||
|
description: Counts Download Payload button clicks
|
||||||
|
category: InternalEventTracking
|
||||||
|
action: usage_data_download_payload_clicked
|
||||||
|
identifiers:
|
||||||
|
- user
|
||||||
|
product_section: analytics
|
||||||
|
product_stage: monitor
|
||||||
|
product_group: analytics_instrumentation
|
||||||
|
milestone: '16.10'
|
||||||
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/146118
|
||||||
|
distributions:
|
||||||
|
- ce
|
||||||
|
- ee
|
||||||
|
tiers:
|
||||||
|
- free
|
||||||
|
- premium
|
||||||
|
- ultimate
|
||||||
|
|
@ -8,11 +8,9 @@ product_group: analytics_instrumentation
|
||||||
value_type: number
|
value_type: number
|
||||||
status: active
|
status: active
|
||||||
time_frame: all
|
time_frame: all
|
||||||
data_source: redis
|
data_source: internal_events
|
||||||
instrumentation_class: RedisMetric
|
events:
|
||||||
options:
|
- name: usage_data_download_payload_clicked
|
||||||
prefix: service_usage_data
|
|
||||||
event: download_payload_click
|
|
||||||
distribution:
|
distribution:
|
||||||
- ce
|
- ce
|
||||||
- ee
|
- ee
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
||||||
description: User mentions in commit messages
|
description: User mentions in commit messages
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19009
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/19009
|
||||||
milestone: '12.6'
|
milestone: '12.6'
|
||||||
gitlab_schema: gitlab_main
|
gitlab_schema: gitlab_main_cell
|
||||||
|
|
|
||||||
|
|
@ -7,4 +7,4 @@ feature_categories:
|
||||||
description: Stores diff notes positions
|
description: Stores diff notes positions
|
||||||
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28113
|
introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/28113
|
||||||
milestone: '13.0'
|
milestone: '13.0'
|
||||||
gitlab_schema: gitlab_main
|
gitlab_schema: gitlab_main_cell
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddOrganizationIdToDependencyListExports < Gitlab::Database::Migration[2.2]
|
||||||
|
milestone '16.10'
|
||||||
|
|
||||||
|
def change
|
||||||
|
add_column :dependency_list_exports, :organization_id, :bigint
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,16 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class IndexOrganizationIdOnDependencyListExports < Gitlab::Database::Migration[2.2]
|
||||||
|
INDEX_NAME = 'index_dependency_list_exports_on_organization_id'
|
||||||
|
|
||||||
|
disable_ddl_transaction!
|
||||||
|
milestone '16.10'
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_concurrent_index :dependency_list_exports, :organization_id, name: INDEX_NAME
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_concurrent_index_by_name :dependency_list_exports, INDEX_NAME
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,17 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddForeignKeyToOrganizationIdOnDependencyListExports < Gitlab::Database::Migration[2.2]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
milestone '16.10'
|
||||||
|
|
||||||
|
def up
|
||||||
|
add_concurrent_foreign_key :dependency_list_exports, :organizations,
|
||||||
|
column: :organization_id,
|
||||||
|
on_delete: :cascade,
|
||||||
|
reverse_lock_order: true
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
remove_foreign_key_if_exists :dependency_list_exports, column: :organization_id
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class UnscheduleOpenAiClearConvosCron < Gitlab::Database::Migration[2.2]
|
||||||
|
milestone '16.10'
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def up
|
||||||
|
# This is to clean up the cron schedule for OpenAi::ClearConversationsWorker
|
||||||
|
# which was removed in
|
||||||
|
# https://gitlab.com/gitlab-org/gitlab/-/commit/8c24e145c14d64c62a5b4f6fe72726140457d9f1#be4e3233708096a83c31a905040cb84cc105703d_780_780
|
||||||
|
Sidekiq::Cron::Job.destroy('open_ai_clear_conversations')
|
||||||
|
|
||||||
|
sidekiq_remove_jobs(job_klasses: %w[OpenAi::ClearConversationsWorker])
|
||||||
|
end
|
||||||
|
|
||||||
|
def down
|
||||||
|
# No-op
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ba88b86b5331d02fa7cfa4416fc2de5dbd451dc1fc03f5c6550f981b91d7ed96
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
d1c427131b7cddcab2891069a03af3c615e6126f3d7a3a5a8e6b30b7f1875d5e
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
0e53c0f6004aad8fee7323e5652dbabc9823561dd73ed017c7bfa34678ff9527
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
f16288a4771fe31dd8e10e3441facc9e79918a4f46f0b8910f5924fd0819b472
|
||||||
|
|
@ -7759,6 +7759,7 @@ CREATE TABLE dependency_list_exports (
|
||||||
group_id bigint,
|
group_id bigint,
|
||||||
pipeline_id bigint,
|
pipeline_id bigint,
|
||||||
export_type smallint DEFAULT 0 NOT NULL,
|
export_type smallint DEFAULT 0 NOT NULL,
|
||||||
|
organization_id bigint,
|
||||||
CONSTRAINT check_fff6fc9b2f CHECK ((char_length(file) <= 255))
|
CONSTRAINT check_fff6fc9b2f CHECK ((char_length(file) <= 255))
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -24751,6 +24752,8 @@ CREATE UNIQUE INDEX index_dep_prox_manifests_on_group_id_file_name_and_status ON
|
||||||
|
|
||||||
CREATE INDEX index_dependency_list_exports_on_group_id ON dependency_list_exports USING btree (group_id);
|
CREATE INDEX index_dependency_list_exports_on_group_id ON dependency_list_exports USING btree (group_id);
|
||||||
|
|
||||||
|
CREATE INDEX index_dependency_list_exports_on_organization_id ON dependency_list_exports USING btree (organization_id);
|
||||||
|
|
||||||
CREATE INDEX index_dependency_list_exports_on_pipeline_id ON dependency_list_exports USING btree (pipeline_id);
|
CREATE INDEX index_dependency_list_exports_on_pipeline_id ON dependency_list_exports USING btree (pipeline_id);
|
||||||
|
|
||||||
CREATE INDEX index_dependency_list_exports_on_project_id ON dependency_list_exports USING btree (project_id);
|
CREATE INDEX index_dependency_list_exports_on_project_id ON dependency_list_exports USING btree (project_id);
|
||||||
|
|
@ -30189,6 +30192,9 @@ ALTER TABLE ONLY sbom_occurrences
|
||||||
ALTER TABLE ONLY issues
|
ALTER TABLE ONLY issues
|
||||||
ADD CONSTRAINT fk_c34dd2b036 FOREIGN KEY (tmp_epic_id) REFERENCES epics(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_c34dd2b036 FOREIGN KEY (tmp_epic_id) REFERENCES epics(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
ALTER TABLE ONLY dependency_list_exports
|
||||||
|
ADD CONSTRAINT fk_c348f16f10 FOREIGN KEY (organization_id) REFERENCES organizations(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
ALTER TABLE ONLY user_group_callouts
|
ALTER TABLE ONLY user_group_callouts
|
||||||
ADD CONSTRAINT fk_c366e12ec3 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
ADD CONSTRAINT fk_c366e12ec3 FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
extends: existence
|
extends: existence
|
||||||
message: "Offerings should be comma-separated, without `and`, and must be capitalized. Example: `GitLab.com, Self-managed, GitLab Dedicated`."
|
message: "Offerings should be comma-separated, without `and`, and must be capitalized. Example: `GitLab.com, Self-managed, GitLab Dedicated`."
|
||||||
link: https://docs.gitlab.com/ee/development/documentation/styleguide/#available-product-tier-badges
|
link: https://docs.gitlab.com/ee/development/documentation/styleguide/#available-product-tier-badges
|
||||||
level: suggestion
|
level: error
|
||||||
scope: raw
|
scope: raw
|
||||||
raw:
|
raw:
|
||||||
- (?<=\n\*\*Offering:\*\* )(Dedicated|[^\n]*(SaaS|self-managed|Self-Managed|GitLab dedicated|and|GitLab Dedicated,|, GitLab\.com|, Dedicated))
|
- (?<=\n\*\*Offering:\*\* )(Dedicated|[^\n]*(SaaS|self-managed|Self-Managed|GitLab dedicated|and|GitLab Dedicated,|, GitLab\.com|, Dedicated))
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,22 @@ self-managed instances. If you are an administrator, to access the Admin Area:
|
||||||
NOTE:
|
NOTE:
|
||||||
Only administrators can access the Admin Area.
|
Only administrators can access the Admin Area.
|
||||||
|
|
||||||
|
## Administering organizations
|
||||||
|
|
||||||
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/419540) in GitLab 16.10 [with a flag](feature_flags.md) named `ui_for_organizations`. Disabled by default.
|
||||||
|
|
||||||
|
FLAG:
|
||||||
|
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](feature_flags.md) named `ui_for_organizations`.
|
||||||
|
On GitLab.com and GitLab Dedicated, this feature is not available.
|
||||||
|
This feature is not ready for production use.
|
||||||
|
|
||||||
|
You can administer all organizations in the GitLab instance from the Admin Area's Organizations page.
|
||||||
|
|
||||||
|
To access the Organizations page:
|
||||||
|
|
||||||
|
1. On the left sidebar, at the bottom, select **Admin Area**.
|
||||||
|
1. Select **Overview > Organizations**.
|
||||||
|
|
||||||
## Administering projects
|
## Administering projects
|
||||||
|
|
||||||
You can administer all projects in the GitLab instance from the Admin Area's Projects page.
|
You can administer all projects in the GitLab instance from the Admin Area's Projects page.
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,12 @@ NOTE:
|
||||||
Audit event types with the `-` scope are limited to either project, group, or instance and user audit events, but the
|
Audit event types with the `-` scope are limited to either project, group, or instance and user audit events, but the
|
||||||
[information on the scope](https://gitlab.com/gitlab-org/gitlab/-/issues/438620) is still being added to the documentation.
|
[information on the scope](https://gitlab.com/gitlab-org/gitlab/-/issues/438620) is still being added to the documentation.
|
||||||
|
|
||||||
|
### Ai framework
|
||||||
|
|
||||||
|
| Name | Description | Saved to database | Streamed | Introduced in | Scope |
|
||||||
|
|:------------|:------------|:------------------|:---------|:--------------|:--------------|
|
||||||
|
| [`duo_features_enabled_updated`](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/145509) | GitLab Duo Features enabled setting on group or project changed| **{check-circle}** Yes | **{check-circle}** Yes | GitLab [16.10](https://gitlab.com/gitlab-org/gitlab/-/issues/442485) | Group, Project |
|
||||||
|
|
||||||
### Audit events
|
### Audit events
|
||||||
|
|
||||||
| Name | Description | Saved to database | Streamed | Introduced in | Scope |
|
| Name | Description | Saved to database | Streamed | Introduced in | Scope |
|
||||||
|
|
|
||||||
|
|
@ -15126,7 +15126,6 @@ Represents the approval policy.
|
||||||
| <a id="approvalpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
| <a id="approvalpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||||
| <a id="approvalpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
|
| <a id="approvalpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
|
||||||
| <a id="approvalpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
| <a id="approvalpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||||
| <a id="approvalpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
|
||||||
| <a id="approvalpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
|
| <a id="approvalpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
|
||||||
| <a id="approvalpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
| <a id="approvalpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
||||||
| <a id="approvalpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
| <a id="approvalpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||||
|
|
@ -25211,16 +25210,6 @@ Represents vulnerability finding of a security report on the pipeline.
|
||||||
| <a id="policyapprovalgroupid"></a>`id` | [`ID!`](#id) | ID of the namespace. |
|
| <a id="policyapprovalgroupid"></a>`id` | [`ID!`](#id) | ID of the namespace. |
|
||||||
| <a id="policyapprovalgroupweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the group. |
|
| <a id="policyapprovalgroupweburl"></a>`webUrl` | [`String!`](#string) | Web URL of the group. |
|
||||||
|
|
||||||
### `PolicyScope`
|
|
||||||
|
|
||||||
#### Fields
|
|
||||||
|
|
||||||
| Name | Type | Description |
|
|
||||||
| ---- | ---- | ----------- |
|
|
||||||
| <a id="policyscopecomplianceframeworks"></a>`complianceFrameworks` | [`ComplianceFrameworkConnection!`](#complianceframeworkconnection) | Compliance Frameworks linked to the policy. (see [Connections](#connections)) |
|
|
||||||
| <a id="policyscopeexcludingprojects"></a>`excludingProjects` | [`ProjectConnection!`](#projectconnection) | Projects to which the policy should not be applied to. (see [Connections](#connections)) |
|
|
||||||
| <a id="policyscopeincludingprojects"></a>`includingProjects` | [`ProjectConnection!`](#projectconnection) | Projects to which the policy should be applied to. (see [Connections](#connections)) |
|
|
||||||
|
|
||||||
### `PreviewBillableUserChange`
|
### `PreviewBillableUserChange`
|
||||||
|
|
||||||
#### Fields
|
#### Fields
|
||||||
|
|
@ -27942,7 +27931,6 @@ Represents the scan execution policy.
|
||||||
| <a id="scanexecutionpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
|
| <a id="scanexecutionpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
|
||||||
| <a id="scanexecutionpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
| <a id="scanexecutionpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||||
| <a id="scanexecutionpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
| <a id="scanexecutionpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||||
| <a id="scanexecutionpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
|
||||||
| <a id="scanexecutionpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
| <a id="scanexecutionpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
||||||
| <a id="scanexecutionpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
| <a id="scanexecutionpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||||
| <a id="scanexecutionpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
|
| <a id="scanexecutionpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
|
||||||
|
|
@ -27961,7 +27949,6 @@ Represents the scan result policy.
|
||||||
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
| <a id="scanresultpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||||
| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
|
| <a id="scanresultpolicygroupapprovers"></a>`groupApprovers` **{warning-solid}** | [`[Group!]`](#group) | **Deprecated** in GitLab 16.5. Use `allGroupApprovers`. |
|
||||||
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
| <a id="scanresultpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||||
| <a id="scanresultpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
|
||||||
| <a id="scanresultpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
|
| <a id="scanresultpolicyroleapprovers"></a>`roleApprovers` | [`[MemberAccessLevelName!]`](#memberaccesslevelname) | Approvers of the role type. Users belonging to these role(s) alone will be approvers. |
|
||||||
| <a id="scanresultpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
| <a id="scanresultpolicysource"></a>`source` | [`SecurityPolicySource!`](#securitypolicysource) | Source of the policy. Its fields depend on the source type. |
|
||||||
| <a id="scanresultpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
| <a id="scanresultpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||||
|
|
@ -34783,7 +34770,6 @@ Implementations:
|
||||||
| <a id="orchestrationpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
|
| <a id="orchestrationpolicyeditpath"></a>`editPath` | [`String!`](#string) | URL of policy edit page. |
|
||||||
| <a id="orchestrationpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
| <a id="orchestrationpolicyenabled"></a>`enabled` | [`Boolean!`](#boolean) | Indicates whether this policy is enabled. |
|
||||||
| <a id="orchestrationpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
| <a id="orchestrationpolicyname"></a>`name` | [`String!`](#string) | Name of the policy. |
|
||||||
| <a id="orchestrationpolicypolicyscope"></a>`policyScope` | [`PolicyScope`](#policyscope) | Scope of the policy. |
|
|
||||||
| <a id="orchestrationpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
| <a id="orchestrationpolicyupdatedat"></a>`updatedAt` | [`Time!`](#time) | Timestamp of when the policy YAML was last updated. |
|
||||||
| <a id="orchestrationpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
|
| <a id="orchestrationpolicyyaml"></a>`yaml` | [`String!`](#string) | YAML definition of the policy. |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ You must have at least the Maintainer role for the project.
|
||||||
1. On the left sidebar, select **Search or go to** and find your project.
|
1. On the left sidebar, select **Search or go to** and find your project.
|
||||||
1. Select **Settings > Access Tokens**.
|
1. Select **Settings > Access Tokens**.
|
||||||
1. Create an access token with the following scopes: `read_api`, `read_observability`, `write_observability`. Be sure to save the access token value for later.
|
1. Create an access token with the following scopes: `read_api`, `read_observability`, `write_observability`. Be sure to save the access token value for later.
|
||||||
1. Select **Monitor > Tracing**, and then select **Enable**.
|
1. Select **Monitor > Metrics**, and then select **Enable**.
|
||||||
1. To configure your application to send GitLab metrics, set the following environment variables:
|
1. To configure your application to send GitLab metrics, set the following environment variables:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Use CI/CD to build your application
|
# Use CI/CD to build your application
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
Use CI/CD to generate your application.
|
Use CI/CD to generate your application.
|
||||||
|
|
||||||
- [Getting started](../ci/index.md)
|
- [Getting started](../ci/index.md)
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Manage your code
|
# Manage your code
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
Store your source files in a repository and create merge requests. Write, debug, and collaborate on code.
|
Store your source files in a repository and create merge requests. Write, debug, and collaborate on code.
|
||||||
|
|
||||||
- [Repositories](../user/project/repository/index.md)
|
- [Repositories](../user/project/repository/index.md)
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Plan and track work
|
# Plan and track work
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
Plan your work by creating requirements, issues, and epics. Schedule work
|
Plan your work by creating requirements, issues, and epics. Schedule work
|
||||||
with milestones and track your team's time. Learn how to save time with
|
with milestones and track your team's time. Learn how to save time with
|
||||||
quick actions, see how GitLab renders Markdown text, and learn how to
|
quick actions, see how GitLab renders Markdown text, and learn how to
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Deploy and release your application
|
# Deploy and release your application
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
Deployment is the step of the software delivery process when your
|
Deployment is the step of the software delivery process when your
|
||||||
application gets deployed to its final, target infrastructure.
|
application gets deployed to its final, target infrastructure.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Set up your organization
|
# Set up your organization
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
Configure your organization and its users. Determine user roles
|
Configure your organization and its users. Determine user roles
|
||||||
and give everyone access to the projects they need.
|
and give everyone access to the projects they need.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Analyze GitLab usage
|
# Analyze GitLab usage
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
GitLab provides different types of analytics insights at the instance, group, and project level.
|
GitLab provides different types of analytics insights at the instance, group, and project level.
|
||||||
These insights appear on the left sidebar, under [**Analyze**](../project/settings/project_features_permissions.md#disable-project-analytics).
|
These insights appear on the left sidebar, under [**Analyze**](../project/settings/project_features_permissions.md#disable-project-analytics).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Secure your application
|
# Secure your application
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
GitLab can check your applications for security vulnerabilities.
|
GitLab can check your applications for security vulnerabilities.
|
||||||
|
|
||||||
- [Get started](get-started-security.md)
|
- [Get started](get-started-security.md)
|
||||||
|
|
|
||||||
|
|
@ -158,11 +158,11 @@ To see the full list of customizations available, see the Helm chart's [README](
|
||||||
##### Use the agent when KAS is behind a self-signed certificate
|
##### Use the agent when KAS is behind a self-signed certificate
|
||||||
|
|
||||||
When [KAS](../../../../administration/clusters/kas.md) is behind a self-signed certificate,
|
When [KAS](../../../../administration/clusters/kas.md) is behind a self-signed certificate,
|
||||||
you can set the value of `config.caCert` to the certificate. For example:
|
you can set the value of `config.kasCaCert` to the certificate. For example:
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
helm upgrade --install gitlab-agent gitlab/gitlab-agent \
|
helm upgrade --install gitlab-agent gitlab/gitlab-agent \
|
||||||
--set-file config.caCert=my-custom-ca.pem
|
--set-file config.kasCaCert=my-custom-ca.pem
|
||||||
```
|
```
|
||||||
|
|
||||||
In this example, `my-custom-ca.pem` is the path to a local file that contains
|
In this example, `my-custom-ca.pem` is the path to a local file that contains
|
||||||
|
|
|
||||||
|
|
@ -12,23 +12,33 @@ DETAILS:
|
||||||
|
|
||||||
In GitLab, you use groups to manage one or more related projects at the same time.
|
In GitLab, you use groups to manage one or more related projects at the same time.
|
||||||
|
|
||||||
You can use groups to manage permissions for your projects. If someone has access to
|
You can use groups to communicate with all group members and manage permissions for your projects.
|
||||||
the group, they get access to all the projects in the group.
|
If someone has access to the group, they get access to all the projects in the group.
|
||||||
|
|
||||||
You can also view all of the issues and merge requests for the projects in the group,
|
You can also view all of the issues and merge requests for the projects in the group,
|
||||||
and view analytics that show the group's activity.
|
and analytics about the group's activity.
|
||||||
|
|
||||||
You can use groups to communicate with all of the members of the group at once.
|
|
||||||
|
|
||||||
For larger organizations, you can also create [subgroups](subgroups/index.md).
|
For larger organizations, you can also create [subgroups](subgroups/index.md).
|
||||||
|
|
||||||
For more information about creating and managing your groups, see [Manage groups](manage.md).
|
For more information about creating and managing your groups, see [Manage groups](manage.md).
|
||||||
|
|
||||||
|
## Group structure
|
||||||
|
|
||||||
|
The way to set up a group depends on your use cases, team size, and access requirements.
|
||||||
|
The following table describes the most common models of structuring groups.
|
||||||
|
|
||||||
|
| Model | Structure | Use cases |
|
||||||
|
| ----- | --------- | --------- |
|
||||||
|
| Simple | One group for all your projects. | Work in a small team or on specific solutions (for example, a marketing website) that require seamless collaboration and access to resources. |
|
||||||
|
| Team | Different groups or subgroups for different types of teams (for example, product and engineering). | Work in a large organization where some teams work autonomously or require centralized resources and limited access from external team members. |
|
||||||
|
| Client | One group for each client. | Provide custom solutions for multiple clients that require different resources and access levels. |
|
||||||
|
| Functionality | One group or subgroup for one type of functionality (for example, AI/ML). | Develop complex products where one functionality requires specific resources and collaboration of subject-matter experts. |
|
||||||
|
|
||||||
NOTE:
|
NOTE:
|
||||||
For self-managed customers it could be beneficial to create one single top-level group, so you can see an overview of
|
On self-managed GitLab, if you want to see an overview of your entire organization, you should create one top-level group.
|
||||||
your entire organization. For more information about efforts to create an
|
For more information about efforts to create an organization view of all groups,
|
||||||
organization view of all groups, [see epic 9266](https://gitlab.com/groups/gitlab-org/-/epics/9266).
|
[see epic 9266](https://gitlab.com/groups/gitlab-org/-/epics/9266).
|
||||||
A single top-level group provides insights in your entire organization via a complete
|
A single top-level group provides insights in your entire organization through a complete
|
||||||
[Security Dashboard and Center](../application_security/security_dashboard/index.md),
|
[Security Dashboard and Center](../application_security/security_dashboard/index.md),
|
||||||
[Vulnerability](../application_security/vulnerability_report/index.md#vulnerability-report) and
|
[Vulnerability](../application_security/vulnerability_report/index.md#vulnerability-report) and
|
||||||
[Compliance center](../compliance/compliance_center/index.md), and
|
[Compliance center](../compliance/compliance_center/index.md), and
|
||||||
|
|
|
||||||
|
|
@ -9,9 +9,9 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/409913) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `ui_for_organizations`. Disabled by default.
|
> - [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/409913) in GitLab 16.1 [with a flag](../../administration/feature_flags.md) named `ui_for_organizations`. Disabled by default.
|
||||||
|
|
||||||
FLAG:
|
FLAG:
|
||||||
This feature is not ready for production use.
|
|
||||||
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `ui_for_organizations`.
|
On self-managed GitLab, by default this feature is not available. To make it available, an administrator can [enable the feature flag](../../administration/feature_flags.md) named `ui_for_organizations`.
|
||||||
On GitLab.com and GitLab Dedicated, this feature is not available.
|
On GitLab.com and GitLab Dedicated, this feature is not available.
|
||||||
|
This feature is not ready for production use.
|
||||||
|
|
||||||
DISCLAIMER:
|
DISCLAIMER:
|
||||||
This page contains information related to upcoming products, features, and functionality.
|
This page contains information related to upcoming products, features, and functionality.
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,6 @@ info: To determine the technical writer assigned to the Stage/Group associated w
|
||||||
|
|
||||||
# Organize work with projects
|
# Organize work with projects
|
||||||
|
|
||||||
DETAILS:
|
|
||||||
**Tier:** Free, Premium, Ultimate
|
|
||||||
**Offering:** GitLab.com, Self-managed, GitLab Dedicated
|
|
||||||
|
|
||||||
In GitLab, you can create projects to host
|
In GitLab, you can create projects to host
|
||||||
your codebase. You can also use projects to track issues, plan work,
|
your codebase. You can also use projects to track issues, plan work,
|
||||||
collaborate on code, and continuously build, test, and use
|
collaborate on code, and continuously build, test, and use
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
variables:
|
variables:
|
||||||
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.85.0'
|
DAST_AUTO_DEPLOY_IMAGE_VERSION: 'v2.86.0'
|
||||||
|
|
||||||
.dast-auto-deploy:
|
.dast-auto-deploy:
|
||||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
|
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${DAST_AUTO_DEPLOY_IMAGE_VERSION}"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
variables:
|
variables:
|
||||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.85.0'
|
AUTO_DEPLOY_IMAGE_VERSION: 'v2.86.0'
|
||||||
|
|
||||||
.auto-deploy:
|
.auto-deploy:
|
||||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
variables:
|
variables:
|
||||||
AUTO_DEPLOY_IMAGE_VERSION: 'v2.85.0'
|
AUTO_DEPLOY_IMAGE_VERSION: 'v2.86.0'
|
||||||
|
|
||||||
.auto-deploy:
|
.auto-deploy:
|
||||||
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
image: "${CI_TEMPLATE_REGISTRY_HOST}/gitlab-org/cluster-integration/auto-deploy-image:${AUTO_DEPLOY_IMAGE_VERSION}"
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ module Gitlab
|
||||||
state :finished, value: 3
|
state :finished, value: 3
|
||||||
state :failed, value: 4
|
state :failed, value: 4
|
||||||
state :finalizing, value: 5
|
state :finalizing, value: 5
|
||||||
|
state :finalized, value: 6
|
||||||
|
|
||||||
event :pause do
|
event :pause do
|
||||||
transition [:active, :paused] => :paused
|
transition [:active, :paused] => :paused
|
||||||
|
|
@ -79,6 +80,10 @@ module Gitlab
|
||||||
transition any => :finalizing
|
transition any => :finalizing
|
||||||
end
|
end
|
||||||
|
|
||||||
|
event :confirm_finalize do
|
||||||
|
transition [:finalized, :finished] => :finalized
|
||||||
|
end
|
||||||
|
|
||||||
before_transition any => :finished do |migration|
|
before_transition any => :finished do |migration|
|
||||||
migration.finished_at = Time.current if migration.respond_to?(:finished_at)
|
migration.finished_at = Time.current if migration.respond_to?(:finished_at)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -216,11 +216,19 @@ module Gitlab
|
||||||
|
|
||||||
return Gitlab::AppLogger.warn "Could not find batched background migration for the given configuration: #{configuration}" if migration.nil?
|
return Gitlab::AppLogger.warn "Could not find batched background migration for the given configuration: #{configuration}" if migration.nil?
|
||||||
|
|
||||||
return if migration.finished?
|
return if migration.finalized?
|
||||||
|
|
||||||
|
if migration.finished?
|
||||||
|
migration.confirm_finalize!
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
finalize_batched_background_migration(job_class_name: job_class_name, table_name: table_name, column_name: column_name, job_arguments: job_arguments) if finalize
|
finalize_batched_background_migration(job_class_name: job_class_name, table_name: table_name, column_name: column_name, job_arguments: job_arguments) if finalize
|
||||||
|
|
||||||
return if migration.reload.finished? # rubocop:disable Cop/ActiveRecordAssociationReload
|
if migration.reload.finished? # rubocop:disable Cop/ActiveRecordAssociationReload -- TODO: ensure that we have latest version of the batched migration
|
||||||
|
migration.confirm_finalize!
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
raise "Expected batched background migration for the given configuration to be marked as 'finished', " \
|
raise "Expected batched background migration for the given configuration to be marked as 'finished', " \
|
||||||
"but it is '#{migration.status_name}':" \
|
"but it is '#{migration.status_name}':" \
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,6 @@ module Gitlab
|
||||||
KubernetesAgentCounter,
|
KubernetesAgentCounter,
|
||||||
NoteCounter,
|
NoteCounter,
|
||||||
SearchCounter,
|
SearchCounter,
|
||||||
ServiceUsageDataCounter,
|
|
||||||
WebIdeCounter,
|
WebIdeCounter,
|
||||||
WikiPageCounter,
|
WikiPageCounter,
|
||||||
SnippetCounter,
|
SnippetCounter,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
module Gitlab::UsageDataCounters
|
|
||||||
class ServiceUsageDataCounter < BaseCounter
|
|
||||||
KNOWN_EVENTS = %w[download_payload_click].freeze
|
|
||||||
PREFIX = 'service_usage_data'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
@ -7,4 +7,5 @@
|
||||||
# NEW_KEY_2: LEGACY_KEY_2
|
# NEW_KEY_2: LEGACY_KEY_2
|
||||||
# ...
|
# ...
|
||||||
#
|
#
|
||||||
|
'{event_counters}_usage_data_download_payload_clicked': USAGE_SERVICE_USAGE_DATA_DOWNLOAD_PAYLOAD_CLICK
|
||||||
'{event_counters}_web_ide_viewed': WEB_IDE_VIEWS_COUNT
|
'{event_counters}_web_ide_viewed': WEB_IDE_VIEWS_COUNT
|
||||||
|
|
|
||||||
|
|
@ -34800,6 +34800,9 @@ msgstr ""
|
||||||
msgid "Organization|An error occurred deleting the project. Please refresh the page to try again."
|
msgid "Organization|An error occurred deleting the project. Please refresh the page to try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Organization|An error occurred loading organizations. Please refresh the page to try again."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
|
msgid "Organization|An error occurred loading the groups. Please refresh the page to try again."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -42752,6 +42755,9 @@ msgstr ""
|
||||||
msgid "Runners|Available to all projects and subgroups in the group"
|
msgid "Runners|Available to all projects and subgroups in the group"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Runners|Before you begin"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Runners|Can run untagged jobs"
|
msgid "Runners|Can run untagged jobs"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -42868,6 +42874,12 @@ msgstr ""
|
||||||
msgid "Runners|Enable stale runner cleanup?"
|
msgid "Runners|Enable stale runner cleanup?"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Runners|Ensure that %{linkStart}billing is enabled for your Google Cloud project%{linkEnd}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Runners|Ensure you have the %{linkStart}Owner%{linkEnd} IAM role on your Google Cloud project."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Runners|Enter the job timeout in seconds. Must be a minimum of 600 seconds."
|
msgid "Runners|Enter the job timeout in seconds. Must be a minimum of 600 seconds."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
@ -43464,6 +43476,9 @@ msgstr ""
|
||||||
msgid "Runners|This step creates the required infrastructure in Google Cloud, installs GitLab Runner, and registers it to this GitLab project. "
|
msgid "Runners|This step creates the required infrastructure in Google Cloud, installs GitLab Runner, and registers it to this GitLab project. "
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
msgid "Runners|To follow the setup instructions, %{gcloudLinkStart}install the Google Cloud CLI%{gcloudLinkEnd} and %{terraformLinkStart}install Terraform%{terraformLinkEnd}."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
msgid "Runners|To improve security, use a dedicated project for CI/CD, separate from resources and identity management projects. %{linkStart}Where’s my project ID in Google Cloud?%{linkEnd}"
|
msgid "Runners|To improve security, use a dedicated project for CI/CD, separate from resources and identity management projects. %{linkStart}Where’s my project ID in Google Cloud?%{linkEnd}"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -59,7 +59,7 @@
|
||||||
"@gitlab/cluster-client": "^2.1.0",
|
"@gitlab/cluster-client": "^2.1.0",
|
||||||
"@gitlab/favicon-overlay": "2.0.0",
|
"@gitlab/favicon-overlay": "2.0.0",
|
||||||
"@gitlab/fonts": "^1.3.0",
|
"@gitlab/fonts": "^1.3.0",
|
||||||
"@gitlab/svgs": "3.86.0",
|
"@gitlab/svgs": "3.88.0",
|
||||||
"@gitlab/ui": "77.1.0",
|
"@gitlab/ui": "77.1.0",
|
||||||
"@gitlab/visual-review-tools": "1.7.3",
|
"@gitlab/visual-review-tools": "1.7.3",
|
||||||
"@gitlab/web-ide": "^0.0.1-dev-20240226152102",
|
"@gitlab/web-ide": "^0.0.1-dev-20240226152102",
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ gem 'gitlab-qa', '~> 14', '>= 14.2.1', require: 'gitlab/qa'
|
||||||
gem 'gitlab_quality-test_tooling', '~> 1.11.0', require: false
|
gem 'gitlab_quality-test_tooling', '~> 1.11.0', require: false
|
||||||
gem 'gitlab-utils', path: '../gems/gitlab-utils'
|
gem 'gitlab-utils', path: '../gems/gitlab-utils'
|
||||||
gem 'activesupport', '~> 7.0.8.1' # This should stay in sync with the root's Gemfile
|
gem 'activesupport', '~> 7.0.8.1' # This should stay in sync with the root's Gemfile
|
||||||
gem 'allure-rspec', '~> 2.24.0'
|
gem 'allure-rspec', '~> 2.24.1'
|
||||||
gem 'capybara', '~> 3.40.0'
|
gem 'capybara', '~> 3.40.0'
|
||||||
gem 'capybara-screenshot', '~> 1.0.26'
|
gem 'capybara-screenshot', '~> 1.0.26'
|
||||||
gem 'rake', '~> 13', '>= 13.1.0'
|
gem 'rake', '~> 13', '>= 13.1.0'
|
||||||
|
|
|
||||||
|
|
@ -29,10 +29,10 @@ GEM
|
||||||
rack-test (>= 1.1.0, < 2.0)
|
rack-test (>= 1.1.0, < 2.0)
|
||||||
rest-client (>= 2.0.2, < 3.0)
|
rest-client (>= 2.0.2, < 3.0)
|
||||||
rspec (~> 3.8)
|
rspec (~> 3.8)
|
||||||
allure-rspec (2.24.0)
|
allure-rspec (2.24.1)
|
||||||
allure-ruby-commons (= 2.24.0)
|
allure-ruby-commons (= 2.24.1)
|
||||||
rspec-core (>= 3.8, < 4)
|
rspec-core (>= 3.8, < 4)
|
||||||
allure-ruby-commons (2.24.0)
|
allure-ruby-commons (2.24.1)
|
||||||
mime-types (>= 3.3, < 4)
|
mime-types (>= 3.3, < 4)
|
||||||
require_all (>= 2, < 4)
|
require_all (>= 2, < 4)
|
||||||
rspec-expectations (~> 3.12)
|
rspec-expectations (~> 3.12)
|
||||||
|
|
@ -347,7 +347,7 @@ PLATFORMS
|
||||||
DEPENDENCIES
|
DEPENDENCIES
|
||||||
activesupport (~> 7.0.8.1)
|
activesupport (~> 7.0.8.1)
|
||||||
airborne (~> 0.3.7)
|
airborne (~> 0.3.7)
|
||||||
allure-rspec (~> 2.24.0)
|
allure-rspec (~> 2.24.1)
|
||||||
capybara (~> 3.40.0)
|
capybara (~> 3.40.0)
|
||||||
capybara-screenshot (~> 1.0.26)
|
capybara-screenshot (~> 1.0.26)
|
||||||
chemlab (~> 0.11, >= 0.11.1)
|
chemlab (~> 0.11, >= 0.11.1)
|
||||||
|
|
|
||||||
|
|
@ -120,14 +120,21 @@ RSpec.describe Admin::ApplicationSettingsController, :do_not_mock_admin_mode_set
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'usage data counter' do
|
describe 'usage data counter' do
|
||||||
let(:counter) { Gitlab::UsageDataCounters::ServiceUsageDataCounter }
|
it_behaves_like 'internal event tracking' do
|
||||||
|
let(:event) { 'usage_data_download_payload_clicked' }
|
||||||
|
let(:user) { admin }
|
||||||
|
let(:project) { nil }
|
||||||
|
let(:namespace) { nil }
|
||||||
|
|
||||||
it 'incremented when json generated' do
|
subject(:track_event) { get :usage_data, format: :json }
|
||||||
expect { get :usage_data, format: :json }.to change { counter.read(:download_payload_click) }.by(1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'not incremented when html format requested' do
|
context 'with html format requested' do
|
||||||
expect { get :usage_data }.not_to change { counter.read(:download_payload_click) }
|
it 'not incremented when html format requested' do
|
||||||
|
expect(Gitlab::InternalEvents).not_to receive(:track_event)
|
||||||
|
|
||||||
|
get :usage_data, format: :html
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,214 @@
|
||||||
|
import { GlButton } from '@gitlab/ui';
|
||||||
|
import Vue from 'vue';
|
||||||
|
import VueApollo from 'vue-apollo';
|
||||||
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
||||||
|
import waitForPromises from 'helpers/wait_for_promises';
|
||||||
|
import { createAlert } from '~/alert';
|
||||||
|
import { DEFAULT_PER_PAGE } from '~/api';
|
||||||
|
import { organizations as nodes, pageInfo, pageInfoEmpty } from '~/organizations/mock_data';
|
||||||
|
import organizationsQuery from '~/admin/organizations/index/graphql/queries/organizations.query.graphql';
|
||||||
|
import OrganizationsIndexApp from '~/admin/organizations/index/components/app.vue';
|
||||||
|
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||||
|
import { MOCK_NEW_ORG_URL } from 'jest/organizations/shared/mock_data';
|
||||||
|
|
||||||
|
jest.mock('~/alert');
|
||||||
|
|
||||||
|
Vue.use(VueApollo);
|
||||||
|
|
||||||
|
describe('AdminOrganizationsIndexApp', () => {
|
||||||
|
let wrapper;
|
||||||
|
let mockApollo;
|
||||||
|
|
||||||
|
const organizations = {
|
||||||
|
nodes,
|
||||||
|
pageInfo,
|
||||||
|
};
|
||||||
|
|
||||||
|
const organizationEmpty = {
|
||||||
|
nodes: [],
|
||||||
|
pageInfo: pageInfoEmpty,
|
||||||
|
};
|
||||||
|
|
||||||
|
const successHandler = jest.fn().mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
organizations,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const createComponent = (handler = successHandler) => {
|
||||||
|
mockApollo = createMockApollo([[organizationsQuery, handler]]);
|
||||||
|
|
||||||
|
wrapper = shallowMountExtended(OrganizationsIndexApp, {
|
||||||
|
apolloProvider: mockApollo,
|
||||||
|
provide: {
|
||||||
|
newOrganizationUrl: MOCK_NEW_ORG_URL,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
mockApollo = null;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Finders
|
||||||
|
const findOrganizationHeaderText = () => wrapper.findByRole('heading', { name: 'Organizations' });
|
||||||
|
const findNewOrganizationButton = () => wrapper.findComponent(GlButton);
|
||||||
|
const findOrganizationsView = () => wrapper.findComponent(OrganizationsView);
|
||||||
|
|
||||||
|
// Assertions
|
||||||
|
const itRendersHeaderText = () => {
|
||||||
|
it('renders the header text', () => {
|
||||||
|
expect(findOrganizationHeaderText().exists()).toBe(true);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const itRendersNewOrganizationButton = () => {
|
||||||
|
it('render new organization button with correct link', () => {
|
||||||
|
expect(findNewOrganizationButton().attributes('href')).toBe(MOCK_NEW_ORG_URL);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const itDoesNotRenderErrorMessage = () => {
|
||||||
|
it('does not render an error message', () => {
|
||||||
|
expect(createAlert).not.toHaveBeenCalled();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const itDoesNotRenderHeaderText = () => {
|
||||||
|
it('does not render the header text', () => {
|
||||||
|
expect(findOrganizationHeaderText().exists()).toBe(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const itDoesNotRenderNewOrganizationButton = () => {
|
||||||
|
it('does not render new organization button', () => {
|
||||||
|
expect(findNewOrganizationButton().exists()).toBe(false);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
describe('when API call is loading', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
createComponent(jest.fn().mockReturnValue(new Promise(() => {})));
|
||||||
|
});
|
||||||
|
|
||||||
|
itRendersHeaderText();
|
||||||
|
itRendersNewOrganizationButton();
|
||||||
|
itDoesNotRenderErrorMessage();
|
||||||
|
|
||||||
|
it('renders the organizations view with loading prop set to true', () => {
|
||||||
|
expect(findOrganizationsView().props('loading')).toBe(true);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when API call is successful', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
createComponent();
|
||||||
|
await waitForPromises();
|
||||||
|
});
|
||||||
|
|
||||||
|
itRendersHeaderText();
|
||||||
|
itRendersNewOrganizationButton();
|
||||||
|
itDoesNotRenderErrorMessage();
|
||||||
|
|
||||||
|
it('passes organizations to view component', () => {
|
||||||
|
expect(findOrganizationsView().props()).toMatchObject({
|
||||||
|
loading: false,
|
||||||
|
organizations,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when API call is successful and returns no organizations', () => {
|
||||||
|
beforeEach(async () => {
|
||||||
|
createComponent(
|
||||||
|
jest.fn().mockResolvedValue({
|
||||||
|
data: {
|
||||||
|
organizations: organizationEmpty,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
await waitForPromises();
|
||||||
|
});
|
||||||
|
|
||||||
|
itDoesNotRenderHeaderText();
|
||||||
|
itDoesNotRenderNewOrganizationButton();
|
||||||
|
itDoesNotRenderErrorMessage();
|
||||||
|
|
||||||
|
it('renders view component with correct organizations and loading props', () => {
|
||||||
|
expect(findOrganizationsView().props()).toMatchObject({
|
||||||
|
loading: false,
|
||||||
|
organizations: organizationEmpty,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when API call is not successful', () => {
|
||||||
|
const error = new Error();
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
createComponent(jest.fn().mockRejectedValue(error));
|
||||||
|
await waitForPromises();
|
||||||
|
});
|
||||||
|
|
||||||
|
itDoesNotRenderHeaderText();
|
||||||
|
itDoesNotRenderNewOrganizationButton();
|
||||||
|
|
||||||
|
it('renders view component with correct organizations and loading props', () => {
|
||||||
|
expect(findOrganizationsView().props()).toMatchObject({
|
||||||
|
loading: false,
|
||||||
|
organizations: {},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('renders error message', () => {
|
||||||
|
expect(createAlert).toHaveBeenCalledWith({
|
||||||
|
message: 'An error occurred loading organizations. Please refresh the page to try again.',
|
||||||
|
error,
|
||||||
|
captureError: true,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when view component emits `next` event', () => {
|
||||||
|
const endCursor = 'mockEndCursor';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
createComponent();
|
||||||
|
await waitForPromises();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls GraphQL query with correct pageInfo variables', async () => {
|
||||||
|
findOrganizationsView().vm.$emit('next', endCursor);
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(successHandler).toHaveBeenCalledWith({
|
||||||
|
first: DEFAULT_PER_PAGE,
|
||||||
|
after: endCursor,
|
||||||
|
last: null,
|
||||||
|
before: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when view component emits `prev` event', () => {
|
||||||
|
const startCursor = 'mockStartCursor';
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
createComponent();
|
||||||
|
await waitForPromises();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('calls GraphQL query with correct pageInfo variables', async () => {
|
||||||
|
findOrganizationsView().vm.$emit('prev', startCursor);
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(successHandler).toHaveBeenCalledWith({
|
||||||
|
first: null,
|
||||||
|
after: null,
|
||||||
|
last: DEFAULT_PER_PAGE,
|
||||||
|
before: startCursor,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
@ -346,7 +346,7 @@ export const runnerInstallHelpPage = 'https://docs.example.com/runner/install/';
|
||||||
|
|
||||||
export const googleCloudRunnerProvisionResponse = {
|
export const googleCloudRunnerProvisionResponse = {
|
||||||
__typename: 'Project',
|
__typename: 'Project',
|
||||||
id: 'gid://gitlab/Project/23',
|
id: 'gid://gitlab/Project/1',
|
||||||
runnerCloudProvisioning: {
|
runnerCloudProvisioning: {
|
||||||
__typename: 'CiRunnerGoogleCloudProvisioning',
|
__typename: 'CiRunnerGoogleCloudProvisioning',
|
||||||
projectSetupShellScript: '#!/bin/bash echo "hello world!"',
|
projectSetupShellScript: '#!/bin/bash echo "hello world!"',
|
||||||
|
|
@ -355,15 +355,13 @@ export const googleCloudRunnerProvisionResponse = {
|
||||||
__typename: 'CiRunnerCloudProvisioningStep',
|
__typename: 'CiRunnerCloudProvisioningStep',
|
||||||
title: 'Save the Terraform script to a file',
|
title: 'Save the Terraform script to a file',
|
||||||
languageIdentifier: 'terraform',
|
languageIdentifier: 'terraform',
|
||||||
instructions:
|
instructions: 'terraform...',
|
||||||
'terraform {\n required_version = "~> 1.5"\n\n required_providers {\n google = {\n source = "hashicorp/google"\n version = "~> 5.12"\n }\n\n tls = {\n source = "hashicorp/tls"\n version = "~> 4.0"\n }\n }\n}\n\nlocals {\n google_project = "dev-gcp-s3c-integrati-9abafed1"\n google_region = "us-central1"\n google_zone = "us-central1-a"\n}\n\nprovider "google" {\n project = local.google_project\n region = local.google_region\n zone = local.google_zone\n}\n\nvariable "runner_token" {\n type = string\n sensitive = true\n}\n\n# Added available customisation\nmodule "runner-deployment" {\n source = "git::https://gitlab.com/gitlab-org/ci-cd/runner-tools/grit.git//scenarios/google/linux/docker-autoscaler-default"\n\n google_project = local.google_project\n google_region = local.google_region\n google_zone = local.google_zone\n\n name = "grit-BQQkbs5X_"\n\n gitlab_url = "http://gdk.test:3000"\n\n runner_token = var.runner_token\n\n ephemeral_runner = {\n # disk_type = "pd-ssd"\n # disk_size = 50\n machine_type = "n2d-standard-2"\n # source_image = "projects/cos-cloud/global/images/family/cos-stable"\n }\n}\n\noutput "runner-manager-external-ip" {\n value = module.runner-deployment.runner_manager_external_ip\n}\n',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
__typename: 'CiRunnerCloudProvisioningStep',
|
__typename: 'CiRunnerCloudProvisioningStep',
|
||||||
title: 'Apply the Terraform script',
|
title: 'Apply the Terraform script',
|
||||||
languageIdentifier: 'shell',
|
languageIdentifier: 'shell',
|
||||||
instructions:
|
instructions: '#!/bin/bash\n\nterraform plan...',
|
||||||
'#!/bin/bash\n\nterraform plan -var gitlab_runner="glrt-BQQkbs5X_f-ys6wLEy2V" -out plan.out\nterraform apply plan.out\n',
|
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@ import { nextTick } from 'vue';
|
||||||
import MockAdapter from 'axios-mock-adapter';
|
import MockAdapter from 'axios-mock-adapter';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
|
import { CONTENT_EDITOR_PASTE } from '~/vue_shared/constants';
|
||||||
|
import markdownEditorEventHub from '~/vue_shared/components/markdown/eventhub';
|
||||||
import ContentEditor from '~/content_editor/components/content_editor.vue';
|
import ContentEditor from '~/content_editor/components/content_editor.vue';
|
||||||
import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue';
|
import ContentEditorAlert from '~/content_editor/components/content_editor_alert.vue';
|
||||||
import ContentEditorProvider from '~/content_editor/components/content_editor_provider.vue';
|
import ContentEditorProvider from '~/content_editor/components/content_editor_provider.vue';
|
||||||
|
|
@ -17,6 +19,7 @@ import LoadingIndicator from '~/content_editor/components/loading_indicator.vue'
|
||||||
import waitForPromises from 'helpers/wait_for_promises';
|
import waitForPromises from 'helpers/wait_for_promises';
|
||||||
import { KEYDOWN_EVENT } from '~/content_editor/constants';
|
import { KEYDOWN_EVENT } from '~/content_editor/constants';
|
||||||
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
|
import EditorModeSwitcher from '~/vue_shared/components/markdown/editor_mode_switcher.vue';
|
||||||
|
import { mockChainedCommands } from '../test_utils';
|
||||||
|
|
||||||
describe('ContentEditor', () => {
|
describe('ContentEditor', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
@ -290,4 +293,29 @@ describe('ContentEditor', () => {
|
||||||
|
|
||||||
expect(wrapper.findComponent(EditorModeSwitcher).exists()).toBe(true);
|
expect(wrapper.findComponent(EditorModeSwitcher).exists()).toBe(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('pastes content when CONTENT_EDITOR_READY_PASTE event is emitted', async () => {
|
||||||
|
const markdown = 'hello world';
|
||||||
|
|
||||||
|
createWrapper({ markdown });
|
||||||
|
|
||||||
|
renderMarkdown.mockResolvedValueOnce(markdown);
|
||||||
|
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
const editorContent = findEditorContent();
|
||||||
|
const commands = mockChainedCommands(editorContent.props('editor'), [
|
||||||
|
'focus',
|
||||||
|
'pasteContent',
|
||||||
|
'run',
|
||||||
|
]);
|
||||||
|
|
||||||
|
markdownEditorEventHub.$emit(CONTENT_EDITOR_PASTE, 'Paste content');
|
||||||
|
|
||||||
|
await waitForPromises();
|
||||||
|
|
||||||
|
expect(commands.focus).toHaveBeenCalled();
|
||||||
|
expect(commands.pasteContent).toHaveBeenCalledWith('Paste content');
|
||||||
|
expect(commands.run).toHaveBeenCalled();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ import { DEFAULT_PER_PAGE } from '~/api';
|
||||||
import { organizations as nodes, pageInfo, pageInfoEmpty } from '~/organizations/mock_data';
|
import { organizations as nodes, pageInfo, pageInfoEmpty } from '~/organizations/mock_data';
|
||||||
import organizationsQuery from '~/organizations/shared/graphql/queries/organizations.query.graphql';
|
import organizationsQuery from '~/organizations/shared/graphql/queries/organizations.query.graphql';
|
||||||
import OrganizationsIndexApp from '~/organizations/index/components/app.vue';
|
import OrganizationsIndexApp from '~/organizations/index/components/app.vue';
|
||||||
import OrganizationsView from '~/organizations/index/components/organizations_view.vue';
|
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||||
import { MOCK_NEW_ORG_URL } from '../mock_data';
|
import { MOCK_NEW_ORG_URL } from '../../shared/mock_data';
|
||||||
|
|
||||||
jest.mock('~/alert');
|
jest.mock('~/alert');
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { GlAvatarLabeled } from '@gitlab/ui';
|
import { GlAvatarLabeled } from '@gitlab/ui';
|
||||||
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
||||||
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
import { getIdFromGraphQLId } from '~/graphql_shared/utils';
|
||||||
import OrganizationsListItem from '~/organizations/index/components/organizations_list_item.vue';
|
import OrganizationsListItem from '~/organizations/shared/components/list/organizations_list_item.vue';
|
||||||
import { organizations } from '~/organizations/mock_data';
|
import { organizations } from '~/organizations/mock_data';
|
||||||
|
|
||||||
const MOCK_ORGANIZATION = organizations[0];
|
const MOCK_ORGANIZATION = organizations[0];
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { GlKeysetPagination } from '@gitlab/ui';
|
import { GlKeysetPagination } from '@gitlab/ui';
|
||||||
import { omit } from 'lodash';
|
import { omit } from 'lodash';
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import OrganizationsList from '~/organizations/index/components/organizations_list.vue';
|
import OrganizationsList from '~/organizations/shared/components/list/organizations_list.vue';
|
||||||
import OrganizationsListItem from '~/organizations/index/components/organizations_list_item.vue';
|
import OrganizationsListItem from '~/organizations/shared/components/list/organizations_list_item.vue';
|
||||||
import { organizations as nodes, pageInfo, pageInfoOnePage } from '~/organizations/mock_data';
|
import { organizations as nodes, pageInfo, pageInfoOnePage } from '~/organizations/mock_data';
|
||||||
|
|
||||||
describe('OrganizationsList', () => {
|
describe('OrganizationsList', () => {
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
|
import { GlLoadingIcon, GlEmptyState } from '@gitlab/ui';
|
||||||
import { shallowMount } from '@vue/test-utils';
|
import { shallowMount } from '@vue/test-utils';
|
||||||
import { organizations } from '~/organizations/mock_data';
|
import { organizations } from '~/organizations/mock_data';
|
||||||
import OrganizationsView from '~/organizations/index/components/organizations_view.vue';
|
import OrganizationsView from '~/organizations/shared/components/organizations_view.vue';
|
||||||
import OrganizationsList from '~/organizations/index/components/organizations_list.vue';
|
import OrganizationsList from '~/organizations/shared/components/list/organizations_list.vue';
|
||||||
import { MOCK_NEW_ORG_URL, MOCK_ORG_EMPTY_STATE_SVG } from '../mock_data';
|
import { MOCK_NEW_ORG_URL, MOCK_ORG_EMPTY_STATE_SVG } from '../mock_data';
|
||||||
|
|
||||||
describe('OrganizationsView', () => {
|
describe('OrganizationsView', () => {
|
||||||
|
|
@ -302,4 +302,15 @@ RSpec.describe Organizations::OrganizationHelper, feature_category: :cell do
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe '#admin_organizations_index_app_data' do
|
||||||
|
it 'returns expected json' do
|
||||||
|
expect(Gitlab::Json.parse(helper.admin_organizations_index_app_data)).to eq(
|
||||||
|
{
|
||||||
|
'new_organization_url' => new_organization_path,
|
||||||
|
'organizations_empty_state_svg_path' => organizations_empty_state_svg_path
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ RSpec.describe Gitlab::Database::BackgroundMigration::BatchedMigration, type: :m
|
||||||
end
|
end
|
||||||
|
|
||||||
describe '.valid_status' do
|
describe '.valid_status' do
|
||||||
valid_status = [:paused, :active, :finished, :failed, :finalizing]
|
valid_status = [:paused, :active, :finished, :failed, :finalizing, :finalized]
|
||||||
|
|
||||||
it 'returns valid status' do
|
it 'returns valid status' do
|
||||||
expect(described_class.valid_status).to eq(valid_status)
|
expect(described_class.valid_status).to eq(valid_status)
|
||||||
|
|
|
||||||
|
|
@ -533,6 +533,25 @@ RSpec.describe Gitlab::Database::Migrations::BatchedBackgroundMigrationHelpers,
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when the migration is `finished`' do
|
||||||
|
let(:finished_status) { 3 }
|
||||||
|
let(:finalized_status) { 6 }
|
||||||
|
let(:migration_record) { create(:batched_background_migration, :finished) }
|
||||||
|
|
||||||
|
let(:configuration) do
|
||||||
|
{
|
||||||
|
job_class_name: migration_record.job_class_name,
|
||||||
|
table_name: migration_record.table_name,
|
||||||
|
column_name: migration_record.column_name,
|
||||||
|
job_arguments: migration_record.job_arguments
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'updates the status to `finalized`' do
|
||||||
|
expect { ensure_batched_background_migration_is_finished }.to change { migration_record.reload.status }.from(finished_status).to(finalized_status)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when within transaction' do
|
context 'when within transaction' do
|
||||||
before do
|
before do
|
||||||
allow(migration).to receive(:transaction_open?).and_return(true)
|
allow(migration).to receive(:transaction_open?).and_return(true)
|
||||||
|
|
|
||||||
|
|
@ -14,11 +14,14 @@ RSpec.describe Gitlab::UsageDataCounters::RedisCounter, :clean_gitlab_redis_shar
|
||||||
end.to change { subject.total_count(redis_key) }.by(1)
|
end.to change { subject.total_count(redis_key) }.by(1)
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'with aliased legacy key' do
|
context 'for every aliased legacy key' do
|
||||||
let(:redis_key) { '{event_counters}_web_ide_viewed' }
|
let(:key_overrides) { YAML.safe_load(File.read(described_class::KEY_OVERRIDES_PATH)) }
|
||||||
|
|
||||||
it 'counter is increased for a legacy key' do
|
it 'counter is increased for a legacy key' do
|
||||||
expect { subject.increment(redis_key) }.to change { subject.total_count('WEB_IDE_VIEWS_COUNT') }.by(1)
|
key_overrides.each do |alias_key, legacy_key|
|
||||||
|
expect { subject.increment(alias_key) }.to change { subject.total_count(legacy_key) }.by(1),
|
||||||
|
"Incrementing #{alias_key} did not increase #{legacy_key}"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -1,7 +0,0 @@
|
||||||
# frozen_string_literal: true
|
|
||||||
|
|
||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
RSpec.describe Gitlab::UsageDataCounters::ServiceUsageDataCounter do
|
|
||||||
it_behaves_like 'a redis usage counter', 'Service Usage Data', :download_payload_click
|
|
||||||
end
|
|
||||||
|
|
@ -7,7 +7,8 @@ require_migration!
|
||||||
RSpec.describe FinalizeNullifyCreatorIdOfOrphanedProjects, :migration, feature_category: :groups_and_projects do
|
RSpec.describe FinalizeNullifyCreatorIdOfOrphanedProjects, :migration, feature_category: :groups_and_projects do
|
||||||
let(:batched_migrations) { table(:batched_background_migrations) }
|
let(:batched_migrations) { table(:batched_background_migrations) }
|
||||||
let(:batch_failed_status) { 2 }
|
let(:batch_failed_status) { 2 }
|
||||||
let(:batch_finalized_status) { 3 }
|
let(:batch_finalized_status) { 6 }
|
||||||
|
let(:job_finished_status) { 3 }
|
||||||
|
|
||||||
let!(:migration) { described_class::MIGRATION }
|
let!(:migration) { described_class::MIGRATION }
|
||||||
|
|
||||||
|
|
@ -19,8 +20,8 @@ RSpec.describe FinalizeNullifyCreatorIdOfOrphanedProjects, :migration, feature_c
|
||||||
|
|
||||||
migration_record.reload
|
migration_record.reload
|
||||||
failed_job.reload
|
failed_job.reload
|
||||||
end.to change { migration_record.status }.from(migration_record.status).to(3).and(
|
end.to change { migration_record.status }.from(migration_record.status).to(batch_finalized_status).and(
|
||||||
change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status)
|
change { failed_job.status }.from(batch_failed_status).to(job_finished_status)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,8 @@ require_migration!
|
||||||
RSpec.describe FinalizeEncryptCiTriggerToken, migration: :gitlab_ci, feature_category: :continuous_integration do
|
RSpec.describe FinalizeEncryptCiTriggerToken, migration: :gitlab_ci, feature_category: :continuous_integration do
|
||||||
let(:batched_migrations) { table(:batched_background_migrations) }
|
let(:batched_migrations) { table(:batched_background_migrations) }
|
||||||
let(:batch_failed_status) { 2 }
|
let(:batch_failed_status) { 2 }
|
||||||
let(:batch_finalized_status) { 3 }
|
let(:batch_finalized_status) { 6 }
|
||||||
|
let(:job_finished_status) { 3 }
|
||||||
|
|
||||||
let!(:migration) { described_class::MIGRATION }
|
let!(:migration) { described_class::MIGRATION }
|
||||||
|
|
||||||
|
|
@ -85,7 +86,7 @@ RSpec.describe FinalizeEncryptCiTriggerToken, migration: :gitlab_ci, feature_cat
|
||||||
end.to(
|
end.to(
|
||||||
change { migration_record.status }.from(status).to(batch_finalized_status)
|
change { migration_record.status }.from(status).to(batch_finalized_status)
|
||||||
.and(
|
.and(
|
||||||
change { failed_job.status }.from(batch_failed_status).to(batch_finalized_status)
|
change { failed_job.status }.from(batch_failed_status).to(job_finished_status)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ RSpec.describe EnsureIncidentWorkItemTypeBackfillIsFinished, :migration, feature
|
||||||
let(:batched_migrations) { table(:batched_background_migrations) }
|
let(:batched_migrations) { table(:batched_background_migrations) }
|
||||||
let(:work_item_types) { table(:work_item_types) }
|
let(:work_item_types) { table(:work_item_types) }
|
||||||
let(:batch_failed_status) { 2 }
|
let(:batch_failed_status) { 2 }
|
||||||
|
let(:batch_finalized_status) { 6 }
|
||||||
|
|
||||||
let!(:migration_class) { described_class::MIGRATION }
|
let!(:migration_class) { described_class::MIGRATION }
|
||||||
|
|
||||||
|
|
@ -68,7 +69,7 @@ RSpec.describe EnsureIncidentWorkItemTypeBackfillIsFinished, :migration, feature
|
||||||
migrate!
|
migrate!
|
||||||
|
|
||||||
backfill_migration.reload
|
backfill_migration.reload
|
||||||
end.to change { backfill_migration.status }.from(status).to(3)
|
end.to change { backfill_migration.status }.from(status).to(batch_finalized_status)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -60,7 +60,7 @@ RSpec.describe FinalizeBackfillResourceLinkEvents, feature_category: :team_plann
|
||||||
migrate!
|
migrate!
|
||||||
|
|
||||||
batched_migration.reload
|
batched_migration.reload
|
||||||
end.to change { batched_migration.status }.from(status).to(3)
|
end.to change { batched_migration.status }.from(status).to(6)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
||||||
|
|
@ -6713,7 +6713,6 @@
|
||||||
- './spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb'
|
- './spec/lib/gitlab/usage_data_counters/quick_action_activity_unique_counter_spec.rb'
|
||||||
- './spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb'
|
- './spec/lib/gitlab/usage_data_counters/redis_counter_spec.rb'
|
||||||
- './spec/lib/gitlab/usage_data_counters/search_counter_spec.rb'
|
- './spec/lib/gitlab/usage_data_counters/search_counter_spec.rb'
|
||||||
- './spec/lib/gitlab/usage_data_counters/service_usage_data_counter_spec.rb'
|
|
||||||
- './spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb'
|
- './spec/lib/gitlab/usage_data_counters/snippet_counter_spec.rb'
|
||||||
- './spec/lib/gitlab/usage_data_counters/source_code_counter_spec.rb'
|
- './spec/lib/gitlab/usage_data_counters/source_code_counter_spec.rb'
|
||||||
- './spec/lib/gitlab/usage_data_counters_spec.rb'
|
- './spec/lib/gitlab/usage_data_counters_spec.rb'
|
||||||
|
|
|
||||||
|
|
@ -1321,10 +1321,10 @@
|
||||||
stylelint-declaration-strict-value "1.10.4"
|
stylelint-declaration-strict-value "1.10.4"
|
||||||
stylelint-scss "6.0.0"
|
stylelint-scss "6.0.0"
|
||||||
|
|
||||||
"@gitlab/svgs@3.86.0":
|
"@gitlab/svgs@3.88.0":
|
||||||
version "3.86.0"
|
version "3.88.0"
|
||||||
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.86.0.tgz#d6546231fc3b1a7ac24dd0cfe9b6f7facf7f3bff"
|
resolved "https://registry.yarnpkg.com/@gitlab/svgs/-/svgs-3.88.0.tgz#f57bd0ea94866038b19d94a2fa815d54f10c2c09"
|
||||||
integrity sha512-+RDeJ6z05AXWAhCHC/4H4CKdw/nQgGIKBph2nsJ7/w0CJldnh/4GO5op8LmVaUVNyHt02AKbSJOnmen1LL+b8A==
|
integrity sha512-j2C+Ddt2LcJTf2hQZZ6sybsiQ/mMnZG4wKmJfM5YjXR5qPVaAUyH+MHnvPGcHnt+tMYr2P52zlcpsQa6WB5xeQ==
|
||||||
|
|
||||||
"@gitlab/ui@77.1.0":
|
"@gitlab/ui@77.1.0":
|
||||||
version "77.1.0"
|
version "77.1.0"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue